From 7b1c275cc2daabf29e2d027ebab3d8d2e5e07b33 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 2 Apr 2019 08:48:35 +0200 Subject: [PATCH 0001/2612] script-updates: add option to ignore global-config changes --- global-config | 3 ++- global-config.changes | 1 + global-functions | 2 +- script-updates | 3 ++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index b57c212..03c9a5c 100644 --- a/global-config +++ b/global-config @@ -6,7 +6,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 3; +:global GlobalConfigVersion 4; # This is used for DNS and backup file. :global Domain "example.com"; @@ -93,6 +93,7 @@ :global ScriptUpdatesIgnore { "global-config" } +:global ScriptUpdatesConfigChangesIgnore false; # Use this for certificate auto-renew :global CertRenewUrl ""; diff --git a/global-config.changes b/global-config.changes index 86a130f..b1fae6e 100644 --- a/global-config.changes +++ b/global-config.changes @@ -6,4 +6,5 @@ 1="moved variables from global-config to global-functions for independence"; 2="variable names became CamelCase to work around scripting issues"; 3="variable for certificate renew passphrase became an array to support multiple passphrases"; + 4="added option to ignore global-config changes"; }; diff --git a/global-functions b/global-functions index 69f2c36..e5dc072 100644 --- a/global-functions +++ b/global-functions @@ -5,7 +5,7 @@ # global functions # expected configuration version -:global ExpectedConfigVersion 3; +:global ExpectedConfigVersion 4; # global variables not to be changed by user :global SentRouterosUpdateNotification "-"; diff --git a/script-updates b/script-updates index d2390db..6ba953c 100644 --- a/script-updates +++ b/script-updates @@ -11,6 +11,7 @@ :global ScriptUpdatesBaseUrl; :global ScriptUpdatesUrlSuffix; :global ScriptUpdatesIgnore; +:global ScriptUpdatesConfigChangesIgnore; :global SendNotification; @@ -77,7 +78,7 @@ } } -:if ($GlobalConfigVersion < $ExpectedConfigVersion) do={ +:if ($ScriptUpdatesConfigChangesIgnore!=true && $GlobalConfigVersion < $ExpectedConfigVersion) do={ :global GlobalConfigChanges; :local ChangeLogCode; :local Changes; From ea73505ecce44ae7dd23ffc7ec16d47f1ee12040 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 3 Apr 2019 08:30:28 +0200 Subject: [PATCH 0002/2612] script-updates: send global-config changes notification just once --- global-functions | 1 + script-updates | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index e5dc072..a4b0f99 100644 --- a/global-functions +++ b/global-functions @@ -8,6 +8,7 @@ :global ExpectedConfigVersion 4; # global variables not to be changed by user +:global SentConfigChangesNotification "-"; :global SentRouterosUpdateNotification "-"; :global SentLteFirmwareUpgradeNotification "-"; :global Identity [ / system identity get name ]; diff --git a/script-updates b/script-updates index 6ba953c..989cbf2 100644 --- a/script-updates +++ b/script-updates @@ -4,9 +4,10 @@ # # update installed scripts from file or url -:global GlobalConfigVersion; :global ExpectedConfigVersion; +:global GlobalConfigVersion; :global Identity; +:global SentConfigChangesNotification; :global ScriptUpdatesFetch; :global ScriptUpdatesBaseUrl; :global ScriptUpdatesUrlSuffix; @@ -78,7 +79,9 @@ } } -:if ($ScriptUpdatesConfigChangesIgnore!=true && $GlobalConfigVersion < $ExpectedConfigVersion) do={ +:if ($ScriptUpdatesConfigChangesIgnore!=true && \ + $SentConfigChangesNotification!=$ExpectedConfigVersion && \ + $GlobalConfigVersion < $ExpectedConfigVersion) do={ :global GlobalConfigChanges; :local ChangeLogCode; :local Changes; @@ -105,4 +108,5 @@ "GlobalConfigVersion (currently " . $GlobalConfigVersion . \ ") to " . $ExpectedConfigVersion . " and re-run global-config.\n\n" . \ "Changes:" . $Changes); + :set SentConfigChangesNotification $ExpectedConfigVersion; } From 27b2fffaaf2529759795b031acea9c8e6980a4ac Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 3 Apr 2019 13:14:09 +0200 Subject: [PATCH 0003/2612] script-updates: clear variable after use --- script-updates | 1 + 1 file changed, 1 insertion(+) diff --git a/script-updates b/script-updates index 989cbf2..9e35e51 100644 --- a/script-updates +++ b/script-updates @@ -101,6 +101,7 @@ :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ :set Changes ( $Changes . "\n * " . $GlobalConfigChanges->[ :tostr $I ] ); } + :set GlobalConfigChanges; $SendNotification "Configuration warning!" \ ("Current configuration on " . $Identity . " is out of date. " . \ From b35c0b8a6f6373201cc9e252a8647935ad54ee19 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 3 Apr 2019 21:30:43 +0200 Subject: [PATCH 0004/2612] always write warnings and errors to log --- check-certificates | 1 + check-routeros-update | 6 ++++-- collect-wireless-mac.capsman | 3 ++- collect-wireless-mac.local | 3 ++- collect-wireless-mac.template | 3 ++- daily-psk-schedule | 6 ++++-- email-backup | 3 ++- packages-update | 6 ++++-- sms-forward | 3 ++- update-tunnelbroker | 3 ++- 10 files changed, 25 insertions(+), 12 deletions(-) diff --git a/check-certificates b/check-certificates index 4c10a52..8315d15 100644 --- a/check-certificates +++ b/check-certificates @@ -30,6 +30,7 @@ :do { :if ([ :len $CertRenewUrl ] = 0) do={ + :log info "No CertRenewUrl given."; :error "No CertRenewUrl given."; } diff --git a/check-routeros-update b/check-routeros-update index ba420da..4d1cf8f 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -22,7 +22,8 @@ :if ([ / system package print count-only where name="wireless" disabled=no ] > 0) do={ :if ([ / interface wireless cap get enabled ] = true && \ [ / caps-man manager get enabled ] = false) do={ - :error "System is managed by CAPsMAN, not checking."; + :log warning "System is managed by CAPsMAN, not checking."; + :error "Warning: See log for details."; } } @@ -64,8 +65,9 @@ } :if ($SentRouterosUpdateNotification = $LatestVersion) do={ - :error ("Already sent the RouterOS update notification for version " . \ + :log info ("Already sent the RouterOS update notification for version " . \ $LatestVersion . "."); + :error "Already sent notification."; } $SendNotification ("RouterOS update notification") \ diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 4e5a7b0..dd27ba6 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -16,7 +16,8 @@ $ScriptLock "collect-wireless-mac.capsman"; :local PlaceBefore [ / caps-man access-list find where comment="--- collected above ---" disabled ]; :if ([ :len $PlaceBefore ] = 0) do={ - :error "Missing disabled access-list entry with comment '--- collected above ---'"; + :log error "Missing disabled access-list entry with comment '--- collected above ---'"; + :error "Error: See log for details."; } :foreach RegTbl in=[ / caps-man registration-table find ] do={ diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 4a4d6e1..a28e2ee 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -16,7 +16,8 @@ $ScriptLock "collect-wireless-mac.local"; :local PlaceBefore [ / interface wireless access-list find where comment="--- collected above ---" disabled ]; :if ([ :len $PlaceBefore ] = 0) do={ - :error "Missing disabled access-list entry with comment '--- collected above ---'"; + :log error "Missing disabled access-list entry with comment '--- collected above ---'"; + :error "Error: See log for details."; } :foreach RegTbl in=[ / interface wireless registration-table find ] do={ diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 2449316..9e06a88 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -17,7 +17,8 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; :local PlaceBefore [ / %PATH% access-list find where comment="--- collected above ---" disabled ]; :if ([ :len $PlaceBefore ] = 0) do={ - :error "Missing disabled access-list entry with comment '--- collected above ---'"; + :log error "Missing disabled access-list entry with comment '--- collected above ---'"; + :error "Error: See log for details."; } :foreach RegTbl in=[ / %PATH% registration-table find ] do={ diff --git a/daily-psk-schedule b/daily-psk-schedule index 2a01bae..bad21a5 100644 --- a/daily-psk-schedule +++ b/daily-psk-schedule @@ -10,11 +10,13 @@ / system scheduler set interval=15s $Scheduler; } else={ :if ([ / tool netwatch get [ find where comment=[ / tool e-mail get address ] ] status ] != "up") do={ - :error "Mail server is not up."; + :log warning "Mail server is not up."; + :error "Warning: See log for details."; } :if ([ / system ntp client get status ] != "synchronized") do={ - :error "Time is not yet synchronized from ntp."; + :log warning "Time is not yet synchronized from ntp."; + :error "Warning: See log for details."; } / system script run [ find where name~"daily-psk\\.(capsman|local)" ]; diff --git a/email-backup b/email-backup index 63e2fbe..e8f8f2b 100644 --- a/email-backup +++ b/email-backup @@ -16,7 +16,8 @@ :if ($BackupSendBinary != true && \ $BackupSendExport != true && \ $BackupCloud != true) do={ - :error ("Configured to send neither backup nor config export."); + :log error ("Configured to send neither backup nor config export."); + :error "Error: See log for details."; } # filename based on identity diff --git a/packages-update b/packages-update index 683e9f8..10b4a45 100644 --- a/packages-update +++ b/packages-update @@ -10,13 +10,15 @@ :local LatestVersion [ / system package update get latest-version ]; :if ($InstalledVersion = $LatestVersion) do={ - :error ("Version " . $LatestVersion . " is already installed."); + :log info ("Version " . $LatestVersion . " is already installed."); + :error "No updates available."; } :foreach Package in=[ / system package find where !bundle ] do={ :local PkgName [ / system package get $Package name ]; if ([ $DownloadPackage $PkgName $LatestVersion ] = false) do={ - :error ("Download for package " . $PkgName . " failed."); + :log error ("Download for package " . $PkgName . " failed."); + :error "Error: See log for details."; } } diff --git a/sms-forward b/sms-forward index f22949f..9850d87 100644 --- a/sms-forward +++ b/sms-forward @@ -10,7 +10,8 @@ # check mail server :if ([ / tool netwatch get [ find where comment=[ / tool e-mail get address ] ] status ] != "up") do={ - :error "Mail server is not up."; + :log warning "Mail server is not up."; + :error "Warning: See log for details."; } :local Allowed [ / tool sms get allowed-number ]; diff --git a/update-tunnelbroker b/update-tunnelbroker index 0460028..4eff911 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -6,7 +6,8 @@ :global CertificateAvailable; :if ([ / ip cloud get ddns-enabled ] != true) do={ - :error "IP cloud DDNS is not enabled."; + :log error "IP cloud DDNS is not enabled."; + :error "Error: See log for details."; } # Get the current ip address from cloud From 228ec7106bd22e4ccca32e1b35ef2f7b70fddf57 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 3 Apr 2019 22:51:15 +0200 Subject: [PATCH 0005/2612] daily-psk: use the template system --- daily-psk.capsman | 2 ++ daily-psk.local | 2 ++ daily-psk.template | 6 ++++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/daily-psk.capsman b/daily-psk.capsman index 2783afa..ff0b658 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -4,6 +4,8 @@ # Michael Gisbers # # update daily PSK (pre shared key) +# +# !! Do not edit this file, it is generated from template! :global Identity; :global DailyPskMatchComment; diff --git a/daily-psk.local b/daily-psk.local index 363765f..1b994fd 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -4,6 +4,8 @@ # Michael Gisbers # # update daily PSK (pre shared key) +# +# !! Do not edit this file, it is generated from template! :global Identity; :global DailyPskMatchComment; diff --git a/daily-psk.template b/daily-psk.template index a9d65f2..2044281 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -4,6 +4,9 @@ # Michael Gisbers # # update daily PSK (pre shared key) +# +# !! This is just a template! Replace '%PATH%' with 'caps-man' +# !! or 'interface wireless'! :global Identity; :global DailyPskMatchComment; @@ -46,8 +49,7 @@ :local Date [ / system clock get date ]; :local NewPsk [ $GeneratePSK $Date ]; -:foreach AccList in=[ / interface wireless access-list find where comment~$DailyPskMatchComment ] do={ -:foreach AccList in=[ / caps-man access-list find where comment~$DailyPskMatchComment ] do={ +:foreach AccList in=[ / %PATH% access-list find where comment~$DailyPskMatchComment ] do={ :local IntName [ / interface wireless access-list get $AccList interface ]; :local Ssid [ / interface wireless get $IntName ssid ]; :local Ssid [ / caps-man access-list get $AccList ssid-regexp ]; From 50279efbdbba484428dec1c030e066d460433344 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 4 Apr 2019 15:27:55 +0200 Subject: [PATCH 0006/2612] ipv6-update: fix with prefix containing section(s) of zeros --- ipv6-update | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ipv6-update b/ipv6-update index f8ad3c1..1b52efc 100644 --- a/ipv6-update +++ b/ipv6-update @@ -23,14 +23,17 @@ if ($OldPrefix != $PdPrefix) do={ :local Suffix [ :pick ($Comment->2) 7 99 ]; :local Prefix [ / ipv6 address get [ find where interface=$IntName from-pool=$Pool global ] address ]; - :local Prefix64 [ :pick $Prefix 0 [ :find $Prefix "::/64" ] ]; + :set Prefix [ :pick $Prefix 0 [ :find $Prefix "::/64" ] ]; + :if ($Prefix~"^[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:") do={ } else={ + :set Prefix ($Prefix . ":"); + } :local Name [ / ip dns static get $Record name ]; :if ([ :len $Name ] = 0) do={ :set Name [ / ip dns static get $Record regex ]; } - :log info ("Updating DNS record for " . $Name . " to " . $Prefix64 . ":" . $Suffix); - / ip dns static set address=($Prefix64 . ":" . $Suffix) $Record; + :log info ("Updating DNS record for " . $Name . " to " . $Prefix . ":" . $Suffix); + / ip dns static set address=($Prefix . ":" . $Suffix) $Record; } } From 15d3e9ea7ba1ed0457277462f409c75a7f4b5171 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 5 Apr 2019 07:56:50 +0200 Subject: [PATCH 0007/2612] global-config: change duplicate word from daily psk --- global-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config b/global-config index 03c9a5c..1084d8e 100644 --- a/global-config +++ b/global-config @@ -54,7 +54,7 @@ "Stale"; "Unusual"; "Useless"; "Various" }; { "Adhesive"; "Amusing"; "Astonishing"; "Frantic"; "Kindhearted"; "Limping"; "Roasted"; "Robust"; - "Staking"; "Thundering"; "Ultra"; "Unusual" }; + "Staking"; "Thundering"; "Ultra"; "Unreal" }; { "Belief"; "Button"; "Curtain"; "Edge"; "Jewel"; "String"; "Whistle" } } From 2e10a80f95274be340ff90979410da239cb67620 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 4 Apr 2019 14:06:44 +0200 Subject: [PATCH 0008/2612] sms-forward: group messages for same sender --- sms-forward | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/sms-forward b/sms-forward index 9850d87..1c50552 100644 --- a/sms-forward +++ b/sms-forward @@ -18,21 +18,32 @@ :local Secret [ / tool sms get secret ]; # forward SMS in a loop -:foreach Sms in=[ / tool sms inbox find ] do={ - :local Message [ / tool sms inbox get $Sms message ]; - :local Phone [ / tool sms inbox get $Sms phone ]; - :local TimeStamp [ / tool sms inbox get $Sms timestamp ]; - :local Type [ / tool sms inbox get $Sms type ]; +:while ([ / tool sms inbox print count-only ] > 0) do={ + :local Phone [ / tool sms inbox get ([ find ]->0) phone ]; + :local Messages ""; + :local Delete [ :toarray "" ]; - :if ($Phone = $Allowed && $Message~("^:cmd " . $Secret . " script ")) do={ - :log debug "Ignoring SMS, which starts a script."; - } else={ + :foreach Sms in=[ / tool sms inbox find where phone=$Phone ] do={ + :local Message [ / tool sms inbox get $Sms message ]; + :local TimeStamp [ / tool sms inbox get $Sms timestamp ]; + :local Type [ / tool sms inbox get $Sms type ]; + + :if ($Phone = $Allowed && $Message~("^:cmd " . $Secret . " script ")) do={ + :log debug "Removing SMS, which started a script."; + / tool sms inbox remove $Sms; + } else={ + :set Messages ($Messages . "\n\nOn " . $TimeStamp . \ + " type " . $Type . ":\n" . $Message); + :set Delete ($Delete, $Sms); + } + } + + :if ([ :len $Messages ] > 0) do={ $SendNotification ("SMS Forwarding") \ - ("A message was received by " . $Identity . ":\n\n" . \ - "Phone: " . $Phone . "\n" . \ - "Timestamp: " . $TimeStamp . "\n" . \ - "Type: " . $Type . "\n\n" . \ - "Message:\n" . $Message); - / tool sms inbox remove $Sms; + ("These message(s) were received by " . $Identity . \ + " from " . $Phone . ":" . $Messages); + :foreach Sms in=$Delete do={ + / tool sms inbox remove $Sms; + } } } From b93d4d40bc946ac31fcdb619343e21717d816e99 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 9 Apr 2019 17:53:48 +0200 Subject: [PATCH 0009/2612] drop deprecated mode= for fetch --- check-certificates | 2 +- daily-psk.capsman | 2 +- daily-psk.local | 2 +- daily-psk.template | 2 +- global-functions | 4 ++-- gps-track | 2 +- update-tunnelbroker | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/check-certificates b/check-certificates index 8315d15..26f17ba 100644 --- a/check-certificates +++ b/check-certificates @@ -34,7 +34,7 @@ :error "No CertRenewUrl given."; } - / tool fetch mode=https check-certificate=yes-without-crl url=($CertRenewUrl . $CommonName . ".pem"); + / tool fetch check-certificate=yes-without-crl ($CertRenewUrl . $CommonName . ".pem"); :foreach PassPhrase in=$CertRenewPass do={ / certificate import file-name=($CommonName . ".pem") passphrase=$PassPhrase; } diff --git a/daily-psk.capsman b/daily-psk.capsman index ff0b658..06c69f8 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -74,7 +74,7 @@ :local Attach "qrcode-daily.png"; :do { - / tool fetch mode=https check-certificate=yes-without-crl \ + / tool fetch check-certificate=yes-without-crl \ $Url dst-path=$Attach; } on-error={ :set Attach ""; diff --git a/daily-psk.local b/daily-psk.local index 1b994fd..8e22e54 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -74,7 +74,7 @@ :local Attach "qrcode-daily.png"; :do { - / tool fetch mode=https check-certificate=yes-without-crl \ + / tool fetch check-certificate=yes-without-crl \ $Url dst-path=$Attach; } on-error={ :set Attach ""; diff --git a/daily-psk.template b/daily-psk.template index 2044281..4cb7cd2 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -80,7 +80,7 @@ :local Attach "qrcode-daily.png"; :do { - / tool fetch mode=https check-certificate=yes-without-crl \ + / tool fetch check-certificate=yes-without-crl \ $Url dst-path=$Attach; } on-error={ :set Attach ""; diff --git a/global-functions b/global-functions index a4b0f99..92d9d57 100644 --- a/global-functions +++ b/global-functions @@ -130,7 +130,7 @@ :do { :local Vendor; $CertificateAvailable "Let's Encrypt Authority X3" "letsencrypt"; - :set Vendor ([ / tool fetch mode=https check-certificate=yes-without-crl \ + :set Vendor ([ / tool fetch check-certificate=yes-without-crl \ ("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data"); :return $Vendor; } on-error={ @@ -176,7 +176,7 @@ $CertificateAvailable "Let's Encrypt Authority X3" "letsencrypt"; :do { - / tool fetch mode=https check-certificate=yes-without-crl \ + / tool fetch check-certificate=yes-without-crl \ ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile) \ dst-path=$PkgDest; } on-error={ diff --git a/gps-track b/gps-track index 3870c60..572d662 100644 --- a/gps-track +++ b/gps-track @@ -13,7 +13,7 @@ if ($Gps->"valid" = true) do={ :set ($Gps->"latitude") [ :pick ($Gps->"latitude") 0 [ :find ($Gps->"latitude") "\00" ] ]; :set ($Gps->"longitude") [ :pick ($Gps->"longitude") 0 [ :find ($Gps->"longitude") "\00" ] ]; - :tool fetch mode=https check-certificate=yes-without-crl \ + :tool fetch check-certificate=yes-without-crl \ $GpsTrackUrl keep-result=no \ http-method=post http-header-field="Content-Type: application/json" \ http-data=("{" . \ diff --git a/update-tunnelbroker b/update-tunnelbroker index 4eff911..f6674b6 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -29,7 +29,7 @@ $CertificateAvailable "Starfield Secure Certificate Authority - G2" "starfield"; :log info ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress); - / tool fetch mode=https check-certificate=yes-without-crl \ + / tool fetch check-certificate=yes-without-crl \ ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Id) \ user=$User password=$Pass keep-result=no; / interface 6to4 set $Interface local-address=$PublicAddress; From c0b73d6e92799dd7d4638863daac1deab5836747 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 Apr 2019 13:56:44 +0200 Subject: [PATCH 0010/2612] check-certificates: just change certificates, no loop --- check-certificates | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/check-certificates b/check-certificates index 26f17ba..308c401 100644 --- a/check-certificates +++ b/check-certificates @@ -43,25 +43,17 @@ :local CertNew [ / certificate find where common-name=$CommonName fingerprint!=$FingerPrint expires-after>3w ]; :local CertNameNew [ / certificate get $CertNew name ]; - :foreach IpService in=[ / ip service find where certificate=$CertName ] do={ - / ip service set $IpService certificate=$CertNameNew; - } + / ip service set certificate=$CertNameNew [ find where certificate=$CertName ]; :do { - :foreach Identity in=[ / ip ipsec identity find where certificate=$CertName ] do={ - / ip ipsec identity set $Identity certificate=$CertNameNew; - } - :foreach Identity in=[ / ip ipsec identity find where remote-certificate=$CertName ] do={ - / ip ipsec identity set $Identity remote-certificate=$CertNameNew; - } + / ip ipsec identity set certificate=$CertNameNew [ find where certificate=$CertName ]; + / ip ipsec identity set remote-certificate=$CertNameNew [ find where remote-certificate=$CertName ]; } on-error={ :log debug ("Setting IPSEC certificates failed. Package 'security' not installed?"); } :do { - :foreach Hotspot in=[ / ip hotspot profile find where ssl-certificate=$CertName ] do={ - / ip hotspot profile set $Hotspot ssl-certificate=$CertNameNew; - } + / ip hotspot profile set ssl-certificate=$CertNameNew [ find where ssl-certificate=$CertName ]; } on-error={ :log debug ("Setting hotspot certificates failed. Package 'hotspot' not installed?"); } From 5beebbe8e89615836760c679aa01c79caa7db798 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 Apr 2019 14:25:56 +0200 Subject: [PATCH 0011/2612] check-certificates: use full path... ... to make sure syntax does not break if package is not installed. --- check-certificates | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/check-certificates b/check-certificates index 308c401..9013151 100644 --- a/check-certificates +++ b/check-certificates @@ -46,14 +46,14 @@ / ip service set certificate=$CertNameNew [ find where certificate=$CertName ]; :do { - / ip ipsec identity set certificate=$CertNameNew [ find where certificate=$CertName ]; - / ip ipsec identity set remote-certificate=$CertNameNew [ find where remote-certificate=$CertName ]; + / ip ipsec identity set certificate=$CertNameNew [ / ip ipsec identity find where certificate=$CertName ]; + / ip ipsec identity set remote-certificate=$CertNameNew [ / ip ipsec identity find where remote-certificate=$CertName ]; } on-error={ :log debug ("Setting IPSEC certificates failed. Package 'security' not installed?"); } :do { - / ip hotspot profile set ssl-certificate=$CertNameNew [ find where ssl-certificate=$CertName ]; + / ip hotspot profile set ssl-certificate=$CertNameNew [ / ip hotspot profile find where ssl-certificate=$CertName ]; } on-error={ :log debug ("Setting hotspot certificates failed. Package 'hotspot' not installed?"); } From e562825bd9580dabdbccb1d1228ea62034e2f65d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 Apr 2019 14:15:41 +0200 Subject: [PATCH 0012/2612] check-certificates: try to fetch PEM and P12 file --- check-certificates | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/check-certificates b/check-certificates index 9013151..b163ba6 100644 --- a/check-certificates +++ b/check-certificates @@ -34,11 +34,17 @@ :error "No CertRenewUrl given."; } - / tool fetch check-certificate=yes-without-crl ($CertRenewUrl . $CommonName . ".pem"); - :foreach PassPhrase in=$CertRenewPass do={ - / certificate import file-name=($CommonName . ".pem") passphrase=$PassPhrase; + :foreach Type in={ ".pem"; ".p12" } do={ + :do { + / tool fetch check-certificate=yes-without-crl ($CertRenewUrl . $CommonName . $Type); + :foreach PassPhrase in=$CertRenewPass do={ + / certificate import file-name=($CommonName . $Type) passphrase=$PassPhrase; + } + / file remove [ find where name=($CommonName . $Type) ]; + } on-error={ + :log debug ("Could not download certificate file " . $CommonName . $Type); + } } - / file remove [ find where name=($CommonName . ".pem") ]; :local CertNew [ / certificate find where common-name=$CommonName fingerprint!=$FingerPrint expires-after>3w ]; :local CertNameNew [ / certificate get $CertNew name ]; From 58c25c8ccaaa9e559f3544b36cfb99af6dcc225e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 Apr 2019 14:47:20 +0200 Subject: [PATCH 0013/2612] check-certificates: add url encoding for certificate download --- check-certificates | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/check-certificates b/check-certificates index b163ba6..16bcd32 100644 --- a/check-certificates +++ b/check-certificates @@ -9,6 +9,7 @@ :global CertRenewPass; :global SendNotification; +:global UrlEncode; :local GetIssuerCN do={ :foreach IssuerI in=$1 do={ @@ -35,14 +36,15 @@ } :foreach Type in={ ".pem"; ".p12" } do={ + :local CertFileName ([ $UrlEncode $CommonName ] . $Type); :do { - / tool fetch check-certificate=yes-without-crl ($CertRenewUrl . $CommonName . $Type); + / tool fetch check-certificate=yes-without-crl ($CertRenewUrl . $CertFileName); :foreach PassPhrase in=$CertRenewPass do={ - / certificate import file-name=($CommonName . $Type) passphrase=$PassPhrase; + / certificate import file-name=$CertFileName passphrase=$PassPhrase; } - / file remove [ find where name=($CommonName . $Type) ]; + / file remove [ find where name=$CertFileName ]; } on-error={ - :log debug ("Could not download certificate file " . $CommonName . $Type); + :log debug ("Could not download certificate file " . $CertFileName); } } From ea94b7598ef20069757a5ced411d2250776560a4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Apr 2019 09:57:20 +0200 Subject: [PATCH 0014/2612] check-certificates: always return a string in $GetIssuerCN --- check-certificates | 1 + 1 file changed, 1 insertion(+) diff --git a/check-certificates b/check-certificates index 16bcd32..4fd90fe 100644 --- a/check-certificates +++ b/check-certificates @@ -17,6 +17,7 @@ :return [ :pick $IssuerI 3 99 ]; } } + :return ""; } :local FormatExpire do={ From 20d7020fe3a2f1e2149fa051526982f9910b67fa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Apr 2019 10:19:46 +0200 Subject: [PATCH 0015/2612] check-certificates: do not send notification for templates --- check-certificates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index 4fd90fe..15e14ea 100644 --- a/check-certificates +++ b/check-certificates @@ -91,7 +91,7 @@ } } -:foreach Cert in=[ / certificate find where !revoked expires-after<2w ] do={ +:foreach Cert in=[ / certificate find where !revoked expires-after<2w fingerprint~"."] do={ :local CertName [ / certificate get $Cert name ]; :local CommonName [ / certificate get $Cert common-name ]; :local FingerPrint [ / certificate get $Cert fingerprint ]; From 5273efda21a7149af1b63b411e14af37e447afcb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Apr 2019 22:22:05 +0200 Subject: [PATCH 0016/2612] check-certificates: make sure fingerprint is a string This makes sure the condition below works for certificate templates, which do not have a fingerprint. --- check-certificates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index 15e14ea..bd1e0ed 100644 --- a/check-certificates +++ b/check-certificates @@ -28,7 +28,7 @@ :foreach Cert in=[ / certificate find where !revoked expires-after<3w ] do={ :local CertName [ / certificate get $Cert name ]; :local CommonName [ / certificate get $Cert common-name ]; - :local FingerPrint [ / certificate get $Cert fingerprint ]; + :local FingerPrint [ :tostr [ / certificate get $Cert fingerprint ] ]; :do { :if ([ :len $CertRenewUrl ] = 0) do={ From 9aac873163051aef8c1f8b5b959e5796a5341e1a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Apr 2019 09:29:43 +0200 Subject: [PATCH 0017/2612] daily-psk-schedule: try to rotate ntp after five minutes uptime --- daily-psk-schedule | 3 +++ 1 file changed, 3 insertions(+) diff --git a/daily-psk-schedule b/daily-psk-schedule index bad21a5..a1a49fa 100644 --- a/daily-psk-schedule +++ b/daily-psk-schedule @@ -15,6 +15,9 @@ } :if ([ / system ntp client get status ] != "synchronized") do={ + :if ([ / system resource get uptime ] > 5m) do={ + / system script run [ find where name="rotate-ntp" ]; + } :log warning "Time is not yet synchronized from ntp."; :error "Warning: See log for details."; } From 7f96e5c9669f30cd22914de7f092d009faddf304 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Apr 2019 10:39:32 +0200 Subject: [PATCH 0018/2612] global-functions: add $WaitForFile, wait for file on fetch The fetch command is asynchronous, the file is not guaranteed to be available when command terminates. I opened an issue at Mikrotik support (Ticket#2019041722004999), their answer: > You should perform a check in a loop. > :delay until file exist > > That can happen also with any configuration not just files. So add a function to wait for a file with given name. I have not seen this with other configuration, though. --- check-certificates | 5 ++++- daily-psk.capsman | 4 +++- daily-psk.local | 4 +++- daily-psk.template | 4 +++- global-functions | 22 ++++++++++++++++++++++ 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/check-certificates b/check-certificates index bd1e0ed..9dd9acb 100644 --- a/check-certificates +++ b/check-certificates @@ -10,6 +10,7 @@ :global SendNotification; :global UrlEncode; +:global WaitForFile; :local GetIssuerCN do={ :foreach IssuerI in=$1 do={ @@ -39,7 +40,9 @@ :foreach Type in={ ".pem"; ".p12" } do={ :local CertFileName ([ $UrlEncode $CommonName ] . $Type); :do { - / tool fetch check-certificate=yes-without-crl ($CertRenewUrl . $CertFileName); + / tool fetch check-certificate=yes-without-crl \ + ($CertRenewUrl . $CertFileName) dst-path=$CertFileName; + $WaitForFile $CertFileName; :foreach PassPhrase in=$CertRenewPass do={ / certificate import file-name=$CertFileName passphrase=$PassPhrase; } diff --git a/daily-psk.capsman b/daily-psk.capsman index 06c69f8..8d562e6 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -9,9 +9,10 @@ :global Identity; :global DailyPskMatchComment; -:global UrlEncode; :global SendNotification; +:global UrlEncode; +:global WaitForFile; :local Seen [ :toarray "" ]; @@ -76,6 +77,7 @@ :do { / tool fetch check-certificate=yes-without-crl \ $Url dst-path=$Attach; + $WaitForFile $Attach; } on-error={ :set Attach ""; } diff --git a/daily-psk.local b/daily-psk.local index 8e22e54..78f7868 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -9,9 +9,10 @@ :global Identity; :global DailyPskMatchComment; -:global UrlEncode; :global SendNotification; +:global UrlEncode; +:global WaitForFile; :local Seen [ :toarray "" ]; @@ -76,6 +77,7 @@ :do { / tool fetch check-certificate=yes-without-crl \ $Url dst-path=$Attach; + $WaitForFile $Attach; } on-error={ :set Attach ""; } diff --git a/daily-psk.template b/daily-psk.template index 4cb7cd2..dfbac13 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -10,9 +10,10 @@ :global Identity; :global DailyPskMatchComment; -:global UrlEncode; :global SendNotification; +:global UrlEncode; +:global WaitForFile; :local Seen [ :toarray "" ]; @@ -82,6 +83,7 @@ :do { / tool fetch check-certificate=yes-without-crl \ $Url dst-path=$Attach; + $WaitForFile $Attach; } on-error={ :set Attach ""; } diff --git a/global-functions b/global-functions index 92d9d57..356a570 100644 --- a/global-functions +++ b/global-functions @@ -68,6 +68,8 @@ :global ScriptUpdatesBaseUrl; :global ScriptUpdatesUrlSuffix; + :global WaitForFile; + :if ([ / certificate print count-only where common-name=$CommonName ] = 0) do={ :log info ("Certificate with CommonName " . $CommonName . \ " not available, downloading and importing."); @@ -76,6 +78,7 @@ ($ScriptUpdatesBaseUrl . "certs/" . \ $FileName . $ScriptUpdatesUrlSuffix) \ dst-path=$FileName; + $WaitForFile $FileName; / certificate import file-name=$FileName passphrase=""; } on-error={ :log warning "Failed imprting certificate!"; @@ -166,6 +169,7 @@ :global CertificateAvailable; :global CleanFilePath; + :global WaitForFile; :if ([ :len $PkgName ] = 0) do={ return false; } :if ([ :len $PkgVer ] = 0) do={ :set PkgVer [ / system package update get installed-version ]; } @@ -179,6 +183,7 @@ / tool fetch check-certificate=yes-without-crl \ ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile) \ dst-path=$PkgDest; + $WaitForFile $PkgDest; } on-error={ / file remove [ find where name=$PkgDest ]; :return false; @@ -196,3 +201,20 @@ :error "Locked." } } + +# wait for file to be available +:global WaitForFile do={ + :global CleanFilePath; + + :local FileName [ $CleanFilePath [ :tostr $1 ] ]; + :local I 0; + + :while ([ file print count-only where name=$FileName ] = 0) do={ + :if ($I > 20) do={ + :return false; + } + :delay 100ms; + :set I ($I + 1); + } + :return true; +} From 42834e9de1a7cdf2b57d41ce9b1e2d11d0089ffc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 30 Apr 2019 16:11:47 +0200 Subject: [PATCH 0019/2612] global-functions: $CertificateAvailable: fetch by CommonName Now that we have a proper $UrlEncode function... Fetch certificates by CommonName. Also remove the PEM after import. --- README.md | 2 +- ...ddy Secure Certificate Authority - G2.pem} | 0 ...ypt.pem => Let's Encrypt Authority X3.pem} | 0 ...eld Secure Certificate Authority - G2.pem} | 0 global-functions | 19 +++++++++++-------- initial-commands | 3 ++- update-tunnelbroker | 2 +- 7 files changed, 15 insertions(+), 11 deletions(-) rename certs/{godaddy.pem => Go Daddy Secure Certificate Authority - G2.pem} (100%) rename certs/{letsencrypt.pem => Let's Encrypt Authority X3.pem} (100%) rename certs/{starfield.pem => Starfield Secure Certificate Authority - G2.pem} (100%) diff --git a/README.md b/README.md index 2b7a009..a739dae 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ download the certificates. If you intend to download the scripts from a different location (for example from github.com) install the corresponding certificate chain. - [admin@MikroTik] > / tool fetch "https://git.eworm.de/cgit.cgi/routeros-scripts/plain/certs/letsencrypt.pem" dst-path="letsencrypt.pem" + [admin@MikroTik] > / tool fetch "https://git.eworm.de/cgit.cgi/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt.pem" status: finished downloaded: 3KiBC-z pause] total: 3KiB diff --git a/certs/godaddy.pem b/certs/Go Daddy Secure Certificate Authority - G2.pem similarity index 100% rename from certs/godaddy.pem rename to certs/Go Daddy Secure Certificate Authority - G2.pem diff --git a/certs/letsencrypt.pem b/certs/Let's Encrypt Authority X3.pem similarity index 100% rename from certs/letsencrypt.pem rename to certs/Let's Encrypt Authority X3.pem diff --git a/certs/starfield.pem b/certs/Starfield Secure Certificate Authority - G2.pem similarity index 100% rename from certs/starfield.pem rename to certs/Starfield Secure Certificate Authority - G2.pem diff --git a/global-functions b/global-functions index 356a570..a629ca6 100644 --- a/global-functions +++ b/global-functions @@ -63,23 +63,26 @@ # check and import required certificates :global CertificateAvailable do={ :local CommonName [ :tostr $1 ]; - :local FileName ([ :tostr $2 ] . ".pem"); :global ScriptUpdatesBaseUrl; :global ScriptUpdatesUrlSuffix; + :global UrlEncode; :global WaitForFile; :if ([ / certificate print count-only where common-name=$CommonName ] = 0) do={ :log info ("Certificate with CommonName " . $CommonName . \ " not available, downloading and importing."); :do { + :local LocalFileName ($CommonName . ".pem"); + :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); / tool fetch check-certificate=yes-without-crl \ ($ScriptUpdatesBaseUrl . "certs/" . \ - $FileName . $ScriptUpdatesUrlSuffix) \ - dst-path=$FileName; - $WaitForFile $FileName; - / certificate import file-name=$FileName passphrase=""; + $UrlFileName . $ScriptUpdatesUrlSuffix) \ + dst-path=$LocalFileName; + $WaitForFile $LocalFileName; + / certificate import file-name=$LocalFileName passphrase=""; + / file remove $LocalFileName; } on-error={ :log warning "Failed imprting certificate!"; } @@ -112,7 +115,7 @@ } :if ([ :len $TelegramTokenId ] > 0 && [ :len $TelegramChatId ] > 0) do={ - $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" "godaddy"; + $CertificateAvailable "Go Daddy Secure Certificate Authority - G2"; :do { / tool fetch check-certificate=yes-without-crl keep-result=no http-method=post \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ @@ -132,7 +135,7 @@ :do { :local Vendor; - $CertificateAvailable "Let's Encrypt Authority X3" "letsencrypt"; + $CertificateAvailable "Let's Encrypt Authority X3"; :set Vendor ([ / tool fetch check-certificate=yes-without-crl \ ("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data"); :return $Vendor; @@ -178,7 +181,7 @@ :local PkgFile ($PkgName . "-" . $PkgVer . "-" . $PkgArch . ".npk"); :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; - $CertificateAvailable "Let's Encrypt Authority X3" "letsencrypt"; + $CertificateAvailable "Let's Encrypt Authority X3"; :do { / tool fetch check-certificate=yes-without-crl \ ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile) \ diff --git a/initial-commands b/initial-commands index c42b001..cc15baf 100644 --- a/initial-commands +++ b/initial-commands @@ -3,7 +3,7 @@ # Copyright (c) 2018-2019 Christian Hesse { - / tool fetch "https://git.eworm.de/cgit.cgi/routeros-scripts/plain/certs/letsencrypt.pem" dst-path="letsencrypt.pem"; + / tool fetch "https://git.eworm.de/cgit.cgi/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt.pem"; :delay 1s; / certificate { import file-name=letsencrypt.pem passphrase=""; @@ -14,6 +14,7 @@ :if ([ / certificate print count-only where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] != 3) do={ :error "Anything is wrong with your certificates!"; } + / file remove "letsencrypt.pem"; :foreach Script in={ "global-config"; "global-functions"; "script-updates" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit.cgi/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } diff --git a/update-tunnelbroker b/update-tunnelbroker index f6674b6..7d0fc35 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -27,7 +27,7 @@ :local Pass [ :pick ($Comment->2) 5 99 ]; :local Id [ :pick ($Comment->3) 3 99 ]; - $CertificateAvailable "Starfield Secure Certificate Authority - G2" "starfield"; + $CertificateAvailable "Starfield Secure Certificate Authority - G2"; :log info ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress); / tool fetch check-certificate=yes-without-crl \ ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Id) \ From 360d30bf2adf91542b041489a5b71ac33daa1ac9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 May 2019 11:12:44 +0200 Subject: [PATCH 0020/2612] check-certificates: give issuer info on locally issued certificates Certificates issued locally do not have an 'issuer' property, but a 'ca' one. Looks like either of both is filled, so just concatenate. --- check-certificates | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index 9dd9acb..0d0ea55 100644 --- a/check-certificates +++ b/check-certificates @@ -98,6 +98,7 @@ :local CertName [ / certificate get $Cert name ]; :local CommonName [ / certificate get $Cert common-name ]; :local FingerPrint [ / certificate get $Cert fingerprint ]; + :local Ca [ / certificate get $Cert ca ]; :local Issuer [ $GetIssuerCN [ / certificate get $Cert issuer ] ]; :local InvalidBefore [ / certificate get $Cert invalid-before ]; :local InvalidAfter [ / certificate get $Cert invalid-after ]; @@ -114,7 +115,7 @@ "Name: " . $CertName . "\n" . \ "CommonName: " . $CommonName . "\n" . \ "Fingerprint: " . $FingerPrint . "\n" . \ - "Issuer: " . $Issuer . "\n" . \ + "Issuer: " . $Ca . $Issuer . "\n" . \ "Validity: " . $InvalidBefore . " to " . $InvalidAfter . "\n" . \ "Expires in: " . $ExpiresAfter); :log warning ("The certificate " . $CertName . " " . $State . \ From b7592f6b1824e12e5856d726547802ea336359db Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 May 2019 11:59:43 +0200 Subject: [PATCH 0021/2612] check-certificates: do not try to renew locally issued certificates --- check-certificates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index 0d0ea55..603d7f2 100644 --- a/check-certificates +++ b/check-certificates @@ -26,7 +26,7 @@ :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; } -:foreach Cert in=[ / certificate find where !revoked expires-after<3w ] do={ +:foreach Cert in=[ / certificate find where !revoked !ca expires-after<3w ] do={ :local CertName [ / certificate get $Cert name ]; :local CommonName [ / certificate get $Cert common-name ]; :local FingerPrint [ :tostr [ / certificate get $Cert fingerprint ] ]; From a1bad3c0aaff664c243ef2596cdbcdc59cc306d5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 May 2019 21:20:44 +0200 Subject: [PATCH 0022/2612] email-backup: make sure to act on first cloud backup --- email-backup | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/email-backup b/email-backup index e8f8f2b..5fe4684 100644 --- a/email-backup +++ b/email-backup @@ -52,10 +52,10 @@ # required to fetch information from cloud / system backup cloud print as-value; :if ([ / system backup cloud print count-only ] > 0) do={ - / system backup cloud remove-file [ find ]; + / system backup cloud remove-file ([ find ]->0); } / system backup cloud upload-file action=upload src-file=($FileName . ".backup"); - :set CloudStatus [ / system backup cloud get [ find ] secret-download-key ]; + :set CloudStatus [ / system backup cloud get ([ find ]->0) secret-download-key ]; } on-error={ :set CloudStatus "failed"; } From 6b603b1e0ede8fe8d9fef80099b9d1c26c9d2ff0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 May 2019 22:07:09 +0200 Subject: [PATCH 0023/2612] gps-track: make workaround conditional This is fixed in 6.45rc42. --- gps-track | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/gps-track b/gps-track index 572d662..03c551c 100644 --- a/gps-track +++ b/gps-track @@ -11,8 +11,13 @@ :local Gps [ / system gps monitor once as-value ]; if ($Gps->"valid" = true) do={ - :set ($Gps->"latitude") [ :pick ($Gps->"latitude") 0 [ :find ($Gps->"latitude") "\00" ] ]; - :set ($Gps->"longitude") [ :pick ($Gps->"longitude") 0 [ :find ($Gps->"longitude") "\00" ] ]; + # TODO: remove workaround when trailing zero bytes are gone + :if (($Gps->"latitude") ~ "\00") do={ + :set ($Gps->"latitude") [ :pick ($Gps->"latitude") 0 [ :find ($Gps->"latitude") "\00" ] ]; + } + :if (($Gps->"longitude") ~ "\00") do={ + :set ($Gps->"longitude") [ :pick ($Gps->"longitude") 0 [ :find ($Gps->"longitude") "\00" ] ]; + } :tool fetch check-certificate=yes-without-crl \ $GpsTrackUrl keep-result=no \ http-method=post http-header-field="Content-Type: application/json" \ From cf3cd8939802c3a88f931f23af9c61ca120c1824 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 20 May 2019 16:25:36 +0200 Subject: [PATCH 0024/2612] check-certificates: get certificate values into array --- check-certificates | 69 ++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/check-certificates b/check-certificates index 603d7f2..ca5ffe3 100644 --- a/check-certificates +++ b/check-certificates @@ -27,9 +27,7 @@ } :foreach Cert in=[ / certificate find where !revoked !ca expires-after<3w ] do={ - :local CertName [ / certificate get $Cert name ]; - :local CommonName [ / certificate get $Cert common-name ]; - :local FingerPrint [ :tostr [ / certificate get $Cert fingerprint ] ]; + :local CertVal [ / certificate get $Cert ]; :do { :if ([ :len $CertRenewUrl ] = 0) do={ @@ -38,7 +36,7 @@ } :foreach Type in={ ".pem"; ".p12" } do={ - :local CertFileName ([ $UrlEncode $CommonName ] . $Type); + :local CertFileName ([ $UrlEncode ($CertVal->"common-name") ] . $Type); :do { / tool fetch check-certificate=yes-without-crl \ ($CertRenewUrl . $CertFileName) dst-path=$CertFileName; @@ -52,72 +50,59 @@ } } - :local CertNew [ / certificate find where common-name=$CommonName fingerprint!=$FingerPrint expires-after>3w ]; - :local CertNameNew [ / certificate get $CertNew name ]; + :local CertNew [ / certificate find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>3w ]; + :local CertNewVal [ / certificate get $CertNew ]; - / ip service set certificate=$CertNameNew [ find where certificate=$CertName ]; + / ip service set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; :do { - / ip ipsec identity set certificate=$CertNameNew [ / ip ipsec identity find where certificate=$CertName ]; - / ip ipsec identity set remote-certificate=$CertNameNew [ / ip ipsec identity find where remote-certificate=$CertName ]; + / ip ipsec identity set certificate=($CertNewVal->"name") [ / ip ipsec identity find where certificate=($CertVal->"name") ]; + / ip ipsec identity set remote-certificate=($CertNewVal->"name") [ / ip ipsec identity find where remote-certificate=($CertVal->"name") ]; } on-error={ :log debug ("Setting IPSEC certificates failed. Package 'security' not installed?"); } :do { - / ip hotspot profile set ssl-certificate=$CertNameNew [ / ip hotspot profile find where ssl-certificate=$CertName ]; + / ip hotspot profile set ssl-certificate=($CertNewVal->"name") [ / ip hotspot profile find where ssl-certificate=($CertVal->"name") ]; } on-error={ :log debug ("Setting hotspot certificates failed. Package 'hotspot' not installed?"); } / certificate remove $Cert; - / certificate set $CertNew name=$CertName; - - :set CommonName [ / certificate get $CertNew common-name ]; - :set FingerPrint [ / certificate get $CertNew fingerprint ]; - :local Issuer [ $GetIssuerCN [ / certificate get $CertNew issuer ] ]; - :local InvalidBefore [ / certificate get $CertNew invalid-before ]; - :local InvalidAfter [ / certificate get $CertNew invalid-after ]; - :local ExpiresAfter [ $FormatExpire [ / certificate get $CertNew expires-after ] ]; + / certificate set $CertNew name=($CertVal->"name") $SendNotification ("Certificate renewed") \ ("A certificate on " . $Identity . " has been renewed.\n\n" . \ - "Name: " . $CertName . "\n" . \ - "CommonName: " . $CommonName . "\n" . \ - "Fingerprint: " . $FingerPrint . "\n" . \ - "Issuer: " . $Issuer . "\n" . \ - "Validity: " . $InvalidBefore . " to " . $InvalidAfter . "\n" . \ - "Expires in: " . $ExpiresAfter); - :log info ("The certificate " . $CertName . " has been renewed."); + "Name: " . ($CertVal->"name") . "\n" . \ + "CommonName: " . ($CertNewVal->"common-name") . "\n" . \ + "Fingerprint: " . ($CertNewVal->"fingerprint") . "\n" . \ + "Issuer: " . [ $GetIssuerCN ($CertNewVal->"issuer") ] . "\n" . \ + "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ + "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]); + :log info ("The certificate " . ($CertVal->"name") . " has been renewed."); } on-error={ - :log debug ("Could not renew certificate " . $CertName "."); + :log debug ("Could not renew certificate " . ($CertVal->"name") . "."); } } :foreach Cert in=[ / certificate find where !revoked expires-after<2w fingerprint~"."] do={ - :local CertName [ / certificate get $Cert name ]; - :local CommonName [ / certificate get $Cert common-name ]; - :local FingerPrint [ / certificate get $Cert fingerprint ]; - :local Ca [ / certificate get $Cert ca ]; - :local Issuer [ $GetIssuerCN [ / certificate get $Cert issuer ] ]; - :local InvalidBefore [ / certificate get $Cert invalid-before ]; - :local InvalidAfter [ / certificate get $Cert invalid-after ]; + :local CertVal [ / certificate get $Cert ]; - :local ExpiresAfter [ $FormatExpire [ / certificate get $Cert expires-after ] ]; + :local ExpiresAfter [ $FormatExpire ($CertVal->"expires-after") ]; :local State "is about to expire"; - :if ([ / certificate get $Cert expired ] = true) do={ + :if (($CertVal->"expired") = true) do={ :set ExpiresAfter "expired"; :set State "expired"; } $SendNotification ("Certificate warning!") \ ("A certificate on " . $Identity . " " . $State . ".\n\n" . \ - "Name: " . $CertName . "\n" . \ - "CommonName: " . $CommonName . "\n" . \ - "Fingerprint: " . $FingerPrint . "\n" . \ - "Issuer: " . $Ca . $Issuer . "\n" . \ - "Validity: " . $InvalidBefore . " to " . $InvalidAfter . "\n" . \ + "Name: " . ($CertVal->"name") . "\n" . \ + "CommonName: " . ($CertVal->"common-name") . "\n" . \ + "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ + "Issuer: " . ($CertVal->"ca") . [ $GetIssuerCN ($CertVal->"issuer") ] . "\n" . \ + "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ "Expires in: " . $ExpiresAfter); - :log warning ("The certificate " . $CertName . " " . $State . \ - ", it is invalid after " . $InvalidAfter . "."); + :log warning ("The certificate " . ($CertVal->"name") . " " . $State . \ + ", it is invalid after " . ($CertVal->"invalid-after") . "."); } From 0c45102798711fff3d06718c89ecf494ed166ad5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 23 May 2019 12:16:34 +0200 Subject: [PATCH 0025/2612] check-routeros-update: drop literal 'notification' --- check-routeros-update | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index 4d1cf8f..7a57a0e 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -2,7 +2,7 @@ # RouterOS script: check-routeros-update # Copyright (c) 2013-2019 Christian Hesse # -# check for RouterOS update, send notification e-mails +# check for RouterOS update, send notification and/or install :global Identity; :global SafeUpdateUrl; @@ -48,7 +48,7 @@ } :if ($Result->"status" = "finished" && $Result->"data" = $LatestVersion) do={ :log info ("Version " . $LatestVersion . " is considered safe, updating..."); - $SendNotification ("RouterOS update notification") \ + $SendNotification ("RouterOS update") \ ("Version " . $LatestVersion . " is considered safe for " . $Channel . \ ", updating on " . $Identity . "..."); $Update; @@ -70,8 +70,8 @@ :error "Already sent notification."; } - $SendNotification ("RouterOS update notification") \ - ("There is a RouterOS update available\n\n" . \ + $SendNotification ("RouterOS update") \ + ("There is a RouterOS update available.\n\n" . \ "Board name: " . $BoardName . "\n" . \ "Model: " . $Model . "\n" . \ "Serial number: " . $SerialNumber . "\n" . \ From a2e63629672b29903a37225323399071d043829a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 23 May 2019 12:17:02 +0200 Subject: [PATCH 0026/2612] check-lte-firmware-upgrade: drop literal 'notification' --- check-lte-firmware-upgrade | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 5a50733..045d893 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -2,7 +2,7 @@ # RouterOS script: check-lte-firmware-upgrade # Copyright (c) 2018-2019 Christian Hesse # -# check for LTE firmware upgrade, send notification e-mails +# check for LTE firmware upgrade, send notification :global Identity; :global SentLteFirmwareUpgradeNotification; @@ -19,7 +19,7 @@ ($Firmware->"latest") . "."); } else={ :if (($Firmware->"installed") != ($Firmware->"latest")) do={ - $SendNotification ("LTE firmware upgrade notification") \ + $SendNotification ("LTE firmware upgrade") \ ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ "LTE interface " . $IntName . " on " . $Identity . "."); :set SentLteFirmwareUpgradeNotification ($Firmware->"latest"); From fd2901cd45aac85e856b9892e1c8e67a644cd09d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 May 2019 14:26:32 +0200 Subject: [PATCH 0027/2612] daily-psk.capsman: pick only first configuration --- daily-psk.capsman | 2 +- daily-psk.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/daily-psk.capsman b/daily-psk.capsman index 8d562e6..3c2c454 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -51,7 +51,7 @@ :foreach AccList in=[ / caps-man access-list find where comment~$DailyPskMatchComment ] do={ :local Ssid [ / caps-man access-list get $AccList ssid-regexp ]; - :local Configuration [ / caps-man configuration get [ find where ssid=$Ssid ] name ]; + :local Configuration [ / caps-man configuration get ([ find where ssid=$Ssid ]->0) name ]; :local OldPsk [ / caps-man access-list get $AccList private-passphrase ]; :local Skip 0; diff --git a/daily-psk.template b/daily-psk.template index dfbac13..692d8e1 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -54,7 +54,7 @@ :local IntName [ / interface wireless access-list get $AccList interface ]; :local Ssid [ / interface wireless get $IntName ssid ]; :local Ssid [ / caps-man access-list get $AccList ssid-regexp ]; - :local Configuration [ / caps-man configuration get [ find where ssid=$Ssid ] name ]; + :local Configuration [ / caps-man configuration get ([ find where ssid=$Ssid ]->0) name ]; :local OldPsk [ / interface wireless access-list get $AccList private-pre-shared-key ]; :local OldPsk [ / caps-man access-list get $AccList private-passphrase ]; :local Skip 0; From 44836ccf04b098d44b3e3f3a5f9b51b6bf1824fd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 12 Jun 2019 20:34:20 +0200 Subject: [PATCH 0028/2612] mode-button-scheduler: beep for confirmation But be silent if silent-boot is enabled. --- mode-button-scheduler | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mode-button-scheduler b/mode-button-scheduler index bce6089..dfd89da 100644 --- a/mode-button-scheduler +++ b/mode-button-scheduler @@ -14,5 +14,14 @@ / system scheduler remove mode-button-scheduler; :log info ("Acting on " . $Count . " mode-button presses: " . $Code); -:delay 1s; + +:if ([ / system routerboard settings get silent-boot ] = false) do={ + :for I from=1 to=$Count do={ + :beep length=200ms; + :delay 200ms; + } +} else={ + :delay 1s; +} + $Parsed; From 2252058202e66051aa6cd4b6dac6d885da9167e8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 13 Jun 2019 08:14:03 +0200 Subject: [PATCH 0029/2612] daily-psk: add hint about device specific rule I tricked myself several times... If a more device specific (or just earlier matching) rule exists the daily PSK is not applied! --- daily-psk.capsman | 1 + daily-psk.local | 1 + daily-psk.template | 1 + 3 files changed, 3 insertions(+) diff --git a/daily-psk.capsman b/daily-psk.capsman index 3c2c454..51e80f9 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -87,6 +87,7 @@ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ "Date: " . $Date . "\n\n" . \ + "A client device specific rule must not exist!\n\n" . \ $Url) $Attach; } } diff --git a/daily-psk.local b/daily-psk.local index 78f7868..a8b41e1 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -87,6 +87,7 @@ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ "Date: " . $Date . "\n\n" . \ + "A client device specific rule must not exist!\n\n" . \ $Url) $Attach; } } diff --git a/daily-psk.template b/daily-psk.template index 692d8e1..70460ce 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -93,6 +93,7 @@ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ "Date: " . $Date . "\n\n" . \ + "A client device specific rule must not exist!\n\n" . \ $Url) $Attach; } } From 5101d57d52e60a3c10b974217af70166a3145c45 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 14 Jun 2019 14:59:49 +0200 Subject: [PATCH 0030/2612] backup: split off cloud-backup Currently backup to MikroTik cloud is pretty unreliable and script can not catch errors at runtime. Looks like this does not change any time soon (Ticket#2019052022003204). So let's just split off the cloud backup to make sure email backup works as expected. --- cloud-backup | 42 +++++++++++++++++++++++++++++++ email-backup | 57 ++++++++++++------------------------------- global-config | 3 +-- global-config.changes | 1 + global-functions | 2 +- 5 files changed, 61 insertions(+), 44 deletions(-) create mode 100644 cloud-backup diff --git a/cloud-backup b/cloud-backup new file mode 100644 index 0000000..f9e7747 --- /dev/null +++ b/cloud-backup @@ -0,0 +1,42 @@ +#!rsc +# RouterOS script: cloud-backup +# Copyright (c) 2013-2019 Christian Hesse +# +# upload backup to MikroTik cloud + +:global Identity; +:global BackupPassword; + +:global SendNotification; + +# get some system information +:local BoardName [ / system resource get board-name ]; +:local Model [ / system routerboard get model ]; +:local SerialNumber [ / system routerboard get serial-number ]; +:local Channel [ / system package update get channel ]; +:local InstalledVersion [ / system package update get installed-version ]; + +:do { + # we are not interested in output, but print without count-only is + # required to fetch information from cloud + / system backup cloud print as-value; + :if ([ / system backup cloud print count-only ] > 0) do={ + / system backup cloud remove-file ([ find ]->0); + } + / system backup cloud upload-file action=create-and-upload password=$BackupPassword; + :local Cloud [ / system backup cloud get ([ find ]->0) ]; + + $SendNotification "Cloud backup" \ + ("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ + "Board name: " . $BoardName . "\n" . \ + "Model: " . $Model . "\n" . \ + "Serial number: " . $SerialNumber . "\n" . \ + "Hostname: " . $Identity . "\n" . \ + "Channel: " . $Channel . "\n" . \ + "RouterOS: " . $InstalledVersion . "\n\n" . \ + "Name: " . $Cloud->"name" . "\n" . \ + "Size: " . $Cloud->"size" . "\n" . \ + "Download key: " . $Cloud->"secret-download-key"); +} on-error={ + :log error ("Failed uploading backup for " . $Identity . " to cloud."); +} diff --git a/email-backup b/email-backup index 5fe4684..3050afc 100644 --- a/email-backup +++ b/email-backup @@ -10,21 +10,18 @@ :global EmailBackupCc; :global BackupSendBinary; :global BackupSendExport; -:global BackupCloud; :global BackupPassword; :if ($BackupSendBinary != true && \ - $BackupSendExport != true && \ - $BackupCloud != true) do={ + $BackupSendExport != true) do={ :log error ("Configured to send neither backup nor config export."); :error "Error: See log for details."; } # filename based on identity :local FileName ($Identity . "." . $Domain); -:local CloudStatus $BackupCloud; -:local BackupStatus $BackupSendBinary; -:local ConfigStatus $BackupSendExport; +:local BackupFile "none"; +:local ConfigFile "none"; :local Attach [ :toarray "" ]; # get some system information @@ -35,52 +32,30 @@ :local InstalledVersion [ / system package update get installed-version ]; # binary backup -:if ($BackupSendBinary = true || \ - $BackupCloud = true) do={ +:if ($BackupSendBinary = true) do={ / system backup save encryption=aes-sha256 name=$FileName password=$BackupPassword; - - # attach to mail - :if ($BackupSendBinary = true) do={ - :set BackupStatus ($FileName . ".backup"); - :set Attach ($Attach, $BackupStatus); - } - - # upload to cloud - :if ($BackupCloud = true) do={ - :do { - # we are not interested in output, but print without count-only is - # required to fetch information from cloud - / system backup cloud print as-value; - :if ([ / system backup cloud print count-only ] > 0) do={ - / system backup cloud remove-file ([ find ]->0); - } - / system backup cloud upload-file action=upload src-file=($FileName . ".backup"); - :set CloudStatus [ / system backup cloud get ([ find ]->0) secret-download-key ]; - } on-error={ - :set CloudStatus "failed"; - } - } + :set BackupFile ($FileName . ".backup"); + :set Attach ($Attach, $BackupFile); } # create configuration export :if ($BackupSendExport = true) do={ / export terse file=$FileName; - :set ConfigStatus ($FileName . ".rsc"); - :set Attach ($Attach, $ConfigStatus); + :set ConfigFile ($FileName . ".rsc"); + :set Attach ($Attach, $ConfigFile); } # send email with status and files / tool e-mail send to=$EmailBackupTo cc=$EmailBackupCc \ subject=("[" . $Identity . "] Backup & Config") \ body=("Backup and config export for " . $Identity . ".\n\n" . \ - "Board name: " . $BoardName . "\n" . \ - "Model: " . $Model . "\n" . \ - "Serial number: " . $SerialNumber . "\n" . \ - "Hostname: " . $Identity . "\n" . \ - "Channel: " . $Channel . "\n" . \ - "RouterOS: " . $InstalledVersion . "\n\n" . \ - "Backup attached: " . $BackupStatus . "\n" . \ - "Config attached: " . $ConfigStatus . "\n" . \ - "Cloud backup: " . $CloudStatus) \ + "Board name: " . $BoardName . "\n" . \ + "Model: " . $Model . "\n" . \ + "Serial number: " . $SerialNumber . "\n" . \ + "Hostname: " . $Identity . "\n" . \ + "Channel: " . $Channel . "\n" . \ + "RouterOS: " . $InstalledVersion . "\n\n" . \ + "Backup file: " . $BackupFile . "\n" . \ + "Config file: " . $ConfigFile) \ file=$Attach; } diff --git a/global-config b/global-config index 1084d8e..ba6f924 100644 --- a/global-config +++ b/global-config @@ -6,7 +6,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 4; +:global GlobalConfigVersion 5; # This is used for DNS and backup file. :global Domain "example.com"; @@ -30,7 +30,6 @@ # This defines what backups to generate and what password to use. :global BackupSendBinary false; :global BackupSendExport true; -:global BackupCloud false; :global BackupPassword "v3ry-s3cr3t"; # Specify an address to enable auto update to version assumed safe. diff --git a/global-config.changes b/global-config.changes index b1fae6e..f3c4e2b 100644 --- a/global-config.changes +++ b/global-config.changes @@ -7,4 +7,5 @@ 2="variable names became CamelCase to work around scripting issues"; 3="variable for certificate renew passphrase became an array to support multiple passphrases"; 4="added option to ignore global-config changes"; + 5="split off new script cloud-backup from email-backup"; }; diff --git a/global-functions b/global-functions index a629ca6..6522bd8 100644 --- a/global-functions +++ b/global-functions @@ -5,7 +5,7 @@ # global functions # expected configuration version -:global ExpectedConfigVersion 4; +:global ExpectedConfigVersion 5; # global variables not to be changed by user :global SentConfigChangesNotification "-"; From e9cdf947855880c0b7299ed7e2dd1770f71c5cfb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Jun 2019 13:30:36 +0200 Subject: [PATCH 0031/2612] add script 'certificate-renew-issued' --- certificate-renew-issued | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 certificate-renew-issued diff --git a/certificate-renew-issued b/certificate-renew-issued new file mode 100644 index 0000000..e7241f2 --- /dev/null +++ b/certificate-renew-issued @@ -0,0 +1,14 @@ +#!rsc +# RouterOS script: certificate-renew-issued +# Copyright (c) 2019 Christian Hesse +# +# renew locally issued certificates + +: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"); +} From 2f22e06b9b944d5df903f0943d1ea7a87a24493e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 25 Jun 2019 14:32:25 +0200 Subject: [PATCH 0032/2612] gps-track: fix the condition for workaround A null byte is always matched in regexp... --- gps-track | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gps-track b/gps-track index 03c551c..7a78482 100644 --- a/gps-track +++ b/gps-track @@ -12,10 +12,10 @@ if ($Gps->"valid" = true) do={ # TODO: remove workaround when trailing zero bytes are gone - :if (($Gps->"latitude") ~ "\00") do={ + :if ([ :find ($Gps->"latitude") "\00" ] > 0) do={ :set ($Gps->"latitude") [ :pick ($Gps->"latitude") 0 [ :find ($Gps->"latitude") "\00" ] ]; } - :if (($Gps->"longitude") ~ "\00") do={ + :if ([ :find ($Gps->"longitude") "\00" ] > 0) do={ :set ($Gps->"longitude") [ :pick ($Gps->"longitude") 0 [ :find ($Gps->"longitude") "\00" ] ]; } :tool fetch check-certificate=yes-without-crl \ From 9d1a59fd646b867ab30712056682f8c643b2cfd9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 25 Jun 2019 23:06:51 +0200 Subject: [PATCH 0033/2612] bridge-port-to-default: get bridge port values into array --- bridge-port-to-default | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/bridge-port-to-default b/bridge-port-to-default index 1117c1d..4d25513 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -13,18 +13,17 @@ :set Len ([ :len $BridgePortTo ] + 1); } -:foreach Interface in=[ / interface bridge port find where comment!="" ] do={ - :foreach Comment in=[ :toarray [ / interface bridge port get $Interface comment ] ] do={ +:foreach BridgePort in=[ / interface bridge port find where comment!="" ] do={ + :local BridgePortVal [ / interface bridge port get $BridgePort ]; + :foreach Comment in=[ :toarray ($BridgePortVal->"comment") ] do={ :if ([ :pick $Comment 0 $Len ] = ($BridgePortTo . ":")) do={ - :local InterfaceName [ / interface bridge port get $Interface interface ]; :local BridgeDefault [ :pick $Comment $Len [ :len $Comment ] ]; - :local BridgeCurrent [ / interface bridge port get $Interface bridge ]; - :if ($BridgeDefault != $BridgeCurrent) do={ - :log info ("Changing interface " . $InterfaceName . " to " . $BridgePortTo . " bridge " . $BridgeDefault); - / interface bridge port set bridge=$BridgeDefault $Interface; + :if ($BridgeDefault != $BridgePortVal->"bridge") do={ + :log info ("Changing interface " . $BridgePortVal->"interface" . " to " . $BridgePortTo . " bridge " . $BridgeDefault); + / interface bridge port set bridge=$BridgeDefault $BridgePort; / ip dhcp-client renew [ find where interface=$BridgeDefault ]; } else={ - :log debug ("Interface " . $InterfaceName . " already connected to " . $BridgePortTo . " bridge " . $BridgeDefault); + :log debug ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . " bridge " . $BridgeDefault); } } } From 44dd4231cb03f258104083f3ec841d400e3814fa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 25 Jun 2019 23:47:53 +0200 Subject: [PATCH 0034/2612] bridge-port-to-default: handle special value 'dhcp-client'... ... which disables the bridge port, but enables a dhcp client. --- bridge-port-to-default | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/bridge-port-to-default b/bridge-port-to-default index 4d25513..e646b33 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -18,12 +18,24 @@ :foreach Comment in=[ :toarray ($BridgePortVal->"comment") ] do={ :if ([ :pick $Comment 0 $Len ] = ($BridgePortTo . ":")) do={ :local BridgeDefault [ :pick $Comment $Len [ :len $Comment ] ]; - :if ($BridgeDefault != $BridgePortVal->"bridge") do={ - :log info ("Changing interface " . $BridgePortVal->"interface" . " to " . $BridgePortTo . " bridge " . $BridgeDefault); - / interface bridge port set bridge=$BridgeDefault $BridgePort; - / ip dhcp-client renew [ find where interface=$BridgeDefault ]; + :if ($BridgeDefault = "dhcp-client") do={ + :if ($BridgePortVal->"disabled" = false) do={ + :log info ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client."); + / interface bridge port disable $BridgePort; + / ip dhcp-client enable [ find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" disabled=yes ]; + } } else={ - :log debug ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . " bridge " . $BridgeDefault); + :if ($BridgePortVal->"disabled" = true) do={ + :log info ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", disabling dhcp client."); + / ip dhcp-client disable [ find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" disabled=no ]; + / interface bridge port enable $BridgePort; + } + :if ($BridgeDefault != $BridgePortVal->"bridge") do={ + :log info ("Changing interface " . $BridgePortVal->"interface" . " to " . $BridgePortTo . " bridge " . $BridgeDefault); + / interface bridge port set bridge=$BridgeDefault $BridgePort; + } else={ + :log debug ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . " bridge " . $BridgeDefault); + } } } } From 08ef63ddbd4e02ebe978f48412c03d08ab8fc153 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 1 Jul 2019 09:41:00 +0200 Subject: [PATCH 0035/2612] check-routeros-update: link a changelog that opens in browser The old link was delivered with MIME type 'application/octet-stream', browsers wanted to download it as file. --- check-routeros-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-routeros-update b/check-routeros-update index 7a57a0e..104567e 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -79,6 +79,6 @@ "Channel: " . $Channel . "\n" . \ "Installed: " . $InstalledVersion . "\n" . \ "Available: " . $LatestVersion . "\n\n" .\ - "https://upgrade.mikrotik.com/routeros/" . $LatestVersion . "/CHANGELOG"); + "https://mikrotik.com/download/changelogs/" . $Channel . "-release-tree"); :set SentRouterosUpdateNotification $LatestVersion; } From 5d0104f0a702a65befb5ebd9914481a14e28cb2e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 1 Jul 2019 10:21:17 +0200 Subject: [PATCH 0036/2612] update-gre-address: update for latest routeros With RouterOS 6.45 "remote-peers" was renamed to "active-peers": *) ipsec - renamed "remote-peers" to "active-peers"; --- update-gre-address | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/update-gre-address b/update-gre-address index 2964d46..7e70a6d 100644 --- a/update-gre-address +++ b/update-gre-address @@ -7,14 +7,14 @@ / interface gre set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; -:foreach Peer in=[ / ip ipsec remote-peers find ] do={ - :local Id [ / ip ipsec remote-peers get $Peer id ]; +:foreach Peer in=[ / ip ipsec active-peers find ] do={ + :local Id [ / ip ipsec active-peers get $Peer id ]; :local GreInt [ / interface gre find where comment=$Id ]; :if ([ :len $GreInt ] > 0) do={ :local GreName [ / interface gre get $GreInt name ]; :local AddrOld [ / interface gre get $GreInt remote-address ]; :local Disabled [ / interface gre get $GreInt disabled ]; - :local AddrNew [ / ip ipsec remote-peers get $Peer dynamic-address ]; + :local AddrNew [ / ip ipsec active-peers get $Peer dynamic-address ]; :if ($AddrNew != $AddrOld || $Disabled = true) do={ :log info ("Update remote address for interface " . $GreName . " to " . $AddrNew); / interface gre set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$AddrNew name!=$GreName ]; From 1272fe1cb163f97b418d60a87efd6e229f357e03 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 1 Jul 2019 10:26:24 +0200 Subject: [PATCH 0037/2612] update-gre-address: get values into arrays --- update-gre-address | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/update-gre-address b/update-gre-address index 7e70a6d..5842669 100644 --- a/update-gre-address +++ b/update-gre-address @@ -8,17 +8,14 @@ / interface gre set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; :foreach Peer in=[ / ip ipsec active-peers find ] do={ - :local Id [ / ip ipsec active-peers get $Peer id ]; - :local GreInt [ / interface gre find where comment=$Id ]; + :local PeerVal [ / ip ipsec active-peers get $Peer ]; + :local GreInt [ / interface gre find where comment=$PeerVal->"id" ]; :if ([ :len $GreInt ] > 0) do={ - :local GreName [ / interface gre get $GreInt name ]; - :local AddrOld [ / interface gre get $GreInt remote-address ]; - :local Disabled [ / interface gre get $GreInt disabled ]; - :local AddrNew [ / ip ipsec active-peers get $Peer dynamic-address ]; - :if ($AddrNew != $AddrOld || $Disabled = true) do={ - :log info ("Update remote address for interface " . $GreName . " to " . $AddrNew); - / interface gre set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$AddrNew name!=$GreName ]; - / interface gre set $GreInt remote-address=$AddrNew disabled=no; + :local GreIntVal [ / interface gre get $GreInt ]; + :if ($PeerVal->"dynamic-address" != $GreIntVal->"remote-address" || $GreIntVal->"disabled" = true) do={ + :log info ("Update remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address"); + / interface gre set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$PeerVal->"dynamic-address" name!=$GreIntVal->"name" ]; + / interface gre set $GreInt remote-address=($PeerVal->"dynamic-address") disabled=no; } } } From 894ee65675ee846bd0c7d98e75b261cf5d6b35cc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 5 Jul 2019 16:09:49 +0200 Subject: [PATCH 0038/2612] ipv6-update: give hint about mis-usage --- ipv6-update | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ipv6-update b/ipv6-update index 1b52efc..869daf3 100644 --- a/ipv6-update +++ b/ipv6-update @@ -6,6 +6,11 @@ :local PdPrefix $"pd-prefix"; +:if ([ :typeof $PdPrefix ] = "nothing") do={ + :log error "This script is supposed to run from ipv6 dhcp-client."; + :error "Error: See log for details."; +} + :local Pool [ / ipv6 pool get [ find where prefix=$PdPrefix ] name ]; :local AddrList [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ]; :local OldPrefix [ / ipv6 firewall address-list get $AddrList address ]; From 15beb9234793fd01752d060ad01cc363c9a744be Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 5 Jul 2019 23:21:46 +0200 Subject: [PATCH 0039/2612] ppp-on-up: give hint about mis-usage --- ppp-on-up | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ppp-on-up b/ppp-on-up index 629e340..7fb80d9 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -4,8 +4,13 @@ # # run scripts on ppp up -# variable $interface is available in ppp on-up script :local Interface $interface; + +:if ([ :typeof $Interface ] = "nothing") do={ + :log error "This script is supposed to run from ppp on-up script hook."; + :error "Error: See log for details."; +} + :local IntName [ / interface get $Interface name ]; :log info ("PPP interface " . $IntName . " is up."); From 933db2ddc89b99c2d54a26fa063068a01fc1c241 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 5 Jul 2019 23:33:45 +0200 Subject: [PATCH 0040/2612] sms-action: give hint about mis-usage --- sms-action | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sms-action b/sms-action index b651c57..0871ef1 100644 --- a/sms-action +++ b/sms-action @@ -8,6 +8,11 @@ :local Action $action; +:if ([ :typeof $Action ] = "nothing") do={ + :log error "This script is supposed to run from SMS hook with action=..."; + :error "Error: See log for details."; +} + :local Code ($SmsAction->$Action); :local Parsed [ :parse $Code ]; From 43d77cb62de30c9419315bc90ca8840dd436dcaa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 5 Jul 2019 23:38:44 +0200 Subject: [PATCH 0041/2612] lease-script: give hint about mis-usage --- lease-script | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lease-script b/lease-script index d8d6562..b934086 100644 --- a/lease-script +++ b/lease-script @@ -4,6 +4,14 @@ # # run scripts on DHCP lease +:if ([ :typeof $leaseActIP ] = "nothing" || \ + [ :typeof $leaseActMAC ] = "nothing" || \ + [ :typeof $leaseServerName ] = "nothing" || \ + [ :typeof $leaseBound ] = "nothing") do={ + :log error "This script is supposed to run from ip dhcp-client."; + :error "Error: See log for details."; +} + :local Scripts; :local ScriptsAssign { "dhcp-to-dns"; From 65c76b8409723fa3c9c736f1106e56775b10c1d7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 8 Jul 2019 15:49:00 +0200 Subject: [PATCH 0042/2612] capsman-rolling-upgrade: log with info, give identity --- capsman-rolling-upgrade | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index 431ac02..11b32e1 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -12,8 +12,9 @@ :local Delay (600 / $RemoteCapCount); :if ($Delay > 120) do={ :set Delay 120; } :foreach RemoteCap in=[ / caps-man remote-cap find where version!=$InstalledVersion ] do={ - :local RemoteCapName [ / caps-man remote-cap get $RemoteCap name ]; - :log debug ("Starting upgrade for CAP " . $RemoteCapName . "..."); + :local RemoteCapVal [ / caps-man remote-cap get $RemoteCap ]; + :log info ("Starting upgrade for " . $RemoteCapVal->"name" . \ + " (" . $RemoteCapVal->"identity" . ")..."); / caps-man remote-cap upgrade $RemoteCap; :delay ($Delay . "s"); } From 13f091e5ae41cfac1c6e520949e2003032956479 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 9 Jul 2019 11:19:41 +0200 Subject: [PATCH 0043/2612] gps-track: remove workaround --- gps-track | 7 ------- 1 file changed, 7 deletions(-) diff --git a/gps-track b/gps-track index 7a78482..c0dbf7e 100644 --- a/gps-track +++ b/gps-track @@ -11,13 +11,6 @@ :local Gps [ / system gps monitor once as-value ]; if ($Gps->"valid" = true) do={ - # TODO: remove workaround when trailing zero bytes are gone - :if ([ :find ($Gps->"latitude") "\00" ] > 0) do={ - :set ($Gps->"latitude") [ :pick ($Gps->"latitude") 0 [ :find ($Gps->"latitude") "\00" ] ]; - } - :if ([ :find ($Gps->"longitude") "\00" ] > 0) do={ - :set ($Gps->"longitude") [ :pick ($Gps->"longitude") 0 [ :find ($Gps->"longitude") "\00" ] ]; - } :tool fetch check-certificate=yes-without-crl \ $GpsTrackUrl keep-result=no \ http-method=post http-header-field="Content-Type: application/json" \ From 12af69b443b24b54461c52cb8e3f69d83dcc6639 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 Jul 2019 11:22:25 +0200 Subject: [PATCH 0044/2612] update-gre-address: handle missing dynamic address --- update-gre-address | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/update-gre-address b/update-gre-address index 5842669..3050d8b 100644 --- a/update-gre-address +++ b/update-gre-address @@ -12,8 +12,10 @@ :local GreInt [ / interface gre find where comment=$PeerVal->"id" ]; :if ([ :len $GreInt ] > 0) do={ :local GreIntVal [ / interface gre get $GreInt ]; - :if ($PeerVal->"dynamic-address" != $GreIntVal->"remote-address" || $GreIntVal->"disabled" = true) do={ - :log info ("Update remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address"); + :if ([ :typeof ($PeerVal->"dynamic-address") ] = "str" && \ + ($PeerVal->"dynamic-address" != $GreIntVal->"remote-address" || \ + $GreIntVal->"disabled" = true)) do={ + :log info ("Updating remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address"); / interface gre set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$PeerVal->"dynamic-address" name!=$GreIntVal->"name" ]; / interface gre set $GreInt remote-address=($PeerVal->"dynamic-address") disabled=no; } From b1b53e3d0de3e82703afba4c03a532aa8d86e2d9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Jul 2019 12:42:40 +0200 Subject: [PATCH 0045/2612] global-functions: append system note in e-mail signature --- global-functions | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 6522bd8..f6d1e70 100644 --- a/global-functions +++ b/global-functions @@ -107,8 +107,13 @@ :if ([ :len $EmailGeneralTo ] > 0) do={ :do { + :local Signature [ / system note get note ]; + :if ([ :len $Signature ] > 0) do={ + :set Signature ("\n-- \n" . $Signature); + } / tool e-mail send to=$EmailGeneralTo cc=$EmailGeneralCc \ - subject=("[" . $Identity . "] " . $Subject) body=$Message file=$Attach; + subject=("[" . $Identity . "] " . $Subject) \ + body=($Message . $Signature) file=$Attach; } on-error={ :log warning "Failed sending notification mail!"; } From 16f04ee7ee83755b7405835d343f9e056986173b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Jul 2019 12:46:33 +0200 Subject: [PATCH 0046/2612] global-functions: $CharacterReplace: use same condition in loop --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index f6d1e70..b8afcd4 100644 --- a/global-functions +++ b/global-functions @@ -51,7 +51,7 @@ :return $String; } - :while ($String ~ $ReplaceFrom) do={ + :while ([ :typeof [ :find $String $ReplaceFrom ] ] != "nil") do={ :local Pos [ :find $String $ReplaceFrom ]; :set Return ($Return . [ :pick $String 0 $Pos ] . $ReplaceWith); :set String [ :pick $String ($Pos + $Len) 999 ]; From f79ba55637169f9e05a51f6f8c24e0543c707458 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 17 Jul 2019 16:27:21 +0200 Subject: [PATCH 0047/2612] global-functions: add $ParseKeyValueStore --- global-functions | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/global-functions b/global-functions index b8afcd4..00eb0c9 100644 --- a/global-functions +++ b/global-functions @@ -226,3 +226,19 @@ } :return true; } + +# parse key value store +:global ParseKeyValueStore do={ + :global CharacterReplace; + + :local Source $1; + :if ([ :typeof $Source ] != "array") do={ + :set Source [ :tostr $1 ]; + } + :local Result [ :toarray "" ]; + :foreach KeyValue in=[ :toarray $Source ] do={ + :set KeyValue [ :toarray [ $CharacterReplace $KeyValue "=" "," ] ]; + :set ($Result->($KeyValue->0)) ($KeyValue->1); + } + :return $Result; +} From 047c0989d880ae0cdec00469dd3d9746cb9d5e01 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 17 Jul 2019 16:28:10 +0200 Subject: [PATCH 0048/2612] ipv6-update: use $ParseKeyValueStore --- ipv6-update | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ipv6-update b/ipv6-update index 869daf3..5d5a3dc 100644 --- a/ipv6-update +++ b/ipv6-update @@ -6,6 +6,8 @@ :local PdPrefix $"pd-prefix"; +:global ParseKeyValueStore; + :if ([ :typeof $PdPrefix ] = "nothing") do={ :log error "This script is supposed to run from ipv6 dhcp-client."; :error "Error: See log for details."; @@ -22,12 +24,10 @@ if ($OldPrefix != $PdPrefix) do={ :log info ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix); / ipv6 firewall address-list set address=$PdPrefix $AddrList; - :foreach Record in=[ / ip dns static find where comment~("ipv6-pool-" . $Pool) ] do={ - :local Comment [ :toarray [ / ip dns static get $Record comment ] ]; - :local IntName [ :pick ($Comment->1) 10 99 ]; - :local Suffix [ :pick ($Comment->2) 7 99 ]; + :foreach Record in=[ / ip dns static find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ + :local Comment [ $ParseKeyValueStore [ / ip dns static get $Record comment ] ]; - :local Prefix [ / ipv6 address get [ find where interface=$IntName from-pool=$Pool global ] address ]; + :local Prefix [ / ipv6 address get [ find where interface=($Comment->"interface") from-pool=$Pool global ] address ]; :set Prefix [ :pick $Prefix 0 [ :find $Prefix "::/64" ] ]; :if ($Prefix~"^[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:") do={ } else={ :set Prefix ($Prefix . ":"); @@ -38,7 +38,7 @@ if ($OldPrefix != $PdPrefix) do={ :set Name [ / ip dns static get $Record regex ]; } - :log info ("Updating DNS record for " . $Name . " to " . $Prefix . ":" . $Suffix); - / ip dns static set address=($Prefix . ":" . $Suffix) $Record; + :log info ("Updating DNS record for " . $Name . " to " . $Prefix . ":" . ($Comment->"suffix")); + / ip dns static set address=($Prefix . ":" . ($Comment->"suffix")) $Record; } } From beb2e70097d187fbdeb1bf25cf0994babd8266fe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 17 Jul 2019 16:28:22 +0200 Subject: [PATCH 0049/2612] check-certificates: use $ParseKeyValueStore --- check-certificates | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/check-certificates b/check-certificates index ca5ffe3..75ff938 100644 --- a/check-certificates +++ b/check-certificates @@ -8,19 +8,11 @@ :global CertRenewUrl; :global CertRenewPass; +:global ParseKeyValueStore; :global SendNotification; :global UrlEncode; :global WaitForFile; -:local GetIssuerCN do={ - :foreach IssuerI in=$1 do={ - :if ([ :pick $IssuerI 0 3 ] = "CN=") do={ - :return [ :pick $IssuerI 3 99 ]; - } - } - :return ""; -} - :local FormatExpire do={ :global CharacterReplace; :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; @@ -76,7 +68,7 @@ "Name: " . ($CertVal->"name") . "\n" . \ "CommonName: " . ($CertNewVal->"common-name") . "\n" . \ "Fingerprint: " . ($CertNewVal->"fingerprint") . "\n" . \ - "Issuer: " . [ $GetIssuerCN ($CertNewVal->"issuer") ] . "\n" . \ + "Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]); :log info ("The certificate " . ($CertVal->"name") . " has been renewed."); @@ -100,7 +92,7 @@ "Name: " . ($CertVal->"name") . "\n" . \ "CommonName: " . ($CertVal->"common-name") . "\n" . \ "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ - "Issuer: " . ($CertVal->"ca") . [ $GetIssuerCN ($CertVal->"issuer") ] . "\n" . \ + "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ "Expires in: " . $ExpiresAfter); :log warning ("The certificate " . ($CertVal->"name") . " " . $State . \ From 5d12be36d744f40e354f4eeb33ad75c1151ed1b3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 17 Jul 2019 16:28:32 +0200 Subject: [PATCH 0050/2612] update-tunnelbroker: use $ParseKeyValueStore --- update-tunnelbroker | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/update-tunnelbroker b/update-tunnelbroker index 7d0fc35..4a8c797 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -4,6 +4,7 @@ # Michael Gisbers :global CertificateAvailable; +:global ParseKeyValueStore; :if ([ / ip cloud get ddns-enabled ] != true) do={ :log error "IP cloud DDNS is not enabled."; @@ -22,16 +23,13 @@ :local LastAddress [ / interface 6to4 get $Interface local-address ]; :if ($PublicAddress != $LastAddress) do={ - :local Comment [ :toarray [ / interface 6to4 get $Interface comment ] ]; - :local User [ :pick ($Comment->1) 5 99 ]; - :local Pass [ :pick ($Comment->2) 5 99 ]; - :local Id [ :pick ($Comment->3) 3 99 ]; + :local Comment [ $ParseKeyValueStore [ / interface 6to4 get $Interface comment ] ]; $CertificateAvailable "Starfield Secure Certificate Authority - G2"; :log info ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress); / tool fetch check-certificate=yes-without-crl \ - ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Id) \ - user=$User password=$Pass keep-result=no; + ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ + user=($Comment->"user") password=($Comment->"pass") keep-result=no; / interface 6to4 set $Interface local-address=$PublicAddress; } else={ :log debug ("All tunnelbroker configuration is up to date for interface " . $IntName . "."); From b68f5ebc8640974f5aa9d37df5c680201ad2c81f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Jul 2019 13:20:10 +0200 Subject: [PATCH 0051/2612] daily-psk-schedule: better matching --- daily-psk-schedule | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daily-psk-schedule b/daily-psk-schedule index a1a49fa..784b336 100644 --- a/daily-psk-schedule +++ b/daily-psk-schedule @@ -22,7 +22,7 @@ :error "Warning: See log for details."; } - / system script run [ find where name~"daily-psk\\.(capsman|local)" ]; + / system script run [ find where name~"^daily-psk\\.(capsman|local)\$" ]; / system scheduler set interval=0s $Scheduler; } From e309dee3b1fb58e0658a566ba0f7197458b22561 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Jul 2019 14:00:53 +0200 Subject: [PATCH 0052/2612] capsman-download-packages: do not require extra permission The idea was to run capsman-download-packages from netwatch when upgrade.mikrotik.com is up. Instead run it from scheduler at startup, but add a delay: / system scheduler add name=capsman-download-packages \ on-event=":delay 2m; capsman-download-packages" start-time=startup --- capsman-download-packages | 2 -- 1 file changed, 2 deletions(-) diff --git a/capsman-download-packages b/capsman-download-packages index 7462699..06fd228 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -3,8 +3,6 @@ # Copyright (c) 2018-2019 Christian Hesse # Michael Gisbers # -# requires: dont-require-permissions=yes -# # download and cleanup packages for CAP installation from CAPsMAN :global DownloadPackage; From 431a4c8176e7a47cfdc1506b05c7e6fca1ae65b5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Jul 2019 14:43:13 +0200 Subject: [PATCH 0053/2612] email-backup: no more than one dot in file name Looks like some providers do not allow more than one dot in attachment's file name to mitigate something like `holiday.png.exe`. Let's just replace dots with underscores. Fixes #2 Reported-by: @Kampfwurst --- email-backup | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/email-backup b/email-backup index 3050afc..de40520 100644 --- a/email-backup +++ b/email-backup @@ -12,6 +12,8 @@ :global BackupSendExport; :global BackupPassword; +:global CharacterReplace; + :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ :log error ("Configured to send neither backup nor config export."); @@ -19,7 +21,7 @@ } # filename based on identity -:local FileName ($Identity . "." . $Domain); +:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; :local BackupFile "none"; :local ConfigFile "none"; :local Attach [ :toarray "" ]; From 26f01b238b914e55396df4c5ce6cbccfa236d3da Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 8 Jul 2019 17:30:39 +0200 Subject: [PATCH 0054/2612] global-config: move config for email-backup Signed-off-by: Christian Hesse --- global-config | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/global-config b/global-config index ba6f924..751fc9e 100644 --- a/global-config +++ b/global-config @@ -12,13 +12,11 @@ :global Domain "example.com"; :global HostNameInZone true; -# These addresses are used to send e-mails to. The to-addresses need -# to be filled, cc-addresses can be empty, one address or a comma +# These addresses are used to send e-mails to. The to-address needs +# to be filled; cc-address can be empty, one address or a comma # separated list of addresses. :global EmailGeneralTo "mail@example.com"; :global EmailGeneralCc "another@example.com"; -:global EmailBackupTo "mail@example.com"; -:global EmailBackupCc ""; # You can send Telegram notifications. Register a bot # and add the token and chat ids here. @@ -31,6 +29,9 @@ :global BackupSendBinary false; :global BackupSendExport true; :global BackupPassword "v3ry-s3cr3t"; +# These addresses are used to send backup and config export files to. +:global EmailBackupTo "mail@example.com"; +:global EmailBackupCc "another@example.com"; # Specify an address to enable auto update to version assumed safe. # The configured channel (bugfix, current, release-candidate) is appended. From 8d1313f58885682dab5789fc9805e573d32fc661 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 8 Jul 2019 17:48:55 +0200 Subject: [PATCH 0055/2612] add script 'upload-backup' --- global-config | 8 ++++- global-config.changes | 1 + global-functions | 2 +- upload-backup | 75 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 upload-backup diff --git a/global-config b/global-config index 751fc9e..b14ff6e 100644 --- a/global-config +++ b/global-config @@ -6,7 +6,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 5; +:global GlobalConfigVersion 6; # This is used for DNS and backup file. :global Domain "example.com"; @@ -32,6 +32,12 @@ # These addresses are used to send backup and config export files to. :global EmailBackupTo "mail@example.com"; :global EmailBackupCc "another@example.com"; +# These credentials are used to upload backup and config export files. +# SFTP authentication is tricky, you may have to limit authentication +# methods for your SSH server. +:global BackupUploadUrl "sftp://example.com/backup/"; +:global BackupUploadUser "mikrotik"; +:global BackupUploadPass "v3ry-s3cr3t"; # Specify an address to enable auto update to version assumed safe. # The configured channel (bugfix, current, release-candidate) is appended. diff --git a/global-config.changes b/global-config.changes index f3c4e2b..656cb7f 100644 --- a/global-config.changes +++ b/global-config.changes @@ -8,4 +8,5 @@ 3="variable for certificate renew passphrase became an array to support multiple passphrases"; 4="added option to ignore global-config changes"; 5="split off new script cloud-backup from email-backup"; + 6="introduced script 'upload-backup' with new configuration parameters"; }; diff --git a/global-functions b/global-functions index 00eb0c9..b0e4eb3 100644 --- a/global-functions +++ b/global-functions @@ -5,7 +5,7 @@ # global functions # expected configuration version -:global ExpectedConfigVersion 5; +:global ExpectedConfigVersion 6; # global variables not to be changed by user :global SentConfigChangesNotification "-"; diff --git a/upload-backup b/upload-backup new file mode 100644 index 0000000..da2a5d7 --- /dev/null +++ b/upload-backup @@ -0,0 +1,75 @@ +#!rsc +# RouterOS script: upload-backup +# Copyright (c) 2013-2019 Christian Hesse +# +# create and upload backup and config file + +:global Identity; +:global Domain; +:global BackupUploadUrl; +:global BackupUploadUser; +:global BackupUploadPass; +:global BackupSendBinary; +:global BackupSendExport; +:global BackupPassword; + +:global CharacterReplace; +:global SendNotification; + +:if ($BackupSendBinary != true && \ + $BackupSendExport != true) do={ + :log error ("Configured to send neither backup nor config export."); + :error "Error: See log for details."; +} + +# filename based on identity +:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; +:local BackupFile "none"; +:local ConfigFile "none"; + +# get some system information +:local BoardName [ / system resource get board-name ]; +:local Model [ / system routerboard get model ]; +:local SerialNumber [ / system routerboard get serial-number ]; +:local Channel [ / system package update get channel ]; +:local InstalledVersion [ / system package update get installed-version ]; + +# binary backup +:if ($BackupSendBinary = true) do={ + / system backup save encryption=aes-sha256 name=$FileName password=$BackupPassword; + + :do { + / tool fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \ + user=$BackupUploadUser password=$BackupUploadPass src-path=($FileName . ".backup"); + :set BackupFile ($FileName . ".backup"); + } on-error={ + :log error ("Uploading backup file failed!"); + :set BackupFile "failed"; + } +} + +# create configuration export +:if ($BackupSendExport = true) do={ + / export terse file=$FileName; + + :do { + / tool fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \ + user=$BackupUploadUser password=$BackupUploadPass src-path=($FileName . ".rsc"); + :set ConfigFile ($FileName . ".rsc"); + } on-error={ + :log error ("Uploading configuration export failed!"); + :set ConfigFile "failed"; + } +} + +$SendNotification "Backup & Config Upload" \ + ("Backup and config export for " . $Identity . ".\n\n" . \ + "Board name: " . $BoardName . "\n" . \ + "Model: " . $Model . "\n" . \ + "Serial number: " . $SerialNumber . "\n" . \ + "Hostname: " . $Identity . "\n" . \ + "Channel: " . $Channel . "\n" . \ + "RouterOS: " . $InstalledVersion . "\n\n" . \ + "Backup uploaded: " . $BackupFile . "\n" . \ + "Config uploaded: " . $ConfigFile); +} From 1e075d8d64f393982722d17c5a44271a0f2858ad Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Jul 2019 13:18:44 +0200 Subject: [PATCH 0056/2612] packages-update: run email-backup and/or upload-backup --- packages-update | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages-update b/packages-update index 10b4a45..44bd7cb 100644 --- a/packages-update +++ b/packages-update @@ -22,8 +22,8 @@ } } -:if ([ / system script print count-only where name="email-backup" ] > 0) do={ - / system script run email-backup; +:foreach Script in=[ / system script find where name~"^(email|upload)-backup\$" ] do={ + / system script run $Script; } :log info ("Rebooting for update."); From 229dc539cc70fd156d8d69af370ae67d4bdb18a0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 19 Jul 2019 15:37:01 +0200 Subject: [PATCH 0057/2612] global-functions: $DownloadPackage: fix downloading for CHR / x86_64 --- global-functions | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global-functions b/global-functions index b0e4eb3..fb30680 100644 --- a/global-functions +++ b/global-functions @@ -184,6 +184,9 @@ :if ([ :len $PkgArch ] = 0) do={ :set PkgArch [ / system resource get architecture-name ]; } :local PkgFile ($PkgName . "-" . $PkgVer . "-" . $PkgArch . ".npk"); + :if ($PkgArch = "x86_64") do={ + :set PkgFile ($PkgName . "-" . $PkgVer . ".npk"); + } :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; $CertificateAvailable "Let's Encrypt Authority X3"; From 3aa4d7ea50dba77605fc1b4f928eaa498bbec3dc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jul 2019 10:13:39 +0200 Subject: [PATCH 0058/2612] packages-update: get values into array --- packages-update | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages-update b/packages-update index 44bd7cb..738ba2a 100644 --- a/packages-update +++ b/packages-update @@ -6,17 +6,16 @@ :global DownloadPackage; -:local InstalledVersion [ / system package update get installed-version ]; -:local LatestVersion [ / system package update get latest-version ]; +:local Update [ / system package update get ]; -:if ($InstalledVersion = $LatestVersion) do={ - :log info ("Version " . $LatestVersion . " is already installed."); +:if ($Update->"installed-version" = $Update->"latest-version") do={ + :log info ("Version " . $Update->"latest-version" . " is already installed."); :error "No updates available."; } :foreach Package in=[ / system package find where !bundle ] do={ :local PkgName [ / system package get $Package name ]; - if ([ $DownloadPackage $PkgName $LatestVersion ] = false) do={ + if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ :log error ("Download for package " . $PkgName . " failed."); :error "Error: See log for details."; } From 7fe0938f86a7041e78fae280b28dae852008ef1b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jul 2019 10:22:37 +0200 Subject: [PATCH 0059/2612] packages-update: break if latest version is unknown --- packages-update | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages-update b/packages-update index 738ba2a..7d161c2 100644 --- a/packages-update +++ b/packages-update @@ -8,6 +8,11 @@ :local Update [ / system package update get ]; +:if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ + :log warning "Latest version is not known."; + :error "Latest version is not known."; +} + :if ($Update->"installed-version" = $Update->"latest-version") do={ :log info ("Version " . $Update->"latest-version" . " is already installed."); :error "No updates available."; From 6699545157e0ecdcdefdad0d6f133bf890612c9b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jul 2019 10:49:51 +0200 Subject: [PATCH 0060/2612] packages-update: allow to downgrade on change of update channel --- packages-update | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages-update b/packages-update index 7d161c2..76bf120 100644 --- a/packages-update +++ b/packages-update @@ -30,6 +30,15 @@ / system script run $Script; } +:if (!([ /system resource get version ] ~ ($Update->"channel"))) do={ + :put "Update channel changed. Want to downgrade? [y/N]"; + :if ([ :terminal inkey timeout=60 ] = 121) do={ + :log info ("Rebooting for downgrade."); + :delay 1s; + / system package downgrade; + } +} + :log info ("Rebooting for update."); :delay 1s; / system reboot; From 9e3ee77a4a18badb17dfe5d199d40717cfc6036a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jul 2019 10:59:53 +0200 Subject: [PATCH 0061/2612] check-routeros-update: get values into array --- check-routeros-update | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index 104567e..cae9212 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -10,7 +10,7 @@ :global SendNotification; -:local Update do={ +:local DoUpdate do={ :if ([ / system script print count-only where name="packages-update" ] > 0) do={ / system script run packages-update; } else={ @@ -28,11 +28,9 @@ } / system package update check-for-updates without-paging; -:local InstalledVersion [ / system package update get installed-version ]; -:local LatestVersion [ / system package update get latest-version ]; +:local Update [ / system package update get ]; -:if ($InstalledVersion != $LatestVersion) do={ - :local Channel [ / system package update get channel ]; +:if ($Update->"installed-version" != $Update->"latest-version") do={ :local BoardName [ / system resource get board-name ]; :local Model [ / system routerboard get model ]; :local SerialNumber [ / system routerboard get serial-number ]; @@ -41,32 +39,32 @@ :local Result; :do { :set Result [ / tool fetch check-certificate=yes-without-crl \ - ($SafeUpdateUrl . $Channel . "?installed=" . $InstalledVersion . \ - "&latest=" . $LatestVersion) output=user as-value ]; + ($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \ + "&latest=" . $Update->"latest-version") output=user as-value ]; } on-error={ - :log warning ("Failed receiving safe version for " . $Channel . "."); + :log warning ("Failed receiving safe version for " . $Update->"channel" . "."); } - :if ($Result->"status" = "finished" && $Result->"data" = $LatestVersion) do={ - :log info ("Version " . $LatestVersion . " is considered safe, updating..."); + :if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={ + :log info ("Version " . $Update->"latest-version" . " is considered safe, updating..."); $SendNotification ("RouterOS update") \ - ("Version " . $LatestVersion . " is considered safe for " . $Channel . \ + ("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ ", updating on " . $Identity . "..."); - $Update; + $DoUpdate; } } :if ([ / system script job print count-only where script="check-routeros-update" parent~"." ] > 0) do={ - :put ("Do you want to install RouterOS version " . $LatestVersion . "? [y/N]"); + :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); :if ([ :terminal inkey timeout=60 ] = 121) do={ - $Update; + $DoUpdate; } else={ :put "Canceled..."; } } - :if ($SentRouterosUpdateNotification = $LatestVersion) do={ + :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ :log info ("Already sent the RouterOS update notification for version " . \ - $LatestVersion . "."); + $Update->"latest-version" . "."); :error "Already sent notification."; } @@ -76,9 +74,9 @@ "Model: " . $Model . "\n" . \ "Serial number: " . $SerialNumber . "\n" . \ "Hostname: " . $Identity . "\n" . \ - "Channel: " . $Channel . "\n" . \ - "Installed: " . $InstalledVersion . "\n" . \ - "Available: " . $LatestVersion . "\n\n" .\ - "https://mikrotik.com/download/changelogs/" . $Channel . "-release-tree"); - :set SentRouterosUpdateNotification $LatestVersion; + "Channel: " . $Update->"channel" . "\n" . \ + "Installed: " . $Update->"installed-version" . "\n" . \ + "Available: " . $Update->"latest-version" . "\n\n" .\ + "https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); + :set SentRouterosUpdateNotification ($Update->"latest-version"); } From 5f592111682f4df7a559a2b2ea48465c5fe1d484 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jul 2019 11:04:31 +0200 Subject: [PATCH 0062/2612] email-backup: get values into array --- email-backup | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/email-backup b/email-backup index de40520..f5b967f 100644 --- a/email-backup +++ b/email-backup @@ -30,8 +30,7 @@ :local BoardName [ / system resource get board-name ]; :local Model [ / system routerboard get model ]; :local SerialNumber [ / system routerboard get serial-number ]; -:local Channel [ / system package update get channel ]; -:local InstalledVersion [ / system package update get installed-version ]; +:local Update [ / system package update get ]; # binary backup :if ($BackupSendBinary = true) do={ @@ -55,8 +54,8 @@ "Model: " . $Model . "\n" . \ "Serial number: " . $SerialNumber . "\n" . \ "Hostname: " . $Identity . "\n" . \ - "Channel: " . $Channel . "\n" . \ - "RouterOS: " . $InstalledVersion . "\n\n" . \ + "Channel: " . $Update->"channel" . "\n" . \ + "RouterOS: " . $Update->"installed-version" . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ "Config file: " . $ConfigFile) \ file=$Attach; From 1020db0b31e32e9b628fd0b1a7b9c74783e90a45 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jul 2019 11:05:44 +0200 Subject: [PATCH 0063/2612] cloud-backup: get values into array --- cloud-backup | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cloud-backup b/cloud-backup index f9e7747..6f163a2 100644 --- a/cloud-backup +++ b/cloud-backup @@ -13,8 +13,7 @@ :local BoardName [ / system resource get board-name ]; :local Model [ / system routerboard get model ]; :local SerialNumber [ / system routerboard get serial-number ]; -:local Channel [ / system package update get channel ]; -:local InstalledVersion [ / system package update get installed-version ]; +:local Update [ / system package update get ]; :do { # we are not interested in output, but print without count-only is @@ -32,8 +31,8 @@ "Model: " . $Model . "\n" . \ "Serial number: " . $SerialNumber . "\n" . \ "Hostname: " . $Identity . "\n" . \ - "Channel: " . $Channel . "\n" . \ - "RouterOS: " . $InstalledVersion . "\n\n" . \ + "Channel: " . $Update->"channel" . "\n" . \ + "RouterOS: " . $Update->"installed-version" . "\n\n" . \ "Name: " . $Cloud->"name" . "\n" . \ "Size: " . $Cloud->"size" . "\n" . \ "Download key: " . $Cloud->"secret-download-key"); From 55313b4841e0ce643cc640cae4f98fc83ce67152 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jul 2019 11:06:50 +0200 Subject: [PATCH 0064/2612] upload-backup: get values into array --- upload-backup | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/upload-backup b/upload-backup index da2a5d7..31efce7 100644 --- a/upload-backup +++ b/upload-backup @@ -31,8 +31,7 @@ :local BoardName [ / system resource get board-name ]; :local Model [ / system routerboard get model ]; :local SerialNumber [ / system routerboard get serial-number ]; -:local Channel [ / system package update get channel ]; -:local InstalledVersion [ / system package update get installed-version ]; +:local Update [ / system package update get ]; # binary backup :if ($BackupSendBinary = true) do={ @@ -68,8 +67,8 @@ $SendNotification "Backup & Config Upload" \ "Model: " . $Model . "\n" . \ "Serial number: " . $SerialNumber . "\n" . \ "Hostname: " . $Identity . "\n" . \ - "Channel: " . $Channel . "\n" . \ - "RouterOS: " . $InstalledVersion . "\n\n" . \ + "Channel: " . $Update->"channel" . "\n" . \ + "RouterOS: " . $Update->"installed-version" . "\n\n" . \ "Backup uploaded: " . $BackupFile . "\n" . \ "Config uploaded: " . $ConfigFile); } From 21996dfcaf676f50e02c2aa5b979b5f2e6065d53 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jul 2019 11:10:47 +0200 Subject: [PATCH 0065/2612] check-routeros-update: get values into array --- check-routeros-update | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index cae9212..cc6d245 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -32,8 +32,7 @@ :if ($Update->"installed-version" != $Update->"latest-version") do={ :local BoardName [ / system resource get board-name ]; - :local Model [ / system routerboard get model ]; - :local SerialNumber [ / system routerboard get serial-number ]; + :local RouterBoard [ / system routerboard get ]; :if ([ :len $SafeUpdateUrl ] > 0) do={ :local Result; @@ -71,8 +70,8 @@ $SendNotification ("RouterOS update") \ ("There is a RouterOS update available.\n\n" . \ "Board name: " . $BoardName . "\n" . \ - "Model: " . $Model . "\n" . \ - "Serial number: " . $SerialNumber . "\n" . \ + "Model: " . $RouterBoard->"model" . "\n" . \ + "Serial number: " . $RouterBoard->"serial-number" . "\n" . \ "Hostname: " . $Identity . "\n" . \ "Channel: " . $Update->"channel" . "\n" . \ "Installed: " . $Update->"installed-version" . "\n" . \ From 32cc5d107896f91a71c677d0eb0033140cace607 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jul 2019 11:11:57 +0200 Subject: [PATCH 0066/2612] email-backup: get values into array --- email-backup | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/email-backup b/email-backup index f5b967f..f1a2f9a 100644 --- a/email-backup +++ b/email-backup @@ -28,8 +28,7 @@ # get some system information :local BoardName [ / system resource get board-name ]; -:local Model [ / system routerboard get model ]; -:local SerialNumber [ / system routerboard get serial-number ]; +:local RouterBoard [ / system routerboard get ]; :local Update [ / system package update get ]; # binary backup @@ -51,8 +50,8 @@ subject=("[" . $Identity . "] Backup & Config") \ body=("Backup and config export for " . $Identity . ".\n\n" . \ "Board name: " . $BoardName . "\n" . \ - "Model: " . $Model . "\n" . \ - "Serial number: " . $SerialNumber . "\n" . \ + "Model: " . $RouterBoard->"model" . "\n" . \ + "Serial number: " . $RouterBoard->"serial-number" . "\n" . \ "Hostname: " . $Identity . "\n" . \ "Channel: " . $Update->"channel" . "\n" . \ "RouterOS: " . $Update->"installed-version" . "\n\n" . \ From 5789b8d9847a0bf0831ea3fff86a8a2a44947249 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jul 2019 11:12:52 +0200 Subject: [PATCH 0067/2612] cloud-backup: get values into array --- cloud-backup | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cloud-backup b/cloud-backup index 6f163a2..2d450cb 100644 --- a/cloud-backup +++ b/cloud-backup @@ -11,8 +11,7 @@ # get some system information :local BoardName [ / system resource get board-name ]; -:local Model [ / system routerboard get model ]; -:local SerialNumber [ / system routerboard get serial-number ]; +:local RouterBoard [ / system routerboard get ]; :local Update [ / system package update get ]; :do { @@ -28,8 +27,8 @@ $SendNotification "Cloud backup" \ ("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ "Board name: " . $BoardName . "\n" . \ - "Model: " . $Model . "\n" . \ - "Serial number: " . $SerialNumber . "\n" . \ + "Model: " . $RouterBoard->"model" . "\n" . \ + "Serial number: " . $RouterBoard->"serial-number" . "\n" . \ "Hostname: " . $Identity . "\n" . \ "Channel: " . $Update->"channel" . "\n" . \ "RouterOS: " . $Update->"installed-version" . "\n\n" . \ From 39eef1a0b1bbc7e41438a37136972202c9ba6d33 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jul 2019 11:13:53 +0200 Subject: [PATCH 0068/2612] upload-backup: get values into array --- upload-backup | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/upload-backup b/upload-backup index 31efce7..87d3960 100644 --- a/upload-backup +++ b/upload-backup @@ -29,8 +29,7 @@ # get some system information :local BoardName [ / system resource get board-name ]; -:local Model [ / system routerboard get model ]; -:local SerialNumber [ / system routerboard get serial-number ]; +:local RouterBoard [ / system routerboard get ]; :local Update [ / system package update get ]; # binary backup @@ -64,8 +63,8 @@ $SendNotification "Backup & Config Upload" \ ("Backup and config export for " . $Identity . ".\n\n" . \ "Board name: " . $BoardName . "\n" . \ - "Model: " . $Model . "\n" . \ - "Serial number: " . $SerialNumber . "\n" . \ + "Model: " . $RouterBoard->"model" . "\n" . \ + "Serial number: " . $RouterBoard->"serial-number" . "\n" . \ "Hostname: " . $Identity . "\n" . \ "Channel: " . $Update->"channel" . "\n" . \ "RouterOS: " . $Update->"installed-version" . "\n\n" . \ From be133146ddcc085777fa5014074c56995266abcd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 14 Jun 2019 15:41:32 +0200 Subject: [PATCH 0069/2612] cloud-backup: do not remove but replace cloud backup The replace functionality for cloud backup is available with version 6.45beta42. --- cloud-backup | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cloud-backup b/cloud-backup index 2d450cb..9bb13ff 100644 --- a/cloud-backup +++ b/cloud-backup @@ -19,9 +19,12 @@ # required to fetch information from cloud / system backup cloud print as-value; :if ([ / system backup cloud print count-only ] > 0) do={ - / system backup cloud remove-file ([ find ]->0); + / 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; } - / system backup cloud upload-file action=create-and-upload password=$BackupPassword; :local Cloud [ / system backup cloud get ([ find ]->0) ]; $SendNotification "Cloud backup" \ From e7dffe0a82e4d00579f43188be5a1a3d29f3ad8c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Jul 2019 10:35:15 +0200 Subject: [PATCH 0070/2612] capsman-download-packages: get values into array --- capsman-download-packages | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/capsman-download-packages b/capsman-download-packages index 06fd228..f71c121 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -14,15 +14,14 @@ :foreach Package in=[ / file find where type=package \ package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ - :local PackageName [ / file get $Package package-name ]; - :local PackageArchitecture [ / file get $Package package-architecture ]; - :if ($PackageArchitecture = "mips") do={ - :set PackageArchitecture "mipsbe"; + :local File [ / file get $Package ]; + :if ($File->"package-architecture" = "mips") do={ + :set ($File->"package-architecture") "mipsbe"; } - :if ($PackageName = "wireless@") do={ - :set PackageName "wireless"; + :if ($File->"package-name" = "wireless@") do={ + :set ($File->"package-name") "wireless"; } - :if ([ $DownloadPackage $PackageName $InstalledVersion $PackageArchitecture $PackagePath ] = true) do={ + :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion $File->"package-architecture" $PackagePath ] = true) do={ :set Updated true; / file remove $Package; } From 46fee70a5660254b4d2ae8a172d8aca8a21e48b0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Jul 2019 10:47:45 +0200 Subject: [PATCH 0071/2612] dhcp-lease-comment: get values into array --- dhcp-lease-comment.capsman | 9 ++++----- dhcp-lease-comment.local | 9 ++++----- dhcp-lease-comment.template | 9 ++++----- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index eda04e4..5cb71cd 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -7,15 +7,14 @@ # !! Do not edit this file, it is generated from template! :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={ - :local MacAddress [ / ip dhcp-server lease get $Lease mac-address ]; - :local OldComment [ / ip dhcp-server lease get $Lease comment ]; + :local LeaseVal [ / ip dhcp-server lease get $Lease ]; :local NewComment; - :local AccessList ([ / caps-man access-list find where mac-address=$MacAddress ]->0); + :local AccessList ([ / caps-man access-list find where mac-address=($LeaseVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ :set NewComment [ / caps-man access-list get $AccessList comment ]; } - :if ([ :len $NewComment ] != 0 && $OldComment != $NewComment) do={ - :log info ("Updating comment for DHCP lease " . $MacAddress . ": " . $NewComment); + :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ + :log info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment); / ip dhcp-server lease set comment=$NewComment $Lease; } } diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index 9e2f9d8..a5c2ff5 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -7,15 +7,14 @@ # !! Do not edit this file, it is generated from template! :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={ - :local MacAddress [ / ip dhcp-server lease get $Lease mac-address ]; - :local OldComment [ / ip dhcp-server lease get $Lease comment ]; + :local LeaseVal [ / ip dhcp-server lease get $Lease ]; :local NewComment; - :local AccessList ([ / interface wireless access-list find where mac-address=$MacAddress ]->0); + :local AccessList ([ / interface wireless access-list find where mac-address=($LeaseVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ :set NewComment [ / interface wireless access-list get $AccessList comment ]; } - :if ([ :len $NewComment ] != 0 && $OldComment != $NewComment) do={ - :log info ("Updating comment for DHCP lease " . $MacAddress . ": " . $NewComment); + :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ + :log info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment); / ip dhcp-server lease set comment=$NewComment $Lease; } } diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index a1541e1..fcff9d4 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -8,15 +8,14 @@ # !! or 'interface wireless'! :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={ - :local MacAddress [ / ip dhcp-server lease get $Lease mac-address ]; - :local OldComment [ / ip dhcp-server lease get $Lease comment ]; + :local LeaseVal [ / ip dhcp-server lease get $Lease ]; :local NewComment; - :local AccessList ([ / %PATH% access-list find where mac-address=$MacAddress ]->0); + :local AccessList ([ / %PATH% access-list find where mac-address=($LeaseVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ :set NewComment [ / %PATH% access-list get $AccessList comment ]; } - :if ([ :len $NewComment ] != 0 && $OldComment != $NewComment) do={ - :log info ("Updating comment for DHCP lease " . $MacAddress . ": " . $NewComment); + :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ + :log info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment); / ip dhcp-server lease set comment=$NewComment $Lease; } } From 8d4dc1e3f6f11daa8d90da634b01eb1826a2b30e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Jul 2019 12:55:11 +0200 Subject: [PATCH 0072/2612] dhcp-to-dns: get values into arrays, general rework --- dhcp-to-dns | 52 +++++++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index e965faf..cd3b793 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -19,50 +19,44 @@ :local Ttl 5m; :local CommentPrefix "managed by dhcp-to-dns for "; -:foreach Static in=[ / ip dns static find where comment ~ $CommentPrefix ] do={ - :local MacAddress [ $CharacterReplace [ / ip dns static get $Static comment ] $CommentPrefix "" ]; - :local IpAddress [ / ip dns static get $Static address ]; - :local HostName [ / ip dns static get $Static name ]; - :if ([ / ip dhcp-server lease print count-only where mac-address=$MacAddress address=$IpAddress dynamic=yes ] > 0) do={ - :log debug ("Lease for " . $MacAddress . " (" . $HostName . ") still exists. Not deleting DNS entry."); +:foreach DnsRecord in=[ / ip dns static find where comment ~ $CommentPrefix ] do={ + :local DnsRecordVal [ / ip dns static get $DnsRecord ]; + :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; + :if ([ / ip dhcp-server lease print count-only where mac-address=$MacAddress address=($DnsRecordVal->"address") dynamic=yes ] > 0) do={ + :log debug ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"host-name" . ") still exists. Not deleting DNS entry."); } else={ :local Found false; - :log info ("Lease expired for " . $MacAddress . " (" . $HostName . "), deleting DNS entry."); - / ip dns static remove $Static; + :log info ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry."); + / ip dns static remove $DnsRecord; } } :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={ - :local Mac [ / ip dhcp-server lease get $Lease mac-address ]; - :local DhcpIp [ / ip dhcp-server lease get $Lease address ]; - :local Comment ($CommentPrefix . $Mac); - :local HostName [ $CharacterReplace [ / ip dhcp-server lease get $Lease host-name ] " " "" ]; + :local LeaseVal [ / ip dhcp-server lease get $Lease ]; + :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); + :local HostName [ $CharacterReplace ($LeaseVal->"host-name") " " "" ]; :if ($HostName = "") do={ - :set HostName [ $CharacterReplace [ / ip dhcp-server lease get $Lease mac-address ] ":" "-" ]; + :set HostName [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ]; } :local Fqdn ($HostName . "." . $Zone); - :local DnsNode [ / ip dns static find where name=$Fqdn ]; - :if ([ :len $DnsNode ] > 0) do={ - :local DnsIp [ / ip dns static get $DnsNode address ]; - :local Leases [ / ip dhcp-server lease find where host-name=$HostName dynamic=yes ]; - :local HostNameCount [ / ip dhcp-server lease print count-only where host-name=$HostName dynamic=yes ]; - :if ($HostNameCount > 1) do={ - :foreach J,Lease in=$Leases do={ - :if ($J + 1 = $HostNameCount) do={ - :set DhcpIp [ / ip dhcp-server lease get $Lease address ]; - } - } + :local DnsRecord [ / ip dns static find where name=$Fqdn ]; + :if ([ :len $DnsRecord ] > 0) do={ + :local DnsIp [ / ip dns static get $DnsRecord address ]; + + :local HostLeases [ / ip dhcp-server lease find where host-name=($LeaseVal->"host-name") dynamic=yes ]; + :if ([ :len $HostLeases ] > 1) do={ + :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($HostLeases->([ :len $HostLeases ] - 1)) address ]; } - :if ($DnsIp = $DhcpIp) do={ + :if ($DnsIp = $LeaseVal->"address") do={ :log debug ("DNS entry for " . $Fqdn . " does not need updating."); } else={ - :log info ("Replacing DNS entry for " . $Fqdn . ", new address is " . $DhcpIp . "."); - / ip dns static set name=$Fqdn address=$DhcpIp ttl=$Ttl comment=$Comment $DnsNode; + :log info ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . "."); + / ip dns static set name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; } } else={ - :log info ("Adding new DNS entry for " . $Fqdn . ", address is " . $DhcpIp . "."); - / ip dns static add name=$Fqdn address=$DhcpIp ttl=$Ttl comment=$Comment; + :log info ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . "."); + / ip dns static add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment; } } From d9d98cfe9ed5b9812e8910098a4f46d057ea127d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Jul 2019 13:12:17 +0200 Subject: [PATCH 0073/2612] script-updates: get values into arrays --- script-updates | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/script-updates b/script-updates index 9e35e51..48d9ca9 100644 --- a/script-updates +++ b/script-updates @@ -18,40 +18,38 @@ :foreach Script in=[ / system script find ] do={ :local Ignore 0; - :local ScriptName [ / system script get $Script name ]; - :local ScriptPolicy [ / system script get $Script policy ]; - :local ScriptFile [ / file find where name=("script-updates/" . $ScriptName) ]; + :local ScriptVal [ / system script get $Script ]; + :local ScriptFile [ / file find where name=("script-updates/" . $ScriptVal->"name") ]; :local SourceNew; :if ([ :len $ScriptFile ] > 0) do={ :set SourceNew [ / file get $ScriptFile content ]; / file remove $ScriptFile; } - :foreach Scheduler in=[ / system scheduler find where on-event=$ScriptName ] do={ - :local SchedulerName [ / system scheduler get $Scheduler name ]; - :local SchedulerPolicy [ / system scheduler get $Scheduler policy ]; - :if ($ScriptPolicy != $SchedulerPolicy) do={ - :log warning ("Policies differ for script " . $ScriptName . \ - " and its scheduler " . $SchedulerName . "!"); + :foreach Scheduler in=[ / system scheduler find where on-event=($ScriptVal->"name") ] do={ + :local SchedulerVal [ / system scheduler get $Scheduler ]; + :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ + :log warning ("Policies differ for script " . $ScriptVal->"name" . \ + " and its scheduler " . $SchedulerVal->"name" . "!"); } } :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ :foreach IgnoreLoop in=$ScriptUpdatesIgnore do={ - :if ($IgnoreLoop = $ScriptName) do={ :set Ignore 1; } + :if ($IgnoreLoop = $ScriptVal->"name") do={ :set Ignore 1; } } :if ($Ignore = 0) do={ - :log debug ("Fetching script from url: " . $ScriptName); + :log debug ("Fetching script from url: " . $ScriptVal->"name"); :do { :local Result [ / tool fetch check-certificate=yes-without-crl \ - ($ScriptUpdatesBaseUrl . $ScriptName . $ScriptUpdatesUrlSuffix) \ + ($ScriptUpdatesBaseUrl . $ScriptVal->"name" . $ScriptUpdatesUrlSuffix) \ output=user as-value ]; :if ($Result->"status" = "finished") do={ :set SourceNew ($Result->"data"); } } on-error={ - :log info ("Failed fetching " . $ScriptName); + :log info ("Failed fetching " . $ScriptVal->"name"); } } } @@ -62,20 +60,20 @@ :if ($SourceNew != $SourceCurrent) do={ :local DontRequirePermissions \ ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); - :log info ("Updating script: " . $ScriptName); - / system script set owner=$ScriptName source=$SourceNew \ + :log info ("Updating script: " . $ScriptVal->"name"); + / system script set owner=($ScriptVal->"name") source=$SourceNew \ dont-require-permissions=$DontRequirePermissions $Script; - :if ($ScriptName = "global-functions") do={ + :if ($ScriptVal->"name" = "global-functions") do={ / system script run global-functions; } } else={ - :log debug ("Script " . $ScriptName . " did not change."); + :log debug ("Script " . $ScriptVal->"name" . " did not change."); } } else={ - :log warning ("Looks like new script " . $ScriptName . " is not valid. Ignoring!"); + :log warning ("Looks like new script " . $ScriptVal->"name" . " is not valid. Ignoring!"); } } else={ - :log debug ("No update for script " . $ScriptName . "."); + :log debug ("No update for script " . $ScriptVal->"name" . "."); } } From cc9b2620e7674ce86660d2214be16cfa17bb0f15 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Jul 2019 13:25:12 +0200 Subject: [PATCH 0074/2612] update-tunnelbroker: get values into array --- update-tunnelbroker | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/update-tunnelbroker b/update-tunnelbroker index 4a8c797..c529d44 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -19,11 +19,10 @@ :local PublicAddress [ / ip cloud get public-address ]; :foreach Interface in=[ / interface 6to4 find where comment~"^tunnelbroker" !disabled ] do={ - :local IntName [ / interface 6to4 get $Interface name ]; - :local LastAddress [ / interface 6to4 get $Interface local-address ]; + :local InterfaceVal [ / interface 6to4 get $Interface ]; - :if ($PublicAddress != $LastAddress) do={ - :local Comment [ $ParseKeyValueStore [ / interface 6to4 get $Interface comment ] ]; + :if ($PublicAddress != $InterfaceVal->"local-address") do={ + :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; $CertificateAvailable "Starfield Secure Certificate Authority - G2"; :log info ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress); @@ -32,6 +31,6 @@ user=($Comment->"user") password=($Comment->"pass") keep-result=no; / interface 6to4 set $Interface local-address=$PublicAddress; } else={ - :log debug ("All tunnelbroker configuration is up to date for interface " . $IntName . "."); + :log debug ("All tunnelbroker configuration is up to date for interface " . $InterfaceVal->"name" . "."); } } From 1c4dfeaa4aef8121377821184c0ed798605e6282 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Jul 2019 13:17:51 +0200 Subject: [PATCH 0075/2612] sms-forward: get values into arrays --- sms-forward | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/sms-forward b/sms-forward index 1c50552..6a3cf70 100644 --- a/sms-forward +++ b/sms-forward @@ -14,8 +14,7 @@ :error "Warning: See log for details."; } -:local Allowed [ / tool sms get allowed-number ]; -:local Secret [ / tool sms get secret ]; +:local Settings [ / tool sms get ]; # forward SMS in a loop :while ([ / tool sms inbox print count-only ] > 0) do={ @@ -24,16 +23,14 @@ :local Delete [ :toarray "" ]; :foreach Sms in=[ / tool sms inbox find where phone=$Phone ] do={ - :local Message [ / tool sms inbox get $Sms message ]; - :local TimeStamp [ / tool sms inbox get $Sms timestamp ]; - :local Type [ / tool sms inbox get $Sms type ]; + :local SmsVal [ / tool sms inbox get $Sms ]; - :if ($Phone = $Allowed && $Message~("^:cmd " . $Secret . " script ")) do={ + :if ($Phone = $Settings->"allowed" && ($SmsVal->"message")~("^:cmd " . $Settings->"secret" . " script ")) do={ :log debug "Removing SMS, which started a script."; / tool sms inbox remove $Sms; } else={ - :set Messages ($Messages . "\n\nOn " . $TimeStamp . \ - " type " . $Type . ":\n" . $Message); + :set Messages ($Messages . "\n\nOn " . $SmsVal->"timestamp" . \ + " type " . $SmsVal->"type" . ":\n" . $SmsVal->"message"); :set Delete ($Delete, $Sms); } } From 25a22e2e1c8d7f2dd195e76acf29b6ae8f6c6bfe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Jul 2019 21:19:10 +0200 Subject: [PATCH 0076/2612] script-updates: get source from array --- script-updates | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/script-updates b/script-updates index 48d9ca9..be9d373 100644 --- a/script-updates +++ b/script-updates @@ -56,8 +56,7 @@ :if ([ :len $SourceNew ] > 0) do={ :if ([ :pick $SourceNew 0 5 ] = "#!rsc") do={ - :local SourceCurrent [ / system script get $Script source ]; - :if ($SourceNew != $SourceCurrent) do={ + :if ($SourceNew != $ScriptVal->"source") do={ :local DontRequirePermissions \ ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); :log info ("Updating script: " . $ScriptVal->"name"); From f49b67f5e7f938b881acbb2fbce8be5b3261bfea Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Jul 2019 17:48:03 +0200 Subject: [PATCH 0077/2612] global-functions: add $GetRandom --- global-functions | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/global-functions b/global-functions index fb30680..6f1776b 100644 --- a/global-functions +++ b/global-functions @@ -245,3 +245,16 @@ } :return $Result; } + +# generate random number +# Warning: This is a *very* weak algorithm and in *no way* +# useful for cryptography or similar! +:global GetRandom do={ + :local Max ([ :tonum $1 ] + 1); + :local Sum 0; + + :foreach Interface in=[ /interface find ] do={ + :set Sum ($Sum + [ /interface get $Interface tx-byte ]); + } + :return ($Sum % $Max); +} From acce2322c347deb75c38337a725ead30320a9f6e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Jul 2019 18:14:33 +0200 Subject: [PATCH 0078/2612] global-functions: add $RandomDelay --- global-functions | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/global-functions b/global-functions index 6f1776b..b7eec27 100644 --- a/global-functions +++ b/global-functions @@ -258,3 +258,10 @@ } :return ($Sum % $Max); } + +# delay a random amount of seconds +:global RandomDelay do={ + :global GetRandom; + + :delay ([ $GetRandom $1 ] . "s"); +} From 70798de8f05e88e39fbcd70078b91b2ec07e9c83 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 Jul 2019 21:04:06 +0200 Subject: [PATCH 0079/2612] check-certificates: fix renewing certificate in place --- check-certificates | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/check-certificates b/check-certificates index 75ff938..d28ef86 100644 --- a/check-certificates +++ b/check-certificates @@ -45,24 +45,28 @@ :local CertNew [ / certificate find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>3w ]; :local CertNewVal [ / certificate get $CertNew ]; - / ip service set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; + :if ($Cert != $CertNew) do={ + :log debug ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced."); - :do { - / ip ipsec identity set certificate=($CertNewVal->"name") [ / ip ipsec identity find where certificate=($CertVal->"name") ]; - / ip ipsec identity set remote-certificate=($CertNewVal->"name") [ / ip ipsec identity find where remote-certificate=($CertVal->"name") ]; - } on-error={ - :log debug ("Setting IPSEC certificates failed. Package 'security' not installed?"); + / ip service set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; + + :do { + / ip ipsec identity set certificate=($CertNewVal->"name") [ / ip ipsec identity find where certificate=($CertVal->"name") ]; + / ip ipsec identity set remote-certificate=($CertNewVal->"name") [ / ip ipsec identity find where remote-certificate=($CertVal->"name") ]; + } on-error={ + :log debug ("Setting IPSEC certificates failed. Package 'security' not installed?"); + } + + :do { + / ip hotspot profile set ssl-certificate=($CertNewVal->"name") [ / ip hotspot profile find where ssl-certificate=($CertVal->"name") ]; + } on-error={ + :log debug ("Setting hotspot certificates failed. Package 'hotspot' not installed?"); + } + + / certificate remove $Cert; + / certificate set $CertNew name=($CertVal->"name"); } - :do { - / ip hotspot profile set ssl-certificate=($CertNewVal->"name") [ / ip hotspot profile find where ssl-certificate=($CertVal->"name") ]; - } on-error={ - :log debug ("Setting hotspot certificates failed. Package 'hotspot' not installed?"); - } - - / certificate remove $Cert; - / certificate set $CertNew name=($CertVal->"name") - $SendNotification ("Certificate renewed") \ ("A certificate on " . $Identity . " has been renewed.\n\n" . \ "Name: " . ($CertVal->"name") . "\n" . \ From ab4aef4dfba35a715f9786566e33a6c1abc3350c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 1 Aug 2019 18:45:54 +0200 Subject: [PATCH 0080/2612] global-functions: $DownloadPackage: re-introduce check for valid package Even if fetch tool does its job right now... Chances are that the download servers have corrupted or empty files. --- global-functions | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/global-functions b/global-functions index b7eec27..a139345 100644 --- a/global-functions +++ b/global-functions @@ -200,6 +200,11 @@ :return false; } + :if ([ / file get [ find where name=$PkgDest ] type ] != "package") do={ + / file remove [ find where name=$PkgDest ]; + :return false; + } + :return true; } From 67f4b135f5558f002b55da3b933b3c278d47ca66 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 2 Aug 2019 15:22:17 +0200 Subject: [PATCH 0081/2612] capsman-download-packages: syntax error with missing parenthesis --- capsman-download-packages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/capsman-download-packages b/capsman-download-packages index f71c121..2a5a0d0 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -21,7 +21,7 @@ :if ($File->"package-name" = "wireless@") do={ :set ($File->"package-name") "wireless"; } - :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion $File->"package-architecture" $PackagePath ] = true) do={ + :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion ($File->"package-architecture") $PackagePath ] = true) do={ :set Updated true; / file remove $Package; } From 5408ba008af2df5b20b3f5ebf166f24fdceb1ff5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 5 Aug 2019 10:32:19 +0200 Subject: [PATCH 0082/2612] sms-forward: fix array access in condition --- sms-forward | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sms-forward b/sms-forward index 6a3cf70..f749644 100644 --- a/sms-forward +++ b/sms-forward @@ -25,7 +25,8 @@ :foreach Sms in=[ / tool sms inbox find where phone=$Phone ] do={ :local SmsVal [ / tool sms inbox get $Sms ]; - :if ($Phone = $Settings->"allowed" && ($SmsVal->"message")~("^:cmd " . $Settings->"secret" . " script ")) do={ + :if ($Phone = $Settings->"allowed-number" && \ + ($SmsVal->"message")~("^:cmd " . $Settings->"secret" . " script ")) do={ :log debug "Removing SMS, which started a script."; / tool sms inbox remove $Sms; } else={ From dcd47d8ac446c3e68e13df5db41ff7d13f05b3da Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Aug 2019 16:15:10 +0200 Subject: [PATCH 0083/2612] sms-forward: add sender in subject --- sms-forward | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sms-forward b/sms-forward index f749644..9c5c494 100644 --- a/sms-forward +++ b/sms-forward @@ -37,7 +37,7 @@ } :if ([ :len $Messages ] > 0) do={ - $SendNotification ("SMS Forwarding") \ + $SendNotification ("SMS Forwarding from " . $Phone) \ ("These message(s) were received by " . $Identity . \ " from " . $Phone . ":" . $Messages); :foreach Sms in=$Delete do={ From 4210a4909802b7c6c594b0fb1263cb4e06e62ad1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Aug 2019 20:27:11 +0200 Subject: [PATCH 0084/2612] check-routeros-update: fail on empty version string --- check-routeros-update | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/check-routeros-update b/check-routeros-update index cc6d245..c4e620c 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -30,6 +30,11 @@ / system package update check-for-updates without-paging; :local Update [ / system package update get ]; +:if ([ :len ($Update->"latest-version") ] = 0) do={ + :log warning "An empty string is not a valid version."; + :error "Warning: See log for details."; +} + :if ($Update->"installed-version" != $Update->"latest-version") do={ :local BoardName [ / system resource get board-name ]; :local RouterBoard [ / system routerboard get ]; From d457421e1e339d9eeaa7645ab83a71190f9109d7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 18 Aug 2019 18:28:43 +0200 Subject: [PATCH 0085/2612] global-functions: split off $SendEMail and $SendTelegram --- global-functions | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/global-functions b/global-functions index a139345..b1548a7 100644 --- a/global-functions +++ b/global-functions @@ -89,21 +89,15 @@ } } -# send notification via e-mail and telegram -# Note that attachment is ignored for telegram! -:global SendNotification do={ +# send notification via e-mail +:global SendEMail do={ :local Subject [ :tostr $1 ]; :local Message [ :tostr $2 ]; - :local Attach [ :tostr $3 ]; + :local Attach [ :tostr $3 ]; :global Identity; :global EmailGeneralTo; :global EmailGeneralCc; - :global TelegramTokenId; - :global TelegramChatId; - - :global UrlEncode; - :global CertificateAvailable; :if ([ :len $EmailGeneralTo ] > 0) do={ :do { @@ -118,6 +112,19 @@ :log warning "Failed sending notification mail!"; } } +} + +# send notification via telegram +:global SendTelegram do={ + :local Subject [ :tostr $1 ]; + :local Message [ :tostr $2 ]; + + :global Identity; + :global TelegramTokenId; + :global TelegramChatId; + + :global UrlEncode; + :global CertificateAvailable; :if ([ :len $TelegramTokenId ] > 0 && [ :len $TelegramChatId ] > 0) do={ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2"; @@ -132,6 +139,21 @@ } } +# send notification via e-mail and telegram +# Note that attachment is ignored for telegram! +:global SendNotification do={ + :local Subject [ :tostr $1 ]; + :local Message [ :tostr $2 ]; + :local Attach [ :tostr $3 ]; + + :global SendEMail; + :global SendTelegram; + + $SendEMail $Subject $Message $Attach; + $SendTelegram $Subject $Message; +} + + # get MAC vendor :global GetMacVendor do={ :local Mac [ :tostr $1 ]; From 06b93ca6c2b754e21d109716bd17da0d7e2909af Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 18 Aug 2019 18:44:07 +0200 Subject: [PATCH 0086/2612] global-functions: support sending silent telegram notifications --- global-functions | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/global-functions b/global-functions index b1548a7..2e4d43c 100644 --- a/global-functions +++ b/global-functions @@ -118,6 +118,7 @@ :global SendTelegram do={ :local Subject [ :tostr $1 ]; :local Message [ :tostr $2 ]; + :local Silent [ :tostr $3 ]; :global Identity; :global TelegramTokenId; @@ -131,8 +132,8 @@ :do { / tool fetch check-certificate=yes-without-crl keep-result=no http-method=post \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ - http-data=("chat_id=" . $TelegramChatId . "&text=" . \ - [ $UrlEncode ("[" . $Identity . "] " . $Subject . "\n\n" . $Message) ]); + http-data=("chat_id=" . $TelegramChatId . "&disable_notification=" . $Silent . \ + "&text=" . [ $UrlEncode ("[" . $Identity . "] " . $Subject . "\n\n" . $Message) ]); } on-error={ :log warning "Failed sending telegram notification!"; } @@ -140,17 +141,18 @@ } # send notification via e-mail and telegram -# Note that attachment is ignored for telegram! +# Note that attachment is ignored for telegram, silent is ignored for e-mail! :global SendNotification do={ :local Subject [ :tostr $1 ]; :local Message [ :tostr $2 ]; :local Attach [ :tostr $3 ]; + :local Silent [ :tostr $4 ]; :global SendEMail; :global SendTelegram; $SendEMail $Subject $Message $Attach; - $SendTelegram $Subject $Message; + $SendTelegram $Subject $Message $Silent; } From a78d9d0470fcb7d4a77880f1f45172697935a636 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 18 Aug 2019 19:13:23 +0200 Subject: [PATCH 0087/2612] check-lte-firmware-upgrade: make notification silent --- check-lte-firmware-upgrade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 045d893..8a76081 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -21,7 +21,7 @@ :if (($Firmware->"installed") != ($Firmware->"latest")) do={ $SendNotification ("LTE firmware upgrade") \ ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ - "LTE interface " . $IntName . " on " . $Identity . "."); + "LTE interface " . $IntName . " on " . $Identity . ".") "" "true"; :set SentLteFirmwareUpgradeNotification ($Firmware->"latest"); } } From 5a3076c7c31751d6bbbeea40f4d9e55825d454dd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 18 Aug 2019 19:16:08 +0200 Subject: [PATCH 0088/2612] check-routeros-update: make notifications silent --- check-routeros-update | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index c4e620c..78fd9c6 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -52,7 +52,7 @@ :log info ("Version " . $Update->"latest-version" . " is considered safe, updating..."); $SendNotification ("RouterOS update") \ ("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ - ", updating on " . $Identity . "..."); + ", updating on " . $Identity . "...") "" "true"; $DoUpdate; } } @@ -81,6 +81,7 @@ "Channel: " . $Update->"channel" . "\n" . \ "Installed: " . $Update->"installed-version" . "\n" . \ "Available: " . $Update->"latest-version" . "\n\n" .\ - "https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); + "https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree") \ + "" "true"; :set SentRouterosUpdateNotification ($Update->"latest-version"); } From 0f27c935d81236787fa9a0f86a79615f976402db Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 18 Aug 2019 19:14:17 +0200 Subject: [PATCH 0089/2612] cloud-backup: make notification silent --- cloud-backup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloud-backup b/cloud-backup index 9bb13ff..5a36f29 100644 --- a/cloud-backup +++ b/cloud-backup @@ -37,7 +37,7 @@ "RouterOS: " . $Update->"installed-version" . "\n\n" . \ "Name: " . $Cloud->"name" . "\n" . \ "Size: " . $Cloud->"size" . "\n" . \ - "Download key: " . $Cloud->"secret-download-key"); + "Download key: " . $Cloud->"secret-download-key") "" "true"; } on-error={ :log error ("Failed uploading backup for " . $Identity . " to cloud."); } From 44437c6846e4385b0c33975815deaa8f5c0757f1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 18 Aug 2019 19:20:09 +0200 Subject: [PATCH 0090/2612] upload-backup: make notification silent --- upload-backup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upload-backup b/upload-backup index 87d3960..b780299 100644 --- a/upload-backup +++ b/upload-backup @@ -69,5 +69,5 @@ $SendNotification "Backup & Config Upload" \ "Channel: " . $Update->"channel" . "\n" . \ "RouterOS: " . $Update->"installed-version" . "\n\n" . \ "Backup uploaded: " . $BackupFile . "\n" . \ - "Config uploaded: " . $ConfigFile); + "Config uploaded: " . $ConfigFile) "" "true"; } From 29dc1b884154d14b45ebf7471f59ec0755bab549 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Aug 2019 10:35:53 +0200 Subject: [PATCH 0091/2612] add script 'check-health' This may be incomplete... Please report if you have missing PSUs, ttemperature sensors, whatever. --- check-health | 57 +++++++++++++++++++++++++++++++++++++++++++ global-config | 10 +++++++- global-config.changes | 5 ++-- global-functions | 2 +- 4 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 check-health diff --git a/check-health b/check-health new file mode 100644 index 0000000..b69ae4a --- /dev/null +++ b/check-health @@ -0,0 +1,57 @@ +#!rsc +# RouterOS script: check-health +# Copyright (c) 2019 Christian Hesse +# +# check for RouterOS health state + +:global CheckHealthLast; +:global CheckHealthTemperature; +:global Identity; + +:global SendNotification; + +:local FormatVoltage do={ + :local Voltage [ :tonum $1 ]; + :return (($Voltage / 10) . "." . ($Voltage % ($Voltage / 10 * 10)) . "V"); +} + +:local CheckHealthCurrent [ / system health get ]; + +:foreach Voltage in={ "psu1-voltage"; "psu2-voltage"; "voltage" } do={ + :if ([ :typeof ($CheckHealthLast->$Voltage) ] = "num" && \ + [ :typeof ($CheckHealthCurrent->$Voltage) ] = "num") do={ + :if ($CheckHealthLast->$Voltage * 115 / 100 < $CheckHealthCurrent->$Voltage || \ + $CheckHealthLast->$Voltage * 100 / 115 > $CheckHealthCurrent->$Voltage) do={ + $SendNotification ("Health warning: " . $Voltage) \ + ("The " . $Voltage . " on " . $Identity . " jumped more than 15%.\n\n" . \ + "old value: " . [ $FormatVoltage ($CheckHealthLast->$Voltage) ] . "\n" . \ + "new value: " . [ $FormatVoltage ($CheckHealthCurrent->$Voltage) ]); + } + } +} + +:foreach PSU in={ "psu1"; "psu2" } do={ + :if ($CheckHealthLast->($PSU . "-state") = "ok" && \ + $CheckHealthCurrent->($PSU . "-state") != "ok") do={ + $SendNotification ("Health warning: " . $PSU . " state") \ + ("The power supply unit '" . $PSU . "' on " . $Identity . " failed!"); + } +} + +:foreach Temperature in={ "temperature"; "cpu-temperature"; "board-temperature1"; "board-temperature2" } do={ + :if ([ :typeof ($CheckHealthLast->$Temperature) ] = "num" && \ + [ :typeof ($CheckHealthCurrent->$Temperature) ] = "num") do={ + :if ([ :typeof ($CheckHealthTemperature->$Temperature) ] != "num" ) do={ + :log warning ("No threshold given for " . $Temperature . ", assuming 50C."); + :set ($CheckHealthTemperature->$Temperature) 50; + } + :if ($CheckHealthLast->$Temperature <= $CheckHealthTemperature->$Temperature && \ + $CheckHealthCurrent->$Temperature > $CheckHealthTemperature->$Temperature) do={ + $SendNotification ("Health warning: " . $Temperature) \ + ("The " . $Temperature . " on " . $Identity . " is above threshold: " . \ + $CheckHealthCurrent->$Temperature . "C"); + } + } +} + +:set CheckHealthLast $CheckHealthCurrent; diff --git a/global-config b/global-config index b14ff6e..e8fd04d 100644 --- a/global-config +++ b/global-config @@ -6,7 +6,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 6; +:global GlobalConfigVersion 7; # This is used for DNS and backup file. :global Domain "example.com"; @@ -44,6 +44,14 @@ :global SafeUpdateUrl ""; #:global SafeUpdateUrl "https://example.com/ros/safe-update/"; +# These thresholds control when to send notification on temperature. +:global CheckHealthTemperature { + temperature=50; + cpu-temperature=70; + board-temperature1=50; + board-temperature2=50; +} + # This controls what configuration is activated by bridge-port-to-default. :global BridgePortTo "default"; diff --git a/global-config.changes b/global-config.changes index 656cb7f..6123855 100644 --- a/global-config.changes +++ b/global-config.changes @@ -3,10 +3,11 @@ # Changes for global-config to be added to notification on script-updates :global GlobalConfigChanges { - 1="moved variables from global-config to global-functions for independence"; + 1="moved variables from 'global-config' to 'global-functions' for independence"; 2="variable names became CamelCase to work around scripting issues"; 3="variable for certificate renew passphrase became an array to support multiple passphrases"; 4="added option to ignore global-config changes"; - 5="split off new script cloud-backup from email-backup"; + 5="split off new script 'cloud-backup' from 'email-backup'"; 6="introduced script 'upload-backup' with new configuration parameters"; + 7="introduced script 'check-health' with new configuration parameters"; }; diff --git a/global-functions b/global-functions index 2e4d43c..c5e63c4 100644 --- a/global-functions +++ b/global-functions @@ -5,7 +5,7 @@ # global functions # expected configuration version -:global ExpectedConfigVersion 6; +:global ExpectedConfigVersion 7; # global variables not to be changed by user :global SentConfigChangesNotification "-"; From b74d465cd050dff793d44ceca78ce6e9745a016b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Aug 2019 15:20:11 +0200 Subject: [PATCH 0092/2612] check-health: also send recovery notifications --- check-health | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/check-health b/check-health index b69ae4a..7c7f169 100644 --- a/check-health +++ b/check-health @@ -36,6 +36,11 @@ $SendNotification ("Health warning: " . $PSU . " state") \ ("The power supply unit '" . $PSU . "' on " . $Identity . " failed!"); } + :if ($CheckHealthLast->($PSU . "-state") != "ok" && \ + $CheckHealthCurrent->($PSU . "-state") = "ok") do={ + $SendNotification ("Health recovery: " . $PSU . " state") \ + ("The power supply unit '" . $PSU . "' on " . $Identity . " recovered!"); + } } :foreach Temperature in={ "temperature"; "cpu-temperature"; "board-temperature1"; "board-temperature2" } do={ @@ -51,6 +56,12 @@ ("The " . $Temperature . " on " . $Identity . " is above threshold: " . \ $CheckHealthCurrent->$Temperature . "C"); } + :if ($CheckHealthLast->$Temperature > $CheckHealthTemperature->$Temperature && \ + $CheckHealthCurrent->$Temperature <= $CheckHealthTemperature->$Temperature) do={ + $SendNotification ("Health recovery: " . $Temperature) \ + ("The " . $Temperature . " on " . $Identity . " dropped below threshold: " . \ + $CheckHealthCurrent->$Temperature . "C"); + } } } From 63ca79b960c30e38eecc9fab9e295d0845663db6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Aug 2019 20:48:32 +0200 Subject: [PATCH 0093/2612] check-health: check for valid psu state data This is required with recovery notifications --- check-health | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/check-health b/check-health index 7c7f169..8cfe47a 100644 --- a/check-health +++ b/check-health @@ -31,15 +31,18 @@ } :foreach PSU in={ "psu1"; "psu2" } do={ - :if ($CheckHealthLast->($PSU . "-state") = "ok" && \ - $CheckHealthCurrent->($PSU . "-state") != "ok") do={ - $SendNotification ("Health warning: " . $PSU . " state") \ - ("The power supply unit '" . $PSU . "' on " . $Identity . " failed!"); - } - :if ($CheckHealthLast->($PSU . "-state") != "ok" && \ - $CheckHealthCurrent->($PSU . "-state") = "ok") do={ - $SendNotification ("Health recovery: " . $PSU . " state") \ - ("The power supply unit '" . $PSU . "' on " . $Identity . " recovered!"); + :if ([ :typeof ($CheckHealthLast->($PSU . "-state")) ] = "str" && \ + [ :typeof ($CheckHealthCurrent->($PSU . "-state")) ] = "str") do={ + :if ($CheckHealthLast->($PSU . "-state") = "ok" && \ + $CheckHealthCurrent->($PSU . "-state") != "ok") do={ + $SendNotification ("Health warning: " . $PSU . " state") \ + ("The power supply unit '" . $PSU . "' on " . $Identity . " failed!"); + } + :if ($CheckHealthLast->($PSU . "-state") != "ok" && \ + $CheckHealthCurrent->($PSU . "-state") = "ok") do={ + $SendNotification ("Health recovery: " . $PSU . " state") \ + ("The power supply unit '" . $PSU . "' on " . $Identity . " recovered!"); + } } } From 2d1a07dd0f9e30d8993e4ecafd937772003553d9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Aug 2019 07:54:00 +0200 Subject: [PATCH 0094/2612] capsman-rolling-upgrade: do not fail on missing cap This is a long running process, chances are that a cap disappears intermittently. So find cap by name and do not fail. --- capsman-rolling-upgrade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index 11b32e1..7723f93 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -15,7 +15,7 @@ :local RemoteCapVal [ / caps-man remote-cap get $RemoteCap ]; :log info ("Starting upgrade for " . $RemoteCapVal->"name" . \ " (" . $RemoteCapVal->"identity" . ")..."); - / caps-man remote-cap upgrade $RemoteCap; + / caps-man remote-cap upgrade [ find where name=$RemoteCapVal->"name" ]; :delay ($Delay . "s"); } } From 1ee3213e028e83564a0bae29294be41a9c3a54b2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Aug 2019 09:13:11 +0200 Subject: [PATCH 0095/2612] script-updates: better regex matching --- script-updates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script-updates b/script-updates index be9d373..d6d05f5 100644 --- a/script-updates +++ b/script-updates @@ -26,7 +26,7 @@ / file remove $ScriptFile; } - :foreach Scheduler in=[ / system scheduler find where on-event=($ScriptVal->"name") ] do={ + :foreach Scheduler in=[ / system scheduler find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ :local SchedulerVal [ / system scheduler get $Scheduler ]; :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ :log warning ("Policies differ for script " . $ScriptVal->"name" . \ From e479f3b01a0004c4488902f87658573ea9876af9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Aug 2019 09:28:34 +0200 Subject: [PATCH 0096/2612] README: add valid script to scheduler --- README.md | 12 ++++++------ initial-commands | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a739dae..97b6c49 100644 --- a/README.md +++ b/README.md @@ -96,8 +96,8 @@ And finally load configuration and functions and add the schedulers. [admin@MikroTik] > / system script run global-config [admin@MikroTik] > / system script run global-functions - [admin@MikroTik] > / system scheduler add name=global-config start-time=startup on-event=global-config - [admin@MikroTik] > / system scheduler add name=global-functions start-time=startup on-event=global-functions + [admin@MikroTik] > / system scheduler add name="global-config" start-time=startup on-event="/ system script run global-config;" + [admin@MikroTik] > / system scheduler add name="global-functions" start-time=startup on-event="/ system script run global-functions;" Updating scripts ---------------- @@ -112,7 +112,7 @@ Adding a script To add a script from the repository create a configuration item first, then update scripts to fetch the source. - [admin@MikroTik] > / system script add name=check-routeros-update + [admin@MikroTik] > / system script add name="check-routeros-update" [admin@MikroTik] > / system script run script-updates Scheduler and events @@ -123,16 +123,16 @@ Most scripts are designed to run regularly from added `check-routeros-update`, so let's run it every hour to make sure not to miss an update. - [admin@MikroTik] > / system scheduler add name=check-routeros-update interval=1h on-event=check-routeros-update + [admin@MikroTik] > / system scheduler add name="check-routeros-update" interval=1h on-event="/ system script run check-routeros-update;" Some events can run a script. If you want your DHCP hostnames to be available in DNS use `dhcp-to-dns` with the events from dhcp server. For a regular cleanup add a scheduler entry. - [admin@MikroTik] > / system script add name=dhcp-to-dns + [admin@MikroTik] > / system script add name="dhcp-to-dns" [admin@MikroTik] > / system script run script-updates [admin@MikroTik] > / ip dhcp-server set lease-script=dhcp-to-dns [ find ] - [admin@MikroTik] > / system scheduler add name=dhcp-to-dns interval=5m on-event=dhcp-to-dns + [admin@MikroTik] > / system scheduler add name="dhcp-to-dns" interval=5m on-event="/ system script run dhcp-to-dns;" There's much more to explore... Have fun! diff --git a/initial-commands b/initial-commands index cc15baf..c829875 100644 --- a/initial-commands +++ b/initial-commands @@ -23,7 +23,7 @@ run global-functions; } / system scheduler { - add name=global-config start-time=startup on-event=global-config; - add name=global-functions start-time=startup on-event=global-functions; + add name="global-config" start-time=startup on-event="/ system script run global-config;"; + add name="global-functions" start-time=startup on-event="/ system script run global-functions;"; } } From 03db080774168d1f26d3abed0257d2752e4ebd6e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Aug 2019 09:29:09 +0200 Subject: [PATCH 0097/2612] mode-button-event: add valid script to scheduler --- mode-button-event | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mode-button-event b/mode-button-event index 82c1f4b..2624383 100644 --- a/mode-button-event +++ b/mode-button-event @@ -12,7 +12,8 @@ :if ([ :len $Scheduler ] = 0) do={ :log info "Creating mode-button scheduler, counting presses..."; - / system scheduler add name=mode-button-scheduler on-event=mode-button-scheduler interval=3s; + / system scheduler add name="mode-button-scheduler" \ + on-event="/ system script run mode-button-scheduler;" interval=3s; } else={ :log debug "Updating mode-button-scheduler..."; / system scheduler set $Scheduler start-time=[ /system clock get time ]; From f559c4ac929c1a850875a5d7cccf72a0a9b9f64e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Aug 2019 09:29:20 +0200 Subject: [PATCH 0098/2612] unattended-lte-firmware-upgrade: add valid script to scheduler --- unattended-lte-firmware-upgrade | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index 73115c9..ac755d9 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -22,6 +22,7 @@ ":log info (\"LTE firmware upgrade finished, waiting for installation before reset.\");\n" . \ ":delay 150s;\n" . \ "/ interface lte at-chat " . $IntName . " input=\"AT+RESET\";"); - / system scheduler add name=($IntName . "-firmware-upgrade") on-event=($IntName . "-firmware-upgrade") interval=1m; + / system scheduler add name=($IntName . "-firmware-upgrade") \ + on-event=("/ system script run " . $IntName . "-firmware-upgrade;") interval=1m; } } From 8c8d7f93f19778b9a41e7dc647c42db2a9a3a945 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Aug 2019 13:58:18 +0200 Subject: [PATCH 0099/2612] ipv6-update: get values into array ... and concatenate name and regexp - just either of both is set. --- ipv6-update | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/ipv6-update b/ipv6-update index 5d5a3dc..e21e6bb 100644 --- a/ipv6-update +++ b/ipv6-update @@ -25,7 +25,8 @@ if ($OldPrefix != $PdPrefix) do={ / ipv6 firewall address-list set address=$PdPrefix $AddrList; :foreach Record in=[ / ip dns static find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ - :local Comment [ $ParseKeyValueStore [ / ip dns static get $Record comment ] ]; + :local RecordVal [ / ip dns static get $Record ]; + :local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ]; :local Prefix [ / ipv6 address get [ find where interface=($Comment->"interface") from-pool=$Pool global ] address ]; :set Prefix [ :pick $Prefix 0 [ :find $Prefix "::/64" ] ]; @@ -33,12 +34,8 @@ if ($OldPrefix != $PdPrefix) do={ :set Prefix ($Prefix . ":"); } - :local Name [ / ip dns static get $Record name ]; - :if ([ :len $Name ] = 0) do={ - :set Name [ / ip dns static get $Record regex ]; - } - - :log info ("Updating DNS record for " . $Name . " to " . $Prefix . ":" . ($Comment->"suffix")); + :log info ("Updating DNS record for " . ($RecordVal->"name") . ($RecordVal->"regexp") . \ + " to " . $Prefix . ":" . ($Comment->"suffix")); / ip dns static set address=($Prefix . ":" . ($Comment->"suffix")) $Record; } } From 05f2d03ad9da4020ad463be28bd6de4c973fbbbb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 Aug 2019 13:28:14 +0200 Subject: [PATCH 0100/2612] use shorter url for my repository --- README.md | 6 +++--- global-config | 2 +- initial-commands | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 97b6c49..4cd614b 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ download the certificates. If you intend to download the scripts from a different location (for example from github.com) install the corresponding certificate chain. - [admin@MikroTik] > / tool fetch "https://git.eworm.de/cgit.cgi/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt.pem" + [admin@MikroTik] > / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt.pem" status: finished downloaded: 3KiBC-z pause] total: 3KiB @@ -85,7 +85,7 @@ crap and a good example how to *not* do it. Now let's download the main scripts and add them in configuration on the fly. - [admin@MikroTik] > :foreach Script in={ "global-config"; "global-functions"; "script-updates" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit.cgi/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } + [admin@MikroTik] > :foreach Script in={ "global-config"; "global-functions"; "script-updates" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } The configuration needs to be tweaked for your needs. Make sure not to send your mails to `mail@example.com`! @@ -142,7 +142,7 @@ URL: [GitHub.com](https://github.com/eworm-de/routeros-scripts#routeros-scripts) Mirror: -[eworm.de](https://git.eworm.de/cgit.cgi/routeros-scripts/about/) +[eworm.de](https://git.eworm.de/cgit/routeros-scripts/about/) [GitLab.com](https://gitlab.com/eworm-de/routeros-scripts#routeros-scripts) --- diff --git a/global-config b/global-config index e8fd04d..2559181 100644 --- a/global-config +++ b/global-config @@ -100,7 +100,7 @@ # Enable this to fetch scripts from given url. :global ScriptUpdatesFetch true; -:global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit.cgi/routeros-scripts/plain/"; +:global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/"; #:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/master/"; #:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/master/"; :global ScriptUpdatesUrlSuffix ""; diff --git a/initial-commands b/initial-commands index c829875..f8dd825 100644 --- a/initial-commands +++ b/initial-commands @@ -3,7 +3,7 @@ # Copyright (c) 2018-2019 Christian Hesse { - / tool fetch "https://git.eworm.de/cgit.cgi/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt.pem"; + / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt.pem"; :delay 1s; / certificate { import file-name=letsencrypt.pem passphrase=""; @@ -16,7 +16,7 @@ } / file remove "letsencrypt.pem"; :foreach Script in={ "global-config"; "global-functions"; "script-updates" } do={ - / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit.cgi/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); + / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } / system script { run global-config; From 914e535eea4b6c2c2834f2ed5031d3430bfe6660 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 Aug 2019 10:42:33 +0200 Subject: [PATCH 0101/2612] README: add contribute section, including donate option --- README.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4cd614b..166fd29 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,25 @@ cleanup add a scheduler entry. There's much more to explore... Have fun! -### Upstream +## Contribute + +### Patches, issues and whishlist + +Feel free to contact me via e-mail or open an +[issue at github](https://github.com/eworm-de/routeros-scripts/issues). + +### Donate + +This project is developed in private spare time and usage is free of charge +for you. If you like the scripts and think this is of value for you or your +business please consider to +[donate with PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J). + +[![donate with PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) + +Thanks a lot for your support! + +## Upstream URL: [GitHub.com](https://github.com/eworm-de/routeros-scripts#routeros-scripts) From c7563d4ffd2c2f2579b320867172708d342158c0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 Aug 2019 11:47:44 +0200 Subject: [PATCH 0102/2612] add info about past contributions --- CONTRIBUTIONS.md | 18 ++++++++++++++++++ README.md | 2 ++ 2 files changed, 20 insertions(+) create mode 100644 CONTRIBUTIONS.md diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md new file mode 100644 index 0000000..f28ad03 --- /dev/null +++ b/CONTRIBUTIONS.md @@ -0,0 +1,18 @@ +Past Contributions +================== + +Thanks a lot for your contributions! + +## Patches + +These persons contributed code. See the git history for details! + +* [Michael Gisbers](mailto:michael@gisbers.de) + +## Donations + +Add yourself to the list, +[donate with PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)! + +* Reiner Vehrenkamp +* Linux-Schmie.de Michael Gisbers diff --git a/README.md b/README.md index 166fd29..588e827 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,8 @@ There's much more to explore... Have fun! ## Contribute +Thanks a lot for [past contributions](CONTRIBUTIONS.md)! + ### Patches, issues and whishlist Feel free to contact me via e-mail or open an From 166bbffe1d45e6b5f5cbf8791d952d431ddde902 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 Aug 2019 13:41:20 +0200 Subject: [PATCH 0103/2612] script-updates: add donation hint in configuration warning notification --- global-config | 9 ++++++++- global-config.changes | 1 + global-functions | 2 +- script-updates | 36 ++++++++++++++++++++++++------------ 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/global-config b/global-config index 2559181..85a4232 100644 --- a/global-config +++ b/global-config @@ -6,7 +6,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 7; +:global GlobalConfigVersion 8; # This is used for DNS and backup file. :global Domain "example.com"; @@ -107,7 +107,14 @@ :global ScriptUpdatesIgnore { "global-config" } +# Enable this to silence all configuration warnings. :global ScriptUpdatesConfigChangesIgnore false; +# This project is developed in private spare time and usage is free of charge +# for you. If you like the scripts and think this is of value for you or your +# business please consider a donation: +# https://git.eworm.de/cgit/routeros-scripts/about/#donate +# Enable this to silence donation hint. +:global IDonate false; # Use this for certificate auto-renew :global CertRenewUrl ""; diff --git a/global-config.changes b/global-config.changes index 6123855..4951996 100644 --- a/global-config.changes +++ b/global-config.changes @@ -10,4 +10,5 @@ 5="split off new script 'cloud-backup' from 'email-backup'"; 6="introduced script 'upload-backup' with new configuration parameters"; 7="introduced script 'check-health' with new configuration parameters"; + 8="added donation hint and option to silence it"; }; diff --git a/global-functions b/global-functions index c5e63c4..1b73b0a 100644 --- a/global-functions +++ b/global-functions @@ -5,7 +5,7 @@ # global functions # expected configuration version -:global ExpectedConfigVersion 7; +:global ExpectedConfigVersion 8; # global variables not to be changed by user :global SentConfigChangesNotification "-"; diff --git a/script-updates b/script-updates index d6d05f5..de8bf40 100644 --- a/script-updates +++ b/script-updates @@ -7,6 +7,7 @@ :global ExpectedConfigVersion; :global GlobalConfigVersion; :global Identity; +:global IDonate; :global SentConfigChangesNotification; :global ScriptUpdatesFetch; :global ScriptUpdatesBaseUrl; @@ -81,7 +82,10 @@ $GlobalConfigVersion < $ExpectedConfigVersion) do={ :global GlobalConfigChanges; :local ChangeLogCode; - :local Changes; + :local NotificationMessage ("Current configuration on " . $Identity . \ + " is out of date. Please update global-config, then increase " . \ + "variable GlobalConfigVersion (currently " . $GlobalConfigVersion . \ + ") to " . $ExpectedConfigVersion . " and re-run global-config."); :log debug ("Fetching changelog."); :do { @@ -91,20 +95,28 @@ :if ($Result->"status" = "finished") do={ :set ChangeLogCode ($Result->"data"); } + :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); + [ :parse $ChangeLogCode ]; + :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ + :set NotificationMessage ($NotificationMessage . \ + "\n * " . $GlobalConfigChanges->[ :tostr $I ]); + } + :set GlobalConfigChanges; } on-error={ :log info ("Failed fetching changes!"); + :set NotificationMessage ($NotificationMessage . \ + "\n\nChanges are not available."); } - [ :parse $ChangeLogCode ]; - :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ - :set Changes ( $Changes . "\n * " . $GlobalConfigChanges->[ :tostr $I ] ); - } - :set GlobalConfigChanges; - $SendNotification "Configuration warning!" \ - ("Current configuration on " . $Identity . " is out of date. " . \ - "Please update global-config, then increase variable " . \ - "GlobalConfigVersion (currently " . $GlobalConfigVersion . \ - ") to " . $ExpectedConfigVersion . " and re-run global-config.\n\n" . \ - "Changes:" . $Changes); + :if ($IDonate != true) do={ + :set NotificationMessage ($NotificationMessage . \ + "\n\n==== donation hint ====\n" . \ + "This project is developed in private spare time and usage is " . \ + "free of charge for you. If you like the scripts and think this is " . \ + "of value for you or your business please consider a donation:\n" . \ + "https://git.eworm.de/cgit/routeros-scripts/about/#donate"); + } + + $SendNotification "Configuration warning!" $NotificationMessage; :set SentConfigChangesNotification $ExpectedConfigVersion; } From ecc281446c2908a2280568ad1e0b8c246d576c88 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Sep 2019 09:39:19 +0200 Subject: [PATCH 0104/2612] packages-update: add option to schedule reboot --- packages-update | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages-update b/packages-update index 76bf120..8807027 100644 --- a/packages-update +++ b/packages-update @@ -39,6 +39,14 @@ } } +:put "Do you want to (s)chedule reboot instead of (r)eboot now? [s/R]"; +:if ([ :terminal inkey timeout=60 ] = 115) do={ + / system scheduler add name="reboot-for-update" start-time=03:00:00 interval=1d \ + on-event="/ system scheduler remove reboot-for-update; / system reboot;" + :log info ("Scheduled reboot for update at 03:00."); + :error ("Scheduled reboot."); +} + :log info ("Rebooting for update."); :delay 1s; / system reboot; From c8d6c4597ff66ca9aad6f3e41d16b43b6011b7e8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Sep 2019 10:21:44 +0200 Subject: [PATCH 0105/2612] packages-update: add random delay for scheduler --- packages-update | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages-update b/packages-update index 8807027..e02505c 100644 --- a/packages-update +++ b/packages-update @@ -42,8 +42,9 @@ :put "Do you want to (s)chedule reboot instead of (r)eboot now? [s/R]"; :if ([ :terminal inkey timeout=60 ] = 115) do={ / system scheduler add name="reboot-for-update" start-time=03:00:00 interval=1d \ - on-event="/ system scheduler remove reboot-for-update; / system reboot;" - :log info ("Scheduled reboot for update at 03:00."); + on-event=(":global RandomDelay; \$RandomDelay 3600; " . \ + "/ system scheduler remove reboot-for-update; / system reboot;"); + :log info ("Scheduled reboot for update between 03:00 and 04:00."); :error ("Scheduled reboot."); } From a7c498a90e5319e876eddadd37f3caa7ef278c41 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Sep 2019 14:48:01 +0200 Subject: [PATCH 0106/2612] update list of contributors / donors Thanks a lot! --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index f28ad03..813b9ed 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -16,3 +16,4 @@ Add yourself to the list, * Reiner Vehrenkamp * Linux-Schmie.de Michael Gisbers +* Christoph Boss (@Kampfwurst) From c7c5da2eca693db96518f5cef92fa5374d2415a9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 3 Sep 2019 20:36:13 +0200 Subject: [PATCH 0107/2612] README: add just one scheduler for global scripts --- README.md | 5 ++--- initial-commands | 5 +---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 588e827..3165684 100644 --- a/README.md +++ b/README.md @@ -92,12 +92,11 @@ your mails to `mail@example.com`! [admin@MikroTik] > / system script edit global-config source -And finally load configuration and functions and add the schedulers. +And finally load configuration and functions and add the scheduler. [admin@MikroTik] > / system script run global-config [admin@MikroTik] > / system script run global-functions - [admin@MikroTik] > / system scheduler add name="global-config" start-time=startup on-event="/ system script run global-config;" - [admin@MikroTik] > / system scheduler add name="global-functions" start-time=startup on-event="/ system script run global-functions;" + [admin@MikroTik] > / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-functions; }" Updating scripts ---------------- diff --git a/initial-commands b/initial-commands index f8dd825..335dbad 100644 --- a/initial-commands +++ b/initial-commands @@ -22,8 +22,5 @@ run global-config; run global-functions; } - / system scheduler { - add name="global-config" start-time=startup on-event="/ system script run global-config;"; - add name="global-functions" start-time=startup on-event="/ system script run global-functions;"; - } + / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-functions; }" } From 23b38fa15ab7c0b39dfeabbf2f45c69f94115ec6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Sep 2019 09:14:41 +0200 Subject: [PATCH 0108/2612] dhcp-to-dns: find duplicate leases by mac-address --- dhcp-to-dns | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index cd3b793..7cd7fa0 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -44,7 +44,7 @@ :if ([ :len $DnsRecord ] > 0) do={ :local DnsIp [ / ip dns static get $DnsRecord address ]; - :local HostLeases [ / ip dhcp-server lease find where host-name=($LeaseVal->"host-name") dynamic=yes ]; + :local HostLeases [ / ip dhcp-server lease find where mac-address=($LeaseVal->"mac-address") dynamic=yes ]; :if ([ :len $HostLeases ] > 1) do={ :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($HostLeases->([ :len $HostLeases ] - 1)) address ]; } From 94581741f42d809a1364accda57cdf1d57519ffa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 12 Sep 2019 13:45:44 +0200 Subject: [PATCH 0109/2612] global-functions: introduce and use $DeviceInfo --- check-routeros-update | 12 ++---------- cloud-backup | 13 ++----------- email-backup | 17 ++++------------- global-functions | 29 +++++++++++++++++++++++++++++ upload-backup | 17 ++++------------- 5 files changed, 41 insertions(+), 47 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index 78fd9c6..dccfcbe 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -8,6 +8,7 @@ :global SafeUpdateUrl; :global SentRouterosUpdateNotification; +:global DeviceInfo; :global SendNotification; :local DoUpdate do={ @@ -36,9 +37,6 @@ } :if ($Update->"installed-version" != $Update->"latest-version") do={ - :local BoardName [ / system resource get board-name ]; - :local RouterBoard [ / system routerboard get ]; - :if ([ :len $SafeUpdateUrl ] > 0) do={ :local Result; :do { @@ -74,13 +72,7 @@ $SendNotification ("RouterOS update") \ ("There is a RouterOS update available.\n\n" . \ - "Board name: " . $BoardName . "\n" . \ - "Model: " . $RouterBoard->"model" . "\n" . \ - "Serial number: " . $RouterBoard->"serial-number" . "\n" . \ - "Hostname: " . $Identity . "\n" . \ - "Channel: " . $Update->"channel" . "\n" . \ - "Installed: " . $Update->"installed-version" . "\n" . \ - "Available: " . $Update->"latest-version" . "\n\n" .\ + [ $DeviceInfo ] . "\n\n" . \ "https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree") \ "" "true"; :set SentRouterosUpdateNotification ($Update->"latest-version"); diff --git a/cloud-backup b/cloud-backup index 5a36f29..d948f99 100644 --- a/cloud-backup +++ b/cloud-backup @@ -7,13 +7,9 @@ :global Identity; :global BackupPassword; +:global DeviceInfo; :global SendNotification; -# get some system information -:local BoardName [ / system resource get board-name ]; -:local RouterBoard [ / system routerboard get ]; -:local Update [ / system package update get ]; - :do { # we are not interested in output, but print without count-only is # required to fetch information from cloud @@ -29,12 +25,7 @@ $SendNotification "Cloud backup" \ ("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ - "Board name: " . $BoardName . "\n" . \ - "Model: " . $RouterBoard->"model" . "\n" . \ - "Serial number: " . $RouterBoard->"serial-number" . "\n" . \ - "Hostname: " . $Identity . "\n" . \ - "Channel: " . $Update->"channel" . "\n" . \ - "RouterOS: " . $Update->"installed-version" . "\n\n" . \ + [ $DeviceInfo ] . "\n\n" . \ "Name: " . $Cloud->"name" . "\n" . \ "Size: " . $Cloud->"size" . "\n" . \ "Download key: " . $Cloud->"secret-download-key") "" "true"; diff --git a/email-backup b/email-backup index f1a2f9a..d5acb44 100644 --- a/email-backup +++ b/email-backup @@ -13,6 +13,7 @@ :global BackupPassword; :global CharacterReplace; +:global DeviceInfo; :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ @@ -26,11 +27,6 @@ :local ConfigFile "none"; :local Attach [ :toarray "" ]; -# get some system information -:local BoardName [ / system resource get board-name ]; -:local RouterBoard [ / system routerboard get ]; -:local Update [ / system package update get ]; - # binary backup :if ($BackupSendBinary = true) do={ / system backup save encryption=aes-sha256 name=$FileName password=$BackupPassword; @@ -49,13 +45,8 @@ / tool e-mail send to=$EmailBackupTo cc=$EmailBackupCc \ subject=("[" . $Identity . "] Backup & Config") \ body=("Backup and config export for " . $Identity . ".\n\n" . \ - "Board name: " . $BoardName . "\n" . \ - "Model: " . $RouterBoard->"model" . "\n" . \ - "Serial number: " . $RouterBoard->"serial-number" . "\n" . \ - "Hostname: " . $Identity . "\n" . \ - "Channel: " . $Update->"channel" . "\n" . \ - "RouterOS: " . $Update->"installed-version" . "\n\n" . \ - "Backup file: " . $BackupFile . "\n" . \ - "Config file: " . $ConfigFile) \ + [ $DeviceInfo ] . "\n\n" . \ + "Backup file: " . $BackupFile . "\n" . \ + "Config file: " . $ConfigFile) \ file=$Attach; } diff --git a/global-functions b/global-functions index 1b73b0a..87cda40 100644 --- a/global-functions +++ b/global-functions @@ -294,3 +294,32 @@ :delay ([ $GetRandom $1 ] . "s"); } + +# get readable device info +:global DeviceInfo do={ + :global Identity; + + :local BoardName [ / system resource get board-name ]; + :local RouterBoard [ / system routerboard get ]; + :local Update [ / system package update get ]; + + :local Info ( \ + "Hostname: " . $Identity . "\n" . \ + "Board name: " . $BoardName); + :if ($RouterBoard->"routerboard" = true) do={ + :set Info ($Info . "\n" . \ + "Model: " . $RouterBoard->"model" . "\n" . \ + "Serial number: " . $RouterBoard->"serial-number"); + } + :set Info ($Info . "\n" . \ + "RouterOS:\n" . \ + " Channel: " . $Update->"channel" . "\n" . \ + " Installed: " . $Update->"installed-version"); + :if ([ :typeof ($Update->"latest-version") ] != "nothing" && \ + $Update->"installed-version" != $Update->"latest-version") do={ + :set Info ($Info . "\n" . \ + " Available: " . $Update->"latest-version"); + } + + :return $Info; +} diff --git a/upload-backup b/upload-backup index b780299..a75f14a 100644 --- a/upload-backup +++ b/upload-backup @@ -14,6 +14,7 @@ :global BackupPassword; :global CharacterReplace; +:global DeviceInfo; :global SendNotification; :if ($BackupSendBinary != true && \ @@ -27,11 +28,6 @@ :local BackupFile "none"; :local ConfigFile "none"; -# get some system information -:local BoardName [ / system resource get board-name ]; -:local RouterBoard [ / system routerboard get ]; -:local Update [ / system package update get ]; - # binary backup :if ($BackupSendBinary = true) do={ / system backup save encryption=aes-sha256 name=$FileName password=$BackupPassword; @@ -62,12 +58,7 @@ $SendNotification "Backup & Config Upload" \ ("Backup and config export for " . $Identity . ".\n\n" . \ - "Board name: " . $BoardName . "\n" . \ - "Model: " . $RouterBoard->"model" . "\n" . \ - "Serial number: " . $RouterBoard->"serial-number" . "\n" . \ - "Hostname: " . $Identity . "\n" . \ - "Channel: " . $Update->"channel" . "\n" . \ - "RouterOS: " . $Update->"installed-version" . "\n\n" . \ - "Backup uploaded: " . $BackupFile . "\n" . \ - "Config uploaded: " . $ConfigFile) "" "true"; + [ $DeviceInfo ] . "\n\n" . \ + "Backup file: " . $BackupFile . "\n" . \ + "Config file: " . $ConfigFile) "" "true"; } From 2258087aab5c94a3970685f7f25587ed5403111d Mon Sep 17 00:00:00 2001 From: Michael Gisbers Date: Thu, 12 Sep 2019 13:48:46 +0200 Subject: [PATCH 0110/2612] global-functions: $DeviceInfo: handle configuration version --- global-functions | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/global-functions b/global-functions index 87cda40..371c230 100644 --- a/global-functions +++ b/global-functions @@ -1,6 +1,7 @@ #!rsc # RouterOS script: global-functions # Copyright (c) 2013-2019 Christian Hesse +# Michael Gisbers # # global functions @@ -297,6 +298,8 @@ # get readable device info :global DeviceInfo do={ + :global ExpectedConfigVersion; + :global GlobalConfigVersion; :global Identity; :local BoardName [ / system resource get board-name ]; @@ -320,6 +323,13 @@ :set Info ($Info . "\n" . \ " Available: " . $Update->"latest-version"); } + :set Info ($Info . "\n" . \ + "RouterOS-Scripts Configuration Version:\n" . \ + " Current: " . $GlobalConfigVersion); + :if ($GlobalConfigVersion != $ExpectedConfigVersion) do={ + :set Info ($Info . "\n" . \ + " Expected: " . $ExpectedConfigVersion); + } :return $Info; } From 1cee36a911ef20374cbafc989a5d3699c3fc0def Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 3 Sep 2019 20:59:00 +0200 Subject: [PATCH 0111/2612] introduce global-config-overlay --- README.md | 14 +++++++------- global-config | 2 +- global-config-overlay | 18 ++++++++++++++++++ global-config.changes | 1 + global-functions | 2 +- initial-commands | 9 +++------ script-updates | 12 ++++++++++-- 7 files changed, 41 insertions(+), 17 deletions(-) create mode 100644 global-config-overlay diff --git a/README.md b/README.md index 3165684..629b7a8 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Initial setup If you know how things work just copy and paste the [initial commands](initial-commands). Remember to edit and rerun -`global-config`! +`global-config-overlay`! First time useres should take the long way below. ### Live presentation @@ -85,18 +85,18 @@ crap and a good example how to *not* do it. Now let's download the main scripts and add them in configuration on the fly. - [admin@MikroTik] > :foreach Script in={ "global-config"; "global-functions"; "script-updates" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } + [admin@MikroTik] > :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions"; "script-updates" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } The configuration needs to be tweaked for your needs. Make sure not to send -your mails to `mail@example.com`! +your mails to `mail@example.com`! Edit `global-config-overlay`, copy +configuration from `global-config`. - [admin@MikroTik] > / system script edit global-config source + [admin@MikroTik] > / system script edit global-config-overlay source And finally load configuration and functions and add the scheduler. - [admin@MikroTik] > / system script run global-config - [admin@MikroTik] > / system script run global-functions - [admin@MikroTik] > / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-functions; }" + [admin@MikroTik] > / system script { run global-config; run global-config-overlay; run global-functions; } + [admin@MikroTik] > / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }" Updating scripts ---------------- diff --git a/global-config b/global-config index 85a4232..7a2787a 100644 --- a/global-config +++ b/global-config @@ -6,7 +6,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 8; +:global GlobalConfigVersion 9; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay new file mode 100644 index 0000000..c1971db --- /dev/null +++ b/global-config-overlay @@ -0,0 +1,18 @@ +#!rsc +# RouterOS script: global-config-overlay +# Copyright (c) 2013-2019 Christian Hesse +# +# global configuration, custom overlay + +# Make sure all configuration properties are up to date and this +# value is in sync with value in script 'global-functions'! +:global GlobalConfigVersion 9; + +# The global-config script is updated by script-updates, +# global-config-overlay becomes an overlay for your changes. +:global ScriptUpdatesIgnore { + "global-config-overlay" +} + +# Copy configuration from global-config here and modify it. + diff --git a/global-config.changes b/global-config.changes index 4951996..98c8a2c 100644 --- a/global-config.changes +++ b/global-config.changes @@ -11,4 +11,5 @@ 6="introduced script 'upload-backup' with new configuration parameters"; 7="introduced script 'check-health' with new configuration parameters"; 8="added donation hint and option to silence it"; + 9="introduced configuration overlay 'global-config-overlay'"; }; diff --git a/global-functions b/global-functions index 371c230..e50c61e 100644 --- a/global-functions +++ b/global-functions @@ -6,7 +6,7 @@ # global functions # expected configuration version -:global ExpectedConfigVersion 8; +:global ExpectedConfigVersion 9; # global variables not to be changed by user :global SentConfigChangesNotification "-"; diff --git a/initial-commands b/initial-commands index 335dbad..3caed40 100644 --- a/initial-commands +++ b/initial-commands @@ -15,12 +15,9 @@ :error "Anything is wrong with your certificates!"; } / file remove "letsencrypt.pem"; - :foreach Script in={ "global-config"; "global-functions"; "script-updates" } do={ + :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions"; "script-updates" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } - / system script { - run global-config; - run global-functions; - } - / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-functions; }" + / system script { run global-config; run global-config-overlay; run global-functions; } + / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }" } diff --git a/script-updates b/script-updates index de8bf40..8b70a98 100644 --- a/script-updates +++ b/script-updates @@ -63,6 +63,10 @@ :log info ("Updating script: " . $ScriptVal->"name"); / system script set owner=($ScriptVal->"name") source=$SourceNew \ dont-require-permissions=$DontRequirePermissions $Script; + :if ($ScriptVal->"name" = "global-config" && \ + [ / system script print count-only where name="global-config-overlay" ] > 0) do={ + / system script { run global-config; run global-config-overlay; } + } :if ($ScriptVal->"name" = "global-functions") do={ / system script run global-functions; } @@ -82,10 +86,14 @@ $GlobalConfigVersion < $ExpectedConfigVersion) do={ :global GlobalConfigChanges; :local ChangeLogCode; + :local ConfigScript "global-config"; + :if ([ /system script print count-only where name="global-config-overlay" ] > 0) do={ + :set ConfigScript "global-config-overlay"; + } :local NotificationMessage ("Current configuration on " . $Identity . \ - " is out of date. Please update global-config, then increase " . \ + " is out of date. Please update " . $ConfigScript . ", then increase " . \ "variable GlobalConfigVersion (currently " . $GlobalConfigVersion . \ - ") to " . $ExpectedConfigVersion . " and re-run global-config."); + ") to " . $ExpectedConfigVersion . " and re-run " . $ConfigScript . "."); :log debug ("Fetching changelog."); :do { From 09ce75c5b10b61bd8fbc15c61895add2ac36f1a8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Sep 2019 11:45:38 +0200 Subject: [PATCH 0112/2612] update list of contributors / donors Thanks for the Mikrotik coffee mug! --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 813b9ed..0c63f8e 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -17,3 +17,4 @@ Add yourself to the list, * Reiner Vehrenkamp * Linux-Schmie.de Michael Gisbers * Christoph Boss (@Kampfwurst) +* Klaus Michael RÃŧbsam From f40bb2c8c85adaa1ee84bb693b76a7a7e334f54a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 14 Oct 2019 19:06:21 +0200 Subject: [PATCH 0113/2612] check-health: make threshold for voltage configurable --- check-health | 7 ++++--- global-config | 6 ++++-- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/check-health b/check-health index 8cfe47a..3b5c0de 100644 --- a/check-health +++ b/check-health @@ -6,6 +6,7 @@ :global CheckHealthLast; :global CheckHealthTemperature; +:global CheckHealthVoltagePercent; :global Identity; :global SendNotification; @@ -20,10 +21,10 @@ :foreach Voltage in={ "psu1-voltage"; "psu2-voltage"; "voltage" } do={ :if ([ :typeof ($CheckHealthLast->$Voltage) ] = "num" && \ [ :typeof ($CheckHealthCurrent->$Voltage) ] = "num") do={ - :if ($CheckHealthLast->$Voltage * 115 / 100 < $CheckHealthCurrent->$Voltage || \ - $CheckHealthLast->$Voltage * 100 / 115 > $CheckHealthCurrent->$Voltage) do={ + :if ($CheckHealthLast->$Voltage * (100 + $CheckHealthVoltagePercent) / 100 < $CheckHealthCurrent->$Voltage || \ + $CheckHealthLast->$Voltage * 100 / (100 + $CheckHealthVoltagePercent) > $CheckHealthCurrent->$Voltage) do={ $SendNotification ("Health warning: " . $Voltage) \ - ("The " . $Voltage . " on " . $Identity . " jumped more than 15%.\n\n" . \ + ("The " . $Voltage . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ "old value: " . [ $FormatVoltage ($CheckHealthLast->$Voltage) ] . "\n" . \ "new value: " . [ $FormatVoltage ($CheckHealthCurrent->$Voltage) ]); } diff --git a/global-config b/global-config index 7a2787a..8089f83 100644 --- a/global-config +++ b/global-config @@ -6,7 +6,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 9; +:global GlobalConfigVersion 10; # This is used for DNS and backup file. :global Domain "example.com"; @@ -44,13 +44,15 @@ :global SafeUpdateUrl ""; #:global SafeUpdateUrl "https://example.com/ros/safe-update/"; -# These thresholds control when to send notification on temperature. +# These thresholds control when to send health notification +# on temperature and voltage. :global CheckHealthTemperature { temperature=50; cpu-temperature=70; board-temperature1=50; board-temperature2=50; } +:global CheckHealthVoltagePercent 15; # This controls what configuration is activated by bridge-port-to-default. :global BridgePortTo "default"; diff --git a/global-config-overlay b/global-config-overlay index c1971db..871aaa4 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -6,7 +6,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 9; +:global GlobalConfigVersion 10; # The global-config script is updated by script-updates, # global-config-overlay becomes an overlay for your changes. diff --git a/global-config.changes b/global-config.changes index 98c8a2c..bd8cac3 100644 --- a/global-config.changes +++ b/global-config.changes @@ -12,4 +12,5 @@ 7="introduced script 'check-health' with new configuration parameters"; 8="added donation hint and option to silence it"; 9="introduced configuration overlay 'global-config-overlay'"; + 10="make health threshold for voltage configurable"; }; diff --git a/global-functions b/global-functions index e50c61e..2336961 100644 --- a/global-functions +++ b/global-functions @@ -6,7 +6,7 @@ # global functions # expected configuration version -:global ExpectedConfigVersion 9; +:global ExpectedConfigVersion 10; # global variables not to be changed by user :global SentConfigChangesNotification "-"; From 9ce5d722b307bfcf76c892823d63328c4fd68590 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 14 Oct 2019 21:24:35 +0200 Subject: [PATCH 0114/2612] add script 'hotspot-to-wpa' --- hotspot-to-wpa | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 hotspot-to-wpa diff --git a/hotspot-to-wpa b/hotspot-to-wpa new file mode 100644 index 0000000..d1e7cee --- /dev/null +++ b/hotspot-to-wpa @@ -0,0 +1,20 @@ +#!rsc +# RouterOS script: hotspot-to-wpa +# Copyright (c) 2019 Christian Hesse +# +# add private WPA passphrase after hotspot login + +:local MacAddress $"mac-address"; +:local UserName $username; +:local Date [ / system clock get date ]; +:local PassWord [ / ip hotspot user get [ find where name=$UserName ] password ]; + +:local PlaceBefore [ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ]; +:if ([ :len $PlaceBefore ] = 0) do={ + :log error "Missing disabled access-list entry with comment '--- hotspot-to-wpa above ---'"; + :error "Error: See log for details."; +} + +/ caps-man access-list remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; +/ caps-man access-list add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + mac-address=$MacAddress private-passphrase=$PassWord ssid-regexp="-wpa\$" place-before=$PlaceBefore; From 39815662f7a7c5ad3fb4996f72d85088229f555b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Oct 2019 12:25:27 +0200 Subject: [PATCH 0115/2612] check-health: work with battery property Seen on wAP R... No idea what this is. --- check-health | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-health b/check-health index 3b5c0de..6569783 100644 --- a/check-health +++ b/check-health @@ -18,7 +18,7 @@ :local CheckHealthCurrent [ / system health get ]; -:foreach Voltage in={ "psu1-voltage"; "psu2-voltage"; "voltage" } do={ +:foreach Voltage in={ "battery"; "psu1-voltage"; "psu2-voltage"; "voltage" } do={ :if ([ :typeof ($CheckHealthLast->$Voltage) ] = "num" && \ [ :typeof ($CheckHealthCurrent->$Voltage) ] = "num") do={ :if ($CheckHealthLast->$Voltage * (100 + $CheckHealthVoltagePercent) / 100 < $CheckHealthCurrent->$Voltage || \ From df0c2afa315653429c8a41b705f100cf8310ccfd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Oct 2019 15:03:52 +0200 Subject: [PATCH 0116/2612] check-health: decrease default threshold for voltage --- global-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config b/global-config index 8089f83..0286abb 100644 --- a/global-config +++ b/global-config @@ -52,7 +52,7 @@ board-temperature1=50; board-temperature2=50; } -:global CheckHealthVoltagePercent 15; +:global CheckHealthVoltagePercent 10; # This controls what configuration is activated by bridge-port-to-default. :global BridgePortTo "default"; From 7c0c27c03f62c2fe636870ab0ab649656cce9d27 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Oct 2019 13:08:04 +0100 Subject: [PATCH 0117/2612] global-functions: add architecture in device info --- global-functions | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 2336961..21ff487 100644 --- a/global-functions +++ b/global-functions @@ -302,13 +302,14 @@ :global GlobalConfigVersion; :global Identity; - :local BoardName [ / system resource get board-name ]; + :local Resource [ / system resource get ]; :local RouterBoard [ / system routerboard get ]; :local Update [ / system package update get ]; :local Info ( \ "Hostname: " . $Identity . "\n" . \ - "Board name: " . $BoardName); + "Board name: " . $Resource->"board-name" . "\n" . \ + "Architecture: " . $Resource->"architecture-name"); :if ($RouterBoard->"routerboard" = true) do={ :set Info ($Info . "\n" . \ "Model: " . $RouterBoard->"model" . "\n" . \ From c93c6e1934ac838da6e8000ff0dfe88e42e364de Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Nov 2019 00:28:30 +0100 Subject: [PATCH 0118/2612] README: fix typo and wording --- README.md | 2 +- initial-commands | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 629b7a8..ec1654e 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Initial setup If you know how things work just copy and paste the [initial commands](initial-commands). Remember to edit and rerun `global-config-overlay`! -First time useres should take the long way below. +First time users should take the long way below. ### Live presentation diff --git a/initial-commands b/initial-commands index 3caed40..d249157 100644 --- a/initial-commands +++ b/initial-commands @@ -12,7 +12,7 @@ set name="DST-Root-CA-X3" [ find where fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ]; } :if ([ / certificate print count-only where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] != 3) do={ - :error "Anything is wrong with your certificates!"; + :error "Something is wrong with your certificates!"; } / file remove "letsencrypt.pem"; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions"; "script-updates" } do={ From 9d5c566b1cce5cd24dab0087ea94fcaa582794c8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 11 Nov 2019 20:47:11 +0100 Subject: [PATCH 0119/2612] check-certificates: make renew notification silent --- check-certificates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index d28ef86..0f2c844 100644 --- a/check-certificates +++ b/check-certificates @@ -74,7 +74,7 @@ "Fingerprint: " . ($CertNewVal->"fingerprint") . "\n" . \ "Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ - "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]); + "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]) "" "true"; :log info ("The certificate " . ($CertVal->"name") . " has been renewed."); } on-error={ :log debug ("Could not renew certificate " . ($CertVal->"name") . "."); From 91776d3388e3b0d8082d7e5acaa18e7116080d7c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 12 Nov 2019 12:49:28 +0100 Subject: [PATCH 0120/2612] dhcp-to-dns: handle duplicate mac-address and host-name * several leases for one mac address (changed client id, different net): -> take address from last lease Most likely this is the same devices which booted different OS or changed to different network. * several leases for one host name: -> take address from first lease We see either different devices with same name or one device with several network interfaces. Keep the first name to mitigate stealing dns name. --- dhcp-to-dns | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index 7cd7fa0..e403881 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -44,9 +44,14 @@ :if ([ :len $DnsRecord ] > 0) do={ :local DnsIp [ / ip dns static get $DnsRecord address ]; - :local HostLeases [ / ip dhcp-server lease find where mac-address=($LeaseVal->"mac-address") dynamic=yes ]; - :if ([ :len $HostLeases ] > 1) do={ - :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($HostLeases->([ :len $HostLeases ] - 1)) address ]; + :local DupMacLeases [ / ip dhcp-server lease find where mac-address=($LeaseVal->"mac-address") dynamic=yes ]; + :if ([ :len $DupMacLeases ] > 1) do={ + :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; + } + + :local DupHostLeases [ / ip dhcp-server lease find where host-name=($LeaseVal->"host-name") dynamic=yes ]; + :if ([ :len $DupHostLeases ] > 1) do={ + :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($DupHostLeases->0) address ]; } :if ($DnsIp = $LeaseVal->"address") do={ From 395bc8c90f89d533486df8fd4867de4cbf6a3114 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 12 Nov 2019 13:02:40 +0100 Subject: [PATCH 0121/2612] dhcp-to-dns: set the temporary variable unconditionally --- dhcp-to-dns | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index e403881..81b2964 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -49,10 +49,7 @@ :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; } - :local DupHostLeases [ / ip dhcp-server lease find where host-name=($LeaseVal->"host-name") dynamic=yes ]; - :if ([ :len $DupHostLeases ] > 1) do={ - :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($DupHostLeases->0) address ]; - } + :set ($LeaseVal->"address") [ / ip dhcp-server lease get ([ find where host-name=($LeaseVal->"host-name") dynamic=yes ]->0) address ]; :if ($DnsIp = $LeaseVal->"address") do={ :log debug ("DNS entry for " . $Fqdn . " does not need updating."); From 845c25f87c4cfa25058f561b938c487b224af00e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 14 Nov 2019 22:16:33 +0100 Subject: [PATCH 0122/2612] dhcp-to-dns: act on hostname only if available --- dhcp-to-dns | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index 81b2964..edb50b4 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -49,7 +49,9 @@ :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; } - :set ($LeaseVal->"address") [ / ip dhcp-server lease get ([ find where host-name=($LeaseVal->"host-name") dynamic=yes ]->0) address ]; + :if ([ :len ($LeaseVal->"host-name") ] > 0) do={ + :set ($LeaseVal->"address") [ / ip dhcp-server lease get ([ find where host-name=($LeaseVal->"host-name") dynamic=yes ]->0) address ]; + } :if ($DnsIp = $LeaseVal->"address") do={ :log debug ("DNS entry for " . $Fqdn . " does not need updating."); From 73a3e58c8f561795c3ba68017e0b009e443e009b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 21 Nov 2019 22:22:04 +0100 Subject: [PATCH 0123/2612] {email,upload}-backup: update wording --- email-backup | 3 ++- upload-backup | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/email-backup b/email-backup index d5acb44..bbd1d8c 100644 --- a/email-backup +++ b/email-backup @@ -44,7 +44,8 @@ # send email with status and files / tool e-mail send to=$EmailBackupTo cc=$EmailBackupCc \ subject=("[" . $Identity . "] Backup & Config") \ - body=("Backup and config export for " . $Identity . ".\n\n" . \ + body=("See attached files for backup and config export for " . \ + $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ "Config file: " . $ConfigFile) \ diff --git a/upload-backup b/upload-backup index a75f14a..d5ba182 100644 --- a/upload-backup +++ b/upload-backup @@ -57,7 +57,7 @@ } $SendNotification "Backup & Config Upload" \ - ("Backup and config export for " . $Identity . ".\n\n" . \ + ("Backup and config export upload for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ "Config file: " . $ConfigFile) "" "true"; From b70d4f7666e4a2ad7c447b84c9faa1f42374158a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 25 Nov 2019 16:39:23 +0100 Subject: [PATCH 0124/2612] collect-wireless-mac: move code into condition --- collect-wireless-mac.capsman | 12 ++++++------ collect-wireless-mac.local | 12 ++++++------ collect-wireless-mac.template | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index dd27ba6..1aa5cb7 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -30,12 +30,12 @@ $ScriptLock "collect-wireless-mac.capsman"; :if ([ :len $Lease ] > 0) do={ :set HostName [ / ip dhcp-server lease get $Lease host-name ]; :set Address [ / ip dhcp-server lease get $Lease address ]; - } - :if ([ :len $HostName ] = 0) do={ - :set HostName "no hostname"; - } - :if ([ :len $Address ] = 0) do={ - :set Address "no address"; + :if ([ :len $HostName ] = 0) do={ + :set HostName "no hostname"; + } + :if ([ :len $Address ] = 0) do={ + :set Address "no address"; + } } :local RegEntry [ / caps-man registration-table find where mac-address=$Mac ]; :local Interface [ / caps-man registration-table get $RegEntry interface ]; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index a28e2ee..882741f 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -30,12 +30,12 @@ $ScriptLock "collect-wireless-mac.local"; :if ([ :len $Lease ] > 0) do={ :set HostName [ / ip dhcp-server lease get $Lease host-name ]; :set Address [ / ip dhcp-server lease get $Lease address ]; - } - :if ([ :len $HostName ] = 0) do={ - :set HostName "no hostname"; - } - :if ([ :len $Address ] = 0) do={ - :set Address "no address"; + :if ([ :len $HostName ] = 0) do={ + :set HostName "no hostname"; + } + :if ([ :len $Address ] = 0) do={ + :set Address "no address"; + } } :local RegEntry [ / interface wireless registration-table find where mac-address=$Mac ]; :local Interface [ / interface wireless registration-table get $RegEntry interface ]; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 9e06a88..eba06ad 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -31,12 +31,12 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; :if ([ :len $Lease ] > 0) do={ :set HostName [ / ip dhcp-server lease get $Lease host-name ]; :set Address [ / ip dhcp-server lease get $Lease address ]; - } - :if ([ :len $HostName ] = 0) do={ - :set HostName "no hostname"; - } - :if ([ :len $Address ] = 0) do={ - :set Address "no address"; + :if ([ :len $HostName ] = 0) do={ + :set HostName "no hostname"; + } + :if ([ :len $Address ] = 0) do={ + :set Address "no address"; + } } :local RegEntry [ / %PATH% registration-table find where mac-address=$Mac ]; :local Interface [ / %PATH% registration-table get $RegEntry interface ]; From 15a6fb325ee25d48c585d2a9c29763ae2c516f39 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 25 Nov 2019 16:43:19 +0100 Subject: [PATCH 0125/2612] collect-wireless-mac: lease without address should be impossible... ... we need the check for empty hostname, though. --- collect-wireless-mac.capsman | 7 ++----- collect-wireless-mac.local | 7 ++----- collect-wireless-mac.template | 7 ++----- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 1aa5cb7..0768a23 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -24,18 +24,15 @@ $ScriptLock "collect-wireless-mac.capsman"; :local Mac [ / caps-man registration-table get $RegTbl mac-address ]; :local AccessList ([ / caps-man access-list find where mac-address=$Mac ]->0); :if ([ :len $AccessList ] = 0) do={ - :local HostName "no dhcp lease"; :local Address "no dhcp lease"; + :local HostName "no dhcp lease"; :local Lease [ / ip dhcp-server lease find where mac-address=$Mac ]; :if ([ :len $Lease ] > 0) do={ - :set HostName [ / ip dhcp-server lease get $Lease host-name ]; :set Address [ / ip dhcp-server lease get $Lease address ]; + :set HostName [ / ip dhcp-server lease get $Lease host-name ]; :if ([ :len $HostName ] = 0) do={ :set HostName "no hostname"; } - :if ([ :len $Address ] = 0) do={ - :set Address "no address"; - } } :local RegEntry [ / caps-man registration-table find where mac-address=$Mac ]; :local Interface [ / caps-man registration-table get $RegEntry interface ]; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 882741f..4e60159 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -24,18 +24,15 @@ $ScriptLock "collect-wireless-mac.local"; :local Mac [ / interface wireless registration-table get $RegTbl mac-address ]; :local AccessList ([ / interface wireless access-list find where mac-address=$Mac ]->0); :if ([ :len $AccessList ] = 0) do={ - :local HostName "no dhcp lease"; :local Address "no dhcp lease"; + :local HostName "no dhcp lease"; :local Lease [ / ip dhcp-server lease find where mac-address=$Mac ]; :if ([ :len $Lease ] > 0) do={ - :set HostName [ / ip dhcp-server lease get $Lease host-name ]; :set Address [ / ip dhcp-server lease get $Lease address ]; + :set HostName [ / ip dhcp-server lease get $Lease host-name ]; :if ([ :len $HostName ] = 0) do={ :set HostName "no hostname"; } - :if ([ :len $Address ] = 0) do={ - :set Address "no address"; - } } :local RegEntry [ / interface wireless registration-table find where mac-address=$Mac ]; :local Interface [ / interface wireless registration-table get $RegEntry interface ]; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index eba06ad..c7a2e54 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -25,18 +25,15 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; :local Mac [ / %PATH% registration-table get $RegTbl mac-address ]; :local AccessList ([ / %PATH% access-list find where mac-address=$Mac ]->0); :if ([ :len $AccessList ] = 0) do={ - :local HostName "no dhcp lease"; :local Address "no dhcp lease"; + :local HostName "no dhcp lease"; :local Lease [ / ip dhcp-server lease find where mac-address=$Mac ]; :if ([ :len $Lease ] > 0) do={ - :set HostName [ / ip dhcp-server lease get $Lease host-name ]; :set Address [ / ip dhcp-server lease get $Lease address ]; + :set HostName [ / ip dhcp-server lease get $Lease host-name ]; :if ([ :len $HostName ] = 0) do={ :set HostName "no hostname"; } - :if ([ :len $Address ] = 0) do={ - :set Address "no address"; - } } :local RegEntry [ / %PATH% registration-table find where mac-address=$Mac ]; :local Interface [ / %PATH% registration-table get $RegEntry interface ]; From a8a0523d33a2760f61d24a42fc057c5c24a596ae Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 25 Nov 2019 17:07:45 +0100 Subject: [PATCH 0126/2612] collect-wireless-mac: add the dns name --- collect-wireless-mac.capsman | 6 ++++++ collect-wireless-mac.local | 6 ++++++ collect-wireless-mac.template | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 0768a23..0b87bf7 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -25,6 +25,7 @@ $ScriptLock "collect-wireless-mac.capsman"; :local AccessList ([ / caps-man access-list find where mac-address=$Mac ]->0); :if ([ :len $AccessList ] = 0) do={ :local Address "no dhcp lease"; + :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; :local Lease [ / ip dhcp-server lease find where mac-address=$Mac ]; :if ([ :len $Lease ] > 0) do={ @@ -33,6 +34,10 @@ $ScriptLock "collect-wireless-mac.capsman"; :if ([ :len $HostName ] = 0) do={ :set HostName "no hostname"; } + :set DnsName [ / ip dns static get ([ find where address=$Address ]->0) name ]; + :if ([ :len $DnsName ] = 0) do={ + :set DnsName "no dns name"; + } } :local RegEntry [ / caps-man registration-table find where mac-address=$Mac ]; :local Interface [ / caps-man registration-table get $RegEntry interface ]; @@ -52,6 +57,7 @@ $ScriptLock "collect-wireless-mac.capsman"; "Vendor: " . $Vendor . "\n" . \ "Hostname: " . $HostName . "\n" . \ "Address: " . $Address . "\n" . \ + "DNS name: " . $DnsName . "\n" . \ "Date: " . $DateTime); } else={ :local Comment [ / caps-man access-list get $AccessList comment ]; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 4e60159..52e8629 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -25,6 +25,7 @@ $ScriptLock "collect-wireless-mac.local"; :local AccessList ([ / interface wireless access-list find where mac-address=$Mac ]->0); :if ([ :len $AccessList ] = 0) do={ :local Address "no dhcp lease"; + :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; :local Lease [ / ip dhcp-server lease find where mac-address=$Mac ]; :if ([ :len $Lease ] > 0) do={ @@ -33,6 +34,10 @@ $ScriptLock "collect-wireless-mac.local"; :if ([ :len $HostName ] = 0) do={ :set HostName "no hostname"; } + :set DnsName [ / ip dns static get ([ find where address=$Address ]->0) name ]; + :if ([ :len $DnsName ] = 0) do={ + :set DnsName "no dns name"; + } } :local RegEntry [ / interface wireless registration-table find where mac-address=$Mac ]; :local Interface [ / interface wireless registration-table get $RegEntry interface ]; @@ -52,6 +57,7 @@ $ScriptLock "collect-wireless-mac.local"; "Vendor: " . $Vendor . "\n" . \ "Hostname: " . $HostName . "\n" . \ "Address: " . $Address . "\n" . \ + "DNS name: " . $DnsName . "\n" . \ "Date: " . $DateTime); } else={ :local Comment [ / interface wireless access-list get $AccessList comment ]; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index c7a2e54..71af0dc 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -26,6 +26,7 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; :local AccessList ([ / %PATH% access-list find where mac-address=$Mac ]->0); :if ([ :len $AccessList ] = 0) do={ :local Address "no dhcp lease"; + :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; :local Lease [ / ip dhcp-server lease find where mac-address=$Mac ]; :if ([ :len $Lease ] > 0) do={ @@ -34,6 +35,10 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; :if ([ :len $HostName ] = 0) do={ :set HostName "no hostname"; } + :set DnsName [ / ip dns static get ([ find where address=$Address ]->0) name ]; + :if ([ :len $DnsName ] = 0) do={ + :set DnsName "no dns name"; + } } :local RegEntry [ / %PATH% registration-table find where mac-address=$Mac ]; :local Interface [ / %PATH% registration-table get $RegEntry interface ]; @@ -54,6 +59,7 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; "Vendor: " . $Vendor . "\n" . \ "Hostname: " . $HostName . "\n" . \ "Address: " . $Address . "\n" . \ + "DNS name: " . $DnsName . "\n" . \ "Date: " . $DateTime); } else={ :local Comment [ / %PATH% access-list get $AccessList comment ]; From ac6c132ea0154de90b4f8f9f8366eab7db86abc8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 28 Nov 2019 10:49:21 +0100 Subject: [PATCH 0127/2612] global-functions: $DeviceInfo: append revision to model --- global-functions | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 21ff487..218262b 100644 --- a/global-functions +++ b/global-functions @@ -311,8 +311,12 @@ "Board name: " . $Resource->"board-name" . "\n" . \ "Architecture: " . $Resource->"architecture-name"); :if ($RouterBoard->"routerboard" = true) do={ + :local Revision ""; + :if ([ :len ($RouterBoard->"revision") ] > 0) do={ + :set Revision (" " . $RouterBoard->"revision"); + } :set Info ($Info . "\n" . \ - "Model: " . $RouterBoard->"model" . "\n" . \ + "Model: " . $RouterBoard->"model" . $Revision . "\n" . \ "Serial number: " . $RouterBoard->"serial-number"); } :set Info ($Info . "\n" . \ From e37af0065c9e52243ea83780c73029b0ec8acf1c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 3 Dec 2019 11:41:18 +0100 Subject: [PATCH 0128/2612] hotspot-to-wpa: get limits from place-before-entry --- hotspot-to-wpa | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/hotspot-to-wpa b/hotspot-to-wpa index d1e7cee..bf5ce81 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -16,5 +16,14 @@ } / caps-man access-list remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; -/ caps-man access-list add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - mac-address=$MacAddress private-passphrase=$PassWord ssid-regexp="-wpa\$" place-before=$PlaceBefore; + +:local Limits [ / caps-man access-list get $PlaceBefore ]; +:if (($Limits->"ap-tx-limit") > 0 && ($Limits->"client-tx-limit") > 0) do={ + / caps-man access-list add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + mac-address=$MacAddress private-passphrase=$PassWord ssid-regexp="-wpa\$" \ + ap-tx-limit=($Limits->"ap-tx-limit") client-tx-limit=($Limits->"client-tx-limit") \ + place-before=$PlaceBefore; +} else={ + / caps-man access-list add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + mac-address=$MacAddress private-passphrase=$PassWord ssid-regexp="-wpa\$" place-before=$PlaceBefore; +} From bccdb47fdedf5cccd779fd54766db05dfd1741ab Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Aug 2019 14:17:34 +0200 Subject: [PATCH 0129/2612] ipv6-update: calculate address with bitwise operator Support for bitwise operator was added in RouterOS 6.46beta38. --- ipv6-update | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/ipv6-update b/ipv6-update index e21e6bb..86bd827 100644 --- a/ipv6-update +++ b/ipv6-update @@ -29,13 +29,10 @@ if ($OldPrefix != $PdPrefix) do={ :local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ]; :local Prefix [ / ipv6 address get [ find where interface=($Comment->"interface") from-pool=$Pool global ] address ]; - :set Prefix [ :pick $Prefix 0 [ :find $Prefix "::/64" ] ]; - :if ($Prefix~"^[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:") do={ } else={ - :set Prefix ($Prefix . ":"); - } + :set Prefix [ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ]; + :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); - :log info ("Updating DNS record for " . ($RecordVal->"name") . ($RecordVal->"regexp") . \ - " to " . $Prefix . ":" . ($Comment->"suffix")); - / ip dns static set address=($Prefix . ":" . ($Comment->"suffix")) $Record; + :log info ("Updating DNS record for " . ($RecordVal->"name") . ($RecordVal->"regexp") . " to " . $Address); + / ip dns static set address=$Address $Record; } } From ebd5ff9bfecf8a843eb7ed87d10b2bacc8518ca6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 3 Dec 2019 21:46:04 +0100 Subject: [PATCH 0130/2612] global-functions: introduce $ScriptFromTerminal Checking whether or not started from terminal is tricky... We have to find the job for the script, find its top most parent and get its type. --- global-functions | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/global-functions b/global-functions index 218262b..2bff9cc 100644 --- a/global-functions +++ b/global-functions @@ -243,6 +243,24 @@ } } +# check if script is run from terminal +:global ScriptFromTerminal do={ + :local Script [ :tostr $1 ]; + + :foreach Job in=[ / system script job find where script=$Script ] do={ + :set Job [ / system script job get $Job ]; + :while ([ :typeof ($Job->"parent") ] = "id") do={ + :set Job [ / system script job get [ find where .id=($Job->"parent") ] ]; + } + :if (($Job->"type") = "login") do={ + :log debug ("Script " . $Script . " started from terminal."); + :return true; + } + } + + :return false; +} + # wait for file to be available :global WaitForFile do={ :global CleanFilePath; From f26222d5a830d9ef8023f43409e95ad67ecf23b4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 3 Dec 2019 22:07:29 +0100 Subject: [PATCH 0131/2612] check-routeros-update: use $ScriptFromTerminal --- check-routeros-update | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/check-routeros-update b/check-routeros-update index dccfcbe..8b9d94d 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -9,6 +9,7 @@ :global SentRouterosUpdateNotification; :global DeviceInfo; +:global ScriptFromTerminal; :global SendNotification; :local DoUpdate do={ @@ -55,7 +56,7 @@ } } - :if ([ / system script job print count-only where script="check-routeros-update" parent~"." ] > 0) do={ + :if ([ $ScriptFromTerminal "check-routeros-update" ] = true) do={ :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); :if ([ :terminal inkey timeout=60 ] = 121) do={ $DoUpdate; From 9548641b606302f9d66bedabda08ca73be1ed04f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 4 Dec 2019 09:21:07 +0100 Subject: [PATCH 0132/2612] packages-update: skip the interactive part of non-terminal --- packages-update | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/packages-update b/packages-update index e02505c..0e0a87f 100644 --- a/packages-update +++ b/packages-update @@ -5,6 +5,7 @@ # download packages and reboot for installation :global DownloadPackage; +:global ScriptFromTerminal; :local Update [ / system package update get ]; @@ -30,22 +31,24 @@ / system script run $Script; } -:if (!([ /system resource get version ] ~ ($Update->"channel"))) do={ - :put "Update channel changed. Want to downgrade? [y/N]"; - :if ([ :terminal inkey timeout=60 ] = 121) do={ - :log info ("Rebooting for downgrade."); - :delay 1s; - / system package downgrade; +:if ([ $ScriptFromTerminal "packages-update" ] = true) do={ + :if (!([ /system resource get version ] ~ ($Update->"channel"))) do={ + :put "Update channel changed. Want to downgrade? [y/N]"; + :if ([ :terminal inkey timeout=60 ] = 121) do={ + :log info ("Rebooting for downgrade."); + :delay 1s; + / system package downgrade; + } } -} -:put "Do you want to (s)chedule reboot instead of (r)eboot now? [s/R]"; -:if ([ :terminal inkey timeout=60 ] = 115) do={ - / system scheduler add name="reboot-for-update" start-time=03:00:00 interval=1d \ - on-event=(":global RandomDelay; \$RandomDelay 3600; " . \ - "/ system scheduler remove reboot-for-update; / system reboot;"); - :log info ("Scheduled reboot for update between 03:00 and 04:00."); - :error ("Scheduled reboot."); + :put "Do you want to (s)chedule reboot instead of (r)eboot now? [s/R]"; + :if ([ :terminal inkey timeout=60 ] = 115) do={ + / system scheduler add name="reboot-for-update" start-time=03:00:00 interval=1d \ + on-event=(":global RandomDelay; \$RandomDelay 3600; " . \ + "/ system scheduler remove reboot-for-update; / system reboot;"); + :log info ("Scheduled reboot for update between 03:00 and 04:00."); + :error ("Scheduled reboot."); + } } :log info ("Rebooting for update."); From b8db93918fa0f15b4b5113c8d98364b0a86607cc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Dec 2019 09:48:50 +0100 Subject: [PATCH 0133/2612] capsman-download-packages: lock against multiple invocation --- capsman-download-packages | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/capsman-download-packages b/capsman-download-packages index 2a5a0d0..dc95afe 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -5,8 +5,11 @@ # # download and cleanup packages for CAP installation from CAPsMAN -:global DownloadPackage; :global CleanFilePath; +:global DownloadPackage; +:global ScriptLock; + +$ScriptLock "capsman-download-packages"; :local PackagePath [ $CleanFilePath [ / caps-man manager get package-path ] ]; :local InstalledVersion [ / system package update get installed-version ]; From 3db466f476ae9bdf51a27647ead8ff34800efd0d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Dec 2019 09:50:44 +0100 Subject: [PATCH 0134/2612] capsman-rolling-upgrade: lock against multiple invocation --- capsman-rolling-upgrade | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index 7723f93..7e172cc 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -5,6 +5,10 @@ # # upgrade CAPs one after another +:global ScriptLock; + +$ScriptLock "capsman-rolling-upgrade"; + :local InstalledVersion [ / system package update get installed-version ]; :local RemoteCapCount [ /caps-man remote-cap print count-only ]; From 7365bfa52510daba4cea452dcf786edaaf990a77 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Dec 2019 09:55:37 +0100 Subject: [PATCH 0135/2612] packages-update: lock against multiple invocation --- packages-update | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages-update b/packages-update index 0e0a87f..9a524e1 100644 --- a/packages-update +++ b/packages-update @@ -6,6 +6,9 @@ :global DownloadPackage; :global ScriptFromTerminal; +:global ScriptLock; + +$ScriptLock "packages-update"; :local Update [ / system package update get ]; From 64341690bfbe01e6efc697746e6e34c1f0d5a3da Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Dec 2019 11:43:46 +0100 Subject: [PATCH 0136/2612] global-functions: $DownloadPackage: retry on error --- global-functions | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/global-functions b/global-functions index 2bff9cc..d0d91a9 100644 --- a/global-functions +++ b/global-functions @@ -215,22 +215,27 @@ :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; $CertificateAvailable "Let's Encrypt Authority X3"; - :do { - / tool fetch check-certificate=yes-without-crl \ - ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile) \ - dst-path=$PkgDest; - $WaitForFile $PkgDest; - } on-error={ + + :local Retry 3; + :while ($Retry > 0) do={ + :do { + / tool fetch check-certificate=yes-without-crl \ + ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile) \ + dst-path=$PkgDest; + $WaitForFile $PkgDest; + + :if ([ / file get [ find where name=$PkgDest ] type ] = "package") do={ + :return true; + } + } on-error={ + # catch error and fall through + } + / file remove [ find where name=$PkgDest ]; - :return false; + :set Retry ($Retry - 1); } - :if ([ / file get [ find where name=$PkgDest ] type ] != "package") do={ - / file remove [ find where name=$PkgDest ]; - :return false; - } - - :return true; + :return false; } # lock script against multiple invocation From d064bd349e9d3629a3b2cbdd84e13c13f0d90b45 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Dec 2019 14:45:35 +0100 Subject: [PATCH 0137/2612] global-functions: define first, set later --- global-functions | 50 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/global-functions b/global-functions index d0d91a9..f6d770d 100644 --- a/global-functions +++ b/global-functions @@ -14,8 +14,26 @@ :global SentLteFirmwareUpgradeNotification "-"; :global Identity [ / system identity get name ]; +# global functions +:global UrlEncode; +:global CharacterReplace; +:global CertificateAvailable; +:global SendEMail; +:global SendTelegram; +:global SendNotification; +:global GetMacVendor; +:global CleanFilePath; +:global DownloadPackage; +:global ScriptLock; +:global ScriptFromTerminal; +:global WaitForFile; +:global ParseKeyValueStore; +:global GetRandom; +:global RandomDelay; +:global DeviceInfo; + # url encoding -:global UrlEncode do={ +:set UrlEncode do={ :local Input [ :tostr $1 ]; :local Return ""; @@ -41,7 +59,7 @@ } # character replace -:global CharacterReplace do={ +:set CharacterReplace do={ :local String [ :tostr $1 ]; :local ReplaceFrom [ :tostr $2 ]; :local ReplaceWith [ :tostr $3 ]; @@ -62,7 +80,7 @@ } # check and import required certificates -:global CertificateAvailable do={ +:set CertificateAvailable do={ :local CommonName [ :tostr $1 ]; :global ScriptUpdatesBaseUrl; @@ -91,7 +109,7 @@ } # send notification via e-mail -:global SendEMail do={ +:set SendEMail do={ :local Subject [ :tostr $1 ]; :local Message [ :tostr $2 ]; :local Attach [ :tostr $3 ]; @@ -116,7 +134,7 @@ } # send notification via telegram -:global SendTelegram do={ +:set SendTelegram do={ :local Subject [ :tostr $1 ]; :local Message [ :tostr $2 ]; :local Silent [ :tostr $3 ]; @@ -143,7 +161,7 @@ # send notification via e-mail and telegram # Note that attachment is ignored for telegram, silent is ignored for e-mail! -:global SendNotification do={ +:set SendNotification do={ :local Subject [ :tostr $1 ]; :local Message [ :tostr $2 ]; :local Attach [ :tostr $3 ]; @@ -158,7 +176,7 @@ # get MAC vendor -:global GetMacVendor do={ +:set GetMacVendor do={ :local Mac [ :tostr $1 ]; :global CertificateAvailable; @@ -175,7 +193,7 @@ } # clean file path -:global CleanFilePath do={ +:set CleanFilePath do={ :local Path [ :tostr $1 ]; :global CharacterReplace; @@ -194,7 +212,7 @@ } # download package from upgrade server -:global DownloadPackage do={ +:set DownloadPackage do={ :local PkgName [ :tostr $1 ]; :local PkgVer [ :tostr $2 ]; :local PkgArch [ :tostr $3 ]; @@ -239,7 +257,7 @@ } # lock script against multiple invocation -:global ScriptLock do={ +:set ScriptLock do={ :local Script [ :tostr $1 ]; :if ([ / system script job print count-only where script=$Script ] > 1) do={ @@ -249,7 +267,7 @@ } # check if script is run from terminal -:global ScriptFromTerminal do={ +:set ScriptFromTerminal do={ :local Script [ :tostr $1 ]; :foreach Job in=[ / system script job find where script=$Script ] do={ @@ -267,7 +285,7 @@ } # wait for file to be available -:global WaitForFile do={ +:set WaitForFile do={ :global CleanFilePath; :local FileName [ $CleanFilePath [ :tostr $1 ] ]; @@ -284,7 +302,7 @@ } # parse key value store -:global ParseKeyValueStore do={ +:set ParseKeyValueStore do={ :global CharacterReplace; :local Source $1; @@ -302,7 +320,7 @@ # generate random number # Warning: This is a *very* weak algorithm and in *no way* # useful for cryptography or similar! -:global GetRandom do={ +:set GetRandom do={ :local Max ([ :tonum $1 ] + 1); :local Sum 0; @@ -313,14 +331,14 @@ } # delay a random amount of seconds -:global RandomDelay do={ +:set RandomDelay do={ :global GetRandom; :delay ([ $GetRandom $1 ] . "s"); } # get readable device info -:global DeviceInfo do={ +:set DeviceInfo do={ :global ExpectedConfigVersion; :global GlobalConfigVersion; :global Identity; From f9c9d67cc926d7cde8ed1a90ee340e136ab647b8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Dec 2019 14:38:42 +0100 Subject: [PATCH 0138/2612] packages-update: improve wording --- packages-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages-update b/packages-update index 9a524e1..56c8c59 100644 --- a/packages-update +++ b/packages-update @@ -44,7 +44,7 @@ $ScriptLock "packages-update"; } } - :put "Do you want to (s)chedule reboot instead of (r)eboot now? [s/R]"; + :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; :if ([ :terminal inkey timeout=60 ] = 115) do={ / system scheduler add name="reboot-for-update" start-time=03:00:00 interval=1d \ on-event=(":global RandomDelay; \$RandomDelay 3600; " . \ From afb9839073d22e560f309535cf9ea6b0a00f848c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Jan 2020 17:00:39 +0100 Subject: [PATCH 0139/2612] update copyright for 2020 --- accesslist-duplicates.capsman | 2 +- accesslist-duplicates.local | 2 +- accesslist-duplicates.template | 2 +- bridge-port-to-default | 2 +- bridge-port-toggle | 2 +- capsman-download-packages | 2 +- capsman-rolling-upgrade | 2 +- certificate-renew-issued | 2 +- check-certificates | 2 +- check-health | 2 +- check-lte-firmware-upgrade | 2 +- check-routeros-update | 2 +- cloud-backup | 2 +- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- daily-psk-schedule | 2 +- daily-psk.capsman | 2 +- daily-psk.local | 2 +- daily-psk.template | 2 +- dhcp-lease-comment.capsman | 2 +- dhcp-lease-comment.local | 2 +- dhcp-lease-comment.template | 2 +- dhcp-to-dns | 2 +- email-backup | 2 +- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 2 +- global-functions | 2 +- gps-track | 2 +- hotspot-to-wpa | 2 +- initial-commands | 2 +- ip-addr-bridge | 2 +- ipv6-update | 2 +- learn-mac-based-vlan | 2 +- lease-script | 2 +- leds-day-mode | 2 +- leds-night-mode | 2 +- leds-toggle-mode | 2 +- manage-umts | 2 +- mode-button-event | 2 +- mode-button-scheduler | 2 +- netwatch-syslog | 2 +- packages-update | 2 +- ppp-on-up | 2 +- rotate-ntp | 2 +- script-updates | 2 +- sms-action | 2 +- sms-forward | 2 +- ssh-keys-import | 2 +- super-mario-theme | 2 +- unattended-lte-firmware-upgrade | 2 +- update-gre-address | 2 +- update-tunnelbroker | 2 +- upload-backup | 2 +- 55 files changed, 55 insertions(+), 55 deletions(-) diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman index a7ae099..e506740 100644 --- a/accesslist-duplicates.capsman +++ b/accesslist-duplicates.capsman @@ -1,6 +1,6 @@ #!rsc # RouterOS script: accesslist-duplicates.capsman -# Copyright (c) 2018-2019 Christian Hesse +# Copyright (c) 2018-2020 Christian Hesse # # print duplicate antries in wireless access list # diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local index 94b6b18..4b812a5 100644 --- a/accesslist-duplicates.local +++ b/accesslist-duplicates.local @@ -1,6 +1,6 @@ #!rsc # RouterOS script: accesslist-duplicates.local -# Copyright (c) 2018-2019 Christian Hesse +# Copyright (c) 2018-2020 Christian Hesse # # print duplicate antries in wireless access list # diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template index 7345ad5..0d1c92c 100644 --- a/accesslist-duplicates.template +++ b/accesslist-duplicates.template @@ -1,6 +1,6 @@ #!rsc # RouterOS script: accesslist-duplicates%TEMPL% -# Copyright (c) 2018-2019 Christian Hesse +# Copyright (c) 2018-2020 Christian Hesse # # print duplicate antries in wireless access list # diff --git a/bridge-port-to-default b/bridge-port-to-default index e646b33..5b7fa7e 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -1,6 +1,6 @@ #!rsc # RouterOS script: bridge-port-to-default -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # reset bridge ports to default bridge diff --git a/bridge-port-toggle b/bridge-port-toggle index fc122f6..b6ca4cd 100644 --- a/bridge-port-toggle +++ b/bridge-port-toggle @@ -1,6 +1,6 @@ #!rsc # RouterOS script: bridge-port-toggle -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # toggle bridge ports between default and alt bridge diff --git a/capsman-download-packages b/capsman-download-packages index dc95afe..c76ceee 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -1,6 +1,6 @@ #!rsc # RouterOS script: capsman-download-packages -# Copyright (c) 2018-2019 Christian Hesse +# Copyright (c) 2018-2020 Christian Hesse # Michael Gisbers # # download and cleanup packages for CAP installation from CAPsMAN diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index 7e172cc..cedfc47 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -1,6 +1,6 @@ #!rsc # RouterOS script: capsman-rolling-upgrade -# Copyright (c) 2018-2019 Christian Hesse +# Copyright (c) 2018-2020 Christian Hesse # Michael Gisbers # # upgrade CAPs one after another diff --git a/certificate-renew-issued b/certificate-renew-issued index e7241f2..3dc50d3 100644 --- a/certificate-renew-issued +++ b/certificate-renew-issued @@ -1,6 +1,6 @@ #!rsc # RouterOS script: certificate-renew-issued -# Copyright (c) 2019 Christian Hesse +# Copyright (c) 2019-2020 Christian Hesse # # renew locally issued certificates diff --git a/check-certificates b/check-certificates index 0f2c844..f378f01 100644 --- a/check-certificates +++ b/check-certificates @@ -1,6 +1,6 @@ #!rsc # RouterOS script: check-certificates -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # check for certificate validity diff --git a/check-health b/check-health index 6569783..fb59740 100644 --- a/check-health +++ b/check-health @@ -1,6 +1,6 @@ #!rsc # RouterOS script: check-health -# Copyright (c) 2019 Christian Hesse +# Copyright (c) 2019-2020 Christian Hesse # # check for RouterOS health state diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 8a76081..101f5e1 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -1,6 +1,6 @@ #!rsc # RouterOS script: check-lte-firmware-upgrade -# Copyright (c) 2018-2019 Christian Hesse +# Copyright (c) 2018-2020 Christian Hesse # # check for LTE firmware upgrade, send notification diff --git a/check-routeros-update b/check-routeros-update index 8b9d94d..85f9168 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -1,6 +1,6 @@ #!rsc # RouterOS script: check-routeros-update -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # check for RouterOS update, send notification and/or install diff --git a/cloud-backup b/cloud-backup index d948f99..5875cd1 100644 --- a/cloud-backup +++ b/cloud-backup @@ -1,6 +1,6 @@ #!rsc # RouterOS script: cloud-backup -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # upload backup to MikroTik cloud diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 0b87bf7..27df0ee 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -1,6 +1,6 @@ #!rsc # RouterOS script: collect-wireless-mac.capsman -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # collect wireless mac adresses in access list # diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 52e8629..f8315f1 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -1,6 +1,6 @@ #!rsc # RouterOS script: collect-wireless-mac.local -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # collect wireless mac adresses in access list # diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 71af0dc..0bd1790 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -1,6 +1,6 @@ #!rsc # RouterOS script: collect-wireless-mac%TEMPL% -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # collect wireless mac adresses in access list # diff --git a/daily-psk-schedule b/daily-psk-schedule index 784b336..c9be0bf 100644 --- a/daily-psk-schedule +++ b/daily-psk-schedule @@ -1,6 +1,6 @@ #!rsc # RouterOS script: daily-psk-schedule -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # schedule daily-psk on startup diff --git a/daily-psk.capsman b/daily-psk.capsman index 51e80f9..36dfc1a 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -1,6 +1,6 @@ #!rsc # RouterOS script: daily-psk.capsman -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers # # update daily PSK (pre shared key) diff --git a/daily-psk.local b/daily-psk.local index a8b41e1..9950db8 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -1,6 +1,6 @@ #!rsc # RouterOS script: daily-psk.local -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers # # update daily PSK (pre shared key) diff --git a/daily-psk.template b/daily-psk.template index 70460ce..e0ae26a 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -1,6 +1,6 @@ #!rsc # RouterOS script: daily-psk%TEMPL% -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers # # update daily PSK (pre shared key) diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index 5cb71cd..a25027e 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -1,6 +1,6 @@ #!rsc # RouterOS script: dhcp-lease-comment.capsman -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # update dhcp-server lease comment with infos from access-list # diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index a5c2ff5..0c960e5 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -1,6 +1,6 @@ #!rsc # RouterOS script: dhcp-lease-comment.local -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # update dhcp-server lease comment with infos from access-list # diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index fcff9d4..75a09ec 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -1,6 +1,6 @@ #!rsc # RouterOS script: dhcp-lease-comment%TEMPL% -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # update dhcp-server lease comment with infos from access-list # diff --git a/dhcp-to-dns b/dhcp-to-dns index edb50b4..d37c469 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -1,6 +1,6 @@ #!rsc # RouterOS script: dhcp-to-dns -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # check DHCP leases and add/remove/update DNS entries diff --git a/email-backup b/email-backup index bbd1d8c..d10acb2 100644 --- a/email-backup +++ b/email-backup @@ -1,6 +1,6 @@ #!rsc # RouterOS script: email-backup -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # create and email backup and config file diff --git a/global-config b/global-config index 0286abb..aa125f2 100644 --- a/global-config +++ b/global-config @@ -1,6 +1,6 @@ #!rsc # RouterOS script: global-config -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # global configuration diff --git a/global-config-overlay b/global-config-overlay index 871aaa4..1b07f15 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -1,6 +1,6 @@ #!rsc # RouterOS script: global-config-overlay -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # global configuration, custom overlay diff --git a/global-config.changes b/global-config.changes index bd8cac3..04ab34f 100644 --- a/global-config.changes +++ b/global-config.changes @@ -1,5 +1,5 @@ # RouterOS global-config changes -# Copyright (c) 2019 Christian Hesse +# Copyright (c) 2019-2020 Christian Hesse # Changes for global-config to be added to notification on script-updates :global GlobalConfigChanges { diff --git a/global-functions b/global-functions index f6d770d..10eeac6 100644 --- a/global-functions +++ b/global-functions @@ -1,6 +1,6 @@ #!rsc # RouterOS script: global-functions -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers # # global functions diff --git a/gps-track b/gps-track index c0dbf7e..932a0dc 100644 --- a/gps-track +++ b/gps-track @@ -1,6 +1,6 @@ #!rsc # RouterOS script: gps-track -# Copyright (c) 2018-2019 Christian Hesse +# Copyright (c) 2018-2020 Christian Hesse # # track gps data by sending json data to http server diff --git a/hotspot-to-wpa b/hotspot-to-wpa index bf5ce81..a072d86 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -1,6 +1,6 @@ #!rsc # RouterOS script: hotspot-to-wpa -# Copyright (c) 2019 Christian Hesse +# Copyright (c) 2019-2020 Christian Hesse # # add private WPA passphrase after hotspot login diff --git a/initial-commands b/initial-commands index d249157..79036e6 100644 --- a/initial-commands +++ b/initial-commands @@ -1,6 +1,6 @@ #!rsc # RouterOS script: initial-commands -# Copyright (c) 2018-2019 Christian Hesse +# Copyright (c) 2018-2020 Christian Hesse { / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt.pem"; diff --git a/ip-addr-bridge b/ip-addr-bridge index f503310..947e7fe 100644 --- a/ip-addr-bridge +++ b/ip-addr-bridge @@ -1,6 +1,6 @@ #!rsc # RouterOS script: ip-addr-bridge -# Copyright (c) 2018-2019 Christian Hesse +# Copyright (c) 2018-2020 Christian Hesse # # enable or disable ip addresses based on bridge port state diff --git a/ipv6-update b/ipv6-update index 86bd827..1004119 100644 --- a/ipv6-update +++ b/ipv6-update @@ -1,6 +1,6 @@ #!rsc # RouterOS script: ipv6-update -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # update firewall and dns settings on IPv6 prefix change diff --git a/learn-mac-based-vlan b/learn-mac-based-vlan index 8ebb16a..73ffc37 100644 --- a/learn-mac-based-vlan +++ b/learn-mac-based-vlan @@ -1,6 +1,6 @@ #!rsc # RouterOS script: learn-mac-based-vlan -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # learn MAC address for MAC-based-VLAN diff --git a/lease-script b/lease-script index b934086..0b32d17 100644 --- a/lease-script +++ b/lease-script @@ -1,6 +1,6 @@ #!rsc # RouterOS script: lease-script -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # run scripts on DHCP lease diff --git a/leds-day-mode b/leds-day-mode index 4fcc41b..0b50648 100644 --- a/leds-day-mode +++ b/leds-day-mode @@ -1,6 +1,6 @@ #!rsc # RouterOS script: leds-day-mode -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # enable LEDs diff --git a/leds-night-mode b/leds-night-mode index 58a3720..6a973e4 100644 --- a/leds-night-mode +++ b/leds-night-mode @@ -1,6 +1,6 @@ #!rsc # RouterOS script: leds-night-mode -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # disable LEDs diff --git a/leds-toggle-mode b/leds-toggle-mode index d2c5bff..7518ef4 100644 --- a/leds-toggle-mode +++ b/leds-toggle-mode @@ -1,6 +1,6 @@ #!rsc # RouterOS script: leds-toggle-mode -# Copyright (c) 2018-2019 Christian Hesse +# Copyright (c) 2018-2020 Christian Hesse # # toggle LEDs mode diff --git a/manage-umts b/manage-umts index e416ee2..f1eb861 100644 --- a/manage-umts +++ b/manage-umts @@ -1,6 +1,6 @@ #!rsc # RouterOS script: manage-umts -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # manage UMTS interface based on ethernet and wireless status diff --git a/mode-button-event b/mode-button-event index 2624383..91b0edb 100644 --- a/mode-button-event +++ b/mode-button-event @@ -1,6 +1,6 @@ #!rsc # RouterOS script: mode-button-event -# Copyright (c) 2018-2019 Christian Hesse +# Copyright (c) 2018-2020 Christian Hesse # # run on mode-button event and count button presses diff --git a/mode-button-scheduler b/mode-button-scheduler index dfd89da..2873398 100644 --- a/mode-button-scheduler +++ b/mode-button-scheduler @@ -1,6 +1,6 @@ #!rsc # RouterOS script: mode-button-scheduler -# Copyright (c) 2018-2019 Christian Hesse +# Copyright (c) 2018-2020 Christian Hesse # # act on multiple mode-botton presses from scheduler diff --git a/netwatch-syslog b/netwatch-syslog index 03aa1a5..b76d31d 100644 --- a/netwatch-syslog +++ b/netwatch-syslog @@ -1,6 +1,6 @@ #!rsc # RouterOS script: netwatch-syslog -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # requires: dont-require-permissions=yes # diff --git a/packages-update b/packages-update index 56c8c59..8918656 100644 --- a/packages-update +++ b/packages-update @@ -1,6 +1,6 @@ #!rsc # RouterOS script: packages-update -# Copyright (c) 2019 Christian Hesse +# Copyright (c) 2019-2020 Christian Hesse # # download packages and reboot for installation diff --git a/ppp-on-up b/ppp-on-up index 7fb80d9..b8f8fcb 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -1,6 +1,6 @@ #!rsc # RouterOS script: ppp-on-up -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # run scripts on ppp up diff --git a/rotate-ntp b/rotate-ntp index f342f98..465a46c 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -1,6 +1,6 @@ #!rsc # RouterOS script: rotate-ntp -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # rotate the ntp servers diff --git a/script-updates b/script-updates index 8b70a98..95af07d 100644 --- a/script-updates +++ b/script-updates @@ -1,6 +1,6 @@ #!rsc # RouterOS script: script-updates -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # update installed scripts from file or url diff --git a/sms-action b/sms-action index 0871ef1..026bdc8 100644 --- a/sms-action +++ b/sms-action @@ -1,6 +1,6 @@ #!rsc # RouterOS script: sms-action -# Copyright (c) 2018-2019 Christian Hesse +# Copyright (c) 2018-2020 Christian Hesse # # run action on received SMS diff --git a/sms-forward b/sms-forward index 9c5c494..c05600e 100644 --- a/sms-forward +++ b/sms-forward @@ -1,6 +1,6 @@ #!rsc # RouterOS script: sms-forward -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # forward SMS to e-mail diff --git a/ssh-keys-import b/ssh-keys-import index 0f7fb5b..da933ce 100644 --- a/ssh-keys-import +++ b/ssh-keys-import @@ -1,6 +1,6 @@ #!rsc # RouterOS script: ssh-keys-import -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # import ssh keys from file diff --git a/super-mario-theme b/super-mario-theme index 3e077c3..671abc5 100644 --- a/super-mario-theme +++ b/super-mario-theme @@ -1,6 +1,6 @@ #!rsc # RouterOS script: super-mario-theme -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # play Super Mario theme diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index ac755d9..a0b297e 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -1,6 +1,6 @@ #!rsc # RouterOS script: unattended-lte-firmware-upgrade -# Copyright (c) 2018-2019 Christian Hesse +# Copyright (c) 2018-2020 Christian Hesse # # schedule unattended lte firmware upgrade diff --git a/update-gre-address b/update-gre-address index 3050d8b..fcd0183 100644 --- a/update-gre-address +++ b/update-gre-address @@ -1,6 +1,6 @@ #!rsc # RouterOS script: update-gre-address -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # update gre interface remote address with dynamic address from # ipsec remote peer diff --git a/update-tunnelbroker b/update-tunnelbroker index c529d44..53c8600 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -1,6 +1,6 @@ #!rsc # RouterOS script: update-tunnelbroker -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers :global CertificateAvailable; diff --git a/upload-backup b/upload-backup index d5ba182..4a10653 100644 --- a/upload-backup +++ b/upload-backup @@ -1,6 +1,6 @@ #!rsc # RouterOS script: upload-backup -# Copyright (c) 2013-2019 Christian Hesse +# Copyright (c) 2013-2020 Christian Hesse # # create and upload backup and config file From cb1e520965ee1b56ea4ec8084be1f0431c560195 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Jan 2020 10:07:55 +0100 Subject: [PATCH 0140/2612] global-functions: split $CertificateAvailable to $CertificateDownload This allows to force download even if certificate is available. We need this for a clean update path with Let's Encrypt. --- global-functions | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/global-functions b/global-functions index 10eeac6..0d490df 100644 --- a/global-functions +++ b/global-functions @@ -17,6 +17,7 @@ # global functions :global UrlEncode; :global CharacterReplace; +:global CertificateDownload; :global CertificateAvailable; :global SendEMail; :global SendTelegram; @@ -79,8 +80,8 @@ :return ($Return . $String); } -# check and import required certificates -:set CertificateAvailable do={ +# download and import certificate +:set CertificateDownload do={ :local CommonName [ :tostr $1 ]; :global ScriptUpdatesBaseUrl; @@ -89,22 +90,32 @@ :global UrlEncode; :global WaitForFile; + :log info ("Downloading and importing certificate with " . \ + "CommonName " . $CommonName . "."); + :do { + :local LocalFileName ($CommonName . ".pem"); + :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); + / tool fetch check-certificate=yes-without-crl \ + ($ScriptUpdatesBaseUrl . "certs/" . \ + $UrlFileName . $ScriptUpdatesUrlSuffix) \ + dst-path=$LocalFileName; + $WaitForFile $LocalFileName; + / certificate import file-name=$LocalFileName passphrase=""; + / file remove $LocalFileName; + } on-error={ + :log warning "Failed imprting certificate!"; + } +} + +# check and download required certificate +:set CertificateAvailable do={ + :local CommonName [ :tostr $1 ]; + + :global CertificateDownload; + :if ([ / certificate print count-only where common-name=$CommonName ] = 0) do={ - :log info ("Certificate with CommonName " . $CommonName . \ - " not available, downloading and importing."); - :do { - :local LocalFileName ($CommonName . ".pem"); - :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); - / tool fetch check-certificate=yes-without-crl \ - ($ScriptUpdatesBaseUrl . "certs/" . \ - $UrlFileName . $ScriptUpdatesUrlSuffix) \ - dst-path=$LocalFileName; - $WaitForFile $LocalFileName; - / certificate import file-name=$LocalFileName passphrase=""; - / file remove $LocalFileName; - } on-error={ - :log warning "Failed imprting certificate!"; - } + :log info ("Certificate with CommonName " . $CommonName . " not available."); + $CertificateDownload $CommonName; } } From b1b7ed83eda50e3147d363f1e4f1dab3191c4b3f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Jan 2020 10:15:34 +0100 Subject: [PATCH 0141/2612] global-functions: $Certificate*: add quoting around CN --- global-functions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 0d490df..45b76d2 100644 --- a/global-functions +++ b/global-functions @@ -91,7 +91,7 @@ :global WaitForFile; :log info ("Downloading and importing certificate with " . \ - "CommonName " . $CommonName . "."); + "CommonName \"" . $CommonName . "\"."); :do { :local LocalFileName ($CommonName . ".pem"); :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); @@ -114,7 +114,7 @@ :global CertificateDownload; :if ([ / certificate print count-only where common-name=$CommonName ] = 0) do={ - :log info ("Certificate with CommonName " . $CommonName . " not available."); + :log info ("Certificate with CommonName \"" . $CommonName . "\" not available."); $CertificateDownload $CommonName; } } From cf79e6c473e8d840aee32922cdc5efb00aa67900 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Jan 2020 11:14:47 +0100 Subject: [PATCH 0142/2612] global-functions: do not encode dash, dot, slash and underscore --- global-functions | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/global-functions b/global-functions index 45b76d2..611241f 100644 --- a/global-functions +++ b/global-functions @@ -39,11 +39,10 @@ :local Return ""; :if ([ :len $Input ] > 0) do={ - :local Chars " !\"#\$%&'()*+,-./:;<=>\?@[\\]^_`{|}~"; + :local Chars " !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~"; :local Subs { "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27"; "%28"; "%29"; - "%2A"; "%2B"; "%2C"; "%2D"; "%2E"; "%2F"; "%3A"; "%3B"; "%3C"; "%3D"; - "%3E"; "%3F"; "%40"; "%5B"; "%5C"; "%5D"; "%5E"; "%5F"; "%60"; "%7B"; - "%7C"; "%7D"; "%7E" }; + "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; "%3F"; "%40"; + "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; "%7E" }; :for I from=0 to=([ :len $Input ] - 1) do={ :local Char [ :pick $Input $I ]; From 0560f828d1f02a9c145806af351faa91fda6b8bf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Jan 2020 08:19:16 +0100 Subject: [PATCH 0143/2612] dhcp-to-dns: act on bound leases only --- dhcp-to-dns | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index d37c469..5343513 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -22,7 +22,7 @@ :foreach DnsRecord in=[ / ip dns static find where comment ~ $CommentPrefix ] do={ :local DnsRecordVal [ / ip dns static get $DnsRecord ]; :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; - :if ([ / ip dhcp-server lease print count-only where mac-address=$MacAddress address=($DnsRecordVal->"address") dynamic=yes ] > 0) do={ + :if ([ / ip dhcp-server lease print count-only where mac-address=$MacAddress address=($DnsRecordVal->"address") dynamic=yes status=bound ] > 0) do={ :log debug ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"host-name" . ") still exists. Not deleting DNS entry."); } else={ :local Found false; @@ -31,7 +31,7 @@ } } -:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={ +:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ :local LeaseVal [ / ip dhcp-server lease get $Lease ]; :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); :local HostName [ $CharacterReplace ($LeaseVal->"host-name") " " "" ]; @@ -44,13 +44,13 @@ :if ([ :len $DnsRecord ] > 0) do={ :local DnsIp [ / ip dns static get $DnsRecord address ]; - :local DupMacLeases [ / ip dhcp-server lease find where mac-address=($LeaseVal->"mac-address") dynamic=yes ]; + :local DupMacLeases [ / ip dhcp-server lease find where mac-address=($LeaseVal->"mac-address") dynamic=yes status=bound ]; :if ([ :len $DupMacLeases ] > 1) do={ :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; } :if ([ :len ($LeaseVal->"host-name") ] > 0) do={ - :set ($LeaseVal->"address") [ / ip dhcp-server lease get ([ find where host-name=($LeaseVal->"host-name") dynamic=yes ]->0) address ]; + :set ($LeaseVal->"address") [ / ip dhcp-server lease get ([ find where host-name=($LeaseVal->"host-name") dynamic=yes status=bound ]->0) address ]; } :if ($DnsIp = $LeaseVal->"address") do={ From bb7c4ef0d9ab5e99d29b3f68a2d0ca44cf25fffa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Jan 2020 09:42:00 +0100 Subject: [PATCH 0144/2612] dhcp-lease-comment: act on bound leases only --- dhcp-lease-comment.capsman | 2 +- dhcp-lease-comment.local | 2 +- dhcp-lease-comment.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index a25027e..e5da51f 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -6,7 +6,7 @@ # # !! Do not edit this file, it is generated from template! -:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={ +:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ :local LeaseVal [ / ip dhcp-server lease get $Lease ]; :local NewComment; :local AccessList ([ / caps-man access-list find where mac-address=($LeaseVal->"mac-address") ]->0); diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index 0c960e5..367ca0b 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -6,7 +6,7 @@ # # !! Do not edit this file, it is generated from template! -:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={ +:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ :local LeaseVal [ / ip dhcp-server lease get $Lease ]; :local NewComment; :local AccessList ([ / interface wireless access-list find where mac-address=($LeaseVal->"mac-address") ]->0); diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index 75a09ec..3734ba4 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -7,7 +7,7 @@ # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! -:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={ +:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ :local LeaseVal [ / ip dhcp-server lease get $Lease ]; :local NewComment; :local AccessList ([ / %PATH% access-list find where mac-address=($LeaseVal->"mac-address") ]->0); From aa885e17e2b929500d5992b396e9460e325036be Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Jan 2020 09:47:32 +0100 Subject: [PATCH 0145/2612] collect-wireless-mac: use dynamic & bound mac address only --- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 27df0ee..2b93e09 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -27,7 +27,7 @@ $ScriptLock "collect-wireless-mac.capsman"; :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease [ / ip dhcp-server lease find where mac-address=$Mac ]; + :local Lease [ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]; :if ([ :len $Lease ] > 0) do={ :set Address [ / ip dhcp-server lease get $Lease address ]; :set HostName [ / ip dhcp-server lease get $Lease host-name ]; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index f8315f1..c38c2c1 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -27,7 +27,7 @@ $ScriptLock "collect-wireless-mac.local"; :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease [ / ip dhcp-server lease find where mac-address=$Mac ]; + :local Lease [ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]; :if ([ :len $Lease ] > 0) do={ :set Address [ / ip dhcp-server lease get $Lease address ]; :set HostName [ / ip dhcp-server lease get $Lease host-name ]; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 0bd1790..03bd532 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -28,7 +28,7 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease [ / ip dhcp-server lease find where mac-address=$Mac ]; + :local Lease [ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]; :if ([ :len $Lease ] > 0) do={ :set Address [ / ip dhcp-server lease get $Lease address ]; :set HostName [ / ip dhcp-server lease get $Lease host-name ]; From b3a76c7e4b5e32be9fcffdeeecfa8c61f365de22 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Jan 2020 10:20:19 +0100 Subject: [PATCH 0146/2612] global-functions: $CertificateDownload: properly name new certificates --- global-functions | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/global-functions b/global-functions index 611241f..f510218 100644 --- a/global-functions +++ b/global-functions @@ -86,6 +86,7 @@ :global ScriptUpdatesBaseUrl; :global ScriptUpdatesUrlSuffix; + :global CharacterReplace; :global UrlEncode; :global WaitForFile; @@ -101,6 +102,10 @@ $WaitForFile $LocalFileName; / certificate import file-name=$LocalFileName passphrase=""; / file remove $LocalFileName; + + :foreach Cert in=[ / certificate find where name~("^" . $LocalFileName . "_[0-9]+\$") ] do={ + / certificate set $Cert name=[ $CharacterReplace [ $CharacterReplace [ get $Cert common-name ] " " "-" ] "---" "-" ]; + } } on-error={ :log warning "Failed imprting certificate!"; } From 08c90c95b71f74a15b09c23efef484d4b471ec04 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Jan 2020 10:33:27 +0100 Subject: [PATCH 0147/2612] mode-button-scheduler: give proper message if no action defined --- mode-button-scheduler | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/mode-button-scheduler b/mode-button-scheduler index 2873398..2b6f083 100644 --- a/mode-button-scheduler +++ b/mode-button-scheduler @@ -8,20 +8,24 @@ :local Count ($ModeButton->"count"); :local Code ($ModeButton->[ :tostr $Count ]); -:local Parsed [ :parse $Code ]; :set ($ModeButton->"count") 0; / system scheduler remove mode-button-scheduler; -:log info ("Acting on " . $Count . " mode-button presses: " . $Code); +:if ([ :len $Code ] > 0) do={ + :log info ("Acting on " . $Count . " mode-button presses: " . $Code); -:if ([ / system routerboard settings get silent-boot ] = false) do={ - :for I from=1 to=$Count do={ - :beep length=200ms; - :delay 200ms; + :if ([ / system routerboard settings get silent-boot ] = false) do={ + :for I from=1 to=$Count do={ + :beep length=200ms; + :delay 200ms; + } + } else={ + :delay 1s; } -} else={ - :delay 1s; -} -$Parsed; + :local Parsed [ :parse $Code ]; + $Parsed; +} else={ + :log info ("No action defined for " . $Count . " mode-button presses."); +} From 12da4de305421fe155e352cc9b1396f56338516e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Jan 2020 16:11:50 +0100 Subject: [PATCH 0148/2612] check-routeros-update: do not act if reboot is scheduled --- check-routeros-update | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/check-routeros-update b/check-routeros-update index 85f9168..1791b23 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -29,6 +29,10 @@ } } +:if ([ / system scheduler print count-only where name="reboot-for-update" ] > 0) do={ + :error "A reboot for update is already scheduled."; +} + / system package update check-for-updates without-paging; :local Update [ / system package update get ]; From 958bfa7ce8d57089b3d66b76eca1c7382f8b4119 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jan 2020 10:36:03 +0100 Subject: [PATCH 0149/2612] collect-wireless-mac: automatically add missing access-list entry --- collect-wireless-mac.capsman | 8 ++++---- collect-wireless-mac.local | 8 ++++---- collect-wireless-mac.template | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 2b93e09..2b9b23f 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -14,11 +14,11 @@ $ScriptLock "collect-wireless-mac.capsman"; -:local PlaceBefore [ / caps-man access-list find where comment="--- collected above ---" disabled ]; -:if ([ :len $PlaceBefore ] = 0) do={ - :log error "Missing disabled access-list entry with comment '--- collected above ---'"; - :error "Error: See log for details."; +:if ([ / caps-man access-list print count-only where comment="--- collected above ---" disabled ] = 0) do={ + / caps-man access-list add comment="--- collected above ---" disabled=yes; + :log warn "Added disabled access-list entry with comment '--- collected above ---'."; } +:local PlaceBefore [ / caps-man access-list find where comment="--- collected above ---" disabled ]; :foreach RegTbl in=[ / caps-man registration-table find ] do={ :local Mac [ / caps-man registration-table get $RegTbl mac-address ]; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index c38c2c1..3241c27 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -14,11 +14,11 @@ $ScriptLock "collect-wireless-mac.local"; -:local PlaceBefore [ / interface wireless access-list find where comment="--- collected above ---" disabled ]; -:if ([ :len $PlaceBefore ] = 0) do={ - :log error "Missing disabled access-list entry with comment '--- collected above ---'"; - :error "Error: See log for details."; +:if ([ / interface wireless access-list print count-only where comment="--- collected above ---" disabled ] = 0) do={ + / interface wireless access-list add comment="--- collected above ---" disabled=yes; + :log warn "Added disabled access-list entry with comment '--- collected above ---'."; } +:local PlaceBefore [ / interface wireless access-list find where comment="--- collected above ---" disabled ]; :foreach RegTbl in=[ / interface wireless registration-table find ] do={ :local Mac [ / interface wireless registration-table get $RegTbl mac-address ]; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 03bd532..6ad55a2 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -15,11 +15,11 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; -:local PlaceBefore [ / %PATH% access-list find where comment="--- collected above ---" disabled ]; -:if ([ :len $PlaceBefore ] = 0) do={ - :log error "Missing disabled access-list entry with comment '--- collected above ---'"; - :error "Error: See log for details."; +:if ([ / %PATH% access-list print count-only where comment="--- collected above ---" disabled ] = 0) do={ + / %PATH% access-list add comment="--- collected above ---" disabled=yes; + :log warn "Added disabled access-list entry with comment '--- collected above ---'."; } +:local PlaceBefore [ / %PATH% access-list find where comment="--- collected above ---" disabled ]; :foreach RegTbl in=[ / %PATH% registration-table find ] do={ :local Mac [ / %PATH% registration-table get $RegTbl mac-address ]; From 6e5e0e72bd695d0e7dd546a24c3afba31ab32cae Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2020 08:08:52 +0100 Subject: [PATCH 0150/2612] check-health: always calculate on the lower voltage value This makes sure an alert is triggered in both directions. Before we could have: 24.0V to 21.8V -> OK 21.8V to 24.0V -> Alert! --- check-health | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-health b/check-health index fb59740..95a92d7 100644 --- a/check-health +++ b/check-health @@ -22,7 +22,7 @@ :if ([ :typeof ($CheckHealthLast->$Voltage) ] = "num" && \ [ :typeof ($CheckHealthCurrent->$Voltage) ] = "num") do={ :if ($CheckHealthLast->$Voltage * (100 + $CheckHealthVoltagePercent) / 100 < $CheckHealthCurrent->$Voltage || \ - $CheckHealthLast->$Voltage * 100 / (100 + $CheckHealthVoltagePercent) > $CheckHealthCurrent->$Voltage) do={ + $CheckHealthLast->$Voltage > $CheckHealthCurrent->$Voltage * (100 + $CheckHealthVoltagePercent) / 100) do={ $SendNotification ("Health warning: " . $Voltage) \ ("The " . $Voltage . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ "old value: " . [ $FormatVoltage ($CheckHealthLast->$Voltage) ] . "\n" . \ From c7034ca5af26b70a06739978e0ea2f7fcf83f611 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2020 08:17:42 +0100 Subject: [PATCH 0151/2612] check-health: never divide, always multiply With RouterOS we have integral numbers only. This prevent from having friction that is cut off. --- check-health | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-health b/check-health index 95a92d7..07ec366 100644 --- a/check-health +++ b/check-health @@ -21,8 +21,8 @@ :foreach Voltage in={ "battery"; "psu1-voltage"; "psu2-voltage"; "voltage" } do={ :if ([ :typeof ($CheckHealthLast->$Voltage) ] = "num" && \ [ :typeof ($CheckHealthCurrent->$Voltage) ] = "num") do={ - :if ($CheckHealthLast->$Voltage * (100 + $CheckHealthVoltagePercent) / 100 < $CheckHealthCurrent->$Voltage || \ - $CheckHealthLast->$Voltage > $CheckHealthCurrent->$Voltage * (100 + $CheckHealthVoltagePercent) / 100) do={ + :if ($CheckHealthLast->$Voltage * (100 + $CheckHealthVoltagePercent) < $CheckHealthCurrent->$Voltage * 100 || \ + $CheckHealthLast->$Voltage * 100 > $CheckHealthCurrent->$Voltage * (100 + $CheckHealthVoltagePercent)) do={ $SendNotification ("Health warning: " . $Voltage) \ ("The " . $Voltage . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ "old value: " . [ $FormatVoltage ($CheckHealthLast->$Voltage) ] . "\n" . \ From 5741924cf92f3ff5c403d7d1ea34d5d6a47c8cf7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 28 Jan 2020 21:51:27 +0100 Subject: [PATCH 0152/2612] global-functions: replace deprecated keep-result=no with output=none --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index f510218..78c8a9f 100644 --- a/global-functions +++ b/global-functions @@ -164,7 +164,7 @@ :if ([ :len $TelegramTokenId ] > 0 && [ :len $TelegramChatId ] > 0) do={ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2"; :do { - / tool fetch check-certificate=yes-without-crl keep-result=no http-method=post \ + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ http-data=("chat_id=" . $TelegramChatId . "&disable_notification=" . $Silent . \ "&text=" . [ $UrlEncode ("[" . $Identity . "] " . $Subject . "\n\n" . $Message) ]); From 639011a9bac9adc2c065d497f1a9d03151e8c31e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 28 Jan 2020 21:52:15 +0100 Subject: [PATCH 0153/2612] gps-track: replace deprecated keep-result=no with output=none --- gps-track | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gps-track b/gps-track index 932a0dc..3b944b3 100644 --- a/gps-track +++ b/gps-track @@ -12,7 +12,7 @@ if ($Gps->"valid" = true) do={ :tool fetch check-certificate=yes-without-crl \ - $GpsTrackUrl keep-result=no \ + $GpsTrackUrl output=none \ http-method=post http-header-field="Content-Type: application/json" \ http-data=("{" . \ "\"lat\":\"" . ($Gps->"latitude") . "\"," . \ From 74f6449e8ac06e30af5511c1876ee518ae8926b9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 28 Jan 2020 21:52:29 +0100 Subject: [PATCH 0154/2612] update-tunnelbroker: replace deprecated keep-result=no with output=none --- update-tunnelbroker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/update-tunnelbroker b/update-tunnelbroker index 53c8600..da621e2 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -28,7 +28,7 @@ :log info ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress); / tool fetch check-certificate=yes-without-crl \ ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ - user=($Comment->"user") password=($Comment->"pass") keep-result=no; + user=($Comment->"user") password=($Comment->"pass") output=none; / interface 6to4 set $Interface local-address=$PublicAddress; } else={ :log debug ("All tunnelbroker configuration is up to date for interface " . $InterfaceVal->"name" . "."); From 801dce05fa593f61103a0e48d2175bcc58c061a0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2020 09:27:00 +0100 Subject: [PATCH 0155/2612] global-functions: $CertificateAvailable: warn about crl download to flash Downloading certificate crls to flash can fill up all available space. So warn about it! --- global-functions | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/global-functions b/global-functions index 78c8a9f..9c58450 100644 --- a/global-functions +++ b/global-functions @@ -117,6 +117,12 @@ :global CertificateDownload; + :if ([ / system resource get free-hdd-space ] < 8388608 && \ + [ / certificate settings get crl-download ] = true && \ + [ / certificate settings get crl-store ] = "system") do={ + :log warn "This system has low free flash space but is configured to download certificate CRLs to system!"; + } + :if ([ / certificate print count-only where common-name=$CommonName ] = 0) do={ :log info ("Certificate with CommonName \"" . $CommonName . "\" not available."); $CertificateDownload $CommonName; From 352818ea48438383216a783ef9448570b343c29b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2020 21:01:48 +0100 Subject: [PATCH 0156/2612] global-functions: $CertificateAvailable: check whole chain The root certificate is a self-signed certificate. Check for the issue certificate until we find the self-signed one. --- global-functions | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/global-functions b/global-functions index 9c58450..5f80c0b 100644 --- a/global-functions +++ b/global-functions @@ -116,6 +116,7 @@ :local CommonName [ :tostr $1 ]; :global CertificateDownload; + :global ParseKeyValueStore; :if ([ / system resource get free-hdd-space ] < 8388608 && \ [ / certificate settings get crl-download ] = true && \ @@ -127,6 +128,17 @@ :log info ("Certificate with CommonName \"" . $CommonName . "\" not available."); $CertificateDownload $CommonName; } + + :local CertVal [ / certificate get [ find where common-name=$CommonName ] ]; + :local Issuer ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN"); + :while ($Issuer != $CertVal->"common-name") do={ + :if ([ / certificate print count-only where common-name=$Issuer ] = 0) do={ + :log info ("Certificate chain for \"" . $CommonName . "\" is incomplete, missing \"" . $Issuer . "\"."); + $CertificateDownload $CommonName; + } + :set CertVal [ / certificate get [ find where common-name=$Issuer ] ]; + :set Issuer ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN"); + } } # send notification via e-mail From c500243c97ec888a72d41b77fa3f7c8f14341ac8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2020 21:38:17 +0100 Subject: [PATCH 0157/2612] global-functions: add $ScriptInstallUpdate Just call without parameters to update scripts: [admin@MikroTik] > $InstallAndUpdate Add comma separated list of scripts to install and update: [admin@MikroTik] > $InstallAndUpdate cloud-backup[,upload-backup][,...] --- global-functions | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/global-functions b/global-functions index 5f80c0b..60f72a4 100644 --- a/global-functions +++ b/global-functions @@ -32,6 +32,7 @@ :global GetRandom; :global RandomDelay; :global DeviceInfo; +:global ScriptInstallUpdate; # url encoding :set UrlEncode do={ @@ -412,3 +413,16 @@ :return $Info; } + +# install new scripts, update existing scripts +:set ScriptInstallUpdate do={ + :local Scripts [ :toarray $1 ]; + + :foreach Script in=$Scripts do={ + :if ([ / system script print count-only where name=$Script ] = 0) do={ + :log info ("Adding new script: " . $Script); + / system script add name=$Script source="#!rsc"; + } + } + / system script run script-updates; +} From 833e72eac86af8966b5de19c25d64c89091eb7bf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2020 21:15:30 +0100 Subject: [PATCH 0158/2612] script-updates: only handle scripts with magic pattern This is supposed to prevent overwriting foreign scripts. New scripts are expected to be installed with function $ScriptInstallUpdate! --- script-updates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script-updates b/script-updates index 95af07d..42ca04a 100644 --- a/script-updates +++ b/script-updates @@ -17,7 +17,7 @@ :global SendNotification; -:foreach Script in=[ / system script find ] do={ +:foreach Script in=[ / system script find where source~"^#!rsc" ] do={ :local Ignore 0; :local ScriptVal [ / system script get $Script ]; :local ScriptFile [ / file find where name=("script-updates/" . $ScriptVal->"name") ]; From 1e72f03e5e568cec4c9850db1770e6f130446cc5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2020 22:10:33 +0100 Subject: [PATCH 0159/2612] README: update instructions to use $ScriptInstallUpdate --- README.md | 16 +++++++++------- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ec1654e..d35d4c4 100644 --- a/README.md +++ b/README.md @@ -105,14 +105,17 @@ To update existing scripts just run `script-updates`. [admin@MikroTik] > / system script run script-updates +Calling function `$ScriptInstallUpdate` does the same. + + [admin@MikroTik] > $ScriptInstallUpdate + Adding a script --------------- -To add a script from the repository create a configuration item first, then -update scripts to fetch the source. +To add a script from the repository run function `$ScriptInstallUpdate` with +a comma separated list of script names. - [admin@MikroTik] > / system script add name="check-routeros-update" - [admin@MikroTik] > / system script run script-updates + [admin@MikroTik] > $ScriptInstallUpdate check-certificates,check-routeros-update Scheduler and events -------------------- @@ -128,9 +131,8 @@ Some events can run a script. If you want your DHCP hostnames to be available in DNS use `dhcp-to-dns` with the events from dhcp server. For a regular cleanup add a scheduler entry. - [admin@MikroTik] > / system script add name="dhcp-to-dns" - [admin@MikroTik] > / system script run script-updates - [admin@MikroTik] > / ip dhcp-server set lease-script=dhcp-to-dns [ find ] + [admin@MikroTik] > $ScriptInstallUpdate dhcp-to-dns,lease-script + [admin@MikroTik] > / ip dhcp-server set lease-script=lease-script [ find ] [admin@MikroTik] > / system scheduler add name="dhcp-to-dns" interval=5m on-event="/ system script run dhcp-to-dns;" There's much more to explore... Have fun! diff --git a/global-config b/global-config index aa125f2..95db1c5 100644 --- a/global-config +++ b/global-config @@ -6,7 +6,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 10; +:global GlobalConfigVersion 11; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 1b07f15..59d6ddb 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -6,7 +6,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 10; +:global GlobalConfigVersion 11; # The global-config script is updated by script-updates, # global-config-overlay becomes an overlay for your changes. diff --git a/global-config.changes b/global-config.changes index 04ab34f..a8b8126 100644 --- a/global-config.changes +++ b/global-config.changes @@ -13,4 +13,5 @@ 8="added donation hint and option to silence it"; 9="introduced configuration overlay 'global-config-overlay'"; 10="make health threshold for voltage configurable"; + 11="introduced function '\$ScriptInstallUpdate' to install new and update existing scripts"; }; diff --git a/global-functions b/global-functions index 60f72a4..796bd0e 100644 --- a/global-functions +++ b/global-functions @@ -6,7 +6,7 @@ # global functions # expected configuration version -:global ExpectedConfigVersion 10; +:global ExpectedConfigVersion 11; # global variables not to be changed by user :global SentConfigChangesNotification "-"; From 7f8173400697e5a15cf39e21ad13612b4a1d28c5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 2 Feb 2020 15:16:36 +0100 Subject: [PATCH 0160/2612] global-functions: $CertificateAvailable: simplify loop --- global-functions | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/global-functions b/global-functions index 796bd0e..05b5093 100644 --- a/global-functions +++ b/global-functions @@ -130,16 +130,16 @@ $CertificateDownload $CommonName; } - :local CertVal [ / certificate get [ find where common-name=$CommonName ] ]; - :local Issuer ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN"); - :while ($Issuer != $CertVal->"common-name") do={ + :local CertVal; + :local Issuer $CommonName; + :do { :if ([ / certificate print count-only where common-name=$Issuer ] = 0) do={ :log info ("Certificate chain for \"" . $CommonName . "\" is incomplete, missing \"" . $Issuer . "\"."); $CertificateDownload $CommonName; } :set CertVal [ / certificate get [ find where common-name=$Issuer ] ]; :set Issuer ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN"); - } + } while=($Issuer != $CertVal->"common-name"); } # send notification via e-mail From 0c705d5311355f182dfb3ba36c9e533c2193a980 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 3 Feb 2020 09:29:53 +0100 Subject: [PATCH 0161/2612] global-config-overlay: add footer ... to guard against truncation by accident. --- global-config-overlay | 2 ++ 1 file changed, 2 insertions(+) diff --git a/global-config-overlay b/global-config-overlay index 59d6ddb..6b74715 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -16,3 +16,5 @@ # Copy configuration from global-config here and modify it. + +# End of global-config-overlay From 03af7d6d9c64cc57d1d0e3280e4ed1a6308e6448 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 3 Feb 2020 21:29:21 +0100 Subject: [PATCH 0162/2612] global-functions: $CharacterReplace: do not limit string length I've tried something like this to update a device: / system script set source=[ $CharacterReplace [ get global-config-overlay source ] "GlobalConfigVersion 10" "GlobalConfigVersion 11" ] global-config-overlay; This broke with global-config-overlay longer than 999 characters. So makes sure there is no limit for string length. --- global-functions | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 05b5093..15cba35 100644 --- a/global-functions +++ b/global-functions @@ -64,7 +64,6 @@ :local String [ :tostr $1 ]; :local ReplaceFrom [ :tostr $2 ]; :local ReplaceWith [ :tostr $3 ]; - :local Len [ :len $ReplaceFrom ]; :local Return ""; :if ($ReplaceFrom = "") do={ @@ -74,7 +73,7 @@ :while ([ :typeof [ :find $String $ReplaceFrom ] ] != "nil") do={ :local Pos [ :find $String $ReplaceFrom ]; :set Return ($Return . [ :pick $String 0 $Pos ] . $ReplaceWith); - :set String [ :pick $String ($Pos + $Len) 999 ]; + :set String [ :pick $String ($Pos + [ :len $ReplaceFrom ]) [ :len $String ] ]; } :return ($Return . $String); From b5f4c2c87eb0c59570811b3accc2dedf0147d61f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 4 Feb 2020 20:19:46 +0100 Subject: [PATCH 0163/2612] global-config: drop $ScriptUpdatesConfigChangesIgnore Comment or remove $GlobalConfigVersion in global-config-overlay to disable change notifications. --- global-config | 4 +--- global-config-overlay | 3 ++- global-config.changes | 1 + global-functions | 2 +- script-updates | 4 +--- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/global-config b/global-config index 95db1c5..a55a9d6 100644 --- a/global-config +++ b/global-config @@ -6,7 +6,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 11; +:global GlobalConfigVersion 12; # This is used for DNS and backup file. :global Domain "example.com"; @@ -109,8 +109,6 @@ :global ScriptUpdatesIgnore { "global-config" } -# Enable this to silence all configuration warnings. -:global ScriptUpdatesConfigChangesIgnore false; # This project is developed in private spare time and usage is free of charge # for you. If you like the scripts and think this is of value for you or your # business please consider a donation: diff --git a/global-config-overlay b/global-config-overlay index 6b74715..e2c8909 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -6,7 +6,8 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 11; +# Comment or remove to disable change notifications. +:global GlobalConfigVersion 12; # The global-config script is updated by script-updates, # global-config-overlay becomes an overlay for your changes. diff --git a/global-config.changes b/global-config.changes index a8b8126..a22f3b4 100644 --- a/global-config.changes +++ b/global-config.changes @@ -14,4 +14,5 @@ 9="introduced configuration overlay 'global-config-overlay'"; 10="make health threshold for voltage configurable"; 11="introduced function '\$ScriptInstallUpdate' to install new and update existing scripts"; + 12="removed '\$ScriptUpdatesConfigChangesIgnore', comment '\$GlobalConfigVersion' in 'global-config-overlay' to disable change notifications"; }; diff --git a/global-functions b/global-functions index 15cba35..caaf0a5 100644 --- a/global-functions +++ b/global-functions @@ -6,7 +6,7 @@ # global functions # expected configuration version -:global ExpectedConfigVersion 11; +:global ExpectedConfigVersion 12; # global variables not to be changed by user :global SentConfigChangesNotification "-"; diff --git a/script-updates b/script-updates index 42ca04a..10a67b6 100644 --- a/script-updates +++ b/script-updates @@ -13,7 +13,6 @@ :global ScriptUpdatesBaseUrl; :global ScriptUpdatesUrlSuffix; :global ScriptUpdatesIgnore; -:global ScriptUpdatesConfigChangesIgnore; :global SendNotification; @@ -81,8 +80,7 @@ } } -:if ($ScriptUpdatesConfigChangesIgnore!=true && \ - $SentConfigChangesNotification!=$ExpectedConfigVersion && \ +:if ($SentConfigChangesNotification!=$ExpectedConfigVersion && \ $GlobalConfigVersion < $ExpectedConfigVersion) do={ :global GlobalConfigChanges; :local ChangeLogCode; From 38b23ddc10e414ece7e59f54d24bda5b4674b6f1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Feb 2020 17:09:30 +0100 Subject: [PATCH 0164/2612] script-updates: prefix variable name with dollar --- script-updates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script-updates b/script-updates index 10a67b6..759c5e0 100644 --- a/script-updates +++ b/script-updates @@ -90,7 +90,7 @@ } :local NotificationMessage ("Current configuration on " . $Identity . \ " is out of date. Please update " . $ConfigScript . ", then increase " . \ - "variable GlobalConfigVersion (currently " . $GlobalConfigVersion . \ + "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \ ") to " . $ExpectedConfigVersion . " and re-run " . $ConfigScript . "."); :log debug ("Fetching changelog."); From e376845b12441eb93e39d733aa1c8072b0056a84 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Feb 2020 18:09:52 +0100 Subject: [PATCH 0165/2612] global-functions: introduce and use $CertificateNameByCN --- global-functions | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index caaf0a5..d4b8801 100644 --- a/global-functions +++ b/global-functions @@ -17,6 +17,7 @@ # global functions :global UrlEncode; :global CharacterReplace; +:global CertificateNameByCN; :global CertificateDownload; :global CertificateAvailable; :global SendEMail; @@ -79,6 +80,16 @@ :return ($Return . $String); } +# name a certificate by its common-name +:set CertificateNameByCN do={ + :local CommonName [ :tostr $1 ]; + + :global CharacterReplace; + + :local Cert [ / certificate find where common-name=$CommonName ]; + / certificate set $Cert name=[ $CharacterReplace [ $CharacterReplace $CommonName " " "-" ] "---" "-" ]; +} + # download and import certificate :set CertificateDownload do={ :local CommonName [ :tostr $1 ]; @@ -86,7 +97,7 @@ :global ScriptUpdatesBaseUrl; :global ScriptUpdatesUrlSuffix; - :global CharacterReplace; + :global CertificateNameByCN; :global UrlEncode; :global WaitForFile; @@ -104,7 +115,7 @@ / file remove $LocalFileName; :foreach Cert in=[ / certificate find where name~("^" . $LocalFileName . "_[0-9]+\$") ] do={ - / certificate set $Cert name=[ $CharacterReplace [ $CharacterReplace [ get $Cert common-name ] " " "-" ] "---" "-" ]; + $CertificateNameByCN [ / certificate get $Cert common-name ]; } } on-error={ :log warning "Failed imprting certificate!"; From 23fe30c4e1134d67650ee0cce2acc350ed154644 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Feb 2020 18:10:47 +0100 Subject: [PATCH 0166/2612] check-certificates: rename all certificates by their common names --- check-certificates | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/check-certificates b/check-certificates index f378f01..e13e984 100644 --- a/check-certificates +++ b/check-certificates @@ -8,6 +8,7 @@ :global CertRenewUrl; :global CertRenewPass; +:global CertificateNameByCN; :global ParseKeyValueStore; :global SendNotification; :global UrlEncode; @@ -37,6 +38,10 @@ / certificate import file-name=$CertFileName passphrase=$PassPhrase; } / file remove [ find where name=$CertFileName ]; + + :foreach CertInChain in=[ / certificate find where name~("^" . $CertFileName . "_[0-9]+\$") common-name!=($CertVal->"common-name") ] do={ + $CertificateNameByCN [ / certificate get $CertInChain common-name ]; + } } on-error={ :log debug ("Could not download certificate file " . $CertFileName); } From 7d2239f24e01497e94c181b247f119592d253eb7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 10:48:04 +0100 Subject: [PATCH 0167/2612] global-functions: introduce $MailServerIsUp --- global-functions | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/global-functions b/global-functions index d4b8801..7d242e6 100644 --- a/global-functions +++ b/global-functions @@ -34,6 +34,7 @@ :global RandomDelay; :global DeviceInfo; :global ScriptInstallUpdate; +:global MailServerIsUp; # url encoding :set UrlEncode do={ @@ -436,3 +437,24 @@ } / system script run script-updates; } + +# check if mail server is up +:set MailServerIsUp do={ + :local MailServer [ / tool e-mail get address ]; + :local MailHost $MailServer; + + :if ([ / tool netwatch print count-only where comment=$MailServer ] = 0) do={ + :log warn ("Adding netwatch entry for mail server."); + :local MailHost $MailServer; + :if ([ :typeof [ :toip $MailHost ] ] != "ip" ) do={ + :set MailHost [ :resolve $MailServer ]; + } + / tool netwatch add comment=$MailServer host=[ :resolve $MailServer ]; + } + + :if ([ / tool netwatch get [ find where comment=$MailServer ] status ] = "up") do={ + :return true; + } + + :return false; +} From e11ddeaf8cca4669bde5449df9d388314cffa548 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 10:48:24 +0100 Subject: [PATCH 0168/2612] sms-forward: use $MailServerIsUp --- sms-forward | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sms-forward b/sms-forward index c05600e..35adba1 100644 --- a/sms-forward +++ b/sms-forward @@ -7,9 +7,10 @@ :global Identity; :global SendNotification; +:global MailServerIsUp; # check mail server -:if ([ / tool netwatch get [ find where comment=[ / tool e-mail get address ] ] status ] != "up") do={ +:if ($MailServerIsUp = false) do={ :log warning "Mail server is not up."; :error "Warning: See log for details."; } From 4984b4fd511e3f4f0352d30c37a312ed6884dcb3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 10:48:41 +0100 Subject: [PATCH 0169/2612] daily-psk-schedule: use $MailServerIsUp --- daily-psk-schedule | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/daily-psk-schedule b/daily-psk-schedule index c9be0bf..6c542a2 100644 --- a/daily-psk-schedule +++ b/daily-psk-schedule @@ -4,12 +4,14 @@ # # schedule daily-psk on startup +:global MailServerIsUp; + :local Scheduler [ / system scheduler find where name="daily-psk-schedule" ]; :if ([ / system scheduler get $Scheduler interval ] = 0s) do={ / system scheduler set interval=15s $Scheduler; } else={ - :if ([ / tool netwatch get [ find where comment=[ / tool e-mail get address ] ] status ] != "up") do={ + :if ($MailServerIsUp = false) do={ :log warning "Mail server is not up."; :error "Warning: See log for details."; } From 77ec3293f0803eacb7d6684b63f4add68ed767b9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 11:06:17 +0100 Subject: [PATCH 0170/2612] global-functions: introduce $TimeIsSync --- global-functions | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/global-functions b/global-functions index 7d242e6..0e1530c 100644 --- a/global-functions +++ b/global-functions @@ -35,6 +35,7 @@ :global DeviceInfo; :global ScriptInstallUpdate; :global MailServerIsUp; +:global TimeIsSync; # url encoding :set UrlEncode do={ @@ -458,3 +459,18 @@ :return false; } + +# check if system time is sync +:set TimeIsSync do={ + :if ([ / system ntp client get enabled ] = true && \ + [ / system ntp client get status ] = "synchronized") do={ + :return true; + } + + :if ([ / ip cloud get update-time ] = true && \ + [ :typeof [ / ip cloud get public-address ] ] = "ip") do={ + :return true; + } + + :return false; +} From 6e8f5f19f60ec3b82a63a19bad39793c8abe09fa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 11:08:11 +0100 Subject: [PATCH 0171/2612] daily-psk-schedule: use $TimeIsSync --- daily-psk-schedule | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/daily-psk-schedule b/daily-psk-schedule index 6c542a2..7e745e1 100644 --- a/daily-psk-schedule +++ b/daily-psk-schedule @@ -5,6 +5,7 @@ # schedule daily-psk on startup :global MailServerIsUp; +:global TimeIsSync; :local Scheduler [ / system scheduler find where name="daily-psk-schedule" ]; @@ -16,11 +17,8 @@ :error "Warning: See log for details."; } - :if ([ / system ntp client get status ] != "synchronized") do={ - :if ([ / system resource get uptime ] > 5m) do={ - / system script run [ find where name="rotate-ntp" ]; - } - :log warning "Time is not yet synchronized from ntp."; + :if ($TimeIsSync = false) do={ + :log warning "Time is not yet synchronized."; :error "Warning: See log for details."; } From 2a80fd6dbe64363123086cb9e7c16f84d9d71569 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 11:12:45 +0100 Subject: [PATCH 0172/2612] check-certificates: check for synced time --- check-certificates | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/check-certificates b/check-certificates index e13e984..b0c2c60 100644 --- a/check-certificates +++ b/check-certificates @@ -11,6 +11,7 @@ :global CertificateNameByCN; :global ParseKeyValueStore; :global SendNotification; +:global TimeIsSync; :global UrlEncode; :global WaitForFile; @@ -19,6 +20,11 @@ :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; } +:if ($TimeIsSync = false) do={ + :log warning "Time is not yet synchronized."; + :error "Warning: See log for details."; +} + :foreach Cert in=[ / certificate find where !revoked !ca expires-after<3w ] do={ :local CertVal [ / certificate get $Cert ]; From 5fab77abad6f4d4cc78118e57aff64b56abc85a4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 11:36:36 +0100 Subject: [PATCH 0173/2612] global-functions: introduce $WaitTimeSync --- global-functions | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/global-functions b/global-functions index 0e1530c..73a6d37 100644 --- a/global-functions +++ b/global-functions @@ -36,6 +36,7 @@ :global ScriptInstallUpdate; :global MailServerIsUp; :global TimeIsSync; +:global WaitTimeSync; # url encoding :set UrlEncode do={ @@ -474,3 +475,12 @@ :return false; } + +# wait for time to become synced +:set WaitTimeSync do={ + :global TimeIsSync; + + :while ([ $TimeIsSync ] = false) do={ + :delay 1s; + } +} From 19b80ee063be901049bf33e63011c96b0f42fc01 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 12:15:06 +0100 Subject: [PATCH 0174/2612] global-functions: $WaitTimeSync: rotate ntp servers minutely Signed-off-by: Christian Hesse --- global-functions | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/global-functions b/global-functions index 73a6d37..d8d5b44 100644 --- a/global-functions +++ b/global-functions @@ -481,6 +481,10 @@ :global TimeIsSync; :while ([ $TimeIsSync ] = false) do={ + :if ([ / system script print count-only where name="rotate-ntp" ] > 0 && \ + [ :tostr [ / system resource get uptime ] ] ~ "00\$") do={ + / system script run rotate-ntp; + } :delay 1s; } } From 125f37615b1e42275fd1766a2cccfba8e8f94b3e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 12:17:42 +0100 Subject: [PATCH 0175/2612] drop script 'daily-psk-schedule' We have some useful functions that can replace the functionality. Just add a schedule like this: add name=daily-psk-startup on-event=":delay 1s; :global WaitTimeSync; \$WaitTimeSync; / system script run daily-psk.local;" start-time=startup --- daily-psk-schedule | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 daily-psk-schedule diff --git a/daily-psk-schedule b/daily-psk-schedule deleted file mode 100644 index 7e745e1..0000000 --- a/daily-psk-schedule +++ /dev/null @@ -1,28 +0,0 @@ -#!rsc -# RouterOS script: daily-psk-schedule -# Copyright (c) 2013-2020 Christian Hesse -# -# schedule daily-psk on startup - -:global MailServerIsUp; -:global TimeIsSync; - -:local Scheduler [ / system scheduler find where name="daily-psk-schedule" ]; - -:if ([ / system scheduler get $Scheduler interval ] = 0s) do={ - / system scheduler set interval=15s $Scheduler; -} else={ - :if ($MailServerIsUp = false) do={ - :log warning "Mail server is not up."; - :error "Warning: See log for details."; - } - - :if ($TimeIsSync = false) do={ - :log warning "Time is not yet synchronized."; - :error "Warning: See log for details."; - } - - / system script run [ find where name~"^daily-psk\\.(capsman|local)\$" ]; - - / system scheduler set interval=0s $Scheduler; -} From 5316ec6ef5fca34cf8c9f49fe9a82a90f1c47b12 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 19:23:32 +0100 Subject: [PATCH 0176/2612] script-updates: warn on scheduler at startup with no interval --- script-updates | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/script-updates b/script-updates index 759c5e0..af45a0a 100644 --- a/script-updates +++ b/script-updates @@ -32,6 +32,13 @@ :log warning ("Policies differ for script " . $ScriptVal->"name" . \ " and its scheduler " . $SchedulerVal->"name" . "!"); } + :if ($SchedulerVal->"name" != "global-scripts" && \ + $SchedulerVal->"start-time" = "startup" && \ + $SchedulerVal->"interval" = 0s && \ + [ :pick ($SchedulerVal->"on-event") 0 7 ] != ":delay ") do={ + :log warning ("Scheduler " . $SchedulerVal->"name" . " starts on startup, " . \ + "without interval. Add delay to make sure the configuration is available!"); + } } :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ From 69352c90d5efc641c7aedd277d8d3499127b96a9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 19:47:17 +0100 Subject: [PATCH 0177/2612] bridge-port-to-default: drop delay Now that we expect the scheduler to have a delay and script-updates warning about it... --- bridge-port-to-default | 7 ------- 1 file changed, 7 deletions(-) diff --git a/bridge-port-to-default b/bridge-port-to-default index 5b7fa7e..1bb4597 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -6,13 +6,6 @@ :global BridgePortTo; -:local Len ([ :len $BridgePortTo ] + 1); - -:if ($Len = 1) do={ - :delay 1s; - :set Len ([ :len $BridgePortTo ] + 1); -} - :foreach BridgePort in=[ / interface bridge port find where comment!="" ] do={ :local BridgePortVal [ / interface bridge port get $BridgePort ]; :foreach Comment in=[ :toarray ($BridgePortVal->"comment") ] do={ From 556fc2d0d3a7a994efed1f2be61692442840d142 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 19:53:15 +0100 Subject: [PATCH 0178/2612] global-functions: introduce $LogAndError --- global-functions | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/global-functions b/global-functions index d8d5b44..335df62 100644 --- a/global-functions +++ b/global-functions @@ -37,6 +37,7 @@ :global MailServerIsUp; :global TimeIsSync; :global WaitTimeSync; +:global LogAndError; # url encoding :set UrlEncode do={ @@ -488,3 +489,11 @@ :delay 1s; } } + +# log and error with same text +:set LogAndError do={ + :local Message [ :tostr $1 ]; + + :log warn $Message; + :error $Message; +} From bb9a4e6ecf25c63fae23d67281925215b67019eb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2020 11:49:11 +0100 Subject: [PATCH 0179/2612] sms-forward: use $LogAndError --- sms-forward | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sms-forward b/sms-forward index 35adba1..8907d19 100644 --- a/sms-forward +++ b/sms-forward @@ -8,11 +8,11 @@ :global SendNotification; :global MailServerIsUp; +:global LogAndError; # check mail server :if ($MailServerIsUp = false) do={ - :log warning "Mail server is not up."; - :error "Warning: See log for details."; + $LogAndError "Mail server is not up."; } :local Settings [ / tool sms get ]; From 9b9ad20b3d2a8bbb92ee35f5d3481508ccac9654 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 19:58:17 +0100 Subject: [PATCH 0180/2612] packages-update: use $LogAndError --- packages-update | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages-update b/packages-update index 8918656..04a25c8 100644 --- a/packages-update +++ b/packages-update @@ -7,6 +7,7 @@ :global DownloadPackage; :global ScriptFromTerminal; :global ScriptLock; +:global LogAndError; $ScriptLock "packages-update"; @@ -25,8 +26,7 @@ $ScriptLock "packages-update"; :foreach Package in=[ / system package find where !bundle ] do={ :local PkgName [ / system package get $Package name ]; if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ - :log error ("Download for package " . $PkgName . " failed."); - :error "Error: See log for details."; + $LogAndError ("Download for package " . $PkgName . " failed."); } } From 1d93bcbc0ddb731e5c484ab5e6b14c9017b9abe7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 20:04:28 +0100 Subject: [PATCH 0181/2612] check-routeros-update: use $LogAndError --- check-routeros-update | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index 1791b23..7f14701 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -11,6 +11,7 @@ :global DeviceInfo; :global ScriptFromTerminal; :global SendNotification; +:global LogAndError; :local DoUpdate do={ :if ([ / system script print count-only where name="packages-update" ] > 0) do={ @@ -24,8 +25,7 @@ :if ([ / system package print count-only where name="wireless" disabled=no ] > 0) do={ :if ([ / interface wireless cap get enabled ] = true && \ [ / caps-man manager get enabled ] = false) do={ - :log warning "System is managed by CAPsMAN, not checking."; - :error "Warning: See log for details."; + $LogAndError "System is managed by CAPsMAN, not checking."; } } @@ -37,8 +37,7 @@ :local Update [ / system package update get ]; :if ([ :len ($Update->"latest-version") ] = 0) do={ - :log warning "An empty string is not a valid version."; - :error "Warning: See log for details."; + $LogAndError "An empty string is not a valid version."; } :if ($Update->"installed-version" != $Update->"latest-version") do={ From f1ab717ae5f1daf9e5296bc5308ce7b0708171b8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 20:07:21 +0100 Subject: [PATCH 0182/2612] ppp-on-up: use $LogAndError --- ppp-on-up | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ppp-on-up b/ppp-on-up index b8f8fcb..6c72a94 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -4,11 +4,12 @@ # # run scripts on ppp up +:global LogAndError; + :local Interface $interface; :if ([ :typeof $Interface ] = "nothing") do={ - :log error "This script is supposed to run from ppp on-up script hook."; - :error "Error: See log for details."; + $LogAndError "This script is supposed to run from ppp on-up script hook."; } :local IntName [ / interface get $Interface name ]; From 7ec411c542c399a8d5f5ddea0253cc068c16b600 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 20:08:22 +0100 Subject: [PATCH 0183/2612] sms-action: use $LogAndError --- sms-action | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sms-action b/sms-action index 026bdc8..5eabdd5 100644 --- a/sms-action +++ b/sms-action @@ -6,11 +6,12 @@ :global SmsAction; +:global LogAndError; + :local Action $action; :if ([ :typeof $Action ] = "nothing") do={ - :log error "This script is supposed to run from SMS hook with action=..."; - :error "Error: See log for details."; + $LogAndError "This script is supposed to run from SMS hook with action=..."; } :local Code ($SmsAction->$Action); From 0326a7222c9c4f2dcb588826d355c94e9454976f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 20:09:51 +0100 Subject: [PATCH 0184/2612] lease-script: use $LogAndError --- lease-script | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lease-script b/lease-script index 0b32d17..588c9ff 100644 --- a/lease-script +++ b/lease-script @@ -4,12 +4,13 @@ # # run scripts on DHCP lease +:global LogAndError; + :if ([ :typeof $leaseActIP ] = "nothing" || \ [ :typeof $leaseActMAC ] = "nothing" || \ [ :typeof $leaseServerName ] = "nothing" || \ [ :typeof $leaseBound ] = "nothing") do={ - :log error "This script is supposed to run from ip dhcp-client."; - :error "Error: See log for details."; + $LogAndError "This script is supposed to run from ip dhcp-client."; } :local Scripts; From 801608eeaf86d3855c8a3883d77b477a1ff36cf3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 20:10:38 +0100 Subject: [PATCH 0185/2612] check-certificates: use $LogAndError --- check-certificates | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-certificates b/check-certificates index b0c2c60..ccc7b15 100644 --- a/check-certificates +++ b/check-certificates @@ -14,6 +14,7 @@ :global TimeIsSync; :global UrlEncode; :global WaitForFile; +:global LogAndError; :local FormatExpire do={ :global CharacterReplace; @@ -21,8 +22,7 @@ } :if ($TimeIsSync = false) do={ - :log warning "Time is not yet synchronized."; - :error "Warning: See log for details."; + $LogAndError "Time is not yet synchronized."; } :foreach Cert in=[ / certificate find where !revoked !ca expires-after<3w ] do={ From 286d7ced11a07686712b07483aacfb684f3311a5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 20:11:23 +0100 Subject: [PATCH 0186/2612] ipv6-update: use $LogAndError --- ipv6-update | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipv6-update b/ipv6-update index 1004119..52c02db 100644 --- a/ipv6-update +++ b/ipv6-update @@ -7,10 +7,10 @@ :local PdPrefix $"pd-prefix"; :global ParseKeyValueStore; +:global LogAndError; :if ([ :typeof $PdPrefix ] = "nothing") do={ - :log error "This script is supposed to run from ipv6 dhcp-client."; - :error "Error: See log for details."; + $LogAndError "This script is supposed to run from ipv6 dhcp-client."; } :local Pool [ / ipv6 pool get [ find where prefix=$PdPrefix ] name ]; From 86ed56e7ad023f75a5662493031b3109d98415ff Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 20:12:09 +0100 Subject: [PATCH 0187/2612] email-backup: use $LogAndError --- email-backup | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/email-backup b/email-backup index d10acb2..9761206 100644 --- a/email-backup +++ b/email-backup @@ -14,11 +14,11 @@ :global CharacterReplace; :global DeviceInfo; +:global LogAndError; :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ - :log error ("Configured to send neither backup nor config export."); - :error "Error: See log for details."; + $LogAndError ("Configured to send neither backup nor config export."); } # filename based on identity From c766d2dfda1a421e8e222e850bbddf644380c691 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 20:13:19 +0100 Subject: [PATCH 0188/2612] update-tunnelbroker: use $LogAndError --- update-tunnelbroker | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/update-tunnelbroker b/update-tunnelbroker index da621e2..1dd11f1 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -5,10 +5,10 @@ :global CertificateAvailable; :global ParseKeyValueStore; +:global LogAndError; :if ([ / ip cloud get ddns-enabled ] != true) do={ - :log error "IP cloud DDNS is not enabled."; - :error "Error: See log for details."; + $LogAndError "IP cloud DDNS is not enabled."; } # Get the current ip address from cloud From 0e6438eaff6aa36d93b6cbb48eeb6c5510856d02 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 20:14:21 +0100 Subject: [PATCH 0189/2612] upload-backup: use $LogAndError --- upload-backup | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/upload-backup b/upload-backup index 4a10653..a761007 100644 --- a/upload-backup +++ b/upload-backup @@ -16,11 +16,11 @@ :global CharacterReplace; :global DeviceInfo; :global SendNotification; +:global LogAndError; :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ - :log error ("Configured to send neither backup nor config export."); - :error "Error: See log for details."; + $LogAndError ("Configured to send neither backup nor config export."); } # filename based on identity From 6ef764c7d7dc855dc40313fbe79702d6949b7abb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2020 20:19:12 +0100 Subject: [PATCH 0190/2612] hotspot-to-wpa: automatically add missing access-list entry --- hotspot-to-wpa | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hotspot-to-wpa b/hotspot-to-wpa index a072d86..5f21878 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -9,11 +9,11 @@ :local Date [ / system clock get date ]; :local PassWord [ / ip hotspot user get [ find where name=$UserName ] password ]; -:local PlaceBefore [ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ]; -:if ([ :len $PlaceBefore ] = 0) do={ - :log error "Missing disabled access-list entry with comment '--- hotspot-to-wpa above ---'"; - :error "Error: See log for details."; +:if ([ / caps-man access-list print count-only where comment="--- hotspot-to-wpa above ---" disabled ] = 0) do={ + / caps-man access-list add comment="--- hotspot-to-wpa above ---" disabled; + log warn "Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'."; } +:local PlaceBefore [ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ]; / caps-man access-list remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; From 3ebf68a08c94e23d742a37815caa3c55b6985806 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2020 12:09:19 +0100 Subject: [PATCH 0191/2612] global-functions: $LogAndError: add severity --- check-certificates | 2 +- check-routeros-update | 4 ++-- email-backup | 2 +- global-functions | 7 ++++--- ipv6-update | 2 +- lease-script | 2 +- packages-update | 2 +- ppp-on-up | 2 +- sms-action | 2 +- sms-forward | 2 +- update-tunnelbroker | 2 +- upload-backup | 2 +- 12 files changed, 16 insertions(+), 15 deletions(-) diff --git a/check-certificates b/check-certificates index ccc7b15..d7c4c8e 100644 --- a/check-certificates +++ b/check-certificates @@ -22,7 +22,7 @@ } :if ($TimeIsSync = false) do={ - $LogAndError "Time is not yet synchronized."; + $LogAndError warning "Time is not yet synchronized."; } :foreach Cert in=[ / certificate find where !revoked !ca expires-after<3w ] do={ diff --git a/check-routeros-update b/check-routeros-update index 7f14701..ff5bc38 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -25,7 +25,7 @@ :if ([ / system package print count-only where name="wireless" disabled=no ] > 0) do={ :if ([ / interface wireless cap get enabled ] = true && \ [ / caps-man manager get enabled ] = false) do={ - $LogAndError "System is managed by CAPsMAN, not checking."; + $LogAndError error "System is managed by CAPsMAN, not checking."; } } @@ -37,7 +37,7 @@ :local Update [ / system package update get ]; :if ([ :len ($Update->"latest-version") ] = 0) do={ - $LogAndError "An empty string is not a valid version."; + $LogAndError warning "An empty string is not a valid version."; } :if ($Update->"installed-version" != $Update->"latest-version") do={ diff --git a/email-backup b/email-backup index 9761206..45e7703 100644 --- a/email-backup +++ b/email-backup @@ -18,7 +18,7 @@ :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ - $LogAndError ("Configured to send neither backup nor config export."); + $LogAndError error ("Configured to send neither backup nor config export."); } # filename based on identity diff --git a/global-functions b/global-functions index 335df62..0e3b5f1 100644 --- a/global-functions +++ b/global-functions @@ -492,8 +492,9 @@ # log and error with same text :set LogAndError do={ - :local Message [ :tostr $1 ]; + :local Severity [ :tostr $1 ]; + :local Message [ :tostr $2 ]; - :log warn $Message; - :error $Message; + [ :parse (":log " . $Severity . " \$Message") ]; + :error ($Severity . ": " . $Message); } diff --git a/ipv6-update b/ipv6-update index 52c02db..eee3536 100644 --- a/ipv6-update +++ b/ipv6-update @@ -10,7 +10,7 @@ :global LogAndError; :if ([ :typeof $PdPrefix ] = "nothing") do={ - $LogAndError "This script is supposed to run from ipv6 dhcp-client."; + $LogAndError error "This script is supposed to run from ipv6 dhcp-client."; } :local Pool [ / ipv6 pool get [ find where prefix=$PdPrefix ] name ]; diff --git a/lease-script b/lease-script index 588c9ff..9109ea9 100644 --- a/lease-script +++ b/lease-script @@ -10,7 +10,7 @@ [ :typeof $leaseActMAC ] = "nothing" || \ [ :typeof $leaseServerName ] = "nothing" || \ [ :typeof $leaseBound ] = "nothing") do={ - $LogAndError "This script is supposed to run from ip dhcp-client."; + $LogAndError error "This script is supposed to run from ip dhcp-client."; } :local Scripts; diff --git a/packages-update b/packages-update index 04a25c8..b4233c8 100644 --- a/packages-update +++ b/packages-update @@ -26,7 +26,7 @@ $ScriptLock "packages-update"; :foreach Package in=[ / system package find where !bundle ] do={ :local PkgName [ / system package get $Package name ]; if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ - $LogAndError ("Download for package " . $PkgName . " failed."); + $LogAndError error ("Download for package " . $PkgName . " failed."); } } diff --git a/ppp-on-up b/ppp-on-up index 6c72a94..415663c 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -9,7 +9,7 @@ :local Interface $interface; :if ([ :typeof $Interface ] = "nothing") do={ - $LogAndError "This script is supposed to run from ppp on-up script hook."; + $LogAndError error "This script is supposed to run from ppp on-up script hook."; } :local IntName [ / interface get $Interface name ]; diff --git a/sms-action b/sms-action index 5eabdd5..ceb9071 100644 --- a/sms-action +++ b/sms-action @@ -11,7 +11,7 @@ :local Action $action; :if ([ :typeof $Action ] = "nothing") do={ - $LogAndError "This script is supposed to run from SMS hook with action=..."; + $LogAndError error "This script is supposed to run from SMS hook with action=..."; } :local Code ($SmsAction->$Action); diff --git a/sms-forward b/sms-forward index 8907d19..f03ab27 100644 --- a/sms-forward +++ b/sms-forward @@ -12,7 +12,7 @@ # check mail server :if ($MailServerIsUp = false) do={ - $LogAndError "Mail server is not up."; + $LogAndError warning "Mail server is not up."; } :local Settings [ / tool sms get ]; diff --git a/update-tunnelbroker b/update-tunnelbroker index 1dd11f1..138fac7 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -8,7 +8,7 @@ :global LogAndError; :if ([ / ip cloud get ddns-enabled ] != true) do={ - $LogAndError "IP cloud DDNS is not enabled."; + $LogAndError error "IP cloud DDNS is not enabled."; } # Get the current ip address from cloud diff --git a/upload-backup b/upload-backup index a761007..817a088 100644 --- a/upload-backup +++ b/upload-backup @@ -20,7 +20,7 @@ :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ - $LogAndError ("Configured to send neither backup nor config export."); + $LogAndError error ("Configured to send neither backup nor config export."); } # filename based on identity From 312caf3f9081c2a18d387b215f989dcd09f1f364 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2020 12:11:50 +0100 Subject: [PATCH 0192/2612] global-functions: introduce $LogAndPut --- global-functions | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/global-functions b/global-functions index 0e3b5f1..7e70d01 100644 --- a/global-functions +++ b/global-functions @@ -38,6 +38,7 @@ :global TimeIsSync; :global WaitTimeSync; :global LogAndError; +:global LogAndPut; # url encoding :set UrlEncode do={ @@ -498,3 +499,12 @@ [ :parse (":log " . $Severity . " \$Message") ]; :error ($Severity . ": " . $Message); } + +# log and put (print on terminal) same text +:set LogAndPut do={ + :local Severity [ :tostr $1 ]; + :local Message [ :tostr $2 ]; + + [ :parse (":log " . $Severity . " \$Message") ]; + :put ($Severity . ": " . $Message); +} From d516b1b2493f11f0d97498685ae2c4d1385087d3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2020 12:15:07 +0100 Subject: [PATCH 0193/2612] script-updates: use $LogAndPut --- script-updates | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/script-updates b/script-updates index af45a0a..b589b9f 100644 --- a/script-updates +++ b/script-updates @@ -15,6 +15,7 @@ :global ScriptUpdatesIgnore; :global SendNotification; +:global LogAndPut; :foreach Script in=[ / system script find where source~"^#!rsc" ] do={ :local Ignore 0; @@ -29,14 +30,14 @@ :foreach Scheduler in=[ / system scheduler find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ :local SchedulerVal [ / system scheduler get $Scheduler ]; :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ - :log warning ("Policies differ for script " . $ScriptVal->"name" . \ + $LogAndPut warning ("Policies differ for script " . $ScriptVal->"name" . \ " and its scheduler " . $SchedulerVal->"name" . "!"); } :if ($SchedulerVal->"name" != "global-scripts" && \ $SchedulerVal->"start-time" = "startup" && \ $SchedulerVal->"interval" = 0s && \ [ :pick ($SchedulerVal->"on-event") 0 7 ] != ":delay ") do={ - :log warning ("Scheduler " . $SchedulerVal->"name" . " starts on startup, " . \ + $LogAndPut warning ("Scheduler " . $SchedulerVal->"name" . " starts on startup, " . \ "without interval. Add delay to make sure the configuration is available!"); } } @@ -56,7 +57,7 @@ :set SourceNew ($Result->"data"); } } on-error={ - :log info ("Failed fetching " . $ScriptVal->"name"); + $LogAndPut warning ("Failed fetching " . $ScriptVal->"name"); } } } @@ -66,7 +67,7 @@ :if ($SourceNew != $ScriptVal->"source") do={ :local DontRequirePermissions \ ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); - :log info ("Updating script: " . $ScriptVal->"name"); + $LogAndPut info ("Updating script: " . $ScriptVal->"name"); / system script set owner=($ScriptVal->"name") source=$SourceNew \ dont-require-permissions=$DontRequirePermissions $Script; :if ($ScriptVal->"name" = "global-config" && \ @@ -80,7 +81,7 @@ :log debug ("Script " . $ScriptVal->"name" . " did not change."); } } else={ - :log warning ("Looks like new script " . $ScriptVal->"name" . " is not valid. Ignoring!"); + $LogAndPut warning ("Looks like new script " . $ScriptVal->"name" . " is not valid. Ignoring!"); } } else={ :log debug ("No update for script " . $ScriptVal->"name" . "."); @@ -116,7 +117,7 @@ } :set GlobalConfigChanges; } on-error={ - :log info ("Failed fetching changes!"); + $LogAndPut warning ("Failed fetching changes!"); :set NotificationMessage ($NotificationMessage . \ "\n\nChanges are not available."); } From b70a460f431e53363880176692b4c2285213a173 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2020 12:54:13 +0100 Subject: [PATCH 0194/2612] check-certificates: use $LogAndError --- check-certificates | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/check-certificates b/check-certificates index d7c4c8e..efa5c10 100644 --- a/check-certificates +++ b/check-certificates @@ -30,8 +30,7 @@ :do { :if ([ :len $CertRenewUrl ] = 0) do={ - :log info "No CertRenewUrl given."; - :error "No CertRenewUrl given."; + $LogAndError warning "No CertRenewUrl given."; } :foreach Type in={ ".pem"; ".p12" } do={ From 3cd9b9ead57e2c62b0409433114a72d1a1e6f4b0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2020 12:55:38 +0100 Subject: [PATCH 0195/2612] check-certificates: use $LogAndPut --- check-certificates | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/check-certificates b/check-certificates index efa5c10..56e9537 100644 --- a/check-certificates +++ b/check-certificates @@ -15,6 +15,7 @@ :global UrlEncode; :global WaitForFile; :global LogAndError; +:global LogAndPut; :local FormatExpire do={ :global CharacterReplace; @@ -85,7 +86,7 @@ "Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]) "" "true"; - :log info ("The certificate " . ($CertVal->"name") . " has been renewed."); + $LogAndPut info ("The certificate " . ($CertVal->"name") . " has been renewed."); } on-error={ :log debug ("Could not renew certificate " . ($CertVal->"name") . "."); } @@ -109,6 +110,6 @@ "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ "Expires in: " . $ExpiresAfter); - :log warning ("The certificate " . ($CertVal->"name") . " " . $State . \ + $LogAndPut warning ("The certificate " . ($CertVal->"name") . " " . $State . \ ", it is invalid after " . ($CertVal->"invalid-after") . "."); } From 6036edb506a7101d95eb293d0509b4ff178d7191 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2020 12:58:49 +0100 Subject: [PATCH 0196/2612] packages-update: use $LogAndError --- packages-update | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages-update b/packages-update index b4233c8..d57ee5d 100644 --- a/packages-update +++ b/packages-update @@ -14,13 +14,11 @@ $ScriptLock "packages-update"; :local Update [ / system package update get ]; :if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ - :log warning "Latest version is not known."; - :error "Latest version is not known."; + $LogAndError warning "Latest version is not known."; } :if ($Update->"installed-version" = $Update->"latest-version") do={ - :log info ("Version " . $Update->"latest-version" . " is already installed."); - :error "No updates available."; + $LogAndError info ("Version " . $Update->"latest-version" . " is already installed."); } :foreach Package in=[ / system package find where !bundle ] do={ @@ -49,8 +47,7 @@ $ScriptLock "packages-update"; / system scheduler add name="reboot-for-update" start-time=03:00:00 interval=1d \ on-event=(":global RandomDelay; \$RandomDelay 3600; " . \ "/ system scheduler remove reboot-for-update; / system reboot;"); - :log info ("Scheduled reboot for update between 03:00 and 04:00."); - :error ("Scheduled reboot."); + $LogAndError info ("Scheduled reboot for update between 03:00 and 04:00."); } } From ceaa83b83edb069ecf1cca181ec461519f0cc020 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2020 14:19:54 +0100 Subject: [PATCH 0197/2612] global-functions: merge $LogAnd{Error,Put} to $LogPrintExit ... ... and fix logging. Logging with severity from variable (:log $severity ...) is not possible, this is considered a syntax error. Also the 'workaround' with parsing code failed with missing message in log. The reliable code is a lot longer, so merge the two functions to save a lot of duplicate code. --- check-certificates | 13 ++++++------- check-routeros-update | 6 +++--- email-backup | 4 ++-- global-functions | 33 +++++++++++++++++---------------- ipv6-update | 4 ++-- lease-script | 4 ++-- packages-update | 10 +++++----- ppp-on-up | 4 ++-- script-updates | 18 +++++++++--------- sms-action | 4 ++-- sms-forward | 4 ++-- update-tunnelbroker | 4 ++-- upload-backup | 4 ++-- 13 files changed, 56 insertions(+), 56 deletions(-) diff --git a/check-certificates b/check-certificates index 56e9537..d94c330 100644 --- a/check-certificates +++ b/check-certificates @@ -14,8 +14,7 @@ :global TimeIsSync; :global UrlEncode; :global WaitForFile; -:global LogAndError; -:global LogAndPut; +:global LogPrintExit; :local FormatExpire do={ :global CharacterReplace; @@ -23,7 +22,7 @@ } :if ($TimeIsSync = false) do={ - $LogAndError warning "Time is not yet synchronized."; + $LogPrintExit warning "Time is not yet synchronized." true; } :foreach Cert in=[ / certificate find where !revoked !ca expires-after<3w ] do={ @@ -31,7 +30,7 @@ :do { :if ([ :len $CertRenewUrl ] = 0) do={ - $LogAndError warning "No CertRenewUrl given."; + $LogPrintExit warning "No CertRenewUrl given." true; } :foreach Type in={ ".pem"; ".p12" } do={ @@ -86,7 +85,7 @@ "Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]) "" "true"; - $LogAndPut info ("The certificate " . ($CertVal->"name") . " has been renewed."); + $LogPrintExit info ("The certificate " . ($CertVal->"name") . " has been renewed.") false; } on-error={ :log debug ("Could not renew certificate " . ($CertVal->"name") . "."); } @@ -110,6 +109,6 @@ "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ "Expires in: " . $ExpiresAfter); - $LogAndPut warning ("The certificate " . ($CertVal->"name") . " " . $State . \ - ", it is invalid after " . ($CertVal->"invalid-after") . "."); + $LogPrintExit warning ("The certificate " . ($CertVal->"name") . " " . $State . \ + ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; } diff --git a/check-routeros-update b/check-routeros-update index ff5bc38..d622ba3 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -11,7 +11,7 @@ :global DeviceInfo; :global ScriptFromTerminal; :global SendNotification; -:global LogAndError; +:global LogPrintExit; :local DoUpdate do={ :if ([ / system script print count-only where name="packages-update" ] > 0) do={ @@ -25,7 +25,7 @@ :if ([ / system package print count-only where name="wireless" disabled=no ] > 0) do={ :if ([ / interface wireless cap get enabled ] = true && \ [ / caps-man manager get enabled ] = false) do={ - $LogAndError error "System is managed by CAPsMAN, not checking."; + $LogPrintExit error "System is managed by CAPsMAN, not checking." true; } } @@ -37,7 +37,7 @@ :local Update [ / system package update get ]; :if ([ :len ($Update->"latest-version") ] = 0) do={ - $LogAndError warning "An empty string is not a valid version."; + $LogPrintExit warning "An empty string is not a valid version." true; } :if ($Update->"installed-version" != $Update->"latest-version") do={ diff --git a/email-backup b/email-backup index 45e7703..978ac4d 100644 --- a/email-backup +++ b/email-backup @@ -14,11 +14,11 @@ :global CharacterReplace; :global DeviceInfo; -:global LogAndError; +:global LogPrintExit; :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ - $LogAndError error ("Configured to send neither backup nor config export."); + $LogPrintExit error ("Configured to send neither backup nor config export.") true; } # filename based on identity diff --git a/global-functions b/global-functions index 7e70d01..ed7363b 100644 --- a/global-functions +++ b/global-functions @@ -37,8 +37,7 @@ :global MailServerIsUp; :global TimeIsSync; :global WaitTimeSync; -:global LogAndError; -:global LogAndPut; +:global LogPrintExit; # url encoding :set UrlEncode do={ @@ -491,20 +490,22 @@ } } -# log and error with same text -:set LogAndError do={ +# log and print with same text, optionally exit +:set LogPrintExit do={ :local Severity [ :tostr $1 ]; - :local Message [ :tostr $2 ]; + :local Message [ :tostr $2 ]; + :local Exit [ :tostr $3 ]; - [ :parse (":log " . $Severity . " \$Message") ]; - :error ($Severity . ": " . $Message); -} - -# log and put (print on terminal) same text -:set LogAndPut do={ - :local Severity [ :tostr $1 ]; - :local Message [ :tostr $2 ]; - - [ :parse (":log " . $Severity . " \$Message") ]; - :put ($Severity . ": " . $Message); + :if ($Severity ~ "^(error|info)\$") do={ + :if ($Severity = "error" ) do={ :log error $Message; } + :if ($Severity = "info" ) do={ :log info $Message; } + } else={ + :log warning $Message; + } + + :if ($Exit = "true") do={ + :error ($Severity . ": " . $Message); + } else={ + :put ($Severity . ": " . $Message); + } } diff --git a/ipv6-update b/ipv6-update index eee3536..7621082 100644 --- a/ipv6-update +++ b/ipv6-update @@ -7,10 +7,10 @@ :local PdPrefix $"pd-prefix"; :global ParseKeyValueStore; -:global LogAndError; +:global LogPrintExit; :if ([ :typeof $PdPrefix ] = "nothing") do={ - $LogAndError error "This script is supposed to run from ipv6 dhcp-client."; + $LogPrintExit error "This script is supposed to run from ipv6 dhcp-client." true; } :local Pool [ / ipv6 pool get [ find where prefix=$PdPrefix ] name ]; diff --git a/lease-script b/lease-script index 9109ea9..1e73b31 100644 --- a/lease-script +++ b/lease-script @@ -4,13 +4,13 @@ # # run scripts on DHCP lease -:global LogAndError; +:global LogPrintExit; :if ([ :typeof $leaseActIP ] = "nothing" || \ [ :typeof $leaseActMAC ] = "nothing" || \ [ :typeof $leaseServerName ] = "nothing" || \ [ :typeof $leaseBound ] = "nothing") do={ - $LogAndError error "This script is supposed to run from ip dhcp-client."; + $LogPrintExit error "This script is supposed to run from ip dhcp-client." true; } :local Scripts; diff --git a/packages-update b/packages-update index d57ee5d..b364b18 100644 --- a/packages-update +++ b/packages-update @@ -7,24 +7,24 @@ :global DownloadPackage; :global ScriptFromTerminal; :global ScriptLock; -:global LogAndError; +:global LogPrintExit; $ScriptLock "packages-update"; :local Update [ / system package update get ]; :if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ - $LogAndError warning "Latest version is not known."; + $LogPrintExit warning "Latest version is not known." true; } :if ($Update->"installed-version" = $Update->"latest-version") do={ - $LogAndError info ("Version " . $Update->"latest-version" . " is already installed."); + $LogPrintExit info ("Version " . $Update->"latest-version" . " is already installed.") true; } :foreach Package in=[ / system package find where !bundle ] do={ :local PkgName [ / system package get $Package name ]; if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ - $LogAndError error ("Download for package " . $PkgName . " failed."); + $LogPrintExit error ("Download for package " . $PkgName . " failed.") true; } } @@ -47,7 +47,7 @@ $ScriptLock "packages-update"; / system scheduler add name="reboot-for-update" start-time=03:00:00 interval=1d \ on-event=(":global RandomDelay; \$RandomDelay 3600; " . \ "/ system scheduler remove reboot-for-update; / system reboot;"); - $LogAndError info ("Scheduled reboot for update between 03:00 and 04:00."); + $LogPrintExit info ("Scheduled reboot for update between 03:00 and 04:00.") true; } } diff --git a/ppp-on-up b/ppp-on-up index 415663c..48d3413 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -4,12 +4,12 @@ # # run scripts on ppp up -:global LogAndError; +:global LogPrintExit; :local Interface $interface; :if ([ :typeof $Interface ] = "nothing") do={ - $LogAndError error "This script is supposed to run from ppp on-up script hook."; + $LogPrintExit error "This script is supposed to run from ppp on-up script hook." true; } :local IntName [ / interface get $Interface name ]; diff --git a/script-updates b/script-updates index b589b9f..2cdc703 100644 --- a/script-updates +++ b/script-updates @@ -15,7 +15,7 @@ :global ScriptUpdatesIgnore; :global SendNotification; -:global LogAndPut; +:global LogPrintExit; :foreach Script in=[ / system script find where source~"^#!rsc" ] do={ :local Ignore 0; @@ -30,15 +30,15 @@ :foreach Scheduler in=[ / system scheduler find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ :local SchedulerVal [ / system scheduler get $Scheduler ]; :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ - $LogAndPut warning ("Policies differ for script " . $ScriptVal->"name" . \ - " and its scheduler " . $SchedulerVal->"name" . "!"); + $LogPrintExit warning ("Policies differ for script " . $ScriptVal->"name" . \ + " and its scheduler " . $SchedulerVal->"name" . "!") false; } :if ($SchedulerVal->"name" != "global-scripts" && \ $SchedulerVal->"start-time" = "startup" && \ $SchedulerVal->"interval" = 0s && \ [ :pick ($SchedulerVal->"on-event") 0 7 ] != ":delay ") do={ - $LogAndPut warning ("Scheduler " . $SchedulerVal->"name" . " starts on startup, " . \ - "without interval. Add delay to make sure the configuration is available!"); + $LogPrintExit warning ("Scheduler " . $SchedulerVal->"name" . " starts on startup, " . \ + "without interval. Add delay to make sure the configuration is available!") false; } } @@ -57,7 +57,7 @@ :set SourceNew ($Result->"data"); } } on-error={ - $LogAndPut warning ("Failed fetching " . $ScriptVal->"name"); + $LogPrintExit warning ("Failed fetching " . $ScriptVal->"name") false; } } } @@ -67,7 +67,7 @@ :if ($SourceNew != $ScriptVal->"source") do={ :local DontRequirePermissions \ ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); - $LogAndPut info ("Updating script: " . $ScriptVal->"name"); + $LogPrintExit info ("Updating script: " . $ScriptVal->"name") false; / system script set owner=($ScriptVal->"name") source=$SourceNew \ dont-require-permissions=$DontRequirePermissions $Script; :if ($ScriptVal->"name" = "global-config" && \ @@ -81,7 +81,7 @@ :log debug ("Script " . $ScriptVal->"name" . " did not change."); } } else={ - $LogAndPut warning ("Looks like new script " . $ScriptVal->"name" . " is not valid. Ignoring!"); + $LogPrintExit warning ("Looks like new script " . $ScriptVal->"name" . " is not valid. Ignoring!") false; } } else={ :log debug ("No update for script " . $ScriptVal->"name" . "."); @@ -117,7 +117,7 @@ } :set GlobalConfigChanges; } on-error={ - $LogAndPut warning ("Failed fetching changes!"); + $LogPrintExit warning ("Failed fetching changes!") false; :set NotificationMessage ($NotificationMessage . \ "\n\nChanges are not available."); } diff --git a/sms-action b/sms-action index ceb9071..4442baf 100644 --- a/sms-action +++ b/sms-action @@ -6,12 +6,12 @@ :global SmsAction; -:global LogAndError; +:global LogPrintExit; :local Action $action; :if ([ :typeof $Action ] = "nothing") do={ - $LogAndError error "This script is supposed to run from SMS hook with action=..."; + $LogPrintExit error "This script is supposed to run from SMS hook with action=..." true; } :local Code ($SmsAction->$Action); diff --git a/sms-forward b/sms-forward index f03ab27..e84cfea 100644 --- a/sms-forward +++ b/sms-forward @@ -8,11 +8,11 @@ :global SendNotification; :global MailServerIsUp; -:global LogAndError; +:global LogPrintExit; # check mail server :if ($MailServerIsUp = false) do={ - $LogAndError warning "Mail server is not up."; + $LogPrintExit warning "Mail server is not up." true; } :local Settings [ / tool sms get ]; diff --git a/update-tunnelbroker b/update-tunnelbroker index 138fac7..bd36439 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -5,10 +5,10 @@ :global CertificateAvailable; :global ParseKeyValueStore; -:global LogAndError; +:global LogPrintExit; :if ([ / ip cloud get ddns-enabled ] != true) do={ - $LogAndError error "IP cloud DDNS is not enabled."; + $LogPrintExit error "IP cloud DDNS is not enabled." true; } # Get the current ip address from cloud diff --git a/upload-backup b/upload-backup index 817a088..fb9f9cd 100644 --- a/upload-backup +++ b/upload-backup @@ -16,11 +16,11 @@ :global CharacterReplace; :global DeviceInfo; :global SendNotification; -:global LogAndError; +:global LogPrintExit; :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ - $LogAndError error ("Configured to send neither backup nor config export."); + $LogPrintExit error ("Configured to send neither backup nor config export.") true; } # filename based on identity From 3db752bc979be5f7eaff4f64e96d5f854b83eff5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 27 Feb 2020 13:51:27 +0100 Subject: [PATCH 0198/2612] global-functions: $ScriptLock: use $LogPrintExit --- global-functions | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index ed7363b..cdc7300 100644 --- a/global-functions +++ b/global-functions @@ -306,11 +306,12 @@ # lock script against multiple invocation :set ScriptLock do={ + :global LogPrintExit; + :local Script [ :tostr $1 ]; :if ([ / system script job print count-only where script=$Script ] > 1) do={ - :log debug ("Script " . $Script . " started more than once... Aborting."); - :error "Locked." + $LogPrintExit info ("Script " . $Script . " started more than once... Aborting.") true; } } From 001e7eeb39ee993539334805622f8cd24fde63e9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 28 Feb 2020 15:26:26 +0100 Subject: [PATCH 0199/2612] global-functions: sort alphabetically --- check-certificates | 6 +- check-routeros-update | 2 +- cloud-backup | 2 +- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- daily-psk.template | 2 +- dhcp-to-dns | 2 +- email-backup | 10 +- global-functions | 615 +++++++++++++++++----------------- gps-track | 2 +- ipv6-update | 2 +- packages-update | 2 +- script-updates | 8 +- sms-forward | 4 +- update-tunnelbroker | 2 +- upload-backup | 14 +- 17 files changed, 339 insertions(+), 340 deletions(-) diff --git a/check-certificates b/check-certificates index d94c330..38f1c79 100644 --- a/check-certificates +++ b/check-certificates @@ -4,17 +4,17 @@ # # check for certificate validity -:global Identity; -:global CertRenewUrl; :global CertRenewPass; +:global CertRenewUrl; +:global Identity; :global CertificateNameByCN; +:global LogPrintExit; :global ParseKeyValueStore; :global SendNotification; :global TimeIsSync; :global UrlEncode; :global WaitForFile; -:global LogPrintExit; :local FormatExpire do={ :global CharacterReplace; diff --git a/check-routeros-update b/check-routeros-update index d622ba3..4ed52f3 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -9,9 +9,9 @@ :global SentRouterosUpdateNotification; :global DeviceInfo; +:global LogPrintExit; :global ScriptFromTerminal; :global SendNotification; -:global LogPrintExit; :local DoUpdate do={ :if ([ / system script print count-only where name="packages-update" ] > 0) do={ diff --git a/cloud-backup b/cloud-backup index 5875cd1..9a225a2 100644 --- a/cloud-backup +++ b/cloud-backup @@ -4,8 +4,8 @@ # # upload backup to MikroTik cloud -:global Identity; :global BackupPassword; +:global Identity; :global DeviceInfo; :global SendNotification; diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 2b9b23f..a280cea 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -9,8 +9,8 @@ :global Identity; :global GetMacVendor; -:global SendNotification; :global ScriptLock; +:global SendNotification; $ScriptLock "collect-wireless-mac.capsman"; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 3241c27..cf09fa5 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -9,8 +9,8 @@ :global Identity; :global GetMacVendor; -:global SendNotification; :global ScriptLock; +:global SendNotification; $ScriptLock "collect-wireless-mac.local"; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 6ad55a2..8f8ded8 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -10,8 +10,8 @@ :global Identity; :global GetMacVendor; -:global SendNotification; :global ScriptLock; +:global SendNotification; $ScriptLock "collect-wireless-mac%TEMPL%"; diff --git a/daily-psk.template b/daily-psk.template index e0ae26a..88353a4 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -8,8 +8,8 @@ # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! -:global Identity; :global DailyPskMatchComment; +:global Identity; :global SendNotification; :global UrlEncode; diff --git a/dhcp-to-dns b/dhcp-to-dns index 5343513..0d92278 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -6,9 +6,9 @@ :global CharacterReplace; -:global Identity; :global Domain; :global HostNameInZone; +:global Identity; :local Zone; :if ($HostNameInZone = true) do={ diff --git a/email-backup b/email-backup index 978ac4d..2449173 100644 --- a/email-backup +++ b/email-backup @@ -4,13 +4,13 @@ # # create and email backup and config file -:global Identity; -:global Domain; -:global EmailBackupTo; -:global EmailBackupCc; +:global BackupPassword; :global BackupSendBinary; :global BackupSendExport; -:global BackupPassword; +:global Domain; +:global EmailBackupCc; +:global EmailBackupTo; +:global Identity; :global CharacterReplace; :global DeviceInfo; diff --git a/global-functions b/global-functions index cdc7300..cc8ca20 100644 --- a/global-functions +++ b/global-functions @@ -9,89 +9,64 @@ :global ExpectedConfigVersion 12; # global variables not to be changed by user -:global SentConfigChangesNotification "-"; -:global SentRouterosUpdateNotification "-"; -:global SentLteFirmwareUpgradeNotification "-"; :global Identity [ / system identity get name ]; +:global SentConfigChangesNotification "-"; +:global SentLteFirmwareUpgradeNotification "-"; +:global SentRouterosUpdateNotification "-"; # global functions -:global UrlEncode; -:global CharacterReplace; -:global CertificateNameByCN; -:global CertificateDownload; :global CertificateAvailable; -:global SendEMail; -:global SendTelegram; -:global SendNotification; -:global GetMacVendor; +:global CertificateDownload; +:global CertificateNameByCN; +:global CharacterReplace; :global CleanFilePath; -:global DownloadPackage; -:global ScriptLock; -:global ScriptFromTerminal; -:global WaitForFile; -:global ParseKeyValueStore; -:global GetRandom; -:global RandomDelay; :global DeviceInfo; -:global ScriptInstallUpdate; -:global MailServerIsUp; -:global TimeIsSync; -:global WaitTimeSync; +:global DownloadPackage; +:global GetMacVendor; +:global GetRandom; :global LogPrintExit; +:global MailServerIsUp; +:global ParseKeyValueStore; +:global RandomDelay; +:global ScriptFromTerminal; +:global ScriptInstallUpdate; +:global ScriptLock; +:global SendEMail; +:global SendNotification; +:global SendTelegram; +:global TimeIsSync; +:global UrlEncode; +:global WaitForFile; +:global WaitTimeSync; -# url encoding -:set UrlEncode do={ - :local Input [ :tostr $1 ]; - :local Return ""; - - :if ([ :len $Input ] > 0) do={ - :local Chars " !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~"; - :local Subs { "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27"; "%28"; "%29"; - "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; "%3F"; "%40"; - "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; "%7E" }; - - :for I from=0 to=([ :len $Input ] - 1) do={ - :local Char [ :pick $Input $I ]; - :local Replace [ :find $Chars $Char ]; - - :if ([ :len $Replace ] > 0) do={ - :set Char ($Subs->$Replace); - } - :set Return ($Return . $Char); - } - } - - :return $Return; -} - -# character replace -:set CharacterReplace do={ - :local String [ :tostr $1 ]; - :local ReplaceFrom [ :tostr $2 ]; - :local ReplaceWith [ :tostr $3 ]; - :local Return ""; - - :if ($ReplaceFrom = "") do={ - :return $String; - } - - :while ([ :typeof [ :find $String $ReplaceFrom ] ] != "nil") do={ - :local Pos [ :find $String $ReplaceFrom ]; - :set Return ($Return . [ :pick $String 0 $Pos ] . $ReplaceWith); - :set String [ :pick $String ($Pos + [ :len $ReplaceFrom ]) [ :len $String ] ]; - } - - :return ($Return . $String); -} - -# name a certificate by its common-name -:set CertificateNameByCN do={ +# check and download required certificate +:set CertificateAvailable do={ :local CommonName [ :tostr $1 ]; - :global CharacterReplace; + :global CertificateDownload; + :global ParseKeyValueStore; - :local Cert [ / certificate find where common-name=$CommonName ]; - / certificate set $Cert name=[ $CharacterReplace [ $CharacterReplace $CommonName " " "-" ] "---" "-" ]; + :if ([ / system resource get free-hdd-space ] < 8388608 && \ + [ / certificate settings get crl-download ] = true && \ + [ / certificate settings get crl-store ] = "system") do={ + :log warn "This system has low free flash space but is configured to download certificate CRLs to system!"; + } + + :if ([ / certificate print count-only where common-name=$CommonName ] = 0) do={ + :log info ("Certificate with CommonName \"" . $CommonName . "\" not available."); + $CertificateDownload $CommonName; + } + + :local CertVal; + :local Issuer $CommonName; + :do { + :if ([ / certificate print count-only where common-name=$Issuer ] = 0) do={ + :log info ("Certificate chain for \"" . $CommonName . "\" is incomplete, missing \"" . $Issuer . "\"."); + $CertificateDownload $CommonName; + } + :set CertVal [ / certificate get [ find where common-name=$Issuer ] ]; + :set Issuer ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN"); + } while=($Issuer != $CertVal->"common-name"); } # download and import certificate @@ -126,118 +101,34 @@ } } -# check and download required certificate -:set CertificateAvailable do={ +# name a certificate by its common-name +:set CertificateNameByCN do={ :local CommonName [ :tostr $1 ]; - :global CertificateDownload; - :global ParseKeyValueStore; + :global CharacterReplace; - :if ([ / system resource get free-hdd-space ] < 8388608 && \ - [ / certificate settings get crl-download ] = true && \ - [ / certificate settings get crl-store ] = "system") do={ - :log warn "This system has low free flash space but is configured to download certificate CRLs to system!"; - } - - :if ([ / certificate print count-only where common-name=$CommonName ] = 0) do={ - :log info ("Certificate with CommonName \"" . $CommonName . "\" not available."); - $CertificateDownload $CommonName; - } - - :local CertVal; - :local Issuer $CommonName; - :do { - :if ([ / certificate print count-only where common-name=$Issuer ] = 0) do={ - :log info ("Certificate chain for \"" . $CommonName . "\" is incomplete, missing \"" . $Issuer . "\"."); - $CertificateDownload $CommonName; - } - :set CertVal [ / certificate get [ find where common-name=$Issuer ] ]; - :set Issuer ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN"); - } while=($Issuer != $CertVal->"common-name"); + :local Cert [ / certificate find where common-name=$CommonName ]; + / certificate set $Cert name=[ $CharacterReplace [ $CharacterReplace $CommonName " " "-" ] "---" "-" ]; } -# send notification via e-mail -:set SendEMail do={ - :local Subject [ :tostr $1 ]; - :local Message [ :tostr $2 ]; - :local Attach [ :tostr $3 ]; +# character replace +:set CharacterReplace do={ + :local String [ :tostr $1 ]; + :local ReplaceFrom [ :tostr $2 ]; + :local ReplaceWith [ :tostr $3 ]; + :local Return ""; - :global Identity; - :global EmailGeneralTo; - :global EmailGeneralCc; - - :if ([ :len $EmailGeneralTo ] > 0) do={ - :do { - :local Signature [ / system note get note ]; - :if ([ :len $Signature ] > 0) do={ - :set Signature ("\n-- \n" . $Signature); - } - / tool e-mail send to=$EmailGeneralTo cc=$EmailGeneralCc \ - subject=("[" . $Identity . "] " . $Subject) \ - body=($Message . $Signature) file=$Attach; - } on-error={ - :log warning "Failed sending notification mail!"; - } + :if ($ReplaceFrom = "") do={ + :return $String; } -} -# send notification via telegram -:set SendTelegram do={ - :local Subject [ :tostr $1 ]; - :local Message [ :tostr $2 ]; - :local Silent [ :tostr $3 ]; - - :global Identity; - :global TelegramTokenId; - :global TelegramChatId; - - :global UrlEncode; - :global CertificateAvailable; - - :if ([ :len $TelegramTokenId ] > 0 && [ :len $TelegramChatId ] > 0) do={ - $CertificateAvailable "Go Daddy Secure Certificate Authority - G2"; - :do { - / tool fetch check-certificate=yes-without-crl output=none http-method=post \ - ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ - http-data=("chat_id=" . $TelegramChatId . "&disable_notification=" . $Silent . \ - "&text=" . [ $UrlEncode ("[" . $Identity . "] " . $Subject . "\n\n" . $Message) ]); - } on-error={ - :log warning "Failed sending telegram notification!"; - } + :while ([ :typeof [ :find $String $ReplaceFrom ] ] != "nil") do={ + :local Pos [ :find $String $ReplaceFrom ]; + :set Return ($Return . [ :pick $String 0 $Pos ] . $ReplaceWith); + :set String [ :pick $String ($Pos + [ :len $ReplaceFrom ]) [ :len $String ] ]; } -} -# send notification via e-mail and telegram -# Note that attachment is ignored for telegram, silent is ignored for e-mail! -:set SendNotification do={ - :local Subject [ :tostr $1 ]; - :local Message [ :tostr $2 ]; - :local Attach [ :tostr $3 ]; - :local Silent [ :tostr $4 ]; - - :global SendEMail; - :global SendTelegram; - - $SendEMail $Subject $Message $Attach; - $SendTelegram $Subject $Message $Silent; -} - - -# get MAC vendor -:set GetMacVendor do={ - :local Mac [ :tostr $1 ]; - - :global CertificateAvailable; - - :do { - :local Vendor; - $CertificateAvailable "Let's Encrypt Authority X3"; - :set Vendor ([ / tool fetch check-certificate=yes-without-crl \ - ("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data"); - :return $Vendor; - } on-error={ - :return "unknown vendor"; - } + :return ($Return . $String); } # clean file path @@ -259,6 +150,49 @@ :return $Path; } +# get readable device info +:set DeviceInfo do={ + :global ExpectedConfigVersion; + :global GlobalConfigVersion; + :global Identity; + + :local Resource [ / system resource get ]; + :local RouterBoard [ / system routerboard get ]; + :local Update [ / system package update get ]; + + :local Info ( \ + "Hostname: " . $Identity . "\n" . \ + "Board name: " . $Resource->"board-name" . "\n" . \ + "Architecture: " . $Resource->"architecture-name"); + :if ($RouterBoard->"routerboard" = true) do={ + :local Revision ""; + :if ([ :len ($RouterBoard->"revision") ] > 0) do={ + :set Revision (" " . $RouterBoard->"revision"); + } + :set Info ($Info . "\n" . \ + "Model: " . $RouterBoard->"model" . $Revision . "\n" . \ + "Serial number: " . $RouterBoard->"serial-number"); + } + :set Info ($Info . "\n" . \ + "RouterOS:\n" . \ + " Channel: " . $Update->"channel" . "\n" . \ + " Installed: " . $Update->"installed-version"); + :if ([ :typeof ($Update->"latest-version") ] != "nothing" && \ + $Update->"installed-version" != $Update->"latest-version") do={ + :set Info ($Info . "\n" . \ + " Available: " . $Update->"latest-version"); + } + :set Info ($Info . "\n" . \ + "RouterOS-Scripts Configuration Version:\n" . \ + " Current: " . $GlobalConfigVersion); + :if ($GlobalConfigVersion != $ExpectedConfigVersion) do={ + :set Info ($Info . "\n" . \ + " Expected: " . $ExpectedConfigVersion); + } + + :return $Info; +} + # download package from upgrade server :set DownloadPackage do={ :local PkgName [ :tostr $1 ]; @@ -304,68 +238,23 @@ :return false; } -# lock script against multiple invocation -:set ScriptLock do={ - :global LogPrintExit; +# get MAC vendor +:set GetMacVendor do={ + :local Mac [ :tostr $1 ]; - :local Script [ :tostr $1 ]; + :global CertificateAvailable; - :if ([ / system script job print count-only where script=$Script ] > 1) do={ - $LogPrintExit info ("Script " . $Script . " started more than once... Aborting.") true; + :do { + :local Vendor; + $CertificateAvailable "Let's Encrypt Authority X3"; + :set Vendor ([ / tool fetch check-certificate=yes-without-crl \ + ("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data"); + :return $Vendor; + } on-error={ + :return "unknown vendor"; } } -# check if script is run from terminal -:set ScriptFromTerminal do={ - :local Script [ :tostr $1 ]; - - :foreach Job in=[ / system script job find where script=$Script ] do={ - :set Job [ / system script job get $Job ]; - :while ([ :typeof ($Job->"parent") ] = "id") do={ - :set Job [ / system script job get [ find where .id=($Job->"parent") ] ]; - } - :if (($Job->"type") = "login") do={ - :log debug ("Script " . $Script . " started from terminal."); - :return true; - } - } - - :return false; -} - -# wait for file to be available -:set WaitForFile do={ - :global CleanFilePath; - - :local FileName [ $CleanFilePath [ :tostr $1 ] ]; - :local I 0; - - :while ([ file print count-only where name=$FileName ] = 0) do={ - :if ($I > 20) do={ - :return false; - } - :delay 100ms; - :set I ($I + 1); - } - :return true; -} - -# parse key value store -:set ParseKeyValueStore do={ - :global CharacterReplace; - - :local Source $1; - :if ([ :typeof $Source ] != "array") do={ - :set Source [ :tostr $1 ]; - } - :local Result [ :toarray "" ]; - :foreach KeyValue in=[ :toarray $Source ] do={ - :set KeyValue [ :toarray [ $CharacterReplace $KeyValue "=" "," ] ]; - :set ($Result->($KeyValue->0)) ($KeyValue->1); - } - :return $Result; -} - # generate random number # Warning: This is a *very* weak algorithm and in *no way* # useful for cryptography or similar! @@ -379,67 +268,24 @@ :return ($Sum % $Max); } -# delay a random amount of seconds -:set RandomDelay do={ - :global GetRandom; +# log and print with same text, optionally exit +:set LogPrintExit do={ + :local Severity [ :tostr $1 ]; + :local Message [ :tostr $2 ]; + :local Exit [ :tostr $3 ]; - :delay ([ $GetRandom $1 ] . "s"); -} - -# get readable device info -:set DeviceInfo do={ - :global ExpectedConfigVersion; - :global GlobalConfigVersion; - :global Identity; - - :local Resource [ / system resource get ]; - :local RouterBoard [ / system routerboard get ]; - :local Update [ / system package update get ]; - - :local Info ( \ - "Hostname: " . $Identity . "\n" . \ - "Board name: " . $Resource->"board-name" . "\n" . \ - "Architecture: " . $Resource->"architecture-name"); - :if ($RouterBoard->"routerboard" = true) do={ - :local Revision ""; - :if ([ :len ($RouterBoard->"revision") ] > 0) do={ - :set Revision (" " . $RouterBoard->"revision"); - } - :set Info ($Info . "\n" . \ - "Model: " . $RouterBoard->"model" . $Revision . "\n" . \ - "Serial number: " . $RouterBoard->"serial-number"); - } - :set Info ($Info . "\n" . \ - "RouterOS:\n" . \ - " Channel: " . $Update->"channel" . "\n" . \ - " Installed: " . $Update->"installed-version"); - :if ([ :typeof ($Update->"latest-version") ] != "nothing" && \ - $Update->"installed-version" != $Update->"latest-version") do={ - :set Info ($Info . "\n" . \ - " Available: " . $Update->"latest-version"); - } - :set Info ($Info . "\n" . \ - "RouterOS-Scripts Configuration Version:\n" . \ - " Current: " . $GlobalConfigVersion); - :if ($GlobalConfigVersion != $ExpectedConfigVersion) do={ - :set Info ($Info . "\n" . \ - " Expected: " . $ExpectedConfigVersion); + :if ($Severity ~ "^(error|info)\$") do={ + :if ($Severity = "error" ) do={ :log error $Message; } + :if ($Severity = "info" ) do={ :log info $Message; } + } else={ + :log warning $Message; } - :return $Info; -} - -# install new scripts, update existing scripts -:set ScriptInstallUpdate do={ - :local Scripts [ :toarray $1 ]; - - :foreach Script in=$Scripts do={ - :if ([ / system script print count-only where name=$Script ] = 0) do={ - :log info ("Adding new script: " . $Script); - / system script add name=$Script source="#!rsc"; - } + :if ($Exit = "true") do={ + :error ($Severity . ": " . $Message); + } else={ + :put ($Severity . ": " . $Message); } - / system script run script-updates; } # check if mail server is up @@ -463,6 +309,137 @@ :return false; } +# parse key value store +:set ParseKeyValueStore do={ + :global CharacterReplace; + + :local Source $1; + :if ([ :typeof $Source ] != "array") do={ + :set Source [ :tostr $1 ]; + } + :local Result [ :toarray "" ]; + :foreach KeyValue in=[ :toarray $Source ] do={ + :set KeyValue [ :toarray [ $CharacterReplace $KeyValue "=" "," ] ]; + :set ($Result->($KeyValue->0)) ($KeyValue->1); + } + :return $Result; +} + +# delay a random amount of seconds +:set RandomDelay do={ + :global GetRandom; + + :delay ([ $GetRandom $1 ] . "s"); +} + +# check if script is run from terminal +:set ScriptFromTerminal do={ + :local Script [ :tostr $1 ]; + + :foreach Job in=[ / system script job find where script=$Script ] do={ + :set Job [ / system script job get $Job ]; + :while ([ :typeof ($Job->"parent") ] = "id") do={ + :set Job [ / system script job get [ find where .id=($Job->"parent") ] ]; + } + :if (($Job->"type") = "login") do={ + :log debug ("Script " . $Script . " started from terminal."); + :return true; + } + } + + :return false; +} + +# install new scripts, update existing scripts +:set ScriptInstallUpdate do={ + :local Scripts [ :toarray $1 ]; + + :foreach Script in=$Scripts do={ + :if ([ / system script print count-only where name=$Script ] = 0) do={ + :log info ("Adding new script: " . $Script); + / system script add name=$Script source="#!rsc"; + } + } + / system script run script-updates; +} + +# lock script against multiple invocation +:set ScriptLock do={ + :global LogPrintExit; + + :local Script [ :tostr $1 ]; + + :if ([ / system script job print count-only where script=$Script ] > 1) do={ + $LogPrintExit info ("Script " . $Script . " started more than once... Aborting.") true; + } +} + +# send notification via e-mail +:set SendEMail do={ + :local Subject [ :tostr $1 ]; + :local Message [ :tostr $2 ]; + :local Attach [ :tostr $3 ]; + + :global Identity; + :global EmailGeneralTo; + :global EmailGeneralCc; + + :if ([ :len $EmailGeneralTo ] > 0) do={ + :do { + :local Signature [ / system note get note ]; + :if ([ :len $Signature ] > 0) do={ + :set Signature ("\n-- \n" . $Signature); + } + / tool e-mail send to=$EmailGeneralTo cc=$EmailGeneralCc \ + subject=("[" . $Identity . "] " . $Subject) \ + body=($Message . $Signature) file=$Attach; + } on-error={ + :log warning "Failed sending notification mail!"; + } + } +} + +# send notification via e-mail and telegram +# Note that attachment is ignored for telegram, silent is ignored for e-mail! +:set SendNotification do={ + :local Subject [ :tostr $1 ]; + :local Message [ :tostr $2 ]; + :local Attach [ :tostr $3 ]; + :local Silent [ :tostr $4 ]; + + :global SendEMail; + :global SendTelegram; + + $SendEMail $Subject $Message $Attach; + $SendTelegram $Subject $Message $Silent; +} + +# send notification via telegram +:set SendTelegram do={ + :local Subject [ :tostr $1 ]; + :local Message [ :tostr $2 ]; + :local Silent [ :tostr $3 ]; + + :global Identity; + :global TelegramTokenId; + :global TelegramChatId; + + :global UrlEncode; + :global CertificateAvailable; + + :if ([ :len $TelegramTokenId ] > 0 && [ :len $TelegramChatId ] > 0) do={ + $CertificateAvailable "Go Daddy Secure Certificate Authority - G2"; + :do { + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ + http-data=("chat_id=" . $TelegramChatId . "&disable_notification=" . $Silent . \ + "&text=" . [ $UrlEncode ("[" . $Identity . "] " . $Subject . "\n\n" . $Message) ]); + } on-error={ + :log warning "Failed sending telegram notification!"; + } + } +} + # check if system time is sync :set TimeIsSync do={ :if ([ / system ntp client get enabled ] = true && \ @@ -478,6 +455,48 @@ :return false; } +# url encoding +:set UrlEncode do={ + :local Input [ :tostr $1 ]; + :local Return ""; + + :if ([ :len $Input ] > 0) do={ + :local Chars " !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~"; + :local Subs { "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27"; "%28"; "%29"; + "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; "%3F"; "%40"; + "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; "%7E" }; + + :for I from=0 to=([ :len $Input ] - 1) do={ + :local Char [ :pick $Input $I ]; + :local Replace [ :find $Chars $Char ]; + + :if ([ :len $Replace ] > 0) do={ + :set Char ($Subs->$Replace); + } + :set Return ($Return . $Char); + } + } + + :return $Return; +} + +# wait for file to be available +:set WaitForFile do={ + :global CleanFilePath; + + :local FileName [ $CleanFilePath [ :tostr $1 ] ]; + :local I 0; + + :while ([ file print count-only where name=$FileName ] = 0) do={ + :if ($I > 20) do={ + :return false; + } + :delay 100ms; + :set I ($I + 1); + } + :return true; +} + # wait for time to become synced :set WaitTimeSync do={ :global TimeIsSync; @@ -490,23 +509,3 @@ :delay 1s; } } - -# log and print with same text, optionally exit -:set LogPrintExit do={ - :local Severity [ :tostr $1 ]; - :local Message [ :tostr $2 ]; - :local Exit [ :tostr $3 ]; - - :if ($Severity ~ "^(error|info)\$") do={ - :if ($Severity = "error" ) do={ :log error $Message; } - :if ($Severity = "info" ) do={ :log info $Message; } - } else={ - :log warning $Message; - } - - :if ($Exit = "true") do={ - :error ($Severity . ": " . $Message); - } else={ - :put ($Severity . ": " . $Message); - } -} diff --git a/gps-track b/gps-track index 3b944b3..2513e03 100644 --- a/gps-track +++ b/gps-track @@ -4,8 +4,8 @@ # # track gps data by sending json data to http server -:global Identity; :global GpsTrackUrl; +:global Identity; :local CoordinateFormat [ /system gps get coordinate-format ]; :local Gps [ / system gps monitor once as-value ]; diff --git a/ipv6-update b/ipv6-update index 7621082..baea7c3 100644 --- a/ipv6-update +++ b/ipv6-update @@ -6,8 +6,8 @@ :local PdPrefix $"pd-prefix"; -:global ParseKeyValueStore; :global LogPrintExit; +:global ParseKeyValueStore; :if ([ :typeof $PdPrefix ] = "nothing") do={ $LogPrintExit error "This script is supposed to run from ipv6 dhcp-client." true; diff --git a/packages-update b/packages-update index b364b18..5baa78b 100644 --- a/packages-update +++ b/packages-update @@ -5,9 +5,9 @@ # download packages and reboot for installation :global DownloadPackage; +:global LogPrintExit; :global ScriptFromTerminal; :global ScriptLock; -:global LogPrintExit; $ScriptLock "packages-update"; diff --git a/script-updates b/script-updates index 2cdc703..b84fcbf 100644 --- a/script-updates +++ b/script-updates @@ -8,14 +8,14 @@ :global GlobalConfigVersion; :global Identity; :global IDonate; -:global SentConfigChangesNotification; -:global ScriptUpdatesFetch; :global ScriptUpdatesBaseUrl; -:global ScriptUpdatesUrlSuffix; +:global ScriptUpdatesFetch; :global ScriptUpdatesIgnore; +:global ScriptUpdatesUrlSuffix; +:global SentConfigChangesNotification; -:global SendNotification; :global LogPrintExit; +:global SendNotification; :foreach Script in=[ / system script find where source~"^#!rsc" ] do={ :local Ignore 0; diff --git a/sms-forward b/sms-forward index e84cfea..2ace48d 100644 --- a/sms-forward +++ b/sms-forward @@ -6,9 +6,9 @@ :global Identity; -:global SendNotification; -:global MailServerIsUp; :global LogPrintExit; +:global MailServerIsUp; +:global SendNotification; # check mail server :if ($MailServerIsUp = false) do={ diff --git a/update-tunnelbroker b/update-tunnelbroker index bd36439..3aed610 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -4,8 +4,8 @@ # Michael Gisbers :global CertificateAvailable; -:global ParseKeyValueStore; :global LogPrintExit; +:global ParseKeyValueStore; :if ([ / ip cloud get ddns-enabled ] != true) do={ $LogPrintExit error "IP cloud DDNS is not enabled." true; diff --git a/upload-backup b/upload-backup index fb9f9cd..16c6bd8 100644 --- a/upload-backup +++ b/upload-backup @@ -4,19 +4,19 @@ # # create and upload backup and config file -:global Identity; -:global Domain; -:global BackupUploadUrl; -:global BackupUploadUser; -:global BackupUploadPass; +:global BackupPassword; :global BackupSendBinary; :global BackupSendExport; -:global BackupPassword; +:global BackupUploadPass; +:global BackupUploadUrl; +:global BackupUploadUser; +:global Domain; +:global Identity; :global CharacterReplace; :global DeviceInfo; -:global SendNotification; :global LogPrintExit; +:global SendNotification; :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ From 4ccdec602ed668d50212177f31cea5bdf2b20ed2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 3 Mar 2020 08:40:16 +0100 Subject: [PATCH 0200/2612] bridge-port-to-default: use $LogPrintExit --- bridge-port-to-default | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bridge-port-to-default b/bridge-port-to-default index 1bb4597..5b3af53 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -6,6 +6,8 @@ :global BridgePortTo; +:global LogPrintExit; + :foreach BridgePort in=[ / interface bridge port find where comment!="" ] do={ :local BridgePortVal [ / interface bridge port get $BridgePort ]; :foreach Comment in=[ :toarray ($BridgePortVal->"comment") ] do={ @@ -13,18 +15,18 @@ :local BridgeDefault [ :pick $Comment $Len [ :len $Comment ] ]; :if ($BridgeDefault = "dhcp-client") do={ :if ($BridgePortVal->"disabled" = false) do={ - :log info ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client."); + $LogPrintExit info ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; / interface bridge port disable $BridgePort; / ip dhcp-client enable [ find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" disabled=yes ]; } } else={ :if ($BridgePortVal->"disabled" = true) do={ - :log info ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", disabling dhcp client."); + $LogPrintExit info ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", disabling dhcp client.") false; / ip dhcp-client disable [ find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" disabled=no ]; / interface bridge port enable $BridgePort; } :if ($BridgeDefault != $BridgePortVal->"bridge") do={ - :log info ("Changing interface " . $BridgePortVal->"interface" . " to " . $BridgePortTo . " bridge " . $BridgeDefault); + $LogPrintExit info ("Changing interface " . $BridgePortVal->"interface" . " to " . $BridgePortTo . " bridge " . $BridgeDefault) false; / interface bridge port set bridge=$BridgeDefault $BridgePort; } else={ :log debug ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . " bridge " . $BridgeDefault); From 628ae1bd7098a4a898bf3fef0c202ae735014bec Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 3 Mar 2020 13:32:00 +0100 Subject: [PATCH 0201/2612] bridge-port-to-default: use $ParseKeyValueStore... ... and unbreak last commit removing delay (69352c90). This requires a change in configuration syntax. Change this... comment="default:br-local, alt:br-guest" to... comment="default=br-local, alt=br-guest" --- bridge-port-to-default | 8 ++++---- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/bridge-port-to-default b/bridge-port-to-default index 5b3af53..bc6b4b1 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -7,12 +7,12 @@ :global BridgePortTo; :global LogPrintExit; +:global ParseKeyValueStore; -:foreach BridgePort in=[ / interface bridge port find where comment!="" ] do={ +:foreach BridgePort in=[ / interface bridge port find where comment~"." ] do={ :local BridgePortVal [ / interface bridge port get $BridgePort ]; - :foreach Comment in=[ :toarray ($BridgePortVal->"comment") ] do={ - :if ([ :pick $Comment 0 $Len ] = ($BridgePortTo . ":")) do={ - :local BridgeDefault [ :pick $Comment $Len [ :len $Comment ] ]; + :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ + :if ($Config = $BridgePortTo) do={ :if ($BridgeDefault = "dhcp-client") do={ :if ($BridgePortVal->"disabled" = false) do={ $LogPrintExit info ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; diff --git a/global-config b/global-config index a55a9d6..22fbf87 100644 --- a/global-config +++ b/global-config @@ -6,7 +6,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 12; +:global GlobalConfigVersion 13; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index e2c8909..b6a983f 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -7,7 +7,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 12; +:global GlobalConfigVersion 13; # The global-config script is updated by script-updates, # global-config-overlay becomes an overlay for your changes. diff --git a/global-config.changes b/global-config.changes index a22f3b4..6df7cfd 100644 --- a/global-config.changes +++ b/global-config.changes @@ -15,4 +15,5 @@ 10="make health threshold for voltage configurable"; 11="introduced function '\$ScriptInstallUpdate' to install new and update existing scripts"; 12="removed '\$ScriptUpdatesConfigChangesIgnore', comment '\$GlobalConfigVersion' in 'global-config-overlay' to disable change notifications"; + 13="configuration for script 'bridge-port-to-default' changed with new syntax in comment"; }; diff --git a/global-functions b/global-functions index cc8ca20..8acc351 100644 --- a/global-functions +++ b/global-functions @@ -6,7 +6,7 @@ # global functions # expected configuration version -:global ExpectedConfigVersion 12; +:global ExpectedConfigVersion 13; # global variables not to be changed by user :global Identity [ / system identity get name ]; From e588607efdad7246d2d75f91cfb4655262b1542b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 4 Mar 2020 15:45:37 +0100 Subject: [PATCH 0202/2612] add script netwatch-notify --- netwatch-notify | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 netwatch-notify diff --git a/netwatch-notify b/netwatch-notify new file mode 100644 index 0000000..8daf014 --- /dev/null +++ b/netwatch-notify @@ -0,0 +1,34 @@ +#!rsc +# RouterOS script: netwatch-notify +# Copyright (c) 2020 Christian Hesse +# +# monitor netwatch and send notifications + +:global NetwatchNotify; + +:global ParseKeyValueStore; +:global SendNotification; + +:if ([ :typeof $NetwatchNotify ] = "nothing") do={ + :set NetwatchNotify [ :toarray "" ]; +} + +:foreach Host in=[ / tool netwatch find where comment~"^notify," ] do={ + :local HostVal [ / tool netwatch get $Host ]; + :local HostName ([ $ParseKeyValueStore ($HostVal->"comment") ]->"hostname"); + :if ($HostVal->"status" = "up") do={ + :set ($NetwatchNotify->($HostName . "-count")) 0; + :if (($NetwatchNotify->($HostName . "-notified")) = true) do={ + $SendNotification ("Netwatch Notify: " . $HostName . " up") \ + ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . "."); + } + :set ($NetwatchNotify->($HostName . "-notified")) false; + } else={ + :set ($NetwatchNotify->($HostName . "-count")) (($NetwatchNotify->($HostName . "-count")) + 1); + :if (($NetwatchNotify->($HostName . "-count")) >= 5 && ($NetwatchNotify->($HostName . "-notified")) != true) do={ + $SendNotification ("Netwatch Notify: " . $HostName . " down") \ + ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); + :set ($NetwatchNotify->($HostName . "-notified")) true; + } + } +} From 478688d5345cd29d6b5b31db91ca6e49b41eaac6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 4 Mar 2020 21:01:21 +0100 Subject: [PATCH 0203/2612] netwatch-notify: use another level of array --- netwatch-notify | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 8daf014..df13f4f 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -16,19 +16,24 @@ :foreach Host in=[ / tool netwatch find where comment~"^notify," ] do={ :local HostVal [ / tool netwatch get $Host ]; :local HostName ([ $ParseKeyValueStore ($HostVal->"comment") ]->"hostname"); + + :if ([ :typeof ($NetwatchNotify->$HostName) ] = "nothing") do={ + :set ($NetwatchNotify->$HostName) [ :toarray "" ]; + } + :if ($HostVal->"status" = "up") do={ - :set ($NetwatchNotify->($HostName . "-count")) 0; - :if (($NetwatchNotify->($HostName . "-notified")) = true) do={ + :set ($NetwatchNotify->$HostName->"count") 0; + :if ($NetwatchNotify->$HostName->"notified" = true) do={ $SendNotification ("Netwatch Notify: " . $HostName . " up") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . "."); } - :set ($NetwatchNotify->($HostName . "-notified")) false; + :set ($NetwatchNotify->$HostName->"notified") false; } else={ - :set ($NetwatchNotify->($HostName . "-count")) (($NetwatchNotify->($HostName . "-count")) + 1); - :if (($NetwatchNotify->($HostName . "-count")) >= 5 && ($NetwatchNotify->($HostName . "-notified")) != true) do={ + :set ($NetwatchNotify->$HostName->"count") ($NetwatchNotify->$HostName->"count" + 1); + :if ($NetwatchNotify->$HostName->"count" >= 5 && $NetwatchNotify->$HostName->"notified" != true) do={ $SendNotification ("Netwatch Notify: " . $HostName . " down") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); - :set ($NetwatchNotify->($HostName . "-notified")) true; + :set ($NetwatchNotify->$HostName->"notified") true; } } } From 792eba8465291b2ae1f372c41b9c833bf5d7a340 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 08:06:43 +0100 Subject: [PATCH 0204/2612] global-functions: $LogPrintExit: add debugging option --- global-functions | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/global-functions b/global-functions index 8acc351..23283f1 100644 --- a/global-functions +++ b/global-functions @@ -274,17 +274,22 @@ :local Message [ :tostr $2 ]; :local Exit [ :tostr $3 ]; - :if ($Severity ~ "^(error|info)\$") do={ - :if ($Severity = "error" ) do={ :log error $Message; } - :if ($Severity = "info" ) do={ :log info $Message; } + :global PrintDebug; + + :if ($Severity ~ "^(debug|error|info)\$") do={ + :if ($Severity = "debug") do={ :log debug $Message; } + :if ($Severity = "error") do={ :log error $Message; } + :if ($Severity = "info" ) do={ :log info $Message; } } else={ :log warning $Message; } - :if ($Exit = "true") do={ - :error ($Severity . ": " . $Message); - } else={ - :put ($Severity . ": " . $Message); + :if ($Severity != "debug" || $PrintDebug = true) do={ + :if ($Exit = "true") do={ + :error ($Severity . ": " . $Message); + } else={ + :put ($Severity . ": " . $Message); + } } } From f90c59e4fb4ce7d7b71ccfd01755b7b7212fc9d1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 08:15:36 +0100 Subject: [PATCH 0205/2612] netwatch-notify: properly initialize default values --- netwatch-notify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index df13f4f..04e3d30 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -18,7 +18,7 @@ :local HostName ([ $ParseKeyValueStore ($HostVal->"comment") ]->"hostname"); :if ([ :typeof ($NetwatchNotify->$HostName) ] = "nothing") do={ - :set ($NetwatchNotify->$HostName) [ :toarray "" ]; + :set ($NetwatchNotify->$HostName) { "count"=0; "notified"=false }; } :if ($HostVal->"status" = "up") do={ From 1dbd91f76d4f5aac19fa8802f38a3d41ae0bec14 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 08:22:47 +0100 Subject: [PATCH 0206/2612] collect-wireless-mac: use $LogPrintExit --- collect-wireless-mac.capsman | 9 +++++---- collect-wireless-mac.local | 9 +++++---- collect-wireless-mac.template | 9 +++++---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index a280cea..771a332 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -9,6 +9,7 @@ :global Identity; :global GetMacVendor; +:global LogPrintExit; :global ScriptLock; :global SendNotification; @@ -16,7 +17,7 @@ $ScriptLock "collect-wireless-mac.capsman"; :if ([ / caps-man access-list print count-only where comment="--- collected above ---" disabled ] = 0) do={ / caps-man access-list add comment="--- collected above ---" disabled=yes; - :log warn "Added disabled access-list entry with comment '--- collected above ---'."; + $LogPrintExit warn "Added disabled access-list entry with comment '--- collected above ---'." false; } :local PlaceBefore [ / caps-man access-list find where comment="--- collected above ---" disabled ]; @@ -46,7 +47,7 @@ $ScriptLock "collect-wireless-mac.capsman"; :local Vendor [ $GetMacVendor $Mac ]; :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \ "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); - / log info $Message; + $LogPrintExit info $Message false; / caps-man access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; $SendNotification ($Mac . " connected to " . $Ssid) \ ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ @@ -60,7 +61,7 @@ $ScriptLock "collect-wireless-mac.capsman"; "DNS name: " . $DnsName . "\n" . \ "Date: " . $DateTime); } else={ - :local Comment [ / caps-man access-list get $AccessList comment ]; - :log debug ("MAC address " . $Mac . " already known: " . $Comment); + $LogPrintExit debug ("MAC address " . $Mac . " already known: " . \ + [ / caps-man access-list get $AccessList comment ]) false; } } diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index cf09fa5..3895ebb 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -9,6 +9,7 @@ :global Identity; :global GetMacVendor; +:global LogPrintExit; :global ScriptLock; :global SendNotification; @@ -16,7 +17,7 @@ $ScriptLock "collect-wireless-mac.local"; :if ([ / interface wireless access-list print count-only where comment="--- collected above ---" disabled ] = 0) do={ / interface wireless access-list add comment="--- collected above ---" disabled=yes; - :log warn "Added disabled access-list entry with comment '--- collected above ---'."; + $LogPrintExit warn "Added disabled access-list entry with comment '--- collected above ---'." false; } :local PlaceBefore [ / interface wireless access-list find where comment="--- collected above ---" disabled ]; @@ -46,7 +47,7 @@ $ScriptLock "collect-wireless-mac.local"; :local Vendor [ $GetMacVendor $Mac ]; :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \ "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); - / log info $Message; + $LogPrintExit info $Message false; / interface wireless access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; $SendNotification ($Mac . " connected to " . $Ssid) \ ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ @@ -60,7 +61,7 @@ $ScriptLock "collect-wireless-mac.local"; "DNS name: " . $DnsName . "\n" . \ "Date: " . $DateTime); } else={ - :local Comment [ / interface wireless access-list get $AccessList comment ]; - :log debug ("MAC address " . $Mac . " already known: " . $Comment); + $LogPrintExit debug ("MAC address " . $Mac . " already known: " . \ + [ / interface wireless access-list get $AccessList comment ]) false; } } diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 8f8ded8..199b021 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -10,6 +10,7 @@ :global Identity; :global GetMacVendor; +:global LogPrintExit; :global ScriptLock; :global SendNotification; @@ -17,7 +18,7 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; :if ([ / %PATH% access-list print count-only where comment="--- collected above ---" disabled ] = 0) do={ / %PATH% access-list add comment="--- collected above ---" disabled=yes; - :log warn "Added disabled access-list entry with comment '--- collected above ---'."; + $LogPrintExit warn "Added disabled access-list entry with comment '--- collected above ---'." false; } :local PlaceBefore [ / %PATH% access-list find where comment="--- collected above ---" disabled ]; @@ -48,7 +49,7 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; :local Vendor [ $GetMacVendor $Mac ]; :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \ "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); - / log info $Message; + $LogPrintExit info $Message false; / %PATH% access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; $SendNotification ($Mac . " connected to " . $Ssid) \ ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ @@ -62,7 +63,7 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; "DNS name: " . $DnsName . "\n" . \ "Date: " . $DateTime); } else={ - :local Comment [ / %PATH% access-list get $AccessList comment ]; - :log debug ("MAC address " . $Mac . " already known: " . $Comment); + $LogPrintExit debug ("MAC address " . $Mac . " already known: " . \ + [ / %PATH% access-list get $AccessList comment ]) false; } } From 3127800496410a9f316e22c57485e83a6c2fe193 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 08:26:05 +0100 Subject: [PATCH 0207/2612] daily-psk: use $LogPrintExit --- daily-psk.capsman | 7 ++++--- daily-psk.local | 7 ++++--- daily-psk.template | 5 +++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/daily-psk.capsman b/daily-psk.capsman index 36dfc1a..59b867e 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -7,9 +7,10 @@ # # !! Do not edit this file, it is generated from template! -:global Identity; :global DailyPskMatchComment; +:global Identity; +:global LogPrintExit; :global SendNotification; :global UrlEncode; :global WaitForFile; @@ -56,13 +57,13 @@ :local Skip 0; :if ($NewPsk != $OldPsk) do={ - :log info ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")"); + $LogPrintExit info ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; / caps-man access-list set $AccList private-passphrase=$NewPsk; :if ([ / caps-man interface print count-only where configuration=$Configuration ] > 0) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ - :log debug ("Already sent a mail for SSID " . $Ssid . ", skipping."); + $LogPrintExit debug ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; :set Skip 1; } } diff --git a/daily-psk.local b/daily-psk.local index 9950db8..3915618 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -7,9 +7,10 @@ # # !! Do not edit this file, it is generated from template! -:global Identity; :global DailyPskMatchComment; +:global Identity; +:global LogPrintExit; :global SendNotification; :global UrlEncode; :global WaitForFile; @@ -56,13 +57,13 @@ :local Skip 0; :if ($NewPsk != $OldPsk) do={ - :log info ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")"); + $LogPrintExit info ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; / interface wireless access-list set $AccList private-pre-shared-key=$NewPsk; :if ([ / interface wireless print count-only where name=$IntName disabled=no ] = 1) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ - :log debug ("Already sent a mail for SSID " . $Ssid . ", skipping."); + $LogPrintExit debug ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; :set Skip 1; } } diff --git a/daily-psk.template b/daily-psk.template index 88353a4..cab65f2 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -11,6 +11,7 @@ :global DailyPskMatchComment; :global Identity; +:global LogPrintExit; :global SendNotification; :global UrlEncode; :global WaitForFile; @@ -60,7 +61,7 @@ :local Skip 0; :if ($NewPsk != $OldPsk) do={ - :log info ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")"); + $LogPrintExit info ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; / interface wireless access-list set $AccList private-pre-shared-key=$NewPsk; / caps-man access-list set $AccList private-passphrase=$NewPsk; @@ -68,7 +69,7 @@ :if ([ / caps-man interface print count-only where configuration=$Configuration ] > 0) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ - :log debug ("Already sent a mail for SSID " . $Ssid . ", skipping."); + $LogPrintExit debug ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; :set Skip 1; } } From be5b6e0687be98cbfefc7d381ab54e4577a670b0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 08:34:33 +0100 Subject: [PATCH 0208/2612] dhcp-lease-comment: use $LogPrintExit --- dhcp-lease-comment.capsman | 4 +++- dhcp-lease-comment.local | 4 +++- dhcp-lease-comment.template | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index e5da51f..5a5d98b 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -6,6 +6,8 @@ # # !! Do not edit this file, it is generated from template! +:global LogPrintExit; + :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ :local LeaseVal [ / ip dhcp-server lease get $Lease ]; :local NewComment; @@ -14,7 +16,7 @@ :set NewComment [ / caps-man access-list get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - :log info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment); + $LogPrintExit info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; / ip dhcp-server lease set comment=$NewComment $Lease; } } diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index 367ca0b..eb74dab 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -6,6 +6,8 @@ # # !! Do not edit this file, it is generated from template! +:global LogPrintExit; + :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ :local LeaseVal [ / ip dhcp-server lease get $Lease ]; :local NewComment; @@ -14,7 +16,7 @@ :set NewComment [ / interface wireless access-list get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - :log info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment); + $LogPrintExit info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; / ip dhcp-server lease set comment=$NewComment $Lease; } } diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index 3734ba4..bcbb39a 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -7,6 +7,8 @@ # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! +:global LogPrintExit; + :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ :local LeaseVal [ / ip dhcp-server lease get $Lease ]; :local NewComment; @@ -15,7 +17,7 @@ :set NewComment [ / %PATH% access-list get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - :log info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment); + $LogPrintExit info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; / ip dhcp-server lease set comment=$NewComment $Lease; } } From 554308a399fd2dea884396a7382f9ec46031a4c3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 08:37:12 +0100 Subject: [PATCH 0209/2612] dhcp-to-dns: use $LogPrintExit --- dhcp-to-dns | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index 0d92278..94c1dfb 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -4,12 +4,13 @@ # # check DHCP leases and add/remove/update DNS entries -:global CharacterReplace; - :global Domain; :global HostNameInZone; :global Identity; +:global CharacterReplace; +:global LogPrintExit; + :local Zone; :if ($HostNameInZone = true) do={ :set Zone ("dhcp." . $Identity . "." . $Domain); @@ -23,10 +24,10 @@ :local DnsRecordVal [ / ip dns static get $DnsRecord ]; :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; :if ([ / ip dhcp-server lease print count-only where mac-address=$MacAddress address=($DnsRecordVal->"address") dynamic=yes status=bound ] > 0) do={ - :log debug ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"host-name" . ") still exists. Not deleting DNS entry."); + $LogPrintExit debug ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"host-name" . ") still exists. Not deleting DNS entry.") false; } else={ :local Found false; - :log info ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry."); + $LogPrintExit info ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry.") false; / ip dns static remove $DnsRecord; } } @@ -54,13 +55,13 @@ } :if ($DnsIp = $LeaseVal->"address") do={ - :log debug ("DNS entry for " . $Fqdn . " does not need updating."); + $LogPrintExit debug ("DNS entry for " . $Fqdn . " does not need updating.") false; } else={ - :log info ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . "."); + $LogPrintExit info ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . ".") false; / ip dns static set name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; } } else={ - :log info ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . "."); + $LogPrintExit info ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false; / ip dns static add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment; } } From 3ec34fa752d6cab8e9e75f6ce22124247464680b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 08:43:56 +0100 Subject: [PATCH 0210/2612] dhcp-to-dns: fix value in message --- dhcp-to-dns | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index 94c1dfb..687db97 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -24,7 +24,7 @@ :local DnsRecordVal [ / ip dns static get $DnsRecord ]; :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; :if ([ / ip dhcp-server lease print count-only where mac-address=$MacAddress address=($DnsRecordVal->"address") dynamic=yes status=bound ] > 0) do={ - $LogPrintExit debug ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"host-name" . ") still exists. Not deleting DNS entry.") false; + $LogPrintExit debug ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; } else={ :local Found false; $LogPrintExit info ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry.") false; From 34255c905085134056c0c9072c174924ae4f7fe8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 08:58:29 +0100 Subject: [PATCH 0211/2612] script-updates: use $LogPrintExit for debug --- script-updates | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/script-updates b/script-updates index b84fcbf..35c8bff 100644 --- a/script-updates +++ b/script-updates @@ -48,7 +48,7 @@ } :if ($Ignore = 0) do={ - :log debug ("Fetching script from url: " . $ScriptVal->"name"); + $LogPrintExit debug ("Fetching script from url: " . $ScriptVal->"name") false; :do { :local Result [ / tool fetch check-certificate=yes-without-crl \ ($ScriptUpdatesBaseUrl . $ScriptVal->"name" . $ScriptUpdatesUrlSuffix) \ @@ -78,13 +78,13 @@ / system script run global-functions; } } else={ - :log debug ("Script " . $ScriptVal->"name" . " did not change."); + $LogPrintExit debug ("Script " . $ScriptVal->"name" . " did not change.") false; } } else={ $LogPrintExit warning ("Looks like new script " . $ScriptVal->"name" . " is not valid. Ignoring!") false; } } else={ - :log debug ("No update for script " . $ScriptVal->"name" . "."); + $LogPrintExit debug ("No update for script " . $ScriptVal->"name" . ".") false; } } @@ -101,7 +101,7 @@ "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \ ") to " . $ExpectedConfigVersion . " and re-run " . $ConfigScript . "."); - :log debug ("Fetching changelog."); + $LogPrintExit debug ("Fetching changelog.") false; :do { :local Result [ / tool fetch check-certificate=yes-without-crl \ ($ScriptUpdatesBaseUrl . "global-config.changes" . $ScriptUpdatesUrlSuffix) \ From 08bb73b6fce071ed9da6803f56ba54ee1cdd51c4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 09:01:11 +0100 Subject: [PATCH 0212/2612] check-certificates: use $LogPrintExit for debug --- check-certificates | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/check-certificates b/check-certificates index 38f1c79..d5dce80 100644 --- a/check-certificates +++ b/check-certificates @@ -48,7 +48,7 @@ $CertificateNameByCN [ / certificate get $CertInChain common-name ]; } } on-error={ - :log debug ("Could not download certificate file " . $CertFileName); + $LogPrintExit debug ("Could not download certificate file " . $CertFileName) false; } } @@ -56,7 +56,7 @@ :local CertNewVal [ / certificate get $CertNew ]; :if ($Cert != $CertNew) do={ - :log debug ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced."); + $LogPrintExit debug ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; / ip service set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; @@ -64,13 +64,13 @@ / ip ipsec identity set certificate=($CertNewVal->"name") [ / ip ipsec identity find where certificate=($CertVal->"name") ]; / ip ipsec identity set remote-certificate=($CertNewVal->"name") [ / ip ipsec identity find where remote-certificate=($CertVal->"name") ]; } on-error={ - :log debug ("Setting IPSEC certificates failed. Package 'security' not installed?"); + $LogPrintExit debug ("Setting IPSEC certificates failed. Package 'security' not installed?") false; } :do { / ip hotspot profile set ssl-certificate=($CertNewVal->"name") [ / ip hotspot profile find where ssl-certificate=($CertVal->"name") ]; } on-error={ - :log debug ("Setting hotspot certificates failed. Package 'hotspot' not installed?"); + $LogPrintExit debug ("Setting hotspot certificates failed. Package 'hotspot' not installed?") false; } / certificate remove $Cert; @@ -87,7 +87,7 @@ "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]) "" "true"; $LogPrintExit info ("The certificate " . ($CertVal->"name") . " has been renewed.") false; } on-error={ - :log debug ("Could not renew certificate " . ($CertVal->"name") . "."); + $LogPrintExit debug ("Could not renew certificate " . ($CertVal->"name") . ".") false; } } From 970641a9740fbe8e42acff44fcfdefaadaf35f24 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 09:08:57 +0100 Subject: [PATCH 0213/2612] check-routeros-update: use $LogPrintExit --- check-routeros-update | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index 4ed52f3..6672f13 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -48,10 +48,10 @@ ($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \ "&latest=" . $Update->"latest-version") output=user as-value ]; } on-error={ - :log warning ("Failed receiving safe version for " . $Update->"channel" . "."); + $LogPrintExit warning ("Failed receiving safe version for " . $Update->"channel" . ".") false; } :if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={ - :log info ("Version " . $Update->"latest-version" . " is considered safe, updating..."); + $LogPrintExit info ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; $SendNotification ("RouterOS update") \ ("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ ", updating on " . $Identity . "...") "" "true"; @@ -69,9 +69,8 @@ } :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ - :log info ("Already sent the RouterOS update notification for version " . \ - $Update->"latest-version" . "."); - :error "Already sent notification."; + $LogPrintExit info ("Already sent the RouterOS update notification for version " . \ + $Update->"latest-version" . ".") true; } $SendNotification ("RouterOS update") \ From e104b54bf0b48fae9b2d5002f86bf6de39aa0770 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 09:17:19 +0100 Subject: [PATCH 0214/2612] hotspot-to-wpa: use $LogPrintExit and add more logging --- hotspot-to-wpa | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hotspot-to-wpa b/hotspot-to-wpa index 5f21878..aa1430a 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -4,6 +4,8 @@ # # add private WPA passphrase after hotspot login +:global LogPrintExit; + :local MacAddress $"mac-address"; :local UserName $username; :local Date [ / system clock get date ]; @@ -11,10 +13,13 @@ :if ([ / caps-man access-list print count-only where comment="--- hotspot-to-wpa above ---" disabled ] = 0) do={ / caps-man access-list add comment="--- hotspot-to-wpa above ---" disabled; - log warn "Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'."; + $LogPrintExit warning "Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'." false; } :local PlaceBefore [ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ]; +$LogPrintExit info ("Adding/updating accesslist entry for mac address " . $MacAddress . \ + " (user " . $UserName . ").") false; + / caps-man access-list remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; :local Limits [ / caps-man access-list get $PlaceBefore ]; From bf41a8d48a1cb0e13e3d0b387c7d15b6eea68ddf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 09:18:23 +0100 Subject: [PATCH 0215/2612] always use severity 'warning', not just 'warn' --- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- global-functions | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 771a332..95e46a2 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -17,7 +17,7 @@ $ScriptLock "collect-wireless-mac.capsman"; :if ([ / caps-man access-list print count-only where comment="--- collected above ---" disabled ] = 0) do={ / caps-man access-list add comment="--- collected above ---" disabled=yes; - $LogPrintExit warn "Added disabled access-list entry with comment '--- collected above ---'." false; + $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; } :local PlaceBefore [ / caps-man access-list find where comment="--- collected above ---" disabled ]; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 3895ebb..8b5d5ac 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -17,7 +17,7 @@ $ScriptLock "collect-wireless-mac.local"; :if ([ / interface wireless access-list print count-only where comment="--- collected above ---" disabled ] = 0) do={ / interface wireless access-list add comment="--- collected above ---" disabled=yes; - $LogPrintExit warn "Added disabled access-list entry with comment '--- collected above ---'." false; + $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; } :local PlaceBefore [ / interface wireless access-list find where comment="--- collected above ---" disabled ]; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 199b021..510afcc 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -18,7 +18,7 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; :if ([ / %PATH% access-list print count-only where comment="--- collected above ---" disabled ] = 0) do={ / %PATH% access-list add comment="--- collected above ---" disabled=yes; - $LogPrintExit warn "Added disabled access-list entry with comment '--- collected above ---'." false; + $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; } :local PlaceBefore [ / %PATH% access-list find where comment="--- collected above ---" disabled ]; diff --git a/global-functions b/global-functions index 23283f1..b9f3cc4 100644 --- a/global-functions +++ b/global-functions @@ -49,7 +49,7 @@ :if ([ / system resource get free-hdd-space ] < 8388608 && \ [ / certificate settings get crl-download ] = true && \ [ / certificate settings get crl-store ] = "system") do={ - :log warn "This system has low free flash space but is configured to download certificate CRLs to system!"; + :log warning "This system has low free flash space but is configured to download certificate CRLs to system!"; } :if ([ / certificate print count-only where common-name=$CommonName ] = 0) do={ @@ -299,7 +299,7 @@ :local MailHost $MailServer; :if ([ / tool netwatch print count-only where comment=$MailServer ] = 0) do={ - :log warn ("Adding netwatch entry for mail server."); + :log warning ("Adding netwatch entry for mail server."); :local MailHost $MailServer; :if ([ :typeof [ :toip $MailHost ] ] != "ip" ) do={ :set MailHost [ :resolve $MailServer ]; From 27e263500717c6e1428a7a113032005aba203060 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 09:24:10 +0100 Subject: [PATCH 0216/2612] bridge-port-to-default: use $LogPrintExit for debug --- bridge-port-to-default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge-port-to-default b/bridge-port-to-default index bc6b4b1..db7cbdc 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -29,7 +29,7 @@ $LogPrintExit info ("Changing interface " . $BridgePortVal->"interface" . " to " . $BridgePortTo . " bridge " . $BridgeDefault) false; / interface bridge port set bridge=$BridgeDefault $BridgePort; } else={ - :log debug ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . " bridge " . $BridgeDefault); + $LogPrintExit debug ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . " bridge " . $BridgeDefault) false; } } } From 71ae8cb75f7ffc4dd3a9672582157b60da12fd34 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 09:42:28 +0100 Subject: [PATCH 0217/2612] rotate-ntp: use $LogPrintExit --- rotate-ntp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rotate-ntp b/rotate-ntp index 465a46c..534f400 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -6,12 +6,14 @@ :global NtpPool; +:global LogPrintExit; + :local Ntp1 [ :resolve ("0." . $NtpPool) ]; :local Ntp2 [ :resolve ("1." . $NtpPool) ]; :if ([ / system ntp client get enabled ] != true) do={ - :log warning "NTP client is not enabled!"; + $LogPrintExit warning "NTP client is not enabled!" true; } -:log info ("Updating NTP servers to " . $Ntp1 . " and " . $Ntp2); +$LogPrintExit info ("Updating NTP servers to " . $Ntp1 . " and " . $Ntp2) false; / system ntp client set primary-ntp=$Ntp1 secondary-ntp=$Ntp2; From 34db2e34db40867c97c87c6604cf8049a3b7e53b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 10:39:34 +0100 Subject: [PATCH 0218/2612] global-functions: $SendTelegram: allow to override chatid This allows to send Telegram messages to different contact or group. Use something like this: /system scheduler add name=netwatch-notify interval=1m start-time=startup \ on-event=":global TelegramChatIdOverride \"-1234\"; / system script run netwatch-notify; :set TelegramChatIdOverride;" --- global-functions | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index b9f3cc4..1fb832a 100644 --- a/global-functions +++ b/global-functions @@ -428,16 +428,22 @@ :global Identity; :global TelegramTokenId; :global TelegramChatId; + :global TelegramChatIdOverride; :global UrlEncode; :global CertificateAvailable; - :if ([ :len $TelegramTokenId ] > 0 && [ :len $TelegramChatId ] > 0) do={ + :local ChatId $TelegramChatId; + :if ([ :len $TelegramChatIdOverride ] > 0) do={ + :set ChatId $TelegramChatIdOverride; + } + + :if ([ :len $TelegramTokenId ] > 0 && [ :len $ChatId ] > 0) do={ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2"; :do { / tool fetch check-certificate=yes-without-crl output=none http-method=post \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ - http-data=("chat_id=" . $TelegramChatId . "&disable_notification=" . $Silent . \ + http-data=("chat_id=" . $ChatId . "&disable_notification=" . $Silent . \ "&text=" . [ $UrlEncode ("[" . $Identity . "] " . $Subject . "\n\n" . $Message) ]); } on-error={ :log warning "Failed sending telegram notification!"; From 227151e189f465ea426dd11bb912ff818046ff8f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 10:59:13 +0100 Subject: [PATCH 0219/2612] global-functions: $SendTelegram: invert condition --- global-functions | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/global-functions b/global-functions index 1fb832a..c2727fc 100644 --- a/global-functions +++ b/global-functions @@ -438,16 +438,18 @@ :set ChatId $TelegramChatIdOverride; } - :if ([ :len $TelegramTokenId ] > 0 && [ :len $ChatId ] > 0) do={ - $CertificateAvailable "Go Daddy Secure Certificate Authority - G2"; - :do { - / tool fetch check-certificate=yes-without-crl output=none http-method=post \ - ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ - http-data=("chat_id=" . $ChatId . "&disable_notification=" . $Silent . \ - "&text=" . [ $UrlEncode ("[" . $Identity . "] " . $Subject . "\n\n" . $Message) ]); - } on-error={ - :log warning "Failed sending telegram notification!"; - } + :if ([ :len $TelegramTokenId ] = 0 || [ :len $ChatId ] = 0) do={ + :return; + } + + $CertificateAvailable "Go Daddy Secure Certificate Authority - G2"; + :do { + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ + http-data=("chat_id=" . $ChatId . "&disable_notification=" . $Silent . \ + "&text=" . [ $UrlEncode ("[" . $Identity . "] " . $Subject . "\n\n" . $Message) ]); + } on-error={ + :log warning "Failed sending telegram notification!"; } } From 3d07ebde0534f3a11d3f149875d1cb0d2f1483e3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 10:57:47 +0100 Subject: [PATCH 0220/2612] global-functions: $SendEMail: invert condition --- global-functions | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/global-functions b/global-functions index c2727fc..ffd34b8 100644 --- a/global-functions +++ b/global-functions @@ -389,18 +389,20 @@ :global EmailGeneralTo; :global EmailGeneralCc; - :if ([ :len $EmailGeneralTo ] > 0) do={ - :do { - :local Signature [ / system note get note ]; - :if ([ :len $Signature ] > 0) do={ - :set Signature ("\n-- \n" . $Signature); - } - / tool e-mail send to=$EmailGeneralTo cc=$EmailGeneralCc \ - subject=("[" . $Identity . "] " . $Subject) \ - body=($Message . $Signature) file=$Attach; - } on-error={ - :log warning "Failed sending notification mail!"; + :if ([ :len $EmailGeneralTo ] = 0) do={ + :return; + } + + :do { + :local Signature [ / system note get note ]; + :if ([ :len $Signature ] > 0) do={ + :set Signature ("\n-- \n" . $Signature); } + / tool e-mail send to=$EmailGeneralTo cc=$EmailGeneralCc \ + subject=("[" . $Identity . "] " . $Subject) \ + body=($Message . $Signature) file=$Attach; + } on-error={ + :log warning "Failed sending notification mail!"; } } From 9aed03693c918aaff5462e9ed2300c05a787d2c4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 12:42:21 +0100 Subject: [PATCH 0221/2612] netwatch-notify: fix handling of array Looks like handling of more-dimensional arrays is a bit tricky in RouterOS... Without this *all* values with the same key name are updated, independent of intermediate name. --- netwatch-notify | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 04e3d30..dfa62e8 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -17,23 +17,25 @@ :local HostVal [ / tool netwatch get $Host ]; :local HostName ([ $ParseKeyValueStore ($HostVal->"comment") ]->"hostname"); - :if ([ :typeof ($NetwatchNotify->$HostName) ] = "nothing") do={ - :set ($NetwatchNotify->$HostName) { "count"=0; "notified"=false }; + :local Metric { "count"=0; "notified"=false }; + :if ([ :typeof ($NetwatchNotify->$HostName) ] = "array") do={ + :set $Metric ($NetwatchNotify->$HostName); } :if ($HostVal->"status" = "up") do={ - :set ($NetwatchNotify->$HostName->"count") 0; - :if ($NetwatchNotify->$HostName->"notified" = true) do={ + :set ($Metric->"count") 0; + :if ($Metric->"notified" = true) do={ $SendNotification ("Netwatch Notify: " . $HostName . " up") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . "."); } - :set ($NetwatchNotify->$HostName->"notified") false; + :set ($Metric->"notified") false; } else={ - :set ($NetwatchNotify->$HostName->"count") ($NetwatchNotify->$HostName->"count" + 1); - :if ($NetwatchNotify->$HostName->"count" >= 5 && $NetwatchNotify->$HostName->"notified" != true) do={ + :set ($Metric->"count") ($Metric->"count" + 1); + :if ($Metric->"count" >= 5 && $Metric->"notified" != true) do={ $SendNotification ("Netwatch Notify: " . $HostName . " down") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); - :set ($NetwatchNotify->$HostName->"notified") true; + :set ($Metric->"notified") true; } } + :set ($NetwatchNotify->$HostName) { "count"=($Metric->"count"); "notified"=($Metric->"notified") }; } From f3e2fb654b171446ce17e7ab01c7929d85f13839 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 12:47:42 +0100 Subject: [PATCH 0222/2612] netwatch-notify: add logging --- netwatch-notify | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netwatch-notify b/netwatch-notify index dfa62e8..d2d256b 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -7,6 +7,7 @@ :global NetwatchNotify; :global ParseKeyValueStore; +:global LogPrintExit; :global SendNotification; :if ([ :typeof $NetwatchNotify ] = "nothing") do={ @@ -23,6 +24,7 @@ } :if ($HostVal->"status" = "up") do={ + $LogPrintExit debug ("Host " . $HostName . " (" . $HostVal->"host" . ") is up.") false; :set ($Metric->"count") 0; :if ($Metric->"notified" = true) do={ $SendNotification ("Netwatch Notify: " . $HostName . " up") \ @@ -31,6 +33,8 @@ :set ($Metric->"notified") false; } else={ :set ($Metric->"count") ($Metric->"count" + 1); + $LogPrintExit info ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ + $Metric->"count" . " checks.") false; :if ($Metric->"count" >= 5 && $Metric->"notified" != true) do={ $SendNotification ("Netwatch Notify: " . $HostName . " down") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); From 8020955b3ba58bf3af7f1277bfcc2d0330213e19 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Mar 2020 20:09:36 +0100 Subject: [PATCH 0223/2612] script-updates: also consider scripts with empty source for update --- script-updates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script-updates b/script-updates index 35c8bff..6ecdd37 100644 --- a/script-updates +++ b/script-updates @@ -17,7 +17,7 @@ :global LogPrintExit; :global SendNotification; -:foreach Script in=[ / system script find where source~"^#!rsc" ] do={ +:foreach Script in=[ / system script find where source~"^#!rsc" or source="" ] do={ :local Ignore 0; :local ScriptVal [ / system script get $Script ]; :local ScriptFile [ / file find where name=("script-updates/" . $ScriptVal->"name") ]; From 8992b1816684d14e12f53f4a0629026589146e37 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Mar 2020 09:29:36 +0100 Subject: [PATCH 0224/2612] global-functions: $DeviceInfo: more indention --- global-functions | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/global-functions b/global-functions index ffd34b8..be7a7ba 100644 --- a/global-functions +++ b/global-functions @@ -175,19 +175,19 @@ } :set Info ($Info . "\n" . \ "RouterOS:\n" . \ - " Channel: " . $Update->"channel" . "\n" . \ - " Installed: " . $Update->"installed-version"); + " Channel: " . $Update->"channel" . "\n" . \ + " Installed: " . $Update->"installed-version"); :if ([ :typeof ($Update->"latest-version") ] != "nothing" && \ $Update->"installed-version" != $Update->"latest-version") do={ :set Info ($Info . "\n" . \ - " Available: " . $Update->"latest-version"); + " Available: " . $Update->"latest-version"); } :set Info ($Info . "\n" . \ "RouterOS-Scripts Configuration Version:\n" . \ - " Current: " . $GlobalConfigVersion); + " Current: " . $GlobalConfigVersion); :if ($GlobalConfigVersion != $ExpectedConfigVersion) do={ :set Info ($Info . "\n" . \ - " Expected: " . $ExpectedConfigVersion); + " Expected: " . $ExpectedConfigVersion); } :return $Info; From 1f8c22b23de1704c6f83f24174daf67167ad53e6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Mar 2020 13:46:06 +0100 Subject: [PATCH 0225/2612] hotspot-to-wpa: unbreak options --- hotspot-to-wpa | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot-to-wpa b/hotspot-to-wpa index aa1430a..f45bd6b 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -12,7 +12,7 @@ :local PassWord [ / ip hotspot user get [ find where name=$UserName ] password ]; :if ([ / caps-man access-list print count-only where comment="--- hotspot-to-wpa above ---" disabled ] = 0) do={ - / caps-man access-list add comment="--- hotspot-to-wpa above ---" disabled; + / caps-man access-list add comment="--- hotspot-to-wpa above ---" disabled=yes; $LogPrintExit warning "Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'." false; } :local PlaceBefore [ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ]; From 63ed093340df70c79ecec21396d136a03d869eca Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Mar 2020 16:23:10 +0100 Subject: [PATCH 0226/2612] check-health: add encoded degree sign --- check-health | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-health b/check-health index 07ec366..b693410 100644 --- a/check-health +++ b/check-health @@ -58,13 +58,13 @@ $CheckHealthCurrent->$Temperature > $CheckHealthTemperature->$Temperature) do={ $SendNotification ("Health warning: " . $Temperature) \ ("The " . $Temperature . " on " . $Identity . " is above threshold: " . \ - $CheckHealthCurrent->$Temperature . "C"); + $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); } :if ($CheckHealthLast->$Temperature > $CheckHealthTemperature->$Temperature && \ $CheckHealthCurrent->$Temperature <= $CheckHealthTemperature->$Temperature) do={ $SendNotification ("Health recovery: " . $Temperature) \ ("The " . $Temperature . " on " . $Identity . " dropped below threshold: " . \ - $CheckHealthCurrent->$Temperature . "C"); + $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); } } } From 98585afe1cc068203e5d713eb9965c930ac762de Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 12 Mar 2020 08:40:29 +0100 Subject: [PATCH 0227/2612] add script 'global-wait' Run this in schedulers that fire on startup without interval. Schedulers should look something like this: / system scheduler { add name=global-scripts on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }" start-time=startup; add name=bridge-port-to-default on-event="/ system script { run global-wait; run bridge-port-to-default; }" start-time=startup; } --- global-functions | 4 ++++ global-wait | 11 +++++++++++ script-updates | 4 ++-- 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 global-wait diff --git a/global-functions b/global-functions index be7a7ba..eda9ab6 100644 --- a/global-functions +++ b/global-functions @@ -9,6 +9,7 @@ :global ExpectedConfigVersion 13; # global variables not to be changed by user +:global GlobalFunctionsReady false; :global Identity [ / system identity get name ]; :global SentConfigChangesNotification "-"; :global SentLteFirmwareUpgradeNotification "-"; @@ -524,3 +525,6 @@ :delay 1s; } } + +# signal we are ready +:set GlobalFunctionsReady true; diff --git a/global-wait b/global-wait new file mode 100644 index 0000000..29d634d --- /dev/null +++ b/global-wait @@ -0,0 +1,11 @@ +#!rsc +# RouterOS script: global-wait +# Copyright (c) 2020 Christian Hesse +# +# wait for global-functions to finish + +:global GlobalFunctionsReady; + +:while ($GlobalFunctionsReady != true) do={ + :delay 500ms; +} diff --git a/script-updates b/script-updates index 6ecdd37..38165c9 100644 --- a/script-updates +++ b/script-updates @@ -36,9 +36,9 @@ :if ($SchedulerVal->"name" != "global-scripts" && \ $SchedulerVal->"start-time" = "startup" && \ $SchedulerVal->"interval" = 0s && \ - [ :pick ($SchedulerVal->"on-event") 0 7 ] != ":delay ") do={ + !(($SchedulerVal->"on-event") ~ "\\brun global-wait\\b")) do={ $LogPrintExit warning ("Scheduler " . $SchedulerVal->"name" . " starts on startup, " . \ - "without interval. Add delay to make sure the configuration is available!") false; + "without waiting for global-functions. Run 'global-wait' to avoid race conditions!") false; } } From f50e416e49a9f390408268a5c173b4e99ec81c0f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Mar 2020 08:44:24 +0100 Subject: [PATCH 0228/2612] global-functions: introduce $MkDir This is a dirty hack... RouterOS does not support creating directories, so we mis-use http server and fetch tool. --- global-functions | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/global-functions b/global-functions index eda9ab6..3187036 100644 --- a/global-functions +++ b/global-functions @@ -27,6 +27,7 @@ :global GetRandom; :global LogPrintExit; :global MailServerIsUp; +:global MkDir; :global ParseKeyValueStore; :global RandomDelay; :global ScriptFromTerminal; @@ -315,6 +316,23 @@ :return false; } +# create directory +:set MkDir do={ + :local Dir [ :tostr $1 ]; + + :global WaitForFile; + + :if ([ / file print count-only where name=$Dir type="directory" ] = 0) do={ + :local WwwVal [ / ip service get www ]; + / ip service set www address=127.0.0.1/32 disabled=no port=80; + / tool fetch http://127.0.0.1/ dst-path=($Dir . "/tmp"); + $WaitForFile ($Dir . "/tmp"); + / file remove ($Dir . "/tmp"); + / ip service set www address=($WwwVal->"address") \ + disabled=($WwwVal->"disabled") port=($WwwVal->"port"); + } +} + # parse key value store :set ParseKeyValueStore do={ :global CharacterReplace; From 739884ecc71ddce1c10f546ed1cd4348298513fb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Mar 2020 08:49:09 +0100 Subject: [PATCH 0229/2612] certificate-renew-issued: support auto-export with given passphrases --- certificate-renew-issued | 10 ++++++++++ global-config | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/certificate-renew-issued b/certificate-renew-issued index 3dc50d3..32da774 100644 --- a/certificate-renew-issued +++ b/certificate-renew-issued @@ -4,6 +4,10 @@ # # renew locally issued certificates +:global CertIssuedExportPass; + +:global MkDir; + :foreach Cert in=[ / certificate find where issued expires-after<3w ] do={ :local CertVal [ / certificate get $Cert ]; / certificate issued-revoke $Cert; @@ -11,4 +15,10 @@ / 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={ + $MkDir "cert-issued"; + / certificate export-certificate ($CertVal->"name") type=pkcs12 \ + file-name=("cert-issued/" . $CertVal->"common-name") \ + export-passphrase=($CertIssuedExportPass->($CertVal->"common-name")); + } } diff --git a/global-config b/global-config index 22fbf87..46c07b8 100644 --- a/global-config +++ b/global-config @@ -123,3 +123,7 @@ "v3ry-s3cr3t"; "4n0th3r-s3cr3t"; } +:global CertIssuedExportPass { + "cert1-cn"="v3ry-s3cr3t"; + "cert2-cn"="4n0th3r-s3cr3t"; +} From 1e7e19cc870f6e7caa3976ac40f6d0fd8f58332e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Mar 2020 08:56:13 +0100 Subject: [PATCH 0230/2612] certificate-renew-issued: log action --- certificate-renew-issued | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/certificate-renew-issued b/certificate-renew-issued index 32da774..d5ff2c8 100644 --- a/certificate-renew-issued +++ b/certificate-renew-issued @@ -6,6 +6,7 @@ :global CertIssuedExportPass; +:global LogPrintExit; :global MkDir; :foreach Cert in=[ / certificate find where issued expires-after<3w ] do={ @@ -20,5 +21,9 @@ / certificate export-certificate ($CertVal->"name") type=pkcs12 \ file-name=("cert-issued/" . $CertVal->"common-name") \ export-passphrase=($CertIssuedExportPass->($CertVal->"common-name")); + $LogPrintExit info ("Issued a new certificate for \"" . $CertVal->"common-name" . \ + "\", exported to \"cert-issued/" . $CertVal->"common-name" . ".p12\".") false; + } else={ + $LogPrintExit info ("Issued a new certificate for \"" . $CertVal->"common-name" . "\".") false; } } From 8a88743e9f6dba4be2abcbd45bf956bb105f33e7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Mar 2020 12:07:11 +0100 Subject: [PATCH 0231/2612] add certificate 'DigiCert ECC Secure Server CA' This is used by DNS over HTTPS services: https://cloudflare-dns.com/dns-query https://dns9.quad9.net/dns-query (secured) https://dns10.quad9.net/dns-query (unsecured) https://github.com/curl/curl/wiki/DNS-over-HTTPS --- certs/DigiCert ECC Secure Server CA.pem | 44 +++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 certs/DigiCert ECC Secure Server CA.pem diff --git a/certs/DigiCert ECC Secure Server CA.pem b/certs/DigiCert ECC Secure Server CA.pem new file mode 100644 index 0000000..184ca1d --- /dev/null +++ b/certs/DigiCert ECC Secure Server CA.pem @@ -0,0 +1,44 @@ +-----BEGIN CERTIFICATE----- +MIIDrDCCApSgAwIBAgIQCssoukZe5TkIdnRw883GEjANBgkqhkiG9w0BAQwFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaMEwxCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJjAkBgNVBAMTHURpZ2lDZXJ0IEVDQyBT +ZWN1cmUgU2VydmVyIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4ghC6nfYJN6g +LGSkE85AnCNyqQIKDjc/ITa4jVMU9tWRlUvzlgKNcR7E2Munn17voOZ/WpIRllNv +68DLP679Wz9HJOeaBy6Wvqgvu1cYr3GkvXg6HuhbPGtkESvMNCuMo4IBITCCAR0w +EgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwNAYIKwYBBQUHAQEE +KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYDVR0f +BDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xv +YmFsUm9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYc +aHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUo53mH/naOU/A +buiRy5Wl2jHiCp8wHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJ +KoZIhvcNAQEMBQADggEBAMeKoENL7HTJxavVHzA1Nm6YVntIrAVjrnuaVyRXzG/6 +3qttnMe2uuzO58pzZNvfBDcKAEmzP58mrZGMIOgfiA4q+2Y3yDDo0sIkp0VILeoB +UEoxlBPfjV/aKrtJPGHzecicZpIalir0ezZYoyxBEHQa0+1IttK7igZFcTMQMHp6 +mCHdJLnsnLWSB62DxsRq+HfmNb4TDydkskO/g+l3VtsIh5RHFPVfKK+jaEyDj2D3 +loB5hWp2Jp2VDCADjT7ueihlZGak2YPqmXTNbk19HOuNssWvFhtOyPNV6og4ETQd +Ea8/B6hPatJ0ES8q/HO3X8IVQwVs1n3aAr0im0/T+Xc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- From f16056ef8ba753a7cf6411bc6455b3f176c4860a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Mar 2020 12:51:28 +0100 Subject: [PATCH 0232/2612] convert initial commands from script to page This is not intended for installation... --- INITIAL-COMMANDS.md | 31 +++++++++++++++++++++++++++++++ README.md | 2 +- initial-commands | 23 ----------------------- 3 files changed, 32 insertions(+), 24 deletions(-) create mode 100644 INITIAL-COMMANDS.md delete mode 100644 initial-commands diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md new file mode 100644 index 0000000..d7625c0 --- /dev/null +++ b/INITIAL-COMMANDS.md @@ -0,0 +1,31 @@ +Initial commands +================ + +[◀ Go back to main README](README.md) + +These command are inteneded for initial setup. If you are not aware of the +procedure please follow [the long way in detail](README.md#the-long-way-in-detail). + + { + / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt.pem"; + :delay 1s; + / certificate { + import file-name=letsencrypt.pem passphrase=""; + set name="ISRG-Root-X1" [ find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ]; + set name="Let-s-Encrypt-Authority-X3" [ find where fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" ]; + set name="DST-Root-CA-X3" [ find where fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ]; + } + :if ([ / certificate print count-only where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] != 3) do={ + :error "Something is wrong with your certificates!"; + } + / file remove "letsencrypt.pem"; + :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions"; "script-updates" } do={ + / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); + } + / system script { run global-config; run global-config-overlay; run global-functions; } + / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }" + } + +--- +[◀ Go back to main README](README.md) +[▲ Go back to top](#top) diff --git a/README.md b/README.md index d35d4c4..15b33ab 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Initial setup ### Get me ready! If you know how things work just copy and paste the -[initial commands](initial-commands). Remember to edit and rerun +[initial commands](INITIAL-COMMANDS.md). Remember to edit and rerun `global-config-overlay`! First time users should take the long way below. diff --git a/initial-commands b/initial-commands deleted file mode 100644 index 79036e6..0000000 --- a/initial-commands +++ /dev/null @@ -1,23 +0,0 @@ -#!rsc -# RouterOS script: initial-commands -# Copyright (c) 2018-2020 Christian Hesse - -{ - / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt.pem"; - :delay 1s; - / certificate { - import file-name=letsencrypt.pem passphrase=""; - set name="ISRG-Root-X1" [ find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ]; - set name="Let-s-Encrypt-Authority-X3" [ find where fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" ]; - set name="DST-Root-CA-X3" [ find where fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ]; - } - :if ([ / certificate print count-only where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] != 3) do={ - :error "Something is wrong with your certificates!"; - } - / file remove "letsencrypt.pem"; - :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions"; "script-updates" } do={ - / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); - } - / system script { run global-config; run global-config-overlay; run global-functions; } - / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }" -} From 1cde38e2da8d02ae722c95a1a499c7b1ad76a7f8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Mar 2020 12:58:47 +0100 Subject: [PATCH 0233/2612] move template to sub directory --- template.md => doc/template.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) rename template.md => doc/template.md (87%) diff --git a/template.md b/doc/template.md similarity index 87% rename from template.md rename to doc/template.md index 8a9aeb7..bc86c32 100644 --- a/template.md +++ b/doc/template.md @@ -1,7 +1,7 @@ Script `template` ================= -[◀ Go back to main README](README.md) +[◀ Go back to main README](../README.md) Description ----------- @@ -42,6 +42,5 @@ See also * ... --- -[◀ Go back to main README](README.md) - +[◀ Go back to main README](../README.md) [▲ Go back to top](#top) From 1282a91f0401deaaa516826afc6b92622389aeee Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Mar 2020 22:03:31 +0100 Subject: [PATCH 0234/2612] check-certificates: exclude certificates issued by SCEP --- check-certificates | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-certificates b/check-certificates index d5dce80..350adc7 100644 --- a/check-certificates +++ b/check-certificates @@ -25,7 +25,7 @@ $LogPrintExit warning "Time is not yet synchronized." true; } -:foreach Cert in=[ / certificate find where !revoked !ca expires-after<3w ] do={ +:foreach Cert in=[ / certificate find where !revoked !ca !scep-url expires-after<3w ] do={ :local CertVal [ / certificate get $Cert ]; :do { @@ -91,7 +91,7 @@ } } -:foreach Cert in=[ / certificate find where !revoked expires-after<2w fingerprint~"."] do={ +:foreach Cert in=[ / certificate find where !revoked !scep-url expires-after<2w fingerprint~"."] do={ :local CertVal [ / certificate get $Cert ]; :local ExpiresAfter [ $FormatExpire ($CertVal->"expires-after") ]; From 5f46ef7635f27f6180898815cebd954617790b37 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 23 Mar 2020 12:21:38 +0100 Subject: [PATCH 0235/2612] completely replace script-updates with $ScriptInstallUpdate --- INITIAL-COMMANDS.md | 2 +- README.md | 8 +-- global-config | 2 +- global-config-overlay | 4 +- global-config.changes | 3 +- global-functions | 136 +++++++++++++++++++++++++++++++++++++++++- script-updates | 132 +--------------------------------------- 7 files changed, 142 insertions(+), 145 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index d7625c0..2f2b7b1 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -19,7 +19,7 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai :error "Something is wrong with your certificates!"; } / file remove "letsencrypt.pem"; - :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions"; "script-updates" } do={ + :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } / system script { run global-config; run global-config-overlay; run global-functions; } diff --git a/README.md b/README.md index 15b33ab..52d5a1b 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ crap and a good example how to *not* do it. Now let's download the main scripts and add them in configuration on the fly. - [admin@MikroTik] > :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions"; "script-updates" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } + [admin@MikroTik] > :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } The configuration needs to be tweaked for your needs. Make sure not to send your mails to `mail@example.com`! Edit `global-config-overlay`, copy @@ -101,11 +101,7 @@ And finally load configuration and functions and add the scheduler. Updating scripts ---------------- -To update existing scripts just run `script-updates`. - - [admin@MikroTik] > / system script run script-updates - -Calling function `$ScriptInstallUpdate` does the same. +To update existing scripts just run function `$ScriptInstallUpdate`. [admin@MikroTik] > $ScriptInstallUpdate diff --git a/global-config b/global-config index 46c07b8..1ad8393 100644 --- a/global-config +++ b/global-config @@ -6,7 +6,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 13; +:global GlobalConfigVersion 14; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index b6a983f..90740cd 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -7,9 +7,9 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 13; +:global GlobalConfigVersion 14; -# The global-config script is updated by script-updates, +# The global-config script is updated by $ScriptInstallUpdate, # global-config-overlay becomes an overlay for your changes. :global ScriptUpdatesIgnore { "global-config-overlay" diff --git a/global-config.changes b/global-config.changes index 6df7cfd..38c23a4 100644 --- a/global-config.changes +++ b/global-config.changes @@ -1,7 +1,7 @@ # RouterOS global-config changes # Copyright (c) 2019-2020 Christian Hesse -# Changes for global-config to be added to notification on script-updates +# Changes for global-config to be added to notification on script updates :global GlobalConfigChanges { 1="moved variables from 'global-config' to 'global-functions' for independence"; 2="variable names became CamelCase to work around scripting issues"; @@ -16,4 +16,5 @@ 11="introduced function '\$ScriptInstallUpdate' to install new and update existing scripts"; 12="removed '\$ScriptUpdatesConfigChangesIgnore', comment '\$GlobalConfigVersion' in 'global-config-overlay' to disable change notifications"; 13="configuration for script 'bridge-port-to-default' changed with new syntax in comment"; + 14="dropped script 'script-updates', use '\$ScriptInstallUpdate' exclusively!"; }; diff --git a/global-functions b/global-functions index 3187036..1aa64d2 100644 --- a/global-functions +++ b/global-functions @@ -6,7 +6,7 @@ # global functions # expected configuration version -:global ExpectedConfigVersion 13; +:global ExpectedConfigVersion 14; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -378,13 +378,143 @@ :set ScriptInstallUpdate do={ :local Scripts [ :toarray $1 ]; + :global ExpectedConfigVersion; + :global GlobalConfigVersion; + :global Identity; + :global IDonate; + :global ScriptUpdatesBaseUrl; + :global ScriptUpdatesFetch; + :global ScriptUpdatesIgnore; + :global ScriptUpdatesUrlSuffix; + :global SentConfigChangesNotification; + + :global LogPrintExit; + :global SendNotification; + :foreach Script in=$Scripts do={ :if ([ / system script print count-only where name=$Script ] = 0) do={ - :log info ("Adding new script: " . $Script); + $LogPrintExit info ("Adding new script: " . $Script) false; / system script add name=$Script source="#!rsc"; } } - / system script run script-updates; + + :foreach Script in=[ / system script find where source~"^#!rsc" or source="" ] do={ + :local Ignore 0; + :local ScriptVal [ / system script get $Script ]; + :local ScriptFile [ / file find where name=("script-updates/" . $ScriptVal->"name") ]; + :local SourceNew; + :if ([ :len $ScriptFile ] > 0) do={ + :set SourceNew [ / file get $ScriptFile content ]; + / file remove $ScriptFile; + } + + :foreach Scheduler in=[ / system scheduler find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ + :local SchedulerVal [ / system scheduler get $Scheduler ]; + :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ + $LogPrintExit warning ("Policies differ for script " . $ScriptVal->"name" . \ + " and its scheduler " . $SchedulerVal->"name" . "!") false; + } + :if ($SchedulerVal->"name" != "global-scripts" && \ + $SchedulerVal->"start-time" = "startup" && \ + $SchedulerVal->"interval" = 0s && \ + !(($SchedulerVal->"on-event") ~ "\\brun global-wait\\b")) do={ + $LogPrintExit warning ("Scheduler " . $SchedulerVal->"name" . " starts on startup, " . \ + "without waiting for global-functions. Run 'global-wait' to avoid race conditions!") false; + } + } + + :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ + :foreach IgnoreLoop in=$ScriptUpdatesIgnore do={ + :if ($IgnoreLoop = $ScriptVal->"name") do={ :set Ignore 1; } + } + + :if ($Ignore = 0) do={ + $LogPrintExit debug ("Fetching script from url: " . $ScriptVal->"name") false; + :do { + :local Result [ / tool fetch check-certificate=yes-without-crl \ + ($ScriptUpdatesBaseUrl . $ScriptVal->"name" . $ScriptUpdatesUrlSuffix) \ + output=user as-value ]; + :if ($Result->"status" = "finished") do={ + :set SourceNew ($Result->"data"); + } + } on-error={ + $LogPrintExit warning ("Failed fetching " . $ScriptVal->"name") false; + } + } + } + + :if ([ :len $SourceNew ] > 0) do={ + :if ([ :pick $SourceNew 0 5 ] = "#!rsc") do={ + :if ($SourceNew != $ScriptVal->"source") do={ + :local DontRequirePermissions \ + ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); + $LogPrintExit info ("Updating script: " . $ScriptVal->"name") false; + / system script set owner=($ScriptVal->"name") source=$SourceNew \ + dont-require-permissions=$DontRequirePermissions $Script; + :if ($ScriptVal->"name" = "global-config" && \ + [ / system script print count-only where name="global-config-overlay" ] > 0) do={ + / system script { run global-config; run global-config-overlay; } + } + :if ($ScriptVal->"name" = "global-functions") do={ + / system script run global-functions; + } + } else={ + $LogPrintExit debug ("Script " . $ScriptVal->"name" . " did not change.") false; + } + } else={ + $LogPrintExit warning ("Looks like new script " . $ScriptVal->"name" . " is not valid. Ignoring!") false; + } + } else={ + $LogPrintExit debug ("No update for script " . $ScriptVal->"name" . ".") false; + } + } + + :if ($SentConfigChangesNotification!=$ExpectedConfigVersion && \ + $GlobalConfigVersion < $ExpectedConfigVersion) do={ + :global GlobalConfigChanges; + :local ChangeLogCode; + :local ConfigScript "global-config"; + :if ([ /system script print count-only where name="global-config-overlay" ] > 0) do={ + :set ConfigScript "global-config-overlay"; + } + :local NotificationMessage ("Current configuration on " . $Identity . \ + " is out of date. Please update " . $ConfigScript . ", then increase " . \ + "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \ + ") to " . $ExpectedConfigVersion . " and re-run " . $ConfigScript . "."); + + $LogPrintExit debug ("Fetching changelog.") false; + :do { + :local Result [ / tool fetch check-certificate=yes-without-crl \ + ($ScriptUpdatesBaseUrl . "global-config.changes" . $ScriptUpdatesUrlSuffix) \ + output=user as-value ]; + :if ($Result->"status" = "finished") do={ + :set ChangeLogCode ($Result->"data"); + } + :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); + [ :parse $ChangeLogCode ]; + :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ + :set NotificationMessage ($NotificationMessage . \ + "\n * " . $GlobalConfigChanges->[ :tostr $I ]); + } + :set GlobalConfigChanges; + } on-error={ + $LogPrintExit warning ("Failed fetching changes!") false; + :set NotificationMessage ($NotificationMessage . \ + "\n\nChanges are not available."); + } + + :if ($IDonate != true) do={ + :set NotificationMessage ($NotificationMessage . \ + "\n\n==== donation hint ====\n" . \ + "This project is developed in private spare time and usage is " . \ + "free of charge for you. If you like the scripts and think this is " . \ + "of value for you or your business please consider a donation:\n" . \ + "https://git.eworm.de/cgit/routeros-scripts/about/#donate"); + } + + $SendNotification "Configuration warning!" $NotificationMessage; + :set SentConfigChangesNotification $ExpectedConfigVersion; + } } # lock script against multiple invocation diff --git a/script-updates b/script-updates index 38165c9..7604cb4 100644 --- a/script-updates +++ b/script-updates @@ -1,136 +1,6 @@ #!rsc # RouterOS script: script-updates -# Copyright (c) 2013-2020 Christian Hesse -# -# update installed scripts from file or url - -:global ExpectedConfigVersion; -:global GlobalConfigVersion; -:global Identity; -:global IDonate; -:global ScriptUpdatesBaseUrl; -:global ScriptUpdatesFetch; -:global ScriptUpdatesIgnore; -:global ScriptUpdatesUrlSuffix; -:global SentConfigChangesNotification; :global LogPrintExit; -:global SendNotification; -:foreach Script in=[ / system script find where source~"^#!rsc" or source="" ] do={ - :local Ignore 0; - :local ScriptVal [ / system script get $Script ]; - :local ScriptFile [ / file find where name=("script-updates/" . $ScriptVal->"name") ]; - :local SourceNew; - :if ([ :len $ScriptFile ] > 0) do={ - :set SourceNew [ / file get $ScriptFile content ]; - / file remove $ScriptFile; - } - - :foreach Scheduler in=[ / system scheduler find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ - :local SchedulerVal [ / system scheduler get $Scheduler ]; - :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ - $LogPrintExit warning ("Policies differ for script " . $ScriptVal->"name" . \ - " and its scheduler " . $SchedulerVal->"name" . "!") false; - } - :if ($SchedulerVal->"name" != "global-scripts" && \ - $SchedulerVal->"start-time" = "startup" && \ - $SchedulerVal->"interval" = 0s && \ - !(($SchedulerVal->"on-event") ~ "\\brun global-wait\\b")) do={ - $LogPrintExit warning ("Scheduler " . $SchedulerVal->"name" . " starts on startup, " . \ - "without waiting for global-functions. Run 'global-wait' to avoid race conditions!") false; - } - } - - :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ - :foreach IgnoreLoop in=$ScriptUpdatesIgnore do={ - :if ($IgnoreLoop = $ScriptVal->"name") do={ :set Ignore 1; } - } - - :if ($Ignore = 0) do={ - $LogPrintExit debug ("Fetching script from url: " . $ScriptVal->"name") false; - :do { - :local Result [ / tool fetch check-certificate=yes-without-crl \ - ($ScriptUpdatesBaseUrl . $ScriptVal->"name" . $ScriptUpdatesUrlSuffix) \ - output=user as-value ]; - :if ($Result->"status" = "finished") do={ - :set SourceNew ($Result->"data"); - } - } on-error={ - $LogPrintExit warning ("Failed fetching " . $ScriptVal->"name") false; - } - } - } - - :if ([ :len $SourceNew ] > 0) do={ - :if ([ :pick $SourceNew 0 5 ] = "#!rsc") do={ - :if ($SourceNew != $ScriptVal->"source") do={ - :local DontRequirePermissions \ - ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); - $LogPrintExit info ("Updating script: " . $ScriptVal->"name") false; - / system script set owner=($ScriptVal->"name") source=$SourceNew \ - dont-require-permissions=$DontRequirePermissions $Script; - :if ($ScriptVal->"name" = "global-config" && \ - [ / system script print count-only where name="global-config-overlay" ] > 0) do={ - / system script { run global-config; run global-config-overlay; } - } - :if ($ScriptVal->"name" = "global-functions") do={ - / system script run global-functions; - } - } else={ - $LogPrintExit debug ("Script " . $ScriptVal->"name" . " did not change.") false; - } - } else={ - $LogPrintExit warning ("Looks like new script " . $ScriptVal->"name" . " is not valid. Ignoring!") false; - } - } else={ - $LogPrintExit debug ("No update for script " . $ScriptVal->"name" . ".") false; - } -} - -:if ($SentConfigChangesNotification!=$ExpectedConfigVersion && \ - $GlobalConfigVersion < $ExpectedConfigVersion) do={ - :global GlobalConfigChanges; - :local ChangeLogCode; - :local ConfigScript "global-config"; - :if ([ /system script print count-only where name="global-config-overlay" ] > 0) do={ - :set ConfigScript "global-config-overlay"; - } - :local NotificationMessage ("Current configuration on " . $Identity . \ - " is out of date. Please update " . $ConfigScript . ", then increase " . \ - "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \ - ") to " . $ExpectedConfigVersion . " and re-run " . $ConfigScript . "."); - - $LogPrintExit debug ("Fetching changelog.") false; - :do { - :local Result [ / tool fetch check-certificate=yes-without-crl \ - ($ScriptUpdatesBaseUrl . "global-config.changes" . $ScriptUpdatesUrlSuffix) \ - output=user as-value ]; - :if ($Result->"status" = "finished") do={ - :set ChangeLogCode ($Result->"data"); - } - :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); - [ :parse $ChangeLogCode ]; - :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ - :set NotificationMessage ($NotificationMessage . \ - "\n * " . $GlobalConfigChanges->[ :tostr $I ]); - } - :set GlobalConfigChanges; - } on-error={ - $LogPrintExit warning ("Failed fetching changes!") false; - :set NotificationMessage ($NotificationMessage . \ - "\n\nChanges are not available."); - } - - :if ($IDonate != true) do={ - :set NotificationMessage ($NotificationMessage . \ - "\n\n==== donation hint ====\n" . \ - "This project is developed in private spare time and usage is " . \ - "free of charge for you. If you like the scripts and think this is " . \ - "of value for you or your business please consider a donation:\n" . \ - "https://git.eworm.de/cgit/routeros-scripts/about/#donate"); - } - - $SendNotification "Configuration warning!" $NotificationMessage; - :set SentConfigChangesNotification $ExpectedConfigVersion; -} +$LogPrintExit warning "This script has been replaced by function '\$ScriptInstallUpdate'." true; From 111e339d06049cc713455749d2978ffd6b9ab819 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 24 Mar 2020 12:12:00 +0100 Subject: [PATCH 0236/2612] netwatch-notify: report the number of checks a host was down --- netwatch-notify | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index d2d256b..85a1ee5 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -25,10 +25,12 @@ :if ($HostVal->"status" = "up") do={ $LogPrintExit debug ("Host " . $HostName . " (" . $HostVal->"host" . ") is up.") false; + :local Count ($Metric->"count"); :set ($Metric->"count") 0; :if ($Metric->"notified" = true) do={ $SendNotification ("Netwatch Notify: " . $HostName . " up") \ - ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . "."); + ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ + "It was down for " . $Count . " checks."); } :set ($Metric->"notified") false; } else={ From 7e982a470d1acbf2983c1bc71049106a94fad109 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 24 Mar 2020 12:28:06 +0100 Subject: [PATCH 0237/2612] netwatch-notify: add fancy unicode symbols https://www.compart.com/de/unicode/block/U+2700 --- netwatch-notify | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 85a1ee5..5b47e3b 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -28,7 +28,7 @@ :local Count ($Metric->"count"); :set ($Metric->"count") 0; :if ($Metric->"notified" = true) do={ - $SendNotification ("Netwatch Notify: " . $HostName . " up") \ + $SendNotification ("Netwatch Notify: \E2\9C\85 " . $HostName . " up") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ "It was down for " . $Count . " checks."); } @@ -38,7 +38,7 @@ $LogPrintExit info ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ $Metric->"count" . " checks.") false; :if ($Metric->"count" >= 5 && $Metric->"notified" != true) do={ - $SendNotification ("Netwatch Notify: " . $HostName . " down") \ + $SendNotification ("Netwatch Notify: \E2\9D\8C " . $HostName . " down") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :set ($Metric->"notified") true; } From 0229516bb5cea7c5f94cc8c9591368d8e89830d7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 24 Mar 2020 12:35:40 +0100 Subject: [PATCH 0238/2612] check-routeros-update: add fancy unicode symbol --- check-routeros-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-routeros-update b/check-routeros-update index 6672f13..e034c0b 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -73,7 +73,7 @@ $Update->"latest-version" . ".") true; } - $SendNotification ("RouterOS update") \ + $SendNotification ("RouterOS update \E2\9C\A8") \ ("There is a RouterOS update available.\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree") \ From 524cc29e996c6fee05e066b21453962f4cd32be6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 24 Mar 2020 12:38:03 +0100 Subject: [PATCH 0239/2612] check-health: add fancy unicode symbols --- check-health | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/check-health b/check-health index b693410..a7ead46 100644 --- a/check-health +++ b/check-health @@ -36,12 +36,12 @@ [ :typeof ($CheckHealthCurrent->($PSU . "-state")) ] = "str") do={ :if ($CheckHealthLast->($PSU . "-state") = "ok" && \ $CheckHealthCurrent->($PSU . "-state") != "ok") do={ - $SendNotification ("Health warning: " . $PSU . " state") \ + $SendNotification ("Health warning: \E2\9D\8C " . $PSU . " state") \ ("The power supply unit '" . $PSU . "' on " . $Identity . " failed!"); } :if ($CheckHealthLast->($PSU . "-state") != "ok" && \ $CheckHealthCurrent->($PSU . "-state") = "ok") do={ - $SendNotification ("Health recovery: " . $PSU . " state") \ + $SendNotification ("Health recovery: \E2\9C\85 " . $PSU . " state") \ ("The power supply unit '" . $PSU . "' on " . $Identity . " recovered!"); } } @@ -56,13 +56,13 @@ } :if ($CheckHealthLast->$Temperature <= $CheckHealthTemperature->$Temperature && \ $CheckHealthCurrent->$Temperature > $CheckHealthTemperature->$Temperature) do={ - $SendNotification ("Health warning: " . $Temperature) \ + $SendNotification ("Health warning: \E2\9D\8C " . $Temperature) \ ("The " . $Temperature . " on " . $Identity . " is above threshold: " . \ $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); } :if ($CheckHealthLast->$Temperature > $CheckHealthTemperature->$Temperature && \ $CheckHealthCurrent->$Temperature <= $CheckHealthTemperature->$Temperature) do={ - $SendNotification ("Health recovery: " . $Temperature) \ + $SendNotification ("Health recovery: \E2\9C\85 " . $Temperature) \ ("The " . $Temperature . " on " . $Identity . " dropped below threshold: " . \ $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); } From 0d6bdd4eb1fe636b5a6775191563d422fbf999fd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Mar 2020 07:53:44 +0100 Subject: [PATCH 0240/2612] README: unify markup --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 52d5a1b..6204ee9 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,8 @@ cleanup add a scheduler entry. There's much more to explore... Have fun! -## Contribute +Contribute +---------- Thanks a lot for [past contributions](CONTRIBUTIONS.md)! @@ -153,7 +154,8 @@ business please consider to Thanks a lot for your support! -## Upstream +Upstream +-------- URL: [GitHub.com](https://github.com/eworm-de/routeros-scripts#routeros-scripts) From a87fbb4be1e1e090b01db9eebd7799a0e1d62771 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Mar 2020 14:22:10 +0100 Subject: [PATCH 0241/2612] start news items with capital letter --- global-config.changes | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/global-config.changes b/global-config.changes index 38c23a4..7bd3c9f 100644 --- a/global-config.changes +++ b/global-config.changes @@ -3,18 +3,18 @@ # Changes for global-config to be added to notification on script updates :global GlobalConfigChanges { - 1="moved variables from 'global-config' to 'global-functions' for independence"; - 2="variable names became CamelCase to work around scripting issues"; - 3="variable for certificate renew passphrase became an array to support multiple passphrases"; - 4="added option to ignore global-config changes"; - 5="split off new script 'cloud-backup' from 'email-backup'"; - 6="introduced script 'upload-backup' with new configuration parameters"; - 7="introduced script 'check-health' with new configuration parameters"; - 8="added donation hint and option to silence it"; - 9="introduced configuration overlay 'global-config-overlay'"; - 10="make health threshold for voltage configurable"; - 11="introduced function '\$ScriptInstallUpdate' to install new and update existing scripts"; - 12="removed '\$ScriptUpdatesConfigChangesIgnore', comment '\$GlobalConfigVersion' in 'global-config-overlay' to disable change notifications"; - 13="configuration for script 'bridge-port-to-default' changed with new syntax in comment"; - 14="dropped script 'script-updates', use '\$ScriptInstallUpdate' exclusively!"; + 1="Moved variables from 'global-config' to 'global-functions' for independence"; + 2="Variable names became CamelCase to work around scripting issues"; + 3="Variable for certificate renew passphrase became an array to support multiple passphrases"; + 4="Added option to ignore global-config changes"; + 5="Split off new script 'cloud-backup' from 'email-backup'"; + 6="Introduced script 'upload-backup' with new configuration parameters"; + 7="Introduced script 'check-health' with new configuration parameters"; + 8="Added donation hint and option to silence it"; + 9="Introduced configuration overlay 'global-config-overlay'"; + 10="Made health threshold for voltage configurable"; + 11="Introduced function '\$ScriptInstallUpdate' to install new and update existing scripts"; + 12="Removed '\$ScriptUpdatesConfigChangesIgnore', comment '\$GlobalConfigVersion' in 'global-config-overlay' to disable change notifications"; + 13="Configuration for script 'bridge-port-to-default' changed with new syntax in comment"; + 14="Dropped script 'script-updates', use '\$ScriptInstallUpdate' exclusively!"; }; From 1d580c39f9c31c6d0bde8ee8c1ad92bdc0322ffa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:38:28 +0100 Subject: [PATCH 0242/2612] drop doc/template.md --- doc/template.md | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 doc/template.md diff --git a/doc/template.md b/doc/template.md deleted file mode 100644 index bc86c32..0000000 --- a/doc/template.md +++ /dev/null @@ -1,46 +0,0 @@ -Script `template` -================= - -[◀ Go back to main README](../README.md) - -Description ------------ - -Short description... - -In detail ---------- - -Get all the details... - -Requirements and installation ------------------------------ - -We need... - -... then we install: - - [admin@MikroTik] > / system script add name=template - [admin@MikroTik] > / system script run script-updates - -Configuration -------------- - -The configuration goes to `global-config`, These are the parameters: - -* ... - -Usage and invocation --------------------- - -This is intended... - -See also --------- - -* [another script](template.md) -* ... - ---- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) From b2f81f7cad319684cb473c503a998caecdf78a71 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:39:13 +0100 Subject: [PATCH 0243/2612] add doc/accesslist-duplicates.md --- accesslist-duplicates.capsman | 1 + accesslist-duplicates.local | 1 + accesslist-duplicates.template | 1 + doc/accesslist-duplicates.md | 49 ++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman index e506740..b441c31 100644 --- a/accesslist-duplicates.capsman +++ b/accesslist-duplicates.capsman @@ -3,6 +3,7 @@ # Copyright (c) 2018-2020 Christian Hesse # # 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! diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local index 4b812a5..00d9ae0 100644 --- a/accesslist-duplicates.local +++ b/accesslist-duplicates.local @@ -3,6 +3,7 @@ # Copyright (c) 2018-2020 Christian Hesse # # 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! diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template index 0d1c92c..f527810 100644 --- a/accesslist-duplicates.template +++ b/accesslist-duplicates.template @@ -3,6 +3,7 @@ # Copyright (c) 2018-2020 Christian Hesse # # print duplicate antries in wireless access list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md # # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md new file mode 100644 index 0000000..2189322 --- /dev/null +++ b/doc/accesslist-duplicates.md @@ -0,0 +1,49 @@ +Find and remove access list duplicates +====================================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script is supposed to run interactively to find and remove duplicate +entries in wireless access list. + +Requirements and installation +----------------------------- + +Depending on whether you use CAPsMAN (`/ caps-man`) or local wireless +interface (`/ interface wireless`) you need to install a different script. + +For CAPsMAN: + + $ScriptInstallUpdate accesslist-duplicates.capsman; + +For local interface: + + $ScriptInstallUpdate accesslist-duplicates.local; + +Usage and invocation +-------------------- + +Run this script from a terminal: + + [admin@kalyke] > / system script run accesslist-duplicates.local + Flags: X - disabled + 0 ;;; First entry with identical mac address... + mac-address=00:11:22:33:44:55 interface=any signal-range=-120..120 allow-signal-out-of-range=10s authentication=yes forwarding=yes ap-tx-limit=0 client-tx-limit=0 private-algo=none private-key="" private-pre-shared-key="" management-protection-key="" vlan-mode=default vlan-id=1 + + 1 ;;; Second entry with identical mac address... + mac-address=00:11:22:33:44:55 interface=any signal-range=-120..120 allow-signal-out-of-range=10s authentication=yes forwarding=yes ap-tx-limit=0 client-tx-limit=0 private-algo=none private-key="" private-pre-shared-key="" management-protection-key="" vlan-mode=default vlan-id=1 + + Numeric id to remove, any key to skip! + Removing numeric id 1... + +See also +-------- + +* [Collect MAC addresses in wireless access list](collect-wireless-mac.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) From 60a21e11b0611c0330f0da4996c95e994cb1a453 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:39:37 +0100 Subject: [PATCH 0244/2612] add doc/bridge-port.md --- bridge-port-to-default | 1 + bridge-port-toggle | 1 + doc/bridge-port.md | 84 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 doc/bridge-port.md diff --git a/bridge-port-to-default b/bridge-port-to-default index db7cbdc..409dcb9 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # reset bridge ports to default bridge +# https://git.eworm.de/cgit/routeros-scripts/about/doc/bridge-port.md :global BridgePortTo; diff --git a/bridge-port-toggle b/bridge-port-toggle index b6ca4cd..a8ad8ad 100644 --- a/bridge-port-toggle +++ b/bridge-port-toggle @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # toggle bridge ports between default and alt bridge +# https://git.eworm.de/cgit/routeros-scripts/about/doc/bridge-port.md :global BridgePortTo; diff --git a/doc/bridge-port.md b/doc/bridge-port.md new file mode 100644 index 0000000..2228ac8 --- /dev/null +++ b/doc/bridge-port.md @@ -0,0 +1,84 @@ +Manage ports in bridge +====================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +These scripts are supposed to handle interfaces and switching them from +one bridge to another. + +Requirements and installation +----------------------------- + +Just install the scripts: + + $ScriptInstallUpdate bridge-port-to-default,bridge-port-toggle; + +Configuration +------------- + +The configuration goes to ports' comments (`/ interface bridge port`). + + / interface bridge port add bridge=br-guest comment="default=dhcp-client, alt=br-guest" disabled=yes interface=en1; + / interface bridge port add bridge=br-intern comment="default=br-intern, alt=br-guest" interface=en2; + / interface bridge port add bridge=br-guest comment="default=br-guest, extra=br-extra" interface=en3; + +Also dhcp client can be handled: + + / ip dhcp-client add comment="toggle with bridge port" disabled=no interface=en1; + +There is also global configuration: + +* `BridgePortTo`: specify the configuration to be applied by default + +Install [global-wait](global-wait.md) and add a scheduler to start with +default setup on system startup: + + / system scheduler add name=bridge-port-to-default on-event="/ system script { run global-wait; run bridge-port-to-default; }" start-time=startup; + +Usage and invocation +-------------------- + +The usage examples show what happens with the configuration from above. + +Running the script `bridge-port-to-default` applies all configuration given +with `default=`: + + / system script run bridge-port-to-default; + +For the three interfaces we get this configuration: + +* The special value `dhcp-client` enables the dhcp client for interface `en1`. The bridge port entry is disabled. +* Interface `en2` is put in bridge `br-intern`. +* Interface `en3` is put in bridge `br-guest`. + +Running the script `bridge-port-toggle` toggles to configuration given +with `alt=`: + + / system script run bridge-port-toggle; + +* Interface `en1` is put in bridge `br-guest`, dhcp client for the interface is disabled. +* Interface `en2` is put in bridge `br-guest`. +* Interface `en3` is unchanged, stays in bridge `br-guest`. + +Running the script `bridge-port-toggle` again toggles back to configuration +given with `default=`. + +More configuration can be loaded by setting `BridgePortTo`: + + :set BridgePortTo "extra"; + / system script run bridge-port-to-default; + +* Interfaces `en1` and `en2` are unchanged. +* Interface `en3` is put in bridge `br-intern`. + +See also +-------- + +* [Wait for configuration und functions](global-wait.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) From 74d192cf539df4744e19cfde9d4be085b6564aa8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:40:02 +0100 Subject: [PATCH 0245/2612] add doc/capsman-download-packages.md --- capsman-download-packages | 1 + doc/capsman-download-packages.md | 51 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 doc/capsman-download-packages.md diff --git a/capsman-download-packages b/capsman-download-packages index c76ceee..de2feb9 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -4,6 +4,7 @@ # Michael Gisbers # # download and cleanup packages for CAP installation from CAPsMAN +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md :global CleanFilePath; :global DownloadPackage; diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md new file mode 100644 index 0000000..ee4912d --- /dev/null +++ b/doc/capsman-download-packages.md @@ -0,0 +1,51 @@ +Download packages for CAP upgrade from CAPsMAN +============================================= + +[◀ Go back to main README](../README.md) + +Description +----------- + +CAPsMAN can upgrate CAP devices. If CAPsMAN device and CAP device(s) are +differnet architecture you need to store packages for CAP device's +architecture on local storage. + +This script automatically downloads these packages. + +Requirements and installation +----------------------------- + +Just install the script on CAPsMAN device: + + $ScriptInstallUpdate capsman-download-packages; + +Optionally create a scheduler to run after startup, with a delay to ensure +internet connectivity is given: + + / system scheduler add name=capsman-download-packages on-event=":delay 2m; / system script run capsman-download-packages;" start-time=startup; + +Only packages available in older version are downloaded. For initial setup +place the required packages to CAPsMAN package path (see +`/ caps-man manager`). + +Usage and invocation +-------------------- + +Run the script manually: + + / system script run capsman-download-packages; + +... or from scheduler. + +After package download all out-of-date CAP devices are upgraded automatically. +For a rolling upgrade install extra script +[capsman-rolling-upgrade](capsman-rolling-upgrade.md). + +See also +-------- + +* [Run rolling CAP upgrades from CAPsMAN](capsman-rolling-upgrade.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) From 77c1f6fd6324dc909ad4b69bdf4eb2083e4107d0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:40:16 +0100 Subject: [PATCH 0246/2612] add doc/capsman-rolling-upgrade.md --- capsman-rolling-upgrade | 1 + doc/capsman-rolling-upgrade.md | 39 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 doc/capsman-rolling-upgrade.md diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index cedfc47..38843e6 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -4,6 +4,7 @@ # Michael Gisbers # # upgrade CAPs one after another +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md :global ScriptLock; diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md new file mode 100644 index 0000000..e78c87a --- /dev/null +++ b/doc/capsman-rolling-upgrade.md @@ -0,0 +1,39 @@ +Run rolling CAP upgrades from CAPsMAN +===================================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +CAPsMAN can upgrate CAP devices. This script runs a rolling upgrade for +out-of-date CAP devices. The idea is to have just a fraction of devices +reboot at a time, having the others to serve wireless connectivity. + + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate capsman-rolling-upgrade; + +Usage and invocation +-------------------- + +This script is intended as an add-on to +[capsman-download-packages](capsman-download-packages.md), being invoked by +that script when required. + +Alternatively run it manually: + + / system script run capsman-rolling-upgrade; + +See also +-------- + +* [Download packages for CAP upgrade from CAPsMAN](capsman-download-packages.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) From d08a342f06e268ef06e49f98e989db4ca26ec946 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:40:35 +0100 Subject: [PATCH 0247/2612] add doc/certificate-renew-issued.md --- certificate-renew-issued | 1 + doc/certificate-renew-issued.md | 47 +++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 doc/certificate-renew-issued.md diff --git a/certificate-renew-issued b/certificate-renew-issued index d5ff2c8..fe33b93 100644 --- a/certificate-renew-issued +++ b/certificate-renew-issued @@ -3,6 +3,7 @@ # Copyright (c) 2019-2020 Christian Hesse # # renew locally issued certificates +# https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md :global CertIssuedExportPass; diff --git a/doc/certificate-renew-issued.md b/doc/certificate-renew-issued.md new file mode 100644 index 0000000..e460ce1 --- /dev/null +++ b/doc/certificate-renew-issued.md @@ -0,0 +1,47 @@ +Renew locally issued certificates +================================= + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script renews certificates issued by a local certificate authority (CA). +Optionally the certificates are exported with individual passphrases for +easy pick-up. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate certificate-renew-issued; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, there is just one +parameter: + +* `CertRenewPass`: an array holding individual passphrases for certificates + +Usage and invocation +-------------------- + +Run the script to renew certificates issued from a local CA. + + / system script run certificate-renew-issued; + +Only scripts with a remaining lifetime of three weeks or less are renewed. +The old certificate is revoked automatically. If a passphrase for a specific +certificate is given in `CertRenewPass` the certificate is exported and +PKCS#12 file (`cert-issued/CN.p12`) can be found on device's storage. + +See also +-------- + +* [Renew certificates and notify on expiration](check-certificates.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) From e962fe91899c169525ea015d702135f0ba10b0e3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:41:18 +0100 Subject: [PATCH 0248/2612] add doc/check-certificates.md --- check-certificates | 1 + doc/check-certificates.md | 52 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 doc/check-certificates.md diff --git a/check-certificates b/check-certificates index 350adc7..b9c9075 100644 --- a/check-certificates +++ b/check-certificates @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # check for certificate validity +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md :global CertRenewPass; :global CertRenewUrl; diff --git a/doc/check-certificates.md b/doc/check-certificates.md new file mode 100644 index 0000000..51ecd14 --- /dev/null +++ b/doc/check-certificates.md @@ -0,0 +1,52 @@ +Renew certificates and notify on expiration +=========================================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script tries to download and renew certificates, then notifies about +certificates that are still about to expire. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate check-certificates; + +Configuration +------------- + +The expiry notifications just require notification settings for e-mail and +telegram. + +For automatic download and renewal of certificates you need configuration +in `global-config-overlay`, these are the parameters: + +* `CertRenewPass`: an array of passphrases to try +* `CertRenewUrl`: the url to download certificates from + +Certificates on the web server should be named `CN.pem` (`PEM` format) or +`CN.p12` (`PKCS#12` format). + +Usage and invocation +-------------------- + +Just run the script: + + / system script run check-certificates; + +... or create a scheduler for periodic execution: + + / system scheduler add interval=1d name=check-certificates on-event="/ system script run check-certificates;" start-time=startup; + +See also +-------- + +* [Renew locally issued certificates](certificate-renew-issued.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) From ff867d1b6b20f90e7cd2296c3deeaec68e7e11cb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:41:40 +0100 Subject: [PATCH 0249/2612] add doc/check-health.md --- check-health | 1 + doc/check-health.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 doc/check-health.md diff --git a/check-health b/check-health index a7ead46..ef9fd23 100644 --- a/check-health +++ b/check-health @@ -3,6 +3,7 @@ # Copyright (c) 2019-2020 Christian Hesse # # check for RouterOS health state +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md :global CheckHealthLast; :global CheckHealthTemperature; diff --git a/doc/check-health.md b/doc/check-health.md new file mode 100644 index 0000000..37f8e34 --- /dev/null +++ b/doc/check-health.md @@ -0,0 +1,43 @@ +Notify about health state +========================= + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script is run from scheduler periodically, sending notification on +health related events: + +* voltage jumps up or down more than configured threshold +* power supply failed or recovered +* temperature is above or below threshold + +Note that bad initial state will not trigger an event. + +Only sensors available in hardware can be checked. See what your +hardware supports: + + / system health print; + +Requirements and installation +----------------------------- + +Just install the script and create a scheduler: + + $ScriptInstallUpdate check-health; + / system scheduler add interval=1m name=check-health on-event="/ system script run check-health;" start-time=startup; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, These are the parameters: + +* `CheckHealthTemperature`: an array specifying temperature thresholds for sensors +* `CheckHealthVoltagePercent`: percentage value to trigger voltage jumps + +Also notification settings are required for e-mail and telegram. + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) From 969ae57fc2f274ffc03e2870e39ca9a6fb9564ea Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:41:56 +0100 Subject: [PATCH 0250/2612] add doc/check-lte-firmware-upgrade.md --- check-lte-firmware-upgrade | 3 ++- doc/check-lte-firmware-upgrade.md | 41 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 doc/check-lte-firmware-upgrade.md diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 101f5e1..6edb6f1 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -3,6 +3,7 @@ # Copyright (c) 2018-2020 Christian Hesse # # check for LTE firmware upgrade, send notification +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md :global Identity; :global SentLteFirmwareUpgradeNotification; @@ -13,7 +14,7 @@ :local IntName [ / interface lte get $Interface name ]; :do { :local Firmware [ / interface lte firmware-upgrade $Interface once as-value ]; - + :if ($SentLteFirmwareUpgradeNotification = ($Firmware->"latest")) do={ :log debug ("Already sent the LTE firmware upgrade notification for version " . \ ($Firmware->"latest") . "."); diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md new file mode 100644 index 0000000..c71dee5 --- /dev/null +++ b/doc/check-lte-firmware-upgrade.md @@ -0,0 +1,41 @@ +Notify on LTE firmware upgrade +============================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script is run from scheduler periodically, checking for LTE firmware +upgrades. Currently supported LTE hardware: + +* R11e-LTE +* R11e-LTE-US +* R11e-4G +* R11e-LTE6 + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate check-lte-firmware-upgrade; + +... and create a scheduler: + + / system scheduler add interval=1d name=check-lte-firmware-upgrade on-event="/ system script run check-lte-firmware-upgrade;" start-time=startup; + +Configuration +------------- + +Notification setting are required for e-mail and telegram. + +See also +-------- + +* [Notify on RouterOS update](check-routeros-update.md) +* [Install LTE firmware upgrade](unattended-lte-firmware-upgrade.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) From c1dcc280289e96d1c0de45b9ead189e31ed75b26 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:42:19 +0100 Subject: [PATCH 0251/2612] add doc/check-routeros-update.md --- check-routeros-update | 1 + doc/check-routeros-update.md | 55 ++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 doc/check-routeros-update.md diff --git a/check-routeros-update b/check-routeros-update index e034c0b..3bec07b 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # check for RouterOS update, send notification and/or install +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md :global Identity; :global SafeUpdateUrl; diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md new file mode 100644 index 0000000..c94381c --- /dev/null +++ b/doc/check-routeros-update.md @@ -0,0 +1,55 @@ +Notify on RouterOS update +========================= + +[◀ Go back to main README](../README.md) + +Description +----------- + +The primary use of this script is to notify about RouterOS updates. + +Run from a terminal you can start the update process or schedule it. + +Centrally managing update process of several devices is possibly by +specifying versions safe to be updated on a web server. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate check-routeros-update; + +And add a scheduler for automatic update notification: + + / system scheduler add interval=1d name=check-routeros-update on-event="/ system script run check-routeros-update;" start-time=startup; + +Configuration +------------- + +Configuration is required only if you want to control update process with +safe versions from a web server. The configuration goes to +`global-config-overlay`, this is the parameter: + +* `SafeUpdateUrl`: url to check for safe update, the channel (`long-term`, +`stable` or `testing`) is appended + +Usage and invocation +-------------------- + +Be notified when run from scheduler or run it manually: + + / system script run check-routeros-update; + +If an update is found you can install it right away. + +Installing script [packages-update](packages-update.md) gives extra options. + +See also +-------- + +* [Manage system update](packages-update.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) From d1bba48cc7c8f56323f503b632994e5b61f512fe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:42:33 +0100 Subject: [PATCH 0252/2612] add doc/cloud-backup.md --- cloud-backup | 1 + doc/cloud-backup.md | 46 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 doc/cloud-backup.md diff --git a/cloud-backup b/cloud-backup index 9a225a2..316a2a4 100644 --- a/cloud-backup +++ b/cloud-backup @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # upload backup to MikroTik cloud +# https://git.eworm.de/cgit/routeros-scripts/about/doc/cloud-backup.md :global BackupPassword; :global Identity; diff --git a/doc/cloud-backup.md b/doc/cloud-backup.md new file mode 100644 index 0000000..bda1267 --- /dev/null +++ b/doc/cloud-backup.md @@ -0,0 +1,46 @@ +Upload backup to Mikrotik cloud +=============================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script uploads [binary backup to Mikrotik cloud](https://wiki.mikrotik.com/wiki/Manual:IP/Cloud#Backup). + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate cloud-backup; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, this is the only parameter: + +* `BackupPassword`: password to encrypt the backup with + +Also notification settings are required for e-mail and telegram. + +Usage and invocation +-------------------- + +Just run the script: + + / system script run cloud-backup; + +Creating a scheduler may be an option: + + / system scheduler add interval=1w name=cloud-backup on-event="/ system script run cloud-backup;" start-time=09:20:00; + +See also +-------- + +* [Send backup via e-mail](email-backup.md) +* [Upload backup to server](upload-backup.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) From 79e7b3229fcfb91c9cca0f7118aafc8dd0c60f37 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:43:01 +0100 Subject: [PATCH 0253/2612] add doc/collect-wireless-mac.md --- collect-wireless-mac.capsman | 1 + collect-wireless-mac.local | 1 + collect-wireless-mac.template | 1 + doc/collect-wireless-mac.md | 54 +++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 doc/collect-wireless-mac.md diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 95e46a2..c89ea19 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # 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! diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 8b5d5ac..eac8734 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # 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! diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 510afcc..0f936b3 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # collect wireless mac adresses in access list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md new file mode 100644 index 0000000..45489bf --- /dev/null +++ b/doc/collect-wireless-mac.md @@ -0,0 +1,54 @@ +Collect MAC addresses in wireless access list +============================================= + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script adds unknown MAC addresses of connected wireless devices to +address list. In addition a notification is sent. + +By default the access list entry is disabled, but you can easily enable +and modify it to your needs. + +Requirements and installation +----------------------------- + +Depending on whether you use CAPsMAN (`/ caps-man`) or local wireless +interface (`/ interface wireless`) you need to install a different script. + +For CAPsMAN: + + $ScriptInstallUpdate collect-wireless-mac.capsman; + +For local interface: + + $ScriptInstallUpdate collect-wireless-mac.local; + +Configuration +------------- + +On first run a disabled access list entry acting as marker (with comment +"`--- collected above ---`") is added. Move this entry to define where new +entries are to be added. + +Also notification settings are required for e-mail and telegram. + +Usage and invocation +-------------------- + +Run this script from a dhcp server as lease-script to collect the MAC +address when a new address is leased. You may want to use +[lease-script](lease-script.md). + +See also +-------- + +* [Comment DHCP leases with info from access list](dhcp-lease-comment.md) +* [Create DNS records for DHCP leases](dhcp-to-dns.md) +* [Run other scripts on DHCP lease](lease-script.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) From e949e527f632927f806d3c0340bc5319d681106a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:44:36 +0100 Subject: [PATCH 0254/2612] add doc/daily-psk.md --- daily-psk.capsman | 1 + daily-psk.local | 1 + daily-psk.template | 1 + doc/daily-psk.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 doc/daily-psk.md diff --git a/daily-psk.capsman b/daily-psk.capsman index 59b867e..623ef0c 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -4,6 +4,7 @@ # Michael Gisbers # # 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! diff --git a/daily-psk.local b/daily-psk.local index 3915618..6245ebe 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -4,6 +4,7 @@ # Michael Gisbers # # 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! diff --git a/daily-psk.template b/daily-psk.template index cab65f2..3181b1a 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -4,6 +4,7 @@ # Michael Gisbers # # update daily PSK (pre shared key) +# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md # # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! diff --git a/doc/daily-psk.md b/doc/daily-psk.md new file mode 100644 index 0000000..e6d7aae --- /dev/null +++ b/doc/daily-psk.md @@ -0,0 +1,56 @@ +Use wireless network with daily psk +=================================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script is supposed to provide a wifi network which changes the +passphrase to a pseudo-random string daily. + +Requirements and installation +----------------------------- + +Just install this script and [global-wait](global-wait.md). + +Depending on whether you use CAPsMAN (`/ caps-man`) or local wireless +interface (`/ interface wireless`) you need to install a different script. + +For CAPsMAN: + + $ScriptInstallUpdate daily-psk.capsman,global-wait; + +For local interface: + + $ScriptInstallUpdate daily-psk.local,global-wait; + +And add schedulers to run the script: + + / system scheduler add interval=1d name=daily-psk-nightly on-event="/ system script run daily-psk.local;" start-date=may/23/2018 start-time=03:00:00; + / system scheduler add name=daily-psk-startup on-event=":global WaitTimeSync; / system script { run global-wait; \$WaitTimeSync; run daily-psk.local; }" start-time=startup; + +These will update the passphrase on boot and nightly at 3:00. + +Configuration +------------- + +The configuration goes to `global-config-overlay`, these are the parameters: + +* `DailyPskMatchComment`: pattern to match the wireless access list comment +* `DailyPskSecrets`: an array with pseudo random strings + +Then add an access list entry: + + / interface wireless access-list add comment="Daily PSK" interface=wl-daily private-pre-shared-key="ToBeChangedDaily"; + +Also notification settings are required for e-mail and telegram. + +See also +-------- + +* [Wait for configuration und functions](global-wait.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) From c9b71398593c0ec1ceb5d6d15d319c16a65e121b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:44:36 +0100 Subject: [PATCH 0255/2612] add doc/dhcp-lease-comment.md --- dhcp-lease-comment.capsman | 1 + dhcp-lease-comment.local | 1 + dhcp-lease-comment.template | 1 + doc/dhcp-lease-comment.md | 49 +++++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index 5a5d98b..51ccca2 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # 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! diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index eb74dab..96b98e1 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # 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! diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index bcbb39a..6892f1b 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # update dhcp-server lease comment with infos from access-list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md # # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! diff --git a/doc/dhcp-lease-comment.md b/doc/dhcp-lease-comment.md new file mode 100644 index 0000000..caba7d6 --- /dev/null +++ b/doc/dhcp-lease-comment.md @@ -0,0 +1,49 @@ +Comment DHCP leases with info from access list +============================================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script adds comments to dynamic dhcp server leases. Infos are taken +from wireless access list. + +Requirements and installation +----------------------------- + +Depending on whether you use CAPsMAN (`/ caps-man`) or local wireless +interface (`/ interface wireless`) you need to install a different script. + +For CAPsMAN: + + $ScriptInstallUpdate dhcp-lease-comment.capsman; + +For local interface: + + $ScriptInstallUpdate dhcp-lease-comment.local; + +Configuration +------------- + +Infos are taken from wireless access list. Add entries with proper comments +there. You may want to use [collect-wireless-mac](collect-wireless-mac.md) +to prepare entries. + +Usage and invocation +-------------------- + +Run this script from a dhcp server as lease-script to update the comment +just after a new address is leased. You may want to use +[lease-script](lease-script.md). + +See also +-------- + +* [Collect MAC addresses in wireless access list](collect-wireless-mac.md) +* [Create DNS records for DHCP leases](dhcp-to-dns.md) +* [Run other scripts on DHCP lease](lease-script.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) From e0346bf60efc96375555277171c994f64714ae86 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:44:56 +0100 Subject: [PATCH 0256/2612] add doc/dhcp-to-dns.md --- dhcp-to-dns | 1 + doc/dhcp-to-dns.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 doc/dhcp-to-dns.md diff --git a/dhcp-to-dns b/dhcp-to-dns index 687db97..f88599c 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # check DHCP leases and add/remove/update DNS entries +# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md :global Domain; :global HostNameInZone; diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md new file mode 100644 index 0000000..3f25659 --- /dev/null +++ b/doc/dhcp-to-dns.md @@ -0,0 +1,42 @@ +Create DNS records for DHCP leases +================================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script adds (and removes) dns records based on dhcp server leases. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate dhcp-to-dns; + +Then run it from dhcp server as lease script. You may want to use +[lease-script](lease-script.md). + +A scheduler cares about cleanup: + + / system scheduler add interval=15m name=dhcp-to-dns on-event="/ system script run dhcp-to-dns;" start-time=startup; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, these are the parameters: + +* `Domain`: the domain used for dns records +* `HostNameInZone`: whether or not to add the dhcp/dns server's hostname + +See also +-------- + +* [Collect MAC addresses in wireless access list](collect-wireless-mac.md) +* [Comment DHCP leases with info from access list](dhcp-lease-comment.md) +* [Run other scripts on DHCP lease](lease-script.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) From 8b724a9b5accef55bb85cc54ce19298f3a7ffc5e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:45:15 +0100 Subject: [PATCH 0257/2612] add doc/email-backup.md --- doc/email-backup.md | 52 +++++++++++++++++++++++++++++++++++++++++++++ email-backup | 1 + 2 files changed, 53 insertions(+) create mode 100644 doc/email-backup.md diff --git a/doc/email-backup.md b/doc/email-backup.md new file mode 100644 index 0000000..7f89a06 --- /dev/null +++ b/doc/email-backup.md @@ -0,0 +1,52 @@ +Send backup via e-mail +====================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script sends binary backup (`/ system backup save`) and complete +configuration export (`/ export terse`) via e-mail. + + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate email-backup; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, These are the parameters: + +* `BackupSendBinary`: whether to send binary backup +* `BackupSendExport`: whether to send configuration export +* `BackupPassword`: password to encrypt the backup with +* `EmailBackupTo`: e-mail address to send to +* `EmailBackupCc`: e-mail address(es) to send in copy + +Also valid e-mail settings in `/ tool e-mail` are required to send mails. + +Usage and invocation +-------------------- + +Just run the script: + + / system script run email-backup; + +Creating a scheduler may be an option: + + / system scheduler add interval=1w name=email-backup on-event="/ system script run email-backup;" start-time=09:15:00; + +See also +-------- + +* [Upload backup to Mikrotik cloud](cloud-backup.md) +* [Upload backup to server](upload-backup.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/email-backup b/email-backup index 2449173..3a00d04 100644 --- a/email-backup +++ b/email-backup @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # create and email backup and config file +# https://git.eworm.de/cgit/routeros-scripts/about/doc/email-backup.md :global BackupPassword; :global BackupSendBinary; From 2e0e83d13654dd0aad44c44b0db350554a562d77 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:45:38 +0100 Subject: [PATCH 0258/2612] add doc/global-wait.md --- doc/global-wait.md | 34 ++++++++++++++++++++++++++++++++++ global-wait | 1 + 2 files changed, 35 insertions(+) create mode 100644 doc/global-wait.md diff --git a/doc/global-wait.md b/doc/global-wait.md new file mode 100644 index 0000000..9fcaa96 --- /dev/null +++ b/doc/global-wait.md @@ -0,0 +1,34 @@ +Wait for configuration und functions +==================================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +The global scripts `global-config`, `global-config-overlay` and +`global-functions` are run by scheduler at system startup. Running another +script at system startup may result in race condition where configuration +and/or function are not yet available. This script is supposed to wait +for everything being prepared. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate global-wait; + +... and add it to your scheduler, for example in combination with +[bridge-port](bridge-port.md): + + / system scheduler add name=bridge-port-to-default on-event="/ system script { run global-wait; run bridge-port-to-default; }" start-time=startup; + +See also +-------- + +* [Manage ports in bridge](bridge-port.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/global-wait b/global-wait index 29d634d..7e3cc6c 100644 --- a/global-wait +++ b/global-wait @@ -3,6 +3,7 @@ # Copyright (c) 2020 Christian Hesse # # wait for global-functions to finish +# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md :global GlobalFunctionsReady; From cba9352fc425528b36943c4715a9908a5bedc3c4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:45:54 +0100 Subject: [PATCH 0259/2612] add doc/gps-track.md --- doc/gps-track.md | 34 ++++++++++++++++++++++++++++++++++ gps-track | 1 + 2 files changed, 35 insertions(+) create mode 100644 doc/gps-track.md diff --git a/doc/gps-track.md b/doc/gps-track.md new file mode 100644 index 0000000..a7b3d7f --- /dev/null +++ b/doc/gps-track.md @@ -0,0 +1,34 @@ +Send GPS position to server +=========================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script is supposed to run periodically from scheduler and send GPS +position data to a server for tracking. + +A hardware GPS antenna is required. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate gps-track; + +... and create a scheduler: + + / system scheduler add interval=1m name=gps-track on-event="/ system script run gps-track;" start-time=startup; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, the only parameter is: + +* `GpsTrackUrl`: the url to send json data to + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/gps-track b/gps-track index 2513e03..4a27eb8 100644 --- a/gps-track +++ b/gps-track @@ -3,6 +3,7 @@ # Copyright (c) 2018-2020 Christian Hesse # # track gps data by sending json data to http server +# https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md :global GpsTrackUrl; :global Identity; From 39857405d55c37542b3bc3b4dcef6d24c9a2ea62 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:46:08 +0100 Subject: [PATCH 0260/2612] add doc/hotspot-to-wpa.md --- doc/hotspot-to-wpa.md | 48 +++++++++++++++++++++++++++++++++++++++++++ hotspot-to-wpa | 1 + 2 files changed, 49 insertions(+) create mode 100644 doc/hotspot-to-wpa.md diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md new file mode 100644 index 0000000..fbb9640 --- /dev/null +++ b/doc/hotspot-to-wpa.md @@ -0,0 +1,48 @@ +Use WPA2 network with hotspot credentials +========================================= + +[◀ Go back to main README](../README.md) + +Description +----------- + +RouterOS supports an unlimited number of MAC address specific passphrases +for WPA2 encrypted wifi networks via access list. The idea of this script +is to transfer hotspot credentials to MAC address specific WPA2 passphrase. + +Requirements and installation +----------------------------- + +You need a properly configured hotspot on one (open) SSID and a WP2 enabled +SSID with suffix "`-wpa`". + +Then install the script: + + $ScriptInstallUpdate hotspot-to-wpa; + +Configure your hotspot to use this script as `on-login` script: + + / ip hotspot user profile set on-login=hotspot-to-wpa [ find ]; + +Configuration +------------- + +On first run a disabled access list entry acting as marker (with comment +"`--- hotspot-to-wpa above ---`") is added. Move this entry to define where new +entries are to be added. + +Usage and invocation +-------------------- + +Create hotspot login credentials: + + / ip hotspot user add add comment="Test User 1" name=user1 password=v3ry; + / ip hotspot user add add comment="Test User 2" name=user2 password=s3cr3t; + +Now let the users connect and login to the hotspot. After that the devices +(identified by MAC address) can connect to the WPA2 network, using the +passphrase from hotspot credentials. + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/hotspot-to-wpa b/hotspot-to-wpa index f45bd6b..e862e45 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -3,6 +3,7 @@ # Copyright (c) 2019-2020 Christian Hesse # # add private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md :global LogPrintExit; From b20fcaa94d64da64412f44afcca7cd4dabaa6fc0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:46:44 +0100 Subject: [PATCH 0261/2612] add doc/ip-addr-bridge.md --- doc/ip-addr-bridge.md | 32 ++++++++++++++++++++++++++++++++ ip-addr-bridge | 1 + 2 files changed, 33 insertions(+) create mode 100644 doc/ip-addr-bridge.md diff --git a/doc/ip-addr-bridge.md b/doc/ip-addr-bridge.md new file mode 100644 index 0000000..44dac6a --- /dev/null +++ b/doc/ip-addr-bridge.md @@ -0,0 +1,32 @@ +Manage IP addresses with bridge status +====================================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +With RouterOS an IP address is always active, even if an interface is down. +Other venders handle this differently - and sometimes this behavior is +expected. This script mimics this behavior. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate ip-addr-bridge; + +... and make it run from scheduler: + + / system scheduler add name=ip-addr-bridge on-event="/ system script run ip-addr-bridge;" start-time=startup; + +This will disable IP addresses on bridges without at lease one running port. +The IP address is enabled if at least one port is running. + +Note that IP addresses on bridges without a single port (acting as loopback +interface) are ignored. + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/ip-addr-bridge b/ip-addr-bridge index 947e7fe..02781cc 100644 --- a/ip-addr-bridge +++ b/ip-addr-bridge @@ -3,6 +3,7 @@ # Copyright (c) 2018-2020 Christian Hesse # # enable or disable ip addresses based on bridge port state +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ip-addr-bridge.md :foreach Bridge in=[ / interface bridge find ] do={ :local BrName [ / interface bridge get $Bridge name ]; From 024e9c97a1f83a9b0eb09702f558af3ba8e048e3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:47:13 +0100 Subject: [PATCH 0262/2612] add doc/ipv6-update.md --- doc/ipv6-update.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++ ipv6-update | 1 + 2 files changed, 57 insertions(+) create mode 100644 doc/ipv6-update.md diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md new file mode 100644 index 0000000..93ada42 --- /dev/null +++ b/doc/ipv6-update.md @@ -0,0 +1,56 @@ +Update configuration on IPv6 prefix change +========================================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +With changing IPv6 prefix from ISP this script handles to update... + +* ipv6 firewall address-list +* dns records + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate ipv6-update; + +Your ISP needs to provide an IPv6 prefix, your device receives it via dhcp: + + / ipv6 dhcp-client add add-default-route=yes interface=ppp-isp pool-name=isp request=prefix script=ipv6-update; + +Note this already adds this script as `script`. The pool name (here: "`isp`") +is important, we need it later. + +Also this expects there is an address assigned from pool to an interface: + + / ipv6 address add from-pool=isp interface=br-local; + +Sometimes dhcp client is stuck on reconnect and needs to be released. +Installing [ppp-on-up](ppp-on-up.md) may solve this. + +Configuration +------------- + +An address list entry is updated with current prefix and can be used in +firewall rules, comment has to be "`ipv6-pool-`" and actual pool name: + + / ipv6 firewall address-list add address=2003:cf:2f0f:de00::/56 comment=ipv6-pool-isp list=extern; + +Static DNS records need a special comment to be updated. Again it has to +start with "`ipv6-pool-`" and actual pool name, followed by a comma, +"`interface=`" and the name of interface this address is connected to: + + / ip dns static add address=2003:cf:2f0f:de00:1122:3344:5566:7788 comment="ipv6-pool-isp, interface=br-local" name=test.example.com ttl=15m; + +See also +-------- + +* [Run scripts on ppp connection](ppp-on-up.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/ipv6-update b/ipv6-update index baea7c3..4e73b8f 100644 --- a/ipv6-update +++ b/ipv6-update @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # update firewall and dns settings on IPv6 prefix change +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md :local PdPrefix $"pd-prefix"; From e1377cbd927e0bca631c1d904d3172878f307410 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:47:26 +0100 Subject: [PATCH 0263/2612] add doc/lease-script.md --- doc/lease-script.md | 36 ++++++++++++++++++++++++++++++++++++ lease-script | 1 + 2 files changed, 37 insertions(+) create mode 100644 doc/lease-script.md diff --git a/doc/lease-script.md b/doc/lease-script.md new file mode 100644 index 0000000..3c774f1 --- /dev/null +++ b/doc/lease-script.md @@ -0,0 +1,36 @@ +Run other scripts on DHCP lease +=============================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script is supposed to run from dhcp server as lease script. Currently +it does: + +* run [dhcp-to-dns](dhcp-to-dns.md) +* run [collect-wireless-mac](collect-wireless-mac.md) +* run [dhcp-lease-comment](dhcp-lease-comment.md) + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate lease-script; + +... and add it as `lease-script` to your dhcp server: + + / ip dhcp-server set lease-script=lease-script [ find ]; + +See also +-------- + +* [Collect MAC addresses in wireless access list](collect-wireless-mac.md) +* [Comment DHCP leases with info from access list](dhcp-lease-comment.md) +* [Create DNS records for DHCP leases](dhcp-to-dns.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/lease-script b/lease-script index 1e73b31..87c0c90 100644 --- a/lease-script +++ b/lease-script @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # run scripts on DHCP lease +# https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md :global LogPrintExit; From 8c3489761ee7c31fbe01d93b9e648bbc671f6bce Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:47:41 +0100 Subject: [PATCH 0264/2612] add doc/leds-mode.md --- doc/leds-mode.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ leds-day-mode | 1 + leds-night-mode | 1 + leds-toggle-mode | 1 + 4 files changed, 53 insertions(+) create mode 100644 doc/leds-mode.md diff --git a/doc/leds-mode.md b/doc/leds-mode.md new file mode 100644 index 0000000..e0f7cf3 --- /dev/null +++ b/doc/leds-mode.md @@ -0,0 +1,50 @@ +Manage LEDs dark mode +===================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +These scripts control LEDs mode and allow to run your device +completely dark. Hardware support for dark mode is required. + +Requirements and installation +----------------------------- + +Just install the scripts: + + $ScriptInstallUpdate leds-day-mode,leds-night-mode,leds-toggle-mode; + +Usage and invocation +-------------------- + +To switch the device to dark mode: + + / system script run leds-night-mode; + +... and back to normal mode: + + / system script run leds-day-mode; + +To toggle between the two modes: + + / system script run leds-toggle-mode; + +Add these schedulers to switch to dark mode in the evening and back to +normal mode in the morning: + + / system scheduler add interval=1d name=leds-day-mode on-event="/ system script run leds-day-mode;" start-time=07:00:00; + / system scheduler add interval=1d name=leds-night-mode on-event="/ system script run leds-night-mode;" start-time=21:00:00; + +The script `leds-toggle-mode` can be used from [mode button](mode-button.md) +to toggle mode. + +See also +-------- + +* [Mode botton with multiple presses](mode-button.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/leds-day-mode b/leds-day-mode index 0b50648..cd59bab 100644 --- a/leds-day-mode +++ b/leds-day-mode @@ -3,5 +3,6 @@ # Copyright (c) 2013-2020 Christian Hesse # # enable LEDs +# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md / system leds settings set all-leds-off=never; diff --git a/leds-night-mode b/leds-night-mode index 6a973e4..9048a83 100644 --- a/leds-night-mode +++ b/leds-night-mode @@ -3,5 +3,6 @@ # Copyright (c) 2013-2020 Christian Hesse # # disable LEDs +# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md / system leds settings set all-leds-off=immediate; diff --git a/leds-toggle-mode b/leds-toggle-mode index 7518ef4..5f67979 100644 --- a/leds-toggle-mode +++ b/leds-toggle-mode @@ -3,6 +3,7 @@ # Copyright (c) 2018-2020 Christian Hesse # # toggle LEDs mode +# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md :if ([ / system leds settings get all-leds-off ] = "never") do={ / system leds settings set all-leds-off=immediate; From 5594ffd69afb9b72e73a62103cd657d51d4b0366 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:48:25 +0100 Subject: [PATCH 0265/2612] add doc/mode-button.md --- doc/mode-button.md | 40 ++++++++++++++++++++++++++++++++++++++++ mode-button-event | 1 + mode-button-scheduler | 1 + 3 files changed, 42 insertions(+) create mode 100644 doc/mode-button.md diff --git a/doc/mode-button.md b/doc/mode-button.md new file mode 100644 index 0000000..5018d6e --- /dev/null +++ b/doc/mode-button.md @@ -0,0 +1,40 @@ +Mode botton with multiple presses +================================= + +[◀ Go back to main README](../README.md) + +Description +----------- + +These scripts extend the functionality of mode button. Instead of just one +you can trigger several actions by pressing the mode button several times. + +The hardware needs to have a mode button, see +`/ system routerboard mode-button`. + +Requirements and installation +----------------------------- + +Just install the scripts: + + $ScriptInstallUpdate mode-button-event,mode-button-scheduler; + +Then configure the mode-button to run `mode-button-event`: + + / system routerboard mode-button set enabled=yes on-event="/ system script run mode-button-event;"; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, the only parameter is: + +* `ModeButton`: an array with defined actions + +Usage and invocation +-------------------- + +Press the mode button. :) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/mode-button-event b/mode-button-event index 91b0edb..4768e09 100644 --- a/mode-button-event +++ b/mode-button-event @@ -3,6 +3,7 @@ # Copyright (c) 2018-2020 Christian Hesse # # run on mode-button event and count button presses +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md :global ModeButton; diff --git a/mode-button-scheduler b/mode-button-scheduler index 2b6f083..03f673b 100644 --- a/mode-button-scheduler +++ b/mode-button-scheduler @@ -3,6 +3,7 @@ # Copyright (c) 2018-2020 Christian Hesse # # act on multiple mode-botton presses from scheduler +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md :global ModeButton; From f482c565c79e9413e45806dc4043ea4d6e1859a9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:48:52 +0100 Subject: [PATCH 0266/2612] add doc/netwatch-notify.md --- doc/netwatch-notify.md | 36 ++++++++++++++++++++++++++++++++++++ netwatch-notify | 1 + 2 files changed, 37 insertions(+) create mode 100644 doc/netwatch-notify.md diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md new file mode 100644 index 0000000..51768ff --- /dev/null +++ b/doc/netwatch-notify.md @@ -0,0 +1,36 @@ +Notify on host up and down +========================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script sends notifications about host UP and DOWN events. In comparison +to just netwatch (`/ tool netwatch`) and its `up-script` and `down-script` +this script implements a simple state machine. Host down events are triggered +only if the host is down for several checks to avoid false alerts. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate netwatch-notify; + +Then add a scheduler to run it periodically: + + / system scheduler add interval=1m name=netwatch-notify on-event="/ system script run netwatch-notify;" start-time=startup; + +Configuration +------------- + +The hosts to be checked have to be added to netwatch with specific comment: + + / tool netwatch add comment="notify, hostname=example.com" host=[ :resolve "example.com" ] timeout=5s; + +Also notification settings are required for e-mail and telegram. + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/netwatch-notify b/netwatch-notify index 5b47e3b..dca8304 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -3,6 +3,7 @@ # Copyright (c) 2020 Christian Hesse # # monitor netwatch and send notifications +# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md :global NetwatchNotify; From 222fe8fd54c6cfa9b4a3d0cd545178659f331bfe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:49:03 +0100 Subject: [PATCH 0267/2612] add doc/netwatch-syslog.md --- doc/netwatch-syslog.md | 34 ++++++++++++++++++++++++++++++++++ netwatch-syslog | 1 + 2 files changed, 35 insertions(+) create mode 100644 doc/netwatch-syslog.md diff --git a/doc/netwatch-syslog.md b/doc/netwatch-syslog.md new file mode 100644 index 0000000..9a28bb9 --- /dev/null +++ b/doc/netwatch-syslog.md @@ -0,0 +1,34 @@ +Manage remote logging +===================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +RouterOS supports sending log messages via network to a remote syslog server. +If the server is not available no log messages (with potentially sensitive +information) should be sent. This script disables remote logging by +availability. + +Requirements and installation +----------------------------- + +Let's assume there is a remote log action and associated logging rule: + + / system logging action set remote=10.0.0.1 [ find where name="remote" ]; + / system logging add action=remote topics=info; + +Just install the script: + + $ScriptInstallUpdate netwatch-syslog; + +... and create a netwatch matching the IP address from logging action above: + + / tool netwatch add down-script=netwatch-syslog host=10.0.0.1 up-script=netwatch-syslog; + +All logging rules are disabled when host is down. + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/netwatch-syslog b/netwatch-syslog index b76d31d..81ef4d5 100644 --- a/netwatch-syslog +++ b/netwatch-syslog @@ -5,6 +5,7 @@ # requires: dont-require-permissions=yes # # manage remote logging facilities +# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-syslog.md :local Remote [ /system logging action get ([ find where target=remote ]->0) remote ]; From d075cce0efa8a9998e1a95c1bbe3be2462b6820d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:49:17 +0100 Subject: [PATCH 0268/2612] add doc/packages-update.md --- doc/packages-update.md | 46 ++++++++++++++++++++++++++++++++++++++++++ packages-update | 1 + 2 files changed, 47 insertions(+) create mode 100644 doc/packages-update.md diff --git a/doc/packages-update.md b/doc/packages-update.md new file mode 100644 index 0000000..882ce80 --- /dev/null +++ b/doc/packages-update.md @@ -0,0 +1,46 @@ +Manage system update +==================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +In rare cases RouterOS fails to properly downlaod package on update +(`/ system package update install`), resulting in borked system with missing +packages. This script tries to avoid this situation by doing some basic +verification. + +But it provides some extra functionality: + +* send backup via e-mail if [email-backup](email-backup.md) is installed +* upload backup if [upload-backup](upload-backup.md) is installed +* schedule reboot at night + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate packages-update; + +It is automatically run by [check-routeros-update](check-routeros-update.md) +if available. + +Usage and invocation +-------------------- + +Alternatively run it manually: + + / system script run packages-update; + +See also +-------- + +* [Notify on RouterOS update](check-routeros-update.md) +* [Send backup via e-mail](email-backup.md) +* [Upload backup to server](upload-backup.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/packages-update b/packages-update index 5baa78b..9158c08 100644 --- a/packages-update +++ b/packages-update @@ -3,6 +3,7 @@ # Copyright (c) 2019-2020 Christian Hesse # # download packages and reboot for installation +# https://git.eworm.de/cgit/routeros-scripts/about/doc/packages-update.md :global DownloadPackage; :global LogPrintExit; From 15995b495fb026584573edf8778ae533c1fce62d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:49:36 +0100 Subject: [PATCH 0269/2612] add doc/ppp-on-up.md --- doc/ppp-on-up.md | 34 ++++++++++++++++++++++++++++++++++ ppp-on-up | 1 + 2 files changed, 35 insertions(+) create mode 100644 doc/ppp-on-up.md diff --git a/doc/ppp-on-up.md b/doc/ppp-on-up.md new file mode 100644 index 0000000..432a640 --- /dev/null +++ b/doc/ppp-on-up.md @@ -0,0 +1,34 @@ +Run scripts on ppp connection +============================= + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script is supposed to run on established ppp connection. Currently +it does: + +* release IPv6 dhcp leases (and thus force a renew) +* run [update-tunnelbroker](update-tunnelbroker.md) + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate ppp-on-up; + +... and make it the `on-up` script for ppp profile: + + / ppp profile set on-up=ppp-on-up [ find ]; + +See also +-------- + +* [Update configuration on IPv6 prefix change](ipv6-update.md) +* [Update tunnelbroker configuration](update-tunnelbroker.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/ppp-on-up b/ppp-on-up index 48d3413..18229eb 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # run scripts on ppp up +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md :global LogPrintExit; From 747af21bea685d75ea524c97fcb6e8d44b466c86 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:49:51 +0100 Subject: [PATCH 0270/2612] add doc/rotate-ntp.md --- doc/rotate-ntp.md | 40 ++++++++++++++++++++++++++++++++++++++++ rotate-ntp | 1 + 2 files changed, 41 insertions(+) create mode 100644 doc/rotate-ntp.md diff --git a/doc/rotate-ntp.md b/doc/rotate-ntp.md new file mode 100644 index 0000000..eb04f5c --- /dev/null +++ b/doc/rotate-ntp.md @@ -0,0 +1,40 @@ +Rotate NTP servers +================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +RouterOS requires NTP servers to be configured by IP address. Servers from a +pool may appear and disappear, leaving broken NTP configuration. + +This script allows to rotate IP addresses from a given pool. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate rotate-ntp; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, this is the parameter: + +* `NtpPool`: dns name of ntp server pool + +Usage and invocation +-------------------- + +Just run the script to update the NTP configuration with actual IP +addresses from pool if required. + +Alternatively a scheduler can be created: + + / system scheduler add interval=5d name=rotate-ntp on-event="/ system script run rotate-ntp;" start-time=startup; + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/rotate-ntp b/rotate-ntp index 534f400..e0c1999 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # rotate the ntp servers +# https://git.eworm.de/cgit/routeros-scripts/about/doc/rotate-ntp.md :global NtpPool; From ed2718da2a7beb6b1b1936681c531ec71612320f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:50:18 +0100 Subject: [PATCH 0271/2612] add doc/sms-action.md --- doc/sms-action.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++ sms-action | 1 + 2 files changed, 50 insertions(+) create mode 100644 doc/sms-action.md diff --git a/doc/sms-action.md b/doc/sms-action.md new file mode 100644 index 0000000..df9e14f --- /dev/null +++ b/doc/sms-action.md @@ -0,0 +1,49 @@ +Act on received SMS +=================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +RouterOS can act on received SMS. Reboot the device from remote or do +whatever is required. + +A broadband interface with SMS support is required. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate sms-action; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, this is the only parameter: + +* `SmsAction`: an array with pre-defined actions + +Then enable SMS actions: + + / tool sms set allowed-number=+491234567890 receive-enabled=yes secret=s3cr3t; + +Usage and invocation +-------------------- + +Send a SMS from allowed number to your device's phone number: + + :cmd s3cr3t script sms-action action=reboot; + +The value given by "`action=`" is one of the pre-defined actions from +`SmsAction`. + +See also +-------- + +* [Forward received SMS](sms-forward.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/sms-action b/sms-action index 4442baf..2384167 100644 --- a/sms-action +++ b/sms-action @@ -3,6 +3,7 @@ # Copyright (c) 2018-2020 Christian Hesse # # run action on received SMS +# https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-action.md :global SmsAction; From e8bc0a7169df0d0995675aa86c1a84f7ebbb10f9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:50:27 +0100 Subject: [PATCH 0272/2612] add doc/sms-forward.md --- doc/sms-forward.md | 36 ++++++++++++++++++++++++++++++++++++ sms-forward | 1 + 2 files changed, 37 insertions(+) create mode 100644 doc/sms-forward.md diff --git a/doc/sms-forward.md b/doc/sms-forward.md new file mode 100644 index 0000000..28fc39b --- /dev/null +++ b/doc/sms-forward.md @@ -0,0 +1,36 @@ +Forward received SMS +==================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +RouterOS can receive SMS. This script forwards SMS as notification. + +A broadband interface with SMS support is required. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate sms-forward; + +... and add a scheduler to run it periodically: + + / system scheduler add interval=2m name=sms-forward on-event="/ system script run sms-forward;" start-time=startup; + +Configuration +------------- + +Notification settings are required for e-mail and telegram. + +See also +-------- + +* [Act on received SMS](sms-action.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/sms-forward b/sms-forward index 2ace48d..2045196 100644 --- a/sms-forward +++ b/sms-forward @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # forward SMS to e-mail +# https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md :global Identity; From 997ef3bf2379c1526e39544067c8257d5e999b14 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:50:53 +0100 Subject: [PATCH 0273/2612] add doc/ssh-keys-import.md --- doc/ssh-keys-import.md | 33 +++++++++++++++++++++++++++++++++ ssh-keys-import | 9 ++++----- 2 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 doc/ssh-keys-import.md diff --git a/doc/ssh-keys-import.md b/doc/ssh-keys-import.md new file mode 100644 index 0000000..d221072 --- /dev/null +++ b/doc/ssh-keys-import.md @@ -0,0 +1,33 @@ +Import SSH keys +=============== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script imports public SSH keys (files with extension "`pub`") into +local store for user authentication. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate ssh-keys-import; + +Usage and invocation +-------------------- + +Copy files with extension "`pub`" containing public SSH keys for your device. +Then run the script: + + / system script run ssh-keys-import; + +Starting with an `authorized_keys` file you can split it on a shell: + + while read type key name; do echo $type $key $name > $name.pub; done < authorized_keys + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/ssh-keys-import b/ssh-keys-import index da933ce..9be92d1 100644 --- a/ssh-keys-import +++ b/ssh-keys-import @@ -3,9 +3,8 @@ # Copyright (c) 2013-2020 Christian Hesse # # import ssh keys from file +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ssh-keys-import.md -# Split files with several keys from a shell... -# while read type key name; do echo $type $key $name > $name.pub; done < keys.pub -# ... then transfer with scp/sftp. - -:foreach Key in=[ / file find where type="ssh key" ] do={ / user ssh-key import user=admin public-key-file=[ / file get $Key name ]; } +:foreach Key in=[ / file find where type="ssh key" ] do={ + / user ssh-key import user=admin public-key-file=[ / file get $Key name ]; +} From 1e5784225a5034713dae8bea8fe8db1572b8bfc1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:51:03 +0100 Subject: [PATCH 0274/2612] add doc/super-mario-theme.md --- doc/super-mario-theme.md | 31 +++++++++++++++++++++++++++++++ super-mario-theme | 1 + 2 files changed, 32 insertions(+) create mode 100644 doc/super-mario-theme.md diff --git a/doc/super-mario-theme.md b/doc/super-mario-theme.md new file mode 100644 index 0000000..68484dc --- /dev/null +++ b/doc/super-mario-theme.md @@ -0,0 +1,31 @@ +Play Super Mario theme +====================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script plays Super Mario theme. + +The hardware needs a beeper. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate super-mario-theme; + +Usage and invocation +-------------------- + +Just run the script to play: + + / system script run super-mario-theme; + +For extra fun use it for dhcp lease script. :) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/super-mario-theme b/super-mario-theme index 671abc5..a7bcb39 100644 --- a/super-mario-theme +++ b/super-mario-theme @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # play Super Mario theme +# https://git.eworm.de/cgit/routeros-scripts/about/doc/super-mario-theme.md :local Beeps { { 660; 100 }; 150; { 660; 100 }; 300; { 660; 100 }; 300; From f45dbb3a7323a40cf8b8d5b5945bcdc3e80d6286 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:51:21 +0100 Subject: [PATCH 0275/2612] add doc/unattended-lte-firmware-upgrade.md --- doc/unattended-lte-firmware-upgrade.md | 42 ++++++++++++++++++++++++++ unattended-lte-firmware-upgrade | 1 + 2 files changed, 43 insertions(+) create mode 100644 doc/unattended-lte-firmware-upgrade.md diff --git a/doc/unattended-lte-firmware-upgrade.md b/doc/unattended-lte-firmware-upgrade.md new file mode 100644 index 0000000..68c74a1 --- /dev/null +++ b/doc/unattended-lte-firmware-upgrade.md @@ -0,0 +1,42 @@ +Install LTE firmware upgrade +============================ + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script upgrades LTE firmware on compatible devices: + +* R11e-LTE +* R11e-LTE-US +* R11e-4G +* R11e-LTE6 + +A temporary scheduler is created to be independent from terminal. Thus +starting the upgrade process over the broadband connection is supported. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate unattended-lte-firmware-upgrade; + +Usage and invocation +-------------------- + +Run the script if an upgrade for your LTE hardware is available: + + / system script run unattended-lte-firmware-upgrade; + +Then be patient, go for a coffee and wait for the upgrade process to finish. + +See also +-------- + +* [Notify on LTE firmware upgrade](check-lte-firmware-upgrade.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index a0b297e..e54c9fb 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -3,6 +3,7 @@ # Copyright (c) 2018-2020 Christian Hesse # # schedule unattended lte firmware upgrade +# https://git.eworm.de/cgit/routeros-scripts/about/doc/unattended-lte-firmware-upgrade.md :foreach Interface in=[ / interface lte find ] do={ :local Firmware; From a2b009502fb04d8e9421bd11b28903ac0ba05eb4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:51:40 +0100 Subject: [PATCH 0276/2612] add doc/update-gre-address.md --- doc/update-gre-address.md | 38 ++++++++++++++++++++++++++++++++++++++ update-gre-address | 1 + 2 files changed, 39 insertions(+) create mode 100644 doc/update-gre-address.md diff --git a/doc/update-gre-address.md b/doc/update-gre-address.md new file mode 100644 index 0000000..870759e --- /dev/null +++ b/doc/update-gre-address.md @@ -0,0 +1,38 @@ +Update GRE configuration with dynamic addresses +=============================================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +Running a GRE tunnel over IPSec with IKEv2 is a common scenario. This is +easy to configure on client, but has an issue on server side: client IP +addresses are assigned dynamically via mode-config and have to be updated +for GRE interface. + +This script handles the address updates and disables the interface if the +client is disconnected. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate update-gre-address; + +... and add a scheduler to run the script periodically: + + / system scheduler add interval=30s name=update-gre-address on-event="/ system script run update-gre-address;" start-time=startup; + +Configuration +------------- + +The configuration goes to interface's comment. Add the client's IKEv2 +certificate CN into the comment: + + / interface gre set comment="ikev2-client1" gre-client1; + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/update-gre-address b/update-gre-address index fcd0183..8ede500 100644 --- a/update-gre-address +++ b/update-gre-address @@ -4,6 +4,7 @@ # # update gre interface remote address with dynamic address from # ipsec remote peer +# https://git.eworm.de/cgit/routeros-scripts/about/doc/update-gre-address.md / interface gre set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; From 3f6539da4c1a2fe29ea5c684af37bcda8b7c8652 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:52:02 +0100 Subject: [PATCH 0277/2612] add doc/update-tunnelbroker.md --- doc/update-tunnelbroker.md | 41 ++++++++++++++++++++++++++++++++++++++ update-tunnelbroker | 3 +++ 2 files changed, 44 insertions(+) create mode 100644 doc/update-tunnelbroker.md diff --git a/doc/update-tunnelbroker.md b/doc/update-tunnelbroker.md new file mode 100644 index 0000000..3641588 --- /dev/null +++ b/doc/update-tunnelbroker.md @@ -0,0 +1,41 @@ +Update tunnelbroker configuration +================================= + +[◀ Go back to main README](../README.md) + +Description +----------- + +Connecting to [tunnelbroker.net](//tunnelbroker.net) from dynamic public +ip address requires the address to be sent to the remote, and to be set +locally. This script does both. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate update-tunnelbroker; + +Installing [ppp-on-up](ppp-on-up.md) makes this script run when ever a ppp +connection is established. + +Configuration +------------- + +The configuration goes to interface's comment: + + / interface 6to4 set comment="tunnelbroker, user=user, pass=s3cr3t, id=12345" tunnelbroker; + +Also enabling dynamic DNS in Mikrotik cloud is required: + + / ip cloud set ddns-enabled=yes; + +See also +-------- + +* [Run scripts on ppp connection](ppp-on-up.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/update-tunnelbroker b/update-tunnelbroker index 3aed610..1b5bb9e 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -2,6 +2,9 @@ # RouterOS script: update-tunnelbroker # Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers +# +# update local address of tunnelbroker interface +# https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md :global CertificateAvailable; :global LogPrintExit; From c32a727b6e4a47058c6c37442ce54e93b2623e02 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:52:17 +0100 Subject: [PATCH 0278/2612] add doc/upload-backup.md --- doc/upload-backup.md | 62 ++++++++++++++++++++++++++++++++++++++++++++ upload-backup | 1 + 2 files changed, 63 insertions(+) create mode 100644 doc/upload-backup.md diff --git a/doc/upload-backup.md b/doc/upload-backup.md new file mode 100644 index 0000000..bbfbcc4 --- /dev/null +++ b/doc/upload-backup.md @@ -0,0 +1,62 @@ +Upload backup to server +======================= + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script uploads binary backup (`/ system backup save`) and complete +configuration export (`/ export terse`) to external server. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate upload-backup; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, these are the parameters: + +* `BackupSendBinary`: whether to send binary backup +* `BackupSendExport`: whether to send configuration export +* `BackupPassword`: password to encrypt the backup with +* `BackupUploadUrl`: url to upload to +* `BackupUploadUser`: username for server authentication +* `BackupUploadPass`: password for server authentication + +Also notification settings are required for e-mail and telegram. + +### Issues with SFTP client + +The RouterOS SFTP client is picky if it comes to authentication methods. +I had to disable all but password authentication on server side. For openssh +edit `/etc/ssh/sshd_config` and add a directive like this, changed for your +needs: + + Match User mikrotik + AuthenticationMethods password + +Usage and invocation +-------------------- + +Just run the script: + + / system script run upload-backup; + +Creating a scheduler may be an option: + + / system scheduler add interval=1w name=upload-backup on-event="/ system script run upload-backup;" start-time=09:25:00; + +See also +-------- + +* [Send backup via e-mail](email-backup.md) +* [Upload backup to Mikrotik cloud](cloud-backup.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/upload-backup b/upload-backup index 16c6bd8..3473884 100644 --- a/upload-backup +++ b/upload-backup @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # create and upload backup and config file +# https://git.eworm.de/cgit/routeros-scripts/about/doc/upload-backup.md :global BackupPassword; :global BackupSendBinary; From 070ae8ecb5d1eb814793ecd3015835cd37c507cd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:54:00 +0100 Subject: [PATCH 0279/2612] link global-{config,config-overlay,functions} to main README --- global-config | 1 + global-config-overlay | 1 + global-functions | 1 + 3 files changed, 3 insertions(+) diff --git a/global-config b/global-config index 1ad8393..87f534b 100644 --- a/global-config +++ b/global-config @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # global configuration +# https://git.eworm.de/cgit/routeros-scripts/about/ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! diff --git a/global-config-overlay b/global-config-overlay index 90740cd..afe0dc4 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -3,6 +3,7 @@ # Copyright (c) 2013-2020 Christian Hesse # # global configuration, custom overlay +# https://git.eworm.de/cgit/routeros-scripts/about/ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! diff --git a/global-functions b/global-functions index 1aa64d2..e98491c 100644 --- a/global-functions +++ b/global-functions @@ -4,6 +4,7 @@ # Michael Gisbers # # global functions +# https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version :global ExpectedConfigVersion 14; From c6389f5d2c6cda949abde1bcbe6d3b80eaf58832 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:54:59 +0100 Subject: [PATCH 0280/2612] README: add section 'Available Scripts' and link documentation --- README.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/README.md b/README.md index 6204ee9..42af97d 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,50 @@ cleanup add a scheduler entry. There's much more to explore... Have fun! +Available Scripts +----------------- + +* [Find and remove access list duplicates](doc/accesslist-duplicates.md) +* [Manage ports in bridge](doc/bridge-port.md) +* [Download packages for CAP upgrade from CAPsMAN](doc/capsman-download-packages.md) +* [Run rolling CAP upgrades from CAPsMAN](doc/capsman-rolling-upgrade.md) +* [Renew locally issued certificates](doc/certificate-renew-issued.md) +* [Renew certificates and notify on expiration](doc/check-certificates.md) +* [Notify about health state](doc/check-health.md) +* [Notify on LTE firmware upgrade](doc/check-lte-firmware-upgrade.md) +* [Notify on RouterOS update](doc/check-routeros-update.md) +* [Upload backup to Mikrotik cloud](doc/cloud-backup.md) +* [Collect MAC addresses in wireless access list](doc/collect-wireless-mac.md) +* [Use wireless network with daily psk](doc/daily-psk.md) +* [Comment DHCP leases with info from access list](doc/dhcp-lease-comment.md) +* [Create DNS records for DHCP leases](doc/dhcp-to-dns.md) +* [Send backup via e-mail](doc/email-backup.md) +* [Wait for configuration und functions](doc/global-wait.md) +* [Send GPS position to server](doc/gps-track.md) +* [Use WPA2 network with hotspot credentials](doc/hotspot-to-wpa.md) +* [Update configuration on IPv6 prefix change](doc/ipv6-update.md) +* [Manage IP addresses with bridge status](doc/ip-addr-bridge.md) +* [Run other scripts on DHCP lease](doc/lease-script.md) +* [Manage LEDs dark mode](doc/leds-mode.md) +* [Mode botton with multiple presses](doc/mode-button.md) +* [Notify on host up and down](doc/netwatch-notify.md) +* [Manage remote logging](doc/netwatch-syslog.md) +* [Manage system update](doc/packages-update.md) +* [Run scripts on ppp connection](doc/ppp-on-up.md) +* [Rotate NTP servers](doc/rotate-ntp.md) +* [Act on received SMS](doc/sms-action.md) +* [Forward received SMS](doc/sms-forward.md) +* [Import SSH keys](doc/ssh-keys-import.md) +* [Play Super Mario theme](doc/super-mario-theme.md) +* [Install LTE firmware upgrade](doc/unattended-lte-firmware-upgrade.md) +* [Update GRE configuration with dynamic addresses](doc/update-gre-address.md) +* [Update tunnelbroker configuration](doc/update-tunnelbroker.md) +* [Upload backup to server](doc/upload-backup.md) + +[comment]: # (TODO: currently undocumented) +[comment]: # (* learn-mac-based-vlan) +[comment]: # (* manage-umts) + Contribute ---------- From 1d93e92dcda753b855e89295f74dafae4743bb80 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 21:57:12 +0100 Subject: [PATCH 0281/2612] Notify about new documentation! --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 87f534b..d8c4fc4 100644 --- a/global-config +++ b/global-config @@ -7,7 +7,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 14; +:global GlobalConfigVersion 15; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index afe0dc4..1e5234b 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 14; +:global GlobalConfigVersion 15; # The global-config script is updated by $ScriptInstallUpdate, # global-config-overlay becomes an overlay for your changes. diff --git a/global-config.changes b/global-config.changes index 7bd3c9f..c683262 100644 --- a/global-config.changes +++ b/global-config.changes @@ -17,4 +17,5 @@ 12="Removed '\$ScriptUpdatesConfigChangesIgnore', comment '\$GlobalConfigVersion' in 'global-config-overlay' to disable change notifications"; 13="Configuration for script 'bridge-port-to-default' changed with new syntax in comment"; 14="Dropped script 'script-updates', use '\$ScriptInstallUpdate' exclusively!"; + 15="New documentation is online! https://git.eworm.de/cgit/routeros-scripts/about/#available-scripts"; }; diff --git a/global-functions b/global-functions index e98491c..cdcba33 100644 --- a/global-functions +++ b/global-functions @@ -7,7 +7,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 14; +:global ExpectedConfigVersion 15; # global variables not to be changed by user :global GlobalFunctionsReady false; From 2363f75e7fb96852e1122d16f664552a05d8c1d1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Mar 2020 22:19:33 +0100 Subject: [PATCH 0282/2612] ask for GitHub and GitLab stars --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index d8c4fc4..d42a5d1 100644 --- a/global-config +++ b/global-config @@ -7,7 +7,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 15; +:global GlobalConfigVersion 16; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 1e5234b..5bb91a9 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 15; +:global GlobalConfigVersion 16; # The global-config script is updated by $ScriptInstallUpdate, # global-config-overlay becomes an overlay for your changes. diff --git a/global-config.changes b/global-config.changes index c683262..9d7ec00 100644 --- a/global-config.changes +++ b/global-config.changes @@ -18,4 +18,5 @@ 13="Configuration for script 'bridge-port-to-default' changed with new syntax in comment"; 14="Dropped script 'script-updates', use '\$ScriptInstallUpdate' exclusively!"; 15="New documentation is online! https://git.eworm.de/cgit/routeros-scripts/about/#available-scripts"; + 16="Happy with RouterOS Scripts and have a GitHub and/or GitLab account? Please star!"; }; diff --git a/global-functions b/global-functions index cdcba33..8ee84f8 100644 --- a/global-functions +++ b/global-functions @@ -7,7 +7,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 15; +:global ExpectedConfigVersion 16; # global variables not to be changed by user :global GlobalFunctionsReady false; From cc69e5ada755b8f695685655dcf4a959902c891b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 30 Mar 2020 16:18:47 +0200 Subject: [PATCH 0283/2612] add GitHub batches from shields.io https://shields.io/category/social --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 42af97d..a604a72 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ RouterOS Scripts ================ +![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?style=social) +![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?style=social) +![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?style=social) + [RouterOS](https://mikrotik.com/software) is the operating system developed by [MikroTik](https://mikrotik.com/aboutus) for networking tasks. This repository holds a number of [scripts](https://wiki.mikrotik.com/wiki/Manual:Scripting) From 4d0b3b078020845dab4a79452988874d269c7432 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 30 Mar 2020 16:30:25 +0200 Subject: [PATCH 0284/2612] add links GitHub batches --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a604a72..63a8d77 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ RouterOS Scripts ================ -![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?style=social) -![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?style=social) -![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?style=social) +[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/network) +[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/stargazers) +[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/watchers) [RouterOS](https://mikrotik.com/software) is the operating system developed by [MikroTik](https://mikrotik.com/aboutus) for networking tasks. This From 04460debfc11dbb88c9a86c56a76053edf9fe71f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 31 Mar 2020 12:51:37 +0200 Subject: [PATCH 0285/2612] script-updates: fix syntax error --- script-updates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script-updates b/script-updates index 7604cb4..1da4987 100644 --- a/script-updates +++ b/script-updates @@ -3,4 +3,4 @@ :global LogPrintExit; -$LogPrintExit warning "This script has been replaced by function '\$ScriptInstallUpdate'." true; +$LogPrintExit warning ("This script has been replaced by function '\$ScriptInstallUpdate'.") true; From e33b4af43396fbe542db11494dbd8053aad9c6c8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 31 Mar 2020 12:58:13 +0200 Subject: [PATCH 0286/2612] global-functions: $ScriptInstallUpdate: ignore empty scripts Now that script-updates is gone we support installing new scripts with $ScriptInstallUpdate only. --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 8ee84f8..cc4f1b9 100644 --- a/global-functions +++ b/global-functions @@ -399,7 +399,7 @@ } } - :foreach Script in=[ / system script find where source~"^#!rsc" or source="" ] do={ + :foreach Script in=[ / system script find where source~"^#!rsc" ] do={ :local Ignore 0; :local ScriptVal [ / system script get $Script ]; :local ScriptFile [ / file find where name=("script-updates/" . $ScriptVal->"name") ]; From 40970fb738ffe932bd8cad92e4cd62c0f19dc2f3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 31 Mar 2020 13:34:30 +0200 Subject: [PATCH 0287/2612] global-functions: $SendEMail: always return a value ... overwise it opens a prompt "value:". --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index cc4f1b9..9655255 100644 --- a/global-functions +++ b/global-functions @@ -540,7 +540,7 @@ :global EmailGeneralCc; :if ([ :len $EmailGeneralTo ] = 0) do={ - :return; + :return false; } :do { From a598cca2da4ed77e597912f8c1a0287e6d6dbcac Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 31 Mar 2020 13:35:59 +0200 Subject: [PATCH 0288/2612] global-functions: $SendTelegram: always return a value ... overwise it opens a prompt "value:". --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 9655255..0692d70 100644 --- a/global-functions +++ b/global-functions @@ -591,7 +591,7 @@ } :if ([ :len $TelegramTokenId ] = 0 || [ :len $ChatId ] = 0) do={ - :return; + :return false; } $CertificateAvailable "Go Daddy Secure Certificate Authority - G2"; From da581dedbf636a1c9e7d4b3b94be86cc357d58c0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 31 Mar 2020 14:34:01 +0200 Subject: [PATCH 0289/2612] add navigation links for initial commands page --- CONTRIBUTIONS.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 0c63f8e..a15a72a 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -1,6 +1,8 @@ Past Contributions ================== +[◀ Go back to main README](README.md) + Thanks a lot for your contributions! ## Patches @@ -18,3 +20,7 @@ Add yourself to the list, * Linux-Schmie.de Michael Gisbers * Christoph Boss (@Kampfwurst) * Klaus Michael RÃŧbsam + +--- +[◀ Go back to main README](README.md) +[▲ Go back to top](#top) From afd33b8e257f9f9b9b666e912504525f04d48d63 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Apr 2020 11:38:25 +0200 Subject: [PATCH 0290/2612] global-functions: $ScriptInstallUpdate: log and print changes --- global-functions | 2 ++ 1 file changed, 2 insertions(+) diff --git a/global-functions b/global-functions index 0692d70..2673d2e 100644 --- a/global-functions +++ b/global-functions @@ -482,6 +482,7 @@ " is out of date. Please update " . $ConfigScript . ", then increase " . \ "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \ ") to " . $ExpectedConfigVersion . " and re-run " . $ConfigScript . "."); + $LogPrintExit info ($NotificationMessage) false; $LogPrintExit debug ("Fetching changelog.") false; :do { @@ -496,6 +497,7 @@ :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ :set NotificationMessage ($NotificationMessage . \ "\n * " . $GlobalConfigChanges->[ :tostr $I ]); + $LogPrintExit info ("Change: " . $GlobalConfigChanges->[ :tostr $I ]) false; } :set GlobalConfigChanges; } on-error={ From c1c8d46dc09af17b33e60c370ea620270e78b8f8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 14:12:09 +0200 Subject: [PATCH 0291/2612] check-certificates: check and download certificate chain --- check-certificates | 3 +++ 1 file changed, 3 insertions(+) diff --git a/check-certificates b/check-certificates index b9c9075..ad19059 100644 --- a/check-certificates +++ b/check-certificates @@ -9,6 +9,7 @@ :global CertRenewUrl; :global Identity; +:global CertificateAvailable :global CertificateNameByCN; :global LogPrintExit; :global ParseKeyValueStore; @@ -56,6 +57,8 @@ :local CertNew [ / certificate find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>3w ]; :local CertNewVal [ / certificate get $CertNew ]; + $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN"); + :if ($Cert != $CertNew) do={ $LogPrintExit debug ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; From dfeaa1ed41765610295c03fe11ee47b7c3658147 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 14:24:24 +0200 Subject: [PATCH 0292/2612] global-functions: $Certificate{Available,Download}: return and check status --- global-functions | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 2673d2e..bcc35f5 100644 --- a/global-functions +++ b/global-functions @@ -57,7 +57,9 @@ :if ([ / certificate print count-only where common-name=$CommonName ] = 0) do={ :log info ("Certificate with CommonName \"" . $CommonName . "\" not available."); - $CertificateDownload $CommonName; + :if ([ $CertificateDownload $CommonName ] = false) do={ + :return false; + } } :local CertVal; @@ -65,11 +67,14 @@ :do { :if ([ / certificate print count-only where common-name=$Issuer ] = 0) do={ :log info ("Certificate chain for \"" . $CommonName . "\" is incomplete, missing \"" . $Issuer . "\"."); - $CertificateDownload $CommonName; + :if ([ $CertificateDownload $CommonName ] = false) do={ + :return false; + } } :set CertVal [ / certificate get [ find where common-name=$Issuer ] ]; :set Issuer ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN"); } while=($Issuer != $CertVal->"common-name"); + :return true; } # download and import certificate @@ -101,7 +106,9 @@ } } on-error={ :log warning "Failed imprting certificate!"; + :return false; } + :return true; } # name a certificate by its common-name From a304a2fa69f68aa1c05058edc6d9569b054b5ddc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 14:29:31 +0200 Subject: [PATCH 0293/2612] update-tunnelbroker: check status of certificate download Also use $LogPrintExit... --- update-tunnelbroker | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/update-tunnelbroker b/update-tunnelbroker index 1b5bb9e..2f7d579 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -27,13 +27,15 @@ :if ($PublicAddress != $InterfaceVal->"local-address") do={ :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; - $CertificateAvailable "Starfield Secure Certificate Authority - G2"; - :log info ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress); + :if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ + $LogPrintExit error ("Downloading required certificate failed.") true; + } + $LogPrintExit info ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress) false; / tool fetch check-certificate=yes-without-crl \ ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ user=($Comment->"user") password=($Comment->"pass") output=none; / interface 6to4 set $Interface local-address=$PublicAddress; } else={ - :log debug ("All tunnelbroker configuration is up to date for interface " . $InterfaceVal->"name" . "."); + $LogPrintExit debug ("All tunnelbroker configuration is up to date for interface " . $InterfaceVal->"name" . ".") false; } } From 151630b6741d19c439713d1e3f31529052a41697 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 14:36:32 +0200 Subject: [PATCH 0294/2612] check-certificates: warn about missing chain --- check-certificates | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index ad19059..40e509b 100644 --- a/check-certificates +++ b/check-certificates @@ -57,7 +57,9 @@ :local CertNew [ / certificate find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>3w ]; :local CertNewVal [ / certificate get $CertNew ]; - $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN"); + :if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") ] = false) do={ + $LogPrintExit warning ("The certificate chain is not available!") false; + } :if ($Cert != $CertNew) do={ $LogPrintExit debug ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; From abb97601cee8772122a1baba470918e66a06fe00 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 14:43:36 +0200 Subject: [PATCH 0295/2612] global-functions: $DownloadPackage: check status of certificate download --- global-functions | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index bcc35f5..3fd45c7 100644 --- a/global-functions +++ b/global-functions @@ -212,6 +212,7 @@ :global CertificateAvailable; :global CleanFilePath; + :global LogPrintExit; :global WaitForFile; :if ([ :len $PkgName ] = 0) do={ return false; } @@ -224,7 +225,9 @@ } :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; - $CertificateAvailable "Let's Encrypt Authority X3"; + :if ([ $CertificateAvailable "Let's Encrypt Authority X3" ] = false) do={ + $LogPrintExit error ("Downloading required certificate failed.") true; + } :local Retry 3; :while ($Retry > 0) do={ From e963e091148dd095cd9d1510eae0249849309e4e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 14:53:29 +0200 Subject: [PATCH 0296/2612] global-functions: $GetMacVendor: check status of certificate download --- global-functions | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 3fd45c7..05d98ed 100644 --- a/global-functions +++ b/global-functions @@ -256,11 +256,13 @@ :local Mac [ :tostr $1 ]; :global CertificateAvailable; + :global LogPrintExit; :do { - :local Vendor; - $CertificateAvailable "Let's Encrypt Authority X3"; - :set Vendor ([ / tool fetch check-certificate=yes-without-crl \ + :if ([ $CertificateAvailable "Let's Encrypt Authority X3" ] = false) do={ + $LogPrintExit warning ("Downloading required certificate failed.") true; + } + :local Vendor ([ / tool fetch check-certificate=yes-without-crl \ ("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data"); :return $Vendor; } on-error={ From 324f5b0ba428abf477f128577f2f6c3604a15ab5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 14:57:51 +0200 Subject: [PATCH 0297/2612] global-functions: $SendTelegram: check status of certificate download --- global-functions | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 05d98ed..29ce59d 100644 --- a/global-functions +++ b/global-functions @@ -596,8 +596,9 @@ :global TelegramChatId; :global TelegramChatIdOverride; - :global UrlEncode; :global CertificateAvailable; + :global LogPrintExit; + :global UrlEncode; :local ChatId $TelegramChatId; :if ([ :len $TelegramChatIdOverride ] > 0) do={ @@ -608,8 +609,10 @@ :return false; } - $CertificateAvailable "Go Daddy Secure Certificate Authority - G2"; :do { + :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ + $LogPrintExit warning ("Downloading required certificate failed.") true; + } / tool fetch check-certificate=yes-without-crl output=none http-method=post \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ http-data=("chat_id=" . $ChatId . "&disable_notification=" . $Silent . \ From 7cdeb9185e10ed35b5590087e035d29626eacb08 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 16:43:55 +0200 Subject: [PATCH 0298/2612] global-functions: $CertificateAvailable: use $LogPrintExit --- global-functions | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 29ce59d..9375688 100644 --- a/global-functions +++ b/global-functions @@ -47,16 +47,18 @@ :local CommonName [ :tostr $1 ]; :global CertificateDownload; + :global LogPrintExit; :global ParseKeyValueStore; :if ([ / system resource get free-hdd-space ] < 8388608 && \ [ / certificate settings get crl-download ] = true && \ [ / certificate settings get crl-store ] = "system") do={ - :log warning "This system has low free flash space but is configured to download certificate CRLs to system!"; + $LogPrintExit warning ("This system has low free flash space but " . \ + "is configured to download certificate CRLs to system!") false; } :if ([ / certificate print count-only where common-name=$CommonName ] = 0) do={ - :log info ("Certificate with CommonName \"" . $CommonName . "\" not available."); + $LogPrintExit info ("Certificate with CommonName \"" . $CommonName . "\" not available.") false; :if ([ $CertificateDownload $CommonName ] = false) do={ :return false; } @@ -66,7 +68,8 @@ :local Issuer $CommonName; :do { :if ([ / certificate print count-only where common-name=$Issuer ] = 0) do={ - :log info ("Certificate chain for \"" . $CommonName . "\" is incomplete, missing \"" . $Issuer . "\"."); + $LogPrintExit info ("Certificate chain for \"" . $CommonName . \ + "\" is incomplete, missing \"" . $Issuer . "\".") false; :if ([ $CertificateDownload $CommonName ] = false) do={ :return false; } From 596fb5f83582b982c0ec336c8cb65e8b76665ba1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 16:45:28 +0200 Subject: [PATCH 0299/2612] global-functions: $CertificateDownload: use $LogPrintExit --- global-functions | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 9375688..3dba487 100644 --- a/global-functions +++ b/global-functions @@ -88,11 +88,12 @@ :global ScriptUpdatesUrlSuffix; :global CertificateNameByCN; + :global LogPrintExit; :global UrlEncode; :global WaitForFile; - :log info ("Downloading and importing certificate with " . \ - "CommonName \"" . $CommonName . "\"."); + $LogPrintExit info ("Downloading and importing certificate with " . \ + "CommonName \"" . $CommonName . "\".") false; :do { :local LocalFileName ($CommonName . ".pem"); :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); @@ -108,7 +109,7 @@ $CertificateNameByCN [ / certificate get $Cert common-name ]; } } on-error={ - :log warning "Failed imprting certificate!"; + $LogPrintExit warning ("Failed imprting certificate!") false; :return false; } :return true; From 9c3ce55ee4767b9708a226b3b51c5ad7e1c390c8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 16:48:22 +0200 Subject: [PATCH 0300/2612] global-functions: $MailServerIsUp: use $LogPrintExit --- global-functions | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 3dba487..42e5fcf 100644 --- a/global-functions +++ b/global-functions @@ -317,8 +317,10 @@ :local MailServer [ / tool e-mail get address ]; :local MailHost $MailServer; + :global LogPrintExit; + :if ([ / tool netwatch print count-only where comment=$MailServer ] = 0) do={ - :log warning ("Adding netwatch entry for mail server."); + $LogPrintExit warning ("Adding netwatch entry for mail server.") false; :local MailHost $MailServer; :if ([ :typeof [ :toip $MailHost ] ] != "ip" ) do={ :set MailHost [ :resolve $MailServer ]; From 6f354c8bb0e412993b7df350f2f9b22e1966677b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 16:50:21 +0200 Subject: [PATCH 0301/2612] global-functions: $ScriptFromTerminal: use $LogPrintExit --- global-functions | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 42e5fcf..0b1ba77 100644 --- a/global-functions +++ b/global-functions @@ -379,16 +379,19 @@ :set ScriptFromTerminal do={ :local Script [ :tostr $1 ]; + :global LogPrintExit; + :foreach Job in=[ / system script job find where script=$Script ] do={ :set Job [ / system script job get $Job ]; :while ([ :typeof ($Job->"parent") ] = "id") do={ :set Job [ / system script job get [ find where .id=($Job->"parent") ] ]; } :if (($Job->"type") = "login") do={ - :log debug ("Script " . $Script . " started from terminal."); + $LogPrintExit debug ("Script " . $Script . " started from terminal.") false; :return true; } } + $LogPrintExit debug ("Script " . $Script . " NOT started from terminal.") false; :return false; } From af776451740af8996851086f102690d7b66553ee Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 16:51:59 +0200 Subject: [PATCH 0302/2612] global-functions: $SendEMail: use $LogPrintExit --- global-functions | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 0b1ba77..85d9d59 100644 --- a/global-functions +++ b/global-functions @@ -562,6 +562,8 @@ :global EmailGeneralTo; :global EmailGeneralCc; + :global LogPrintExit; + :if ([ :len $EmailGeneralTo ] = 0) do={ :return false; } @@ -575,7 +577,7 @@ subject=("[" . $Identity . "] " . $Subject) \ body=($Message . $Signature) file=$Attach; } on-error={ - :log warning "Failed sending notification mail!"; + $LogPrintExit warning ("Failed sending notification mail!") false; } } From df177212d1ee91cb6ca5af234866c8db77d9438d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 16:53:06 +0200 Subject: [PATCH 0303/2612] global-functions: $SendTelegram: use $LogPrintExit --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 85d9d59..747dd25 100644 --- a/global-functions +++ b/global-functions @@ -629,7 +629,7 @@ http-data=("chat_id=" . $ChatId . "&disable_notification=" . $Silent . \ "&text=" . [ $UrlEncode ("[" . $Identity . "] " . $Subject . "\n\n" . $Message) ]); } on-error={ - :log warning "Failed sending telegram notification!"; + $LogPrintExit warning ("Failed sending telegram notification!") false; } } From 004569045997f8a425137d0205790c94707b8930 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 17:16:42 +0200 Subject: [PATCH 0304/2612] gps-track: use $LogPrintExit --- gps-track | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gps-track b/gps-track index 4a27eb8..f839eac 100644 --- a/gps-track +++ b/gps-track @@ -8,6 +8,8 @@ :global GpsTrackUrl; :global Identity; +:global LogPrintExit; + :local CoordinateFormat [ /system gps get coordinate-format ]; :local Gps [ / system gps monitor once as-value ]; @@ -20,9 +22,9 @@ if ($Gps->"valid" = true) do={ "\"lon\":\"" . ($Gps->"longitude") . "\"," . \ "\"identity\":\"" . $Identity . "\"" . \ "}"); - :log debug ("Sending GPS data in " . $CoordinateFormat . " format: " . \ + $LogPrintExit debug ("Sending GPS data in " . $CoordinateFormat . " format: " . \ "lat: " . ($Gps->"latitude") . " " . \ - "lon: " . ($Gps->"longitude")); + "lon: " . ($Gps->"longitude")) false; } else={ - :log debug ("GPS data not valid."); + $LogPrintExit debug ("GPS data not valid.") false; } From d2b1f036ca79cfc8da0b27ff7037418bb5862d08 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 17:18:05 +0200 Subject: [PATCH 0305/2612] update-gre-address: use $LogPrintExit --- update-gre-address | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/update-gre-address b/update-gre-address index 8ede500..c0c7e31 100644 --- a/update-gre-address +++ b/update-gre-address @@ -6,6 +6,8 @@ # ipsec remote peer # https://git.eworm.de/cgit/routeros-scripts/about/doc/update-gre-address.md +:global LogPrintExit; + / interface gre set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; :foreach Peer in=[ / ip ipsec active-peers find ] do={ @@ -16,7 +18,7 @@ :if ([ :typeof ($PeerVal->"dynamic-address") ] = "str" && \ ($PeerVal->"dynamic-address" != $GreIntVal->"remote-address" || \ $GreIntVal->"disabled" = true)) do={ - :log info ("Updating remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address"); + $LogPrintExit info ("Updating remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address") false; / interface gre set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$PeerVal->"dynamic-address" name!=$GreIntVal->"name" ]; / interface gre set $GreInt remote-address=($PeerVal->"dynamic-address") disabled=no; } From ee903e263f0c82927dea4db8aa7cdc846d0be961 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 17:19:34 +0200 Subject: [PATCH 0306/2612] check-lte-firmware-upgrade: use $LogPrintExit --- check-lte-firmware-upgrade | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 6edb6f1..4b0e749 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -8,6 +8,7 @@ :global Identity; :global SentLteFirmwareUpgradeNotification; +:global LogPrintExit; :global SendNotification; :foreach Interface in=[ / interface lte find ] do={ @@ -16,8 +17,8 @@ :local Firmware [ / interface lte firmware-upgrade $Interface once as-value ]; :if ($SentLteFirmwareUpgradeNotification = ($Firmware->"latest")) do={ - :log debug ("Already sent the LTE firmware upgrade notification for version " . \ - ($Firmware->"latest") . "."); + $LogPrintExit debug ("Already sent the LTE firmware upgrade notification for version " . \ + ($Firmware->"latest") . ".") false; } else={ :if (($Firmware->"installed") != ($Firmware->"latest")) do={ $SendNotification ("LTE firmware upgrade") \ @@ -27,7 +28,7 @@ } } } on-error={ - :log debug ("Could not get latest LTE firmware version for interface " . \ - $IntName . "."); + $LogPrintExit debug ("Could not get latest LTE firmware version for interface " . \ + $IntName . ".") false; } } From 972a481faadc7ae35f9d1a4178704cc17b0cc6ca Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 17:20:56 +0200 Subject: [PATCH 0307/2612] sms-forward: use $LogPrintExit --- sms-forward | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sms-forward b/sms-forward index 2045196..7f79aaa 100644 --- a/sms-forward +++ b/sms-forward @@ -29,7 +29,7 @@ :if ($Phone = $Settings->"allowed-number" && \ ($SmsVal->"message")~("^:cmd " . $Settings->"secret" . " script ")) do={ - :log debug "Removing SMS, which started a script."; + $LogPrintExit debug ("Removing SMS, which started a script.") false; / tool sms inbox remove $Sms; } else={ :set Messages ($Messages . "\n\nOn " . $SmsVal->"timestamp" . \ From 93e72b5d07bdfe21949f26e6c8c742f8db443e6d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 17:22:03 +0200 Subject: [PATCH 0308/2612] packages-update: use $LogPrintExit --- packages-update | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages-update b/packages-update index 9158c08..fb7ff58 100644 --- a/packages-update +++ b/packages-update @@ -37,7 +37,7 @@ $ScriptLock "packages-update"; :if (!([ /system resource get version ] ~ ($Update->"channel"))) do={ :put "Update channel changed. Want to downgrade? [y/N]"; :if ([ :terminal inkey timeout=60 ] = 121) do={ - :log info ("Rebooting for downgrade."); + $LogPrintExit info ("Rebooting for downgrade.") false; :delay 1s; / system package downgrade; } @@ -52,6 +52,6 @@ $ScriptLock "packages-update"; } } -:log info ("Rebooting for update."); +$LogPrintExit info ("Rebooting for update.") false; :delay 1s; / system reboot; From b17ca4bb63022b952a939990bcbde14a8bbb6acd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 17:23:33 +0200 Subject: [PATCH 0309/2612] mode-button-scheduler: use $LogPrintExit --- mode-button-scheduler | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mode-button-scheduler b/mode-button-scheduler index 03f673b..632d6e3 100644 --- a/mode-button-scheduler +++ b/mode-button-scheduler @@ -7,6 +7,8 @@ :global ModeButton; +:global LogPrintExit; + :local Count ($ModeButton->"count"); :local Code ($ModeButton->[ :tostr $Count ]); @@ -14,7 +16,7 @@ / system scheduler remove mode-button-scheduler; :if ([ :len $Code ] > 0) do={ - :log info ("Acting on " . $Count . " mode-button presses: " . $Code); + $LogPrintExit info ("Acting on " . $Count . " mode-button presses: " . $Code) false; :if ([ / system routerboard settings get silent-boot ] = false) do={ :for I from=1 to=$Count do={ @@ -28,5 +30,5 @@ :local Parsed [ :parse $Code ]; $Parsed; } else={ - :log info ("No action defined for " . $Count . " mode-button presses."); + $LogPrintExit info ("No action defined for " . $Count . " mode-button presses.") false; } From b2d1b64bd2801cfbad728896f4302111272205b2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 17:26:35 +0200 Subject: [PATCH 0310/2612] capsman-rolling-upgrade: use $LogPrintExit --- capsman-rolling-upgrade | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index 38843e6..a496167 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -6,6 +6,7 @@ # upgrade CAPs one after another # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md +:global LogPrintExit; :global ScriptLock; $ScriptLock "capsman-rolling-upgrade"; @@ -18,8 +19,8 @@ $ScriptLock "capsman-rolling-upgrade"; :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 ]; - :log info ("Starting upgrade for " . $RemoteCapVal->"name" . \ - " (" . $RemoteCapVal->"identity" . ")..."); + $LogPrintExit info ("Starting upgrade for " . $RemoteCapVal->"name" . \ + " (" . $RemoteCapVal->"identity" . ")...") false; / caps-man remote-cap upgrade [ find where name=$RemoteCapVal->"name" ]; :delay ($Delay . "s"); } From 1f1fef9fb59ec6653f3faff1096708039883dfc5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 17:29:08 +0200 Subject: [PATCH 0311/2612] check-health: use $LogPrintExit --- check-health | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/check-health b/check-health index ef9fd23..e41984f 100644 --- a/check-health +++ b/check-health @@ -10,6 +10,7 @@ :global CheckHealthVoltagePercent; :global Identity; +:global LogPrintExit; :global SendNotification; :local FormatVoltage do={ @@ -52,7 +53,7 @@ :if ([ :typeof ($CheckHealthLast->$Temperature) ] = "num" && \ [ :typeof ($CheckHealthCurrent->$Temperature) ] = "num") do={ :if ([ :typeof ($CheckHealthTemperature->$Temperature) ] != "num" ) do={ - :log warning ("No threshold given for " . $Temperature . ", assuming 50C."); + $LogPrintExit warning ("No threshold given for " . $Temperature . ", assuming 50C.") false; :set ($CheckHealthTemperature->$Temperature) 50; } :if ($CheckHealthLast->$Temperature <= $CheckHealthTemperature->$Temperature && \ From 03ae65c5f16111984f510969e2815908d59a0a0a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 17:30:00 +0200 Subject: [PATCH 0312/2612] cloud-backup: use $LogPrintExit --- cloud-backup | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cloud-backup b/cloud-backup index 316a2a4..89648d5 100644 --- a/cloud-backup +++ b/cloud-backup @@ -9,6 +9,7 @@ :global Identity; :global DeviceInfo; +:global LogPrintExit; :global SendNotification; :do { @@ -31,5 +32,5 @@ "Size: " . $Cloud->"size" . "\n" . \ "Download key: " . $Cloud->"secret-download-key") "" "true"; } on-error={ - :log error ("Failed uploading backup for " . $Identity . " to cloud."); + $LogPrintExit error ("Failed uploading backup for " . $Identity . " to cloud.") false; } From 413287586f185dd4ce3a03c53b8fdab76b17b501 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 17:30:51 +0200 Subject: [PATCH 0313/2612] upload-backup: use $LogPrintExit --- upload-backup | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/upload-backup b/upload-backup index 3473884..1fc724b 100644 --- a/upload-backup +++ b/upload-backup @@ -38,7 +38,7 @@ user=$BackupUploadUser password=$BackupUploadPass src-path=($FileName . ".backup"); :set BackupFile ($FileName . ".backup"); } on-error={ - :log error ("Uploading backup file failed!"); + $LogPrintExit error ("Uploading backup file failed!") false; :set BackupFile "failed"; } } @@ -52,7 +52,7 @@ user=$BackupUploadUser password=$BackupUploadPass src-path=($FileName . ".rsc"); :set ConfigFile ($FileName . ".rsc"); } on-error={ - :log error ("Uploading configuration export failed!"); + $LogPrintExit error ("Uploading configuration export failed!") false; :set ConfigFile "failed"; } } From 289fd215c485b714561afdd720772fdd8080a128 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 17:32:19 +0200 Subject: [PATCH 0314/2612] mode-button-event: use $LogPrintExit --- mode-button-event | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mode-button-event b/mode-button-event index 4768e09..0e1ac0d 100644 --- a/mode-button-event +++ b/mode-button-event @@ -7,15 +7,17 @@ :global ModeButton; +:global LogPrintExit; + :set ($ModeButton->"count") ($ModeButton->"count" + 1); :local Scheduler [ / system scheduler find where name="mode-button-scheduler" ]; :if ([ :len $Scheduler ] = 0) do={ - :log info "Creating mode-button scheduler, counting presses..."; + $LogPrintExit info ("Creating mode-button scheduler, counting presses...") false; / system scheduler add name="mode-button-scheduler" \ on-event="/ system script run mode-button-scheduler;" interval=3s; } else={ - :log debug "Updating mode-button-scheduler..."; + $LogPrintExit debug ("Updating mode-button-scheduler...") false; / system scheduler set $Scheduler start-time=[ /system clock get time ]; } From 2cd8a56aa7d33714ff24c3b473931d560e67235f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Apr 2020 11:51:33 +0200 Subject: [PATCH 0315/2612] capsman-download-packages: create package path --- capsman-download-packages | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/capsman-download-packages b/capsman-download-packages index de2feb9..c17a09d 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -8,6 +8,8 @@ :global CleanFilePath; :global DownloadPackage; +:global LogPrintExit; +:global MkDir; :global ScriptLock; $ScriptLock "capsman-download-packages"; @@ -16,6 +18,12 @@ $ScriptLock "capsman-download-packages"; :local InstalledVersion [ / system package update get installed-version ]; :local Updated false; +:if ([ / file print count-only where name=$PackagePath type="directory" ] = 0) do={ + $MkDir $PackagePath; + $LogPrintExit info ("Created directory at package path (" . $PackagePath . \ + "). Please place your packages!") false; +} + :foreach Package in=[ / file find where type=package \ package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ :local File [ / file get $Package ]; From 96598b2d342dcd25074272a47239588a8b6b894b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Apr 2020 12:54:46 +0200 Subject: [PATCH 0316/2612] global-functions: $DownloadPackage: do not re-download --- global-functions | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/global-functions b/global-functions index 747dd25..145ec09 100644 --- a/global-functions +++ b/global-functions @@ -229,6 +229,11 @@ } :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; + :if ([ / file print count-only where name=$PkgDest type="package" ] > 0) do={ + $LogPrintExit info ("Package file alreasy exists.") false; + :return true; + } + :if ([ $CertificateAvailable "Let's Encrypt Authority X3" ] = false) do={ $LogPrintExit error ("Downloading required certificate failed.") true; } From d87f5899c25cb0af2b2df7ae51f4ffffaa8cd5aa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Apr 2020 13:23:34 +0200 Subject: [PATCH 0317/2612] doc/capsman-download-packages: document how to download packages --- doc/capsman-download-packages.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index ee4912d..add9b83 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -26,7 +26,16 @@ internet connectivity is given: Only packages available in older version are downloaded. For initial setup place the required packages to CAPsMAN package path (see -`/ caps-man manager`). +`/ caps-man manager`). The packages can be downloaded from device with +function `$DownloadPackage`, use something like this to download latest +packages to directory `routeros`: + + $DownloadPackage system "" arm routeros; + $DownloadPackage security "" arm routeros; + [...] + $DownloadPackage system "" mipsbe routeros; + $DownloadPackage security "" mipsbe routeros; + [...] Usage and invocation -------------------- From fe8820d7d536ab30cdde4ccb62797bed07bc146e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Apr 2020 13:30:27 +0200 Subject: [PATCH 0318/2612] doc/capsman-rolling-upgrade: explain what happens --- doc/capsman-rolling-upgrade.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index e78c87a..04952e2 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -6,10 +6,13 @@ Run rolling CAP upgrades from CAPsMAN Description ----------- -CAPsMAN can upgrate CAP devices. This script runs a rolling upgrade for +CAPsMAN can upgrade CAP devices. This script runs a rolling upgrade for out-of-date CAP devices. The idea is to have just a fraction of devices reboot at a time, having the others to serve wireless connectivity. +Note that the script does not wait for the CAPs to reconnect, it just defers +the upgrade commands. The more CAPs you have the more will upgrade in +parallel. Requirements and installation ----------------------------- From 06c8f279f80a42cb8342873d9491eb95037ee688 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Apr 2020 16:07:00 +0200 Subject: [PATCH 0319/2612] check-lte-firmware-upgrade: give current and available version --- check-lte-firmware-upgrade | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 4b0e749..218aac0 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -23,7 +23,9 @@ :if (($Firmware->"installed") != ($Firmware->"latest")) do={ $SendNotification ("LTE firmware upgrade") \ ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ - "LTE interface " . $IntName . " on " . $Identity . ".") "" "true"; + "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ + "Installed: " . ($Firmware->"installed") . "\n" . \ + "Available: " . ($Firmware->"latest")) "" "true"; :set SentLteFirmwareUpgradeNotification ($Firmware->"latest"); } } From aedc31451950809f9f7dae4a4d7e40d1495f9ac5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Apr 2020 16:13:44 +0200 Subject: [PATCH 0320/2612] check-routeros-update: update notification wording --- check-routeros-update | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/check-routeros-update b/check-routeros-update index 3bec07b..7df980e 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -75,7 +75,8 @@ } $SendNotification ("RouterOS update \E2\9C\A8") \ - ("There is a RouterOS update available.\n\n" . \ + ("A new RouterOS version " . ($Update->"latest-version") . \ + " is available for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree") \ "" "true"; From c8770efd7222f317ccedf228c0a1cae6c1b16262 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 18 Apr 2020 23:20:29 +0200 Subject: [PATCH 0321/2612] add script 'early-erros' --- README.md | 1 + doc/early-errors.md | 42 ++++++++++++++++++++++++++++++++++++++++++ early-errors | 22 ++++++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 doc/early-errors.md create mode 100644 early-errors diff --git a/README.md b/README.md index 63a8d77..c1b1923 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,7 @@ Available Scripts * [Use wireless network with daily psk](doc/daily-psk.md) * [Comment DHCP leases with info from access list](doc/dhcp-lease-comment.md) * [Create DNS records for DHCP leases](doc/dhcp-to-dns.md) +* [Send notification with early errors](doc/early-errors.md) * [Send backup via e-mail](doc/email-backup.md) * [Wait for configuration und functions](doc/global-wait.md) * [Send GPS position to server](doc/gps-track.md) diff --git a/doc/early-errors.md b/doc/early-errors.md new file mode 100644 index 0000000..35a11f9 --- /dev/null +++ b/doc/early-errors.md @@ -0,0 +1,42 @@ +Send notification with early errors +=================================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +RouterOS supports sending log messages via e-mail or to a syslog server. +However this does not work early after boot if network connectivity is not +yet established. For example log messages about reboot without proper +shutdown may be missed: + +> router rebooted without proper shutdown, probably power outage + +The script collects log messages with severity `error` and sends a +notification. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate early-errors; + +... and add a scheduler: + + / system scheduler add name=early-erros on-event=":global WaitTimeSync; / system script { run global-wait; \$WaitTimeSync; run early-errors; }" start-time=startup; + +Configuration +------------- + +The notifications just require notification settings for e-mail and telegram. + +See also +-------- + +* [Wait for configuration und functions](global-wait.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/early-errors b/early-errors new file mode 100644 index 0000000..ad871f6 --- /dev/null +++ b/early-errors @@ -0,0 +1,22 @@ +#!rsc +# RouterOS script: early-errors +# Copyright (c) 2020 Christian Hesse +# +# send notification with early errors +# https://git.eworm.de/cgit/routeros-scripts/about/doc/early-errors.md + +:global Identity; + +:global SendNotification; + +:local ErrCount [ / log print count-only where topics~"error" ]; +:if ($ErrCount > 0) do={ + :local Message ("The log on " . $Identity . " contains " . $ErrCount . \ + " errors after " . [ / system resource get uptime ] . " uptime.\n"); + :foreach Log in=[ / log find where topics~"error" ] do={ + :local LogVal [ / log get $Log ]; + :set Message ($Message . "\n" . [ :tostr ($LogVal->"topics") ] . \ + " " . ($LogVal->"message")); + } + $SendNotification ("\E2\9A\A0 Early errors") ($Message); +} From d6ce774fd8abeeca9c2ee30f810cde527ba902b0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Apr 2020 10:08:23 +0200 Subject: [PATCH 0322/2612] global-functions: $TimeIsSync: unbreak with bundled ntp client --- global-functions | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 145ec09..d18a859 100644 --- a/global-functions +++ b/global-functions @@ -640,9 +640,16 @@ # check if system time is sync :set TimeIsSync do={ - :if ([ / system ntp client get enabled ] = true && \ - [ / system ntp client get status ] = "synchronized") do={ - :return true; + :if ([ / system ntp client get enabled ] = true) do={ + :do { + :if ([ / system ntp client get status ] = "synchronized") do={ + :return true; + } + } on-error={ + :if ([ :typeof [ / system ntp client get last-adjustment ] ] = "time") do={ + :return true; + } + } } :if ([ / ip cloud get update-time ] = true && \ From 999763a263ab3c1847b2cafa9dca0c11a0c91573 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Apr 2020 22:20:42 +0200 Subject: [PATCH 0323/2612] global-functions: add $DefaultRouteIsReachable --- global-functions | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/global-functions b/global-functions index d18a859..5d059fe 100644 --- a/global-functions +++ b/global-functions @@ -22,6 +22,7 @@ :global CertificateNameByCN; :global CharacterReplace; :global CleanFilePath; +:global DefaultRouteIsReachable; :global DeviceInfo; :global DownloadPackage; :global GetMacVendor; @@ -164,6 +165,14 @@ :return $Path; } +# default route is reachable +:set DefaultRouteIsReachable do={ + :if ([ / ip route print count-only where dst-address=0.0.0.0/0 !unreachable active !routing-mark ] > 0) do={ + :return true; + } + :return false; +} + # get readable device info :set DeviceInfo do={ :global ExpectedConfigVersion; From b67712cfe449ee59476e62fa45264a152ca36220 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Apr 2020 22:21:06 +0200 Subject: [PATCH 0324/2612] global-functions: add $WaitDefaultRouteReachable --- global-functions | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/global-functions b/global-functions index 5d059fe..686b1fa 100644 --- a/global-functions +++ b/global-functions @@ -40,6 +40,7 @@ :global SendTelegram; :global TimeIsSync; :global UrlEncode; +:global WaitDefaultRouteReachable; :global WaitForFile; :global WaitTimeSync; @@ -694,6 +695,15 @@ :return $Return; } +# wait for default route to be reachable +:set WaitDefaultRouteReachable do={ + :global DefaultRouteIsReachable; + + :while ([ $DefaultRouteIsReachable ] = false) do={ + :delay 1s; + } +} + # wait for file to be available :set WaitForFile do={ :global CleanFilePath; From 14dd16ef5a351c0e9d5c19895ae5d47a57962bf6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Apr 2020 11:09:02 +0200 Subject: [PATCH 0325/2612] global-functions: $CertificateNameByCN: replace apostrophe --- global-functions | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 686b1fa..48e743f 100644 --- a/global-functions +++ b/global-functions @@ -124,7 +124,8 @@ :global CharacterReplace; :local Cert [ / certificate find where common-name=$CommonName ]; - / certificate set $Cert name=[ $CharacterReplace [ $CharacterReplace $CommonName " " "-" ] "---" "-" ]; + / certificate set $Cert \ + name=[ $CharacterReplace [ $CharacterReplace [ $CharacterReplace $CommonName "'" "-" ] " " "-" ] "---" "-" ]; } # character replace From 8f03a856e154cc893a9260a3dd14f147a58ac31f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Apr 2020 12:19:14 +0200 Subject: [PATCH 0326/2612] check-certificates: add missing blank --- check-certificates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index 40e509b..4aece69 100644 --- a/check-certificates +++ b/check-certificates @@ -97,7 +97,7 @@ } } -:foreach Cert in=[ / certificate find where !revoked !scep-url expires-after<2w fingerprint~"."] do={ +:foreach Cert in=[ / certificate find where !revoked !scep-url expires-after<2w fingerprint~"." ] do={ :local CertVal [ / certificate get $Cert ]; :local ExpiresAfter [ $FormatExpire ($CertVal->"expires-after") ]; From 1e12c0e159e0968fa8be73cf240d77263f1aec2b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Apr 2020 13:49:50 +0200 Subject: [PATCH 0327/2612] check-certificates: always use parenthesis --- check-certificates | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-certificates b/check-certificates index 4aece69..cd3b580 100644 --- a/check-certificates +++ b/check-certificates @@ -24,7 +24,7 @@ } :if ($TimeIsSync = false) do={ - $LogPrintExit warning "Time is not yet synchronized." true; + $LogPrintExit warning ("Time is not yet synchronized.") true; } :foreach Cert in=[ / certificate find where !revoked !ca !scep-url expires-after<3w ] do={ @@ -32,7 +32,7 @@ :do { :if ([ :len $CertRenewUrl ] = 0) do={ - $LogPrintExit warning "No CertRenewUrl given." true; + $LogPrintExit warning ("No CertRenewUrl given.") true; } :foreach Type in={ ".pem"; ".p12" } do={ From 85f9c5d62e3871f62775e7e8732bbe4bec940590 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Apr 2020 14:26:00 +0200 Subject: [PATCH 0328/2612] check-certificates: exclude issued certificates on SCEP server --- check-certificates | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/check-certificates b/check-certificates index cd3b580..0964bde 100644 --- a/check-certificates +++ b/check-certificates @@ -100,21 +100,25 @@ :foreach Cert in=[ / certificate find where !revoked !scep-url expires-after<2w fingerprint~"." ] do={ :local CertVal [ / certificate get $Cert ]; - :local ExpiresAfter [ $FormatExpire ($CertVal->"expires-after") ]; - :local State "is about to expire"; - :if (($CertVal->"expired") = true) do={ - :set ExpiresAfter "expired"; - :set State "expired"; - } + :if ([ / certificate scep-server print count-only where ca-cert=($CertVal->"ca") ] > 0) do={ + $LogPrintExit debug ("Certificate \"" . ($CertVal->"name") . "\" is handled by SCEP, skipping.") false; + } else={ + :local ExpiresAfter [ $FormatExpire ($CertVal->"expires-after") ]; + :local State "is about to expire"; + :if (($CertVal->"expired") = true) do={ + :set ExpiresAfter "expired"; + :set State "expired"; + } - $SendNotification ("Certificate warning!") \ - ("A certificate on " . $Identity . " " . $State . ".\n\n" . \ - "Name: " . ($CertVal->"name") . "\n" . \ - "CommonName: " . ($CertVal->"common-name") . "\n" . \ - "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ - "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ - "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ - "Expires in: " . $ExpiresAfter); - $LogPrintExit warning ("The certificate " . ($CertVal->"name") . " " . $State . \ - ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; + $SendNotification ("Certificate warning!") \ + ("A certificate on " . $Identity . " " . $State . ".\n\n" . \ + "Name: " . ($CertVal->"name") . "\n" . \ + "CommonName: " . ($CertVal->"common-name") . "\n" . \ + "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ + "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ + "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ + "Expires in: " . $ExpiresAfter); + $LogPrintExit warning ("The certificate " . ($CertVal->"name") . " " . $State . \ + ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; + } } From 29315c7377ab420121f8b75646d4f6366ce1c270 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Apr 2020 14:55:41 +0200 Subject: [PATCH 0329/2612] INITIAL-COMMANDS: use function to rename certificates --- INITIAL-COMMANDS.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 2f2b7b1..4541430 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -9,12 +9,7 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai { / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt.pem"; :delay 1s; - / certificate { - import file-name=letsencrypt.pem passphrase=""; - set name="ISRG-Root-X1" [ find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ]; - set name="Let-s-Encrypt-Authority-X3" [ find where fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" ]; - set name="DST-Root-CA-X3" [ find where fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ]; - } + / certificate import file-name=letsencrypt.pem passphrase=""; :if ([ / certificate print count-only where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] != 3) do={ :error "Something is wrong with your certificates!"; } @@ -24,6 +19,9 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai } / system script { run global-config; run global-config-overlay; run global-functions; } / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }" + $CertificateNameByCN "ISRG Root X1"; + $CertificateNameByCN "Let's Encrypt Authority X3"; + $CertificateNameByCN "DST Root CA X3"; } --- From 0a48f37918f1c9ec202f4a0f3e598f2724ddb7a6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Apr 2020 20:47:47 +0200 Subject: [PATCH 0330/2612] doc/mode-button: the reset button can do the same ... starting with RouterOS 6.47beta60. --- doc/mode-button.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/mode-button.md b/doc/mode-button.md index 5018d6e..0e5fa47 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -10,7 +10,9 @@ These scripts extend the functionality of mode button. Instead of just one you can trigger several actions by pressing the mode button several times. The hardware needs to have a mode button, see -`/ system routerboard mode-button`. +`/ system routerboard mode-button`. Starting with RouterOS 6.47beta60 you +can configure the reset button to act the same, see +`/ system routerboard reset-button`. Requirements and installation ----------------------------- @@ -19,10 +21,14 @@ Just install the scripts: $ScriptInstallUpdate mode-button-event,mode-button-scheduler; -Then configure the mode-button to run `mode-button-event`: +Then configure the mode button to run `mode-button-event`: / system routerboard mode-button set enabled=yes on-event="/ system script run mode-button-event;"; +To use the reset button instead: + + / system routerboard reset-button set enabled=yes on-event="/ system script run mode-button-event;"; + Configuration ------------- From 940c1e9381e289a4224987bddeeae52a3d23d770 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Apr 2020 23:14:58 +0200 Subject: [PATCH 0331/2612] early-errors: get errors into array --- early-errors | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/early-errors b/early-errors index ad871f6..eaee745 100644 --- a/early-errors +++ b/early-errors @@ -9,11 +9,12 @@ :global SendNotification; -:local ErrCount [ / log print count-only where topics~"error" ]; +:local Errors [ / log find where topics~"error" ]; +:local ErrCount [ :len $Errors ]; :if ($ErrCount > 0) do={ :local Message ("The log on " . $Identity . " contains " . $ErrCount . \ " errors after " . [ / system resource get uptime ] . " uptime.\n"); - :foreach Log in=[ / log find where topics~"error" ] do={ + :foreach Log in=$Errors do={ :local LogVal [ / log get $Log ]; :set Message ($Message . "\n" . [ :tostr ($LogVal->"topics") ] . \ " " . ($LogVal->"message")); From 7c288c6203c52eeecc63d6847582cc6d8dd77b74 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Apr 2020 23:16:00 +0200 Subject: [PATCH 0332/2612] early-errors: also include critical messages --- early-errors | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/early-errors b/early-errors index eaee745..2660bd1 100644 --- a/early-errors +++ b/early-errors @@ -9,7 +9,7 @@ :global SendNotification; -:local Errors [ / log find where topics~"error" ]; +:local Errors [ / log find where topics~"error" or topics~"critical" ]; :local ErrCount [ :len $Errors ]; :if ($ErrCount > 0) do={ :local Message ("The log on " . $Identity . " contains " . $ErrCount . \ From fee2c4d4ad960f1c98f78bbee1891412ca2342ac Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Apr 2020 23:17:21 +0200 Subject: [PATCH 0333/2612] early-errors: ... but exclude e-mail messages Most likely these are just error and critical messages failed sending anyway. --- early-errors | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/early-errors b/early-errors index 2660bd1..36cc23e 100644 --- a/early-errors +++ b/early-errors @@ -9,7 +9,7 @@ :global SendNotification; -:local Errors [ / log find where topics~"error" or topics~"critical" ]; +:local Errors [ / log find where (topics~"error" or topics~"critical") !(topics~"e-mail") ]; :local ErrCount [ :len $Errors ]; :if ($ErrCount > 0) do={ :local Message ("The log on " . $Identity . " contains " . $ErrCount . \ From 1bce625ca931671978774eb7ada728bb82bc48db Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Apr 2020 23:31:21 +0200 Subject: [PATCH 0334/2612] early-errors: ... and exclude dns messages Using DoH (DNS over HTTPS) results in a number of error messages before network becomes available: dns;error DoH server connection error: Network is unreachable Exclude these. --- early-errors | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/early-errors b/early-errors index 36cc23e..f2793fc 100644 --- a/early-errors +++ b/early-errors @@ -9,7 +9,7 @@ :global SendNotification; -:local Errors [ / log find where (topics~"error" or topics~"critical") !(topics~"e-mail") ]; +:local Errors [ / log find where (topics~"error" or topics~"critical") !(topics~"e-mail") !(topics~"dns") ]; :local ErrCount [ :len $Errors ]; :if ($ErrCount > 0) do={ :local Message ("The log on " . $Identity . " contains " . $ErrCount . \ From 8f44e0e0a76e826694e75be7cb9ded1b4a1febd7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 28 Apr 2020 15:01:14 +0200 Subject: [PATCH 0335/2612] doc/bridge-port: add command to install global-wait --- doc/bridge-port.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/bridge-port.md b/doc/bridge-port.md index 2228ac8..167fa87 100644 --- a/doc/bridge-port.md +++ b/doc/bridge-port.md @@ -36,6 +36,7 @@ There is also global configuration: Install [global-wait](global-wait.md) and add a scheduler to start with default setup on system startup: + $ScriptInstallUpdate global-wait; / system scheduler add name=bridge-port-to-default on-event="/ system script { run global-wait; run bridge-port-to-default; }" start-time=startup; Usage and invocation From 59ba87d30edf9d691ae8716b91a97eea3ebf7f48 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 28 Apr 2020 15:02:14 +0200 Subject: [PATCH 0336/2612] doc/early-errors: also install global-wait --- doc/early-errors.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/early-errors.md b/doc/early-errors.md index 35a11f9..53c04a5 100644 --- a/doc/early-errors.md +++ b/doc/early-errors.md @@ -19,9 +19,9 @@ notification. Requirements and installation ----------------------------- -Just install the script: +Just install this script and [global-wait](global-wait.md): - $ScriptInstallUpdate early-errors; + $ScriptInstallUpdate early-errors,global-wait; ... and add a scheduler: From ce4d332f55d1b4003a71e142b0ce23a41ad68540 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 May 2020 09:21:23 +0200 Subject: [PATCH 0337/2612] global-functions: $DownloadPackage: support downloading bundle --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 48e743f..5f903d0 100644 --- a/global-functions +++ b/global-functions @@ -235,7 +235,7 @@ :if ([ :len $PkgArch ] = 0) do={ :set PkgArch [ / system resource get architecture-name ]; } :local PkgFile ($PkgName . "-" . $PkgVer . "-" . $PkgArch . ".npk"); - :if ($PkgArch = "x86_64") do={ + :if ($PkgArch = "x86_64" || $PkgName ~ "^routeros-") do={ :set PkgFile ($PkgName . "-" . $PkgVer . ".npk"); } :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; From 378a1785f4b1115c13e3fa2c1403524e4955872b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 May 2020 11:06:02 +0200 Subject: [PATCH 0338/2612] global-functions: $ScriptInstallUpdate: log when reloading code --- global-functions | 2 ++ 1 file changed, 2 insertions(+) diff --git a/global-functions b/global-functions index 5f903d0..b95e9cf 100644 --- a/global-functions +++ b/global-functions @@ -491,9 +491,11 @@ dont-require-permissions=$DontRequirePermissions $Script; :if ($ScriptVal->"name" = "global-config" && \ [ / system script print count-only where name="global-config-overlay" ] > 0) do={ + $LogPrintExit info ("Reloading global configuration and overlay.") false; / system script { run global-config; run global-config-overlay; } } :if ($ScriptVal->"name" = "global-functions") do={ + $LogPrintExit info ("Reloading global functions.") false; / system script run global-functions; } } else={ From 07603f1c7b9430a19d59ea4b3064616486172f98 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 May 2020 14:08:49 +0200 Subject: [PATCH 0339/2612] README: expect recent RouterOS RouterOS 6.43 can be considered obsolete these days. --- README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c1b1923..1780dd3 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,10 @@ to manage RouterOS devices or extend their functionality. Requirements ------------ -Latest version of the scripts require at least **RouterOS 6.43** to function -properly. The changelog lists the corresponding change as follows: +Latest version of the scripts require recent RouterOS to function properly. +Make sure to install latest updates before you begin. -> *) fetch - added "as-value" output format; - -Specific scripts may require even newer RouterOS version, for example cloud -backup was added in 6.44. +Specific scripts may require even newer RouterOS version. Initial setup ------------- From 5666006527850b568c8f75620e3514098907528b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 May 2020 14:14:42 +0200 Subject: [PATCH 0340/2612] README: warn about deprecated commands in presentation --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 1780dd3..bcc0890 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,9 @@ RouterOS script distribution](https://www.youtube.com/watch?v=B9neG3oAhcY) including demonstation recorded live at [MUM Europe 2019](https://mum.mikrotik.com/2019/EU/) in Vienna. +*Be warned!* Some details changed. So see the presentation, then follow +the steps below for up-to-date commands. + ### The long way in detail The update script does server certificate verification, so first step is to From 9e4c6d70a9704a267abf774e75f250bfdf0d848d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 11 May 2020 14:03:04 +0200 Subject: [PATCH 0341/2612] doc/gps-track: add hint on coordinate format --- doc/gps-track.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/gps-track.md b/doc/gps-track.md index a7b3d7f..cda7901 100644 --- a/doc/gps-track.md +++ b/doc/gps-track.md @@ -29,6 +29,9 @@ The configuration goes to `global-config-overlay`, the only parameter is: * `GpsTrackUrl`: the url to send json data to +The configured coordinate format (see `/ system gps`) defines the format +sent to the server. + --- [◀ Go back to main README](../README.md) [▲ Go back to top](#top) From 12a29d076f4de3e8a254b6306d53cf717ca6ff48 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 May 2020 14:07:12 +0200 Subject: [PATCH 0342/2612] global-functions: $WaitTimeSync: failing rotate-ntp is not fatal Resolving ntp servers fais if internet connectivity is not established. So this is not fatal, we want to catch error and fall through, then continue. --- global-functions | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index b95e9cf..53aed48 100644 --- a/global-functions +++ b/global-functions @@ -731,7 +731,11 @@ :while ([ $TimeIsSync ] = false) do={ :if ([ / system script print count-only where name="rotate-ntp" ] > 0 && \ [ :tostr [ / system resource get uptime ] ] ~ "00\$") do={ - / system script run rotate-ntp; + :do { + / system script run rotate-ntp; + } on-error={ + # catch error and fall through + } } :delay 1s; } From 56b6da71c3d30ae3961f1251afcbb5617dae17a3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 May 2020 20:10:24 +0200 Subject: [PATCH 0343/2612] rotate-ntp: log resolve errors --- rotate-ntp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/rotate-ntp b/rotate-ntp index e0c1999..22eca07 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -9,12 +9,19 @@ :global LogPrintExit; -:local Ntp1 [ :resolve ("0." . $NtpPool) ]; -:local Ntp2 [ :resolve ("1." . $NtpPool) ]; +:local Ntp1; +:local Ntp2; :if ([ / system ntp client get enabled ] != true) do={ $LogPrintExit warning "NTP client is not enabled!" true; } +:do { + :set Ntp1 [ :resolve ("0." . $NtpPool) ]; + :set Ntp2 [ :resolve ("1." . $NtpPool) ]; +} on-error={ + $LogPrintExit warning "Resolving NTP server failed." true; +} + $LogPrintExit info ("Updating NTP servers to " . $Ntp1 . " and " . $Ntp2) false; / system ntp client set primary-ntp=$Ntp1 secondary-ntp=$Ntp2; From b5d1e7aa833a747439f711610277edfceaa0a395 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 May 2020 20:23:14 +0200 Subject: [PATCH 0344/2612] global-functions: $WaitTimeSync: run rotate-ntp less frequently --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 53aed48..c234d5a 100644 --- a/global-functions +++ b/global-functions @@ -730,7 +730,7 @@ :while ([ $TimeIsSync ] = false) do={ :if ([ / system script print count-only where name="rotate-ntp" ] > 0 && \ - [ :tostr [ / system resource get uptime ] ] ~ "00\$") do={ + [ :tostr [ / system resource get uptime ] ] ~ "[369]:00\$") do={ :do { / system script run rotate-ntp; } on-error={ From 77338563b742251c1a629dcf581f830b3c42eed2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 May 2020 20:29:15 +0200 Subject: [PATCH 0345/2612] global-functions: $MailServerIsUp: use prepared value --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index c234d5a..c7a0aaf 100644 --- a/global-functions +++ b/global-functions @@ -341,7 +341,7 @@ :if ([ :typeof [ :toip $MailHost ] ] != "ip" ) do={ :set MailHost [ :resolve $MailServer ]; } - / tool netwatch add comment=$MailServer host=[ :resolve $MailServer ]; + / tool netwatch add comment=$MailServer host=$MailHost; } :if ([ / tool netwatch get [ find where comment=$MailServer ] status ] = "up") do={ From 215bf78ce1dca7596629bd88793d0859c96ed24e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 May 2020 20:31:54 +0200 Subject: [PATCH 0346/2612] global-functions: $MailServerIsUp: remove duplicate define --- global-functions | 1 - 1 file changed, 1 deletion(-) diff --git a/global-functions b/global-functions index c7a0aaf..83d7b2a 100644 --- a/global-functions +++ b/global-functions @@ -331,7 +331,6 @@ # check if mail server is up :set MailServerIsUp do={ :local MailServer [ / tool e-mail get address ]; - :local MailHost $MailServer; :global LogPrintExit; From 255b2a8244cce98a0d5253b0b11ba0860a009425 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 May 2020 20:34:33 +0200 Subject: [PATCH 0347/2612] global-functions: $MailServerIsUp: handle resolve errors --- global-functions | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 83d7b2a..bae9fd6 100644 --- a/global-functions +++ b/global-functions @@ -338,7 +338,12 @@ $LogPrintExit warning ("Adding netwatch entry for mail server.") false; :local MailHost $MailServer; :if ([ :typeof [ :toip $MailHost ] ] != "ip" ) do={ - :set MailHost [ :resolve $MailServer ]; + :do { + :set MailHost [ :resolve $MailServer ]; + } on-error={ + $LogPrintExit warning ("Resolving mail server failed.") false; + :return false; + } } / tool netwatch add comment=$MailServer host=$MailHost; } From a806b37a47363b882d14cae0e940773949facaa3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 17 May 2020 22:34:17 +0200 Subject: [PATCH 0348/2612] sms-forward: warn and exit if receiving is not enabled --- sms-forward | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sms-forward b/sms-forward index 7f79aaa..2c6082c 100644 --- a/sms-forward +++ b/sms-forward @@ -11,6 +11,10 @@ :global MailServerIsUp; :global SendNotification; +:if ([ / tool sms get receive-enabled ] = false) do={ + $LogPrintExit warning "Receiving of SMS is not enabled." true; +} + # check mail server :if ($MailServerIsUp = false) do={ $LogPrintExit warning "Mail server is not up." true; From ce5e34ef9e4d99f6f98819cd5960e9e839ab090b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 17 May 2020 22:36:30 +0200 Subject: [PATCH 0349/2612] doc/sms-forward: add a hint on receiving sms --- doc/sms-forward.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 28fc39b..27c3847 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -24,7 +24,10 @@ Just install the script: Configuration ------------- -Notification settings are required for e-mail and telegram. +Notification settings are required for e-mail and telegram. Also you have +to enable receiving of SMS: + + / tool sms set receive-enabled=yes; See also -------- From 31799940177cf2c5f8860fba6bd4cc81cbba8244 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 17 May 2020 23:40:59 +0200 Subject: [PATCH 0350/2612] global-functions: $DownloadPackage: replace comment with debug output --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index bae9fd6..b4dae22 100644 --- a/global-functions +++ b/global-functions @@ -261,7 +261,7 @@ :return true; } } on-error={ - # catch error and fall through + $LogPrintExit debug ("Downloading package failed.") false; } / file remove [ find where name=$PkgDest ]; From 83a8743879918942dba3d81894f12ca2cff6dc4f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 17 May 2020 23:41:54 +0200 Subject: [PATCH 0351/2612] global-functions: $WaitTimeSync: replace comment with debug output --- global-functions | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index b4dae22..2ff1f43 100644 --- a/global-functions +++ b/global-functions @@ -730,6 +730,7 @@ # wait for time to become synced :set WaitTimeSync do={ + :global LogPrintExit; :global TimeIsSync; :while ([ $TimeIsSync ] = false) do={ @@ -738,7 +739,7 @@ :do { / system script run rotate-ntp; } on-error={ - # catch error and fall through + $LogPrintExit debug ("Running rotate-ntp failed.") false; } } :delay 1s; From bcf57f0adb17cdc44d391caed54a6319522ba089 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 May 2020 22:59:14 +0200 Subject: [PATCH 0352/2612] check-routeros-update: accept lower and upper case characters --- check-routeros-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-routeros-update b/check-routeros-update index 7df980e..079c918 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -62,7 +62,7 @@ :if ([ $ScriptFromTerminal "check-routeros-update" ] = true) do={ :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); - :if ([ :terminal inkey timeout=60 ] = 121) do={ + :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ $DoUpdate; } else={ :put "Canceled..."; From 856c879fd8cccc2f8dc7243b60233efd1453e22d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 May 2020 22:59:50 +0200 Subject: [PATCH 0353/2612] packages-update: accept lower and upper case characters --- packages-update | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages-update b/packages-update index fb7ff58..f4f5407 100644 --- a/packages-update +++ b/packages-update @@ -36,7 +36,7 @@ $ScriptLock "packages-update"; :if ([ $ScriptFromTerminal "packages-update" ] = true) do={ :if (!([ /system resource get version ] ~ ($Update->"channel"))) do={ :put "Update channel changed. Want to downgrade? [y/N]"; - :if ([ :terminal inkey timeout=60 ] = 121) do={ + :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ $LogPrintExit info ("Rebooting for downgrade.") false; :delay 1s; / system package downgrade; @@ -44,7 +44,7 @@ $ScriptLock "packages-update"; } :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; - :if ([ :terminal inkey timeout=60 ] = 115) do={ + :if (([ :terminal inkey timeout=60 ] % 32) = 19) do={ / system scheduler add name="reboot-for-update" start-time=03:00:00 interval=1d \ on-event=(":global RandomDelay; \$RandomDelay 3600; " . \ "/ system scheduler remove reboot-for-update; / system reboot;"); From b7172b69cee46cf9e001918333855e9b79aa15e0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 May 2020 23:33:49 +0200 Subject: [PATCH 0354/2612] global-functions: add $DNSIsResolving --- global-functions | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/global-functions b/global-functions index 2ff1f43..d7ee6b8 100644 --- a/global-functions +++ b/global-functions @@ -24,6 +24,7 @@ :global CleanFilePath; :global DefaultRouteIsReachable; :global DeviceInfo; +:global DNSIsResolving; :global DownloadPackage; :global GetMacVendor; :global GetRandom; @@ -218,6 +219,16 @@ :return $Info; } +# check if DNS is resolving +:set DNSIsResolving do={ + :do { + :resolve mikrotik.com; + :return true; + } on-error={ + :return false; + } +} + # download package from upgrade server :set DownloadPackage do={ :local PkgName [ :tostr $1 ]; From 4166bf91c348a261563087e14cb839e2695b991f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 May 2020 23:34:58 +0200 Subject: [PATCH 0355/2612] global-functions: add $WaitDNSResolving --- global-functions | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/global-functions b/global-functions index d7ee6b8..21e89af 100644 --- a/global-functions +++ b/global-functions @@ -42,6 +42,7 @@ :global TimeIsSync; :global UrlEncode; :global WaitDefaultRouteReachable; +:global WaitDNSResolving; :global WaitForFile; :global WaitTimeSync; @@ -722,6 +723,15 @@ } } +# wait for DNS to resolve +:set WaitDNSResolving do={ + :global DNSIsResolving; + + :while ([ $DNSIsResolving ] = false) do={ + :delay 1s; + } +} + # wait for file to be available :set WaitForFile do={ :global CleanFilePath; From e871cb5a6918c7f4f721fee7be94fe3f261089be Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 May 2020 23:35:24 +0200 Subject: [PATCH 0356/2612] global-functions: add $WaitFullyConnected --- global-functions | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/global-functions b/global-functions index 21e89af..4bc0d0b 100644 --- a/global-functions +++ b/global-functions @@ -44,6 +44,7 @@ :global WaitDefaultRouteReachable; :global WaitDNSResolving; :global WaitForFile; +:global WaitFullyConnected; :global WaitTimeSync; # check and download required certificate @@ -749,6 +750,17 @@ :return true; } +# wait to be fully connected (default route is reachable, time is sync, DNS resolves) +:set WaitFullyConnected do={ + :global WaitDefaultRouteReachable; + :global WaitDNSResolving; + :global WaitTimeSync; + + $WaitDefaultRouteReachable; + $WaitTimeSync; + $WaitDNSResolving; +} + # wait for time to become synced :set WaitTimeSync do={ :global LogPrintExit; From c88de834e4e30b3797c184857a9d8dffea94ab35 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 May 2020 23:58:46 +0200 Subject: [PATCH 0357/2612] doc/daily-psk: use $WaitFullyConnected --- doc/daily-psk.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/daily-psk.md b/doc/daily-psk.md index e6d7aae..26ab3d1 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -28,7 +28,7 @@ For local interface: And add schedulers to run the script: / system scheduler add interval=1d name=daily-psk-nightly on-event="/ system script run daily-psk.local;" start-date=may/23/2018 start-time=03:00:00; - / system scheduler add name=daily-psk-startup on-event=":global WaitTimeSync; / system script { run global-wait; \$WaitTimeSync; run daily-psk.local; }" start-time=startup; + / system scheduler add name=daily-psk-startup on-event=":global WaitFullyConnected; / system script { run global-wait; \$WaitFullyConnected; run daily-psk.local; }" start-time=startup; These will update the passphrase on boot and nightly at 3:00. From 6a50e80825cb99903968935f1932b77ae7e32886 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 May 2020 23:59:12 +0200 Subject: [PATCH 0358/2612] doc/early-errors: use $WaitFullyConnected --- doc/early-errors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/early-errors.md b/doc/early-errors.md index 53c04a5..adae531 100644 --- a/doc/early-errors.md +++ b/doc/early-errors.md @@ -25,7 +25,7 @@ Just install this script and [global-wait](global-wait.md): ... and add a scheduler: - / system scheduler add name=early-erros on-event=":global WaitTimeSync; / system script { run global-wait; \$WaitTimeSync; run early-errors; }" start-time=startup; + / system scheduler add name=early-erros on-event=":global WaitFullyConnected; / system script { run global-wait; \$WaitFullyConnected; run early-errors; }" start-time=startup; Configuration ------------- From 7ecda2204fa5ee69996ab579c89bdf87e175686c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 27 May 2020 00:13:57 +0200 Subject: [PATCH 0359/2612] early-errors: wait to be fully connected --- doc/early-errors.md | 2 +- early-errors | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/early-errors.md b/doc/early-errors.md index adae531..f6209b7 100644 --- a/doc/early-errors.md +++ b/doc/early-errors.md @@ -25,7 +25,7 @@ Just install this script and [global-wait](global-wait.md): ... and add a scheduler: - / system scheduler add name=early-erros on-event=":global WaitFullyConnected; / system script { run global-wait; \$WaitFullyConnected; run early-errors; }" start-time=startup; + / system scheduler add name=early-erros on-event="/ system script { run global-wait; run early-errors; }" start-time=startup; Configuration ------------- diff --git a/early-errors b/early-errors index f2793fc..a48c3cd 100644 --- a/early-errors +++ b/early-errors @@ -8,6 +8,9 @@ :global Identity; :global SendNotification; +:global WaitFullyConnected; + +$WaitFullyConnected; :local Errors [ / log find where (topics~"error" or topics~"critical") !(topics~"e-mail") !(topics~"dns") ]; :local ErrCount [ :len $Errors ]; From 75979116727eed330b404dfb9c01354704193fc9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 27 May 2020 00:21:30 +0200 Subject: [PATCH 0360/2612] daily-psk: wait to be fully connected --- daily-psk.capsman | 4 +++- daily-psk.local | 4 +++- daily-psk.template | 4 +++- doc/daily-psk.md | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/daily-psk.capsman b/daily-psk.capsman index 623ef0c..a457454 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -15,8 +15,9 @@ :global SendNotification; :global UrlEncode; :global WaitForFile; +:global WaitFullyConnected; -:local Seen [ :toarray "" ]; +$WaitFullyConnected; # return pseudo-random string for PSK :local GeneratePSK do={ @@ -48,6 +49,7 @@ ($DailyPskSecrets->2->$WeekDay)); } +:local Seen [ :toarray "" ]; :local Date [ / system clock get date ]; :local NewPsk [ $GeneratePSK $Date ]; diff --git a/daily-psk.local b/daily-psk.local index 6245ebe..d4d6a72 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -15,8 +15,9 @@ :global SendNotification; :global UrlEncode; :global WaitForFile; +:global WaitFullyConnected; -:local Seen [ :toarray "" ]; +$WaitFullyConnected; # return pseudo-random string for PSK :local GeneratePSK do={ @@ -48,6 +49,7 @@ ($DailyPskSecrets->2->$WeekDay)); } +:local Seen [ :toarray "" ]; :local Date [ / system clock get date ]; :local NewPsk [ $GeneratePSK $Date ]; diff --git a/daily-psk.template b/daily-psk.template index 3181b1a..e9f061f 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -16,8 +16,9 @@ :global SendNotification; :global UrlEncode; :global WaitForFile; +:global WaitFullyConnected; -:local Seen [ :toarray "" ]; +$WaitFullyConnected; # return pseudo-random string for PSK :local GeneratePSK do={ @@ -49,6 +50,7 @@ ($DailyPskSecrets->2->$WeekDay)); } +:local Seen [ :toarray "" ]; :local Date [ / system clock get date ]; :local NewPsk [ $GeneratePSK $Date ]; diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 26ab3d1..c6055d6 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -28,7 +28,7 @@ For local interface: And add schedulers to run the script: / system scheduler add interval=1d name=daily-psk-nightly on-event="/ system script run daily-psk.local;" start-date=may/23/2018 start-time=03:00:00; - / system scheduler add name=daily-psk-startup on-event=":global WaitFullyConnected; / system script { run global-wait; \$WaitFullyConnected; run daily-psk.local; }" start-time=startup; + / system scheduler add name=daily-psk-startup on-event="/ system script { run global-wait; run daily-psk.local; }" start-time=startup; These will update the passphrase on boot and nightly at 3:00. From bfcf861b51039c394cf91b65db4cdd4fe4cd3846 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 2 Jun 2020 22:05:21 +0200 Subject: [PATCH 0361/2612] dhcp-to-dns: add a marker for new records --- dhcp-to-dns | 8 +++++++- doc/dhcp-to-dns.md | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index f88599c..f883cd0 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -21,6 +21,12 @@ :local Ttl 5m; :local CommentPrefix "managed by dhcp-to-dns for "; +:if ([ / ip dns static print count-only where comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled ] = 0) do={ + / ip dns static add comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled=yes; + $LogPrintExit warning "Added disabled static dns record with comment '--- dhcp-to-dns above ---'." false; +} +:local PlaceBefore [ / ip dns static find where comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled ]; + :foreach DnsRecord in=[ / ip dns static find where comment ~ $CommentPrefix ] do={ :local DnsRecordVal [ / ip dns static get $DnsRecord ]; :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; @@ -63,6 +69,6 @@ } } else={ $LogPrintExit info ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false; - / ip dns static add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment; + / ip dns static add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 3f25659..9f8cb8b 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -25,6 +25,10 @@ A scheduler cares about cleanup: Configuration ------------- +On first run a disabled static dns record acting as marker (with comment +"`--- dhcp-to-dns above ---`") is added. Move this entry to define where new +entries are to be added. + The configuration goes to `global-config-overlay`, these are the parameters: * `Domain`: the domain used for dns records From 35894168408096ce7e33c52bf06b5ad80d3493d1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 Jun 2020 11:08:18 +0200 Subject: [PATCH 0362/2612] add certificate 'GTS CA 1O1' This is used by DNS over HTTPS services: https://dns.google/dns-query --- certs/GTS CA 1O1.pem | 47 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 certs/GTS CA 1O1.pem diff --git a/certs/GTS CA 1O1.pem b/certs/GTS CA 1O1.pem new file mode 100644 index 0000000..dc3aff5 --- /dev/null +++ b/certs/GTS CA 1O1.pem @@ -0,0 +1,47 @@ +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 +MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL +v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 +eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq +tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd +C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa +zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB +mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH +V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n +bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG +3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs +J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO +291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS +ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd +AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIESjCCAzKgAwIBAgINAeO0mqGNiqmBJWlQuDANBgkqhkiG9w0BAQsFADBMMSAw +HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFs +U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xNzA2MTUwMDAwNDJaFw0yMTEy +MTUwMDAwNDJaMEIxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVHb29nbGUgVHJ1c3Qg +U2VydmljZXMxEzARBgNVBAMTCkdUUyBDQSAxTzEwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDQGM9F1IvN05zkQO9+tN1pIRvJzzyOTHW5DzEZhD2ePCnv +UA0Qk28FgICfKqC9EksC4T2fWBYk/jCfC3R3VZMdS/dN4ZKCEPZRrAzDsiKUDzRr +mBBJ5wudgzndIMYcLe/RGGFl5yODIKgjEv/SJH/UL+dEaltN11BmsK+eQmMF++Ac +xGNhr59qM/9il71I2dN8FGfcddwuaej4bXhp0LcQBbjxMcI7JP0aM3T4I+DsaxmK +FsbjzaTNC9uzpFlgOIg7rR25xoynUxv8vNmkq7zdPGHXkxWY7oG9j+JkRyBABk7X +rJfoucBZEqFJJSPk7XA0LKW0Y3z5oz2D0c1tJKwHAgMBAAGjggEzMIIBLzAOBgNV +HQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1Ud +EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJjR+G4Q68+b7GCfGJAboOt9Cf0rMB8G +A1UdIwQYMBaAFJviB1dnHB7AagbeWbSaLd/cGYYuMDUGCCsGAQUFBwEBBCkwJzAl +BggrBgEFBQcwAYYZaHR0cDovL29jc3AucGtpLmdvb2cvZ3NyMjAyBgNVHR8EKzAp +MCegJaAjhiFodHRwOi8vY3JsLnBraS5nb29nL2dzcjIvZ3NyMi5jcmwwPwYDVR0g +BDgwNjA0BgZngQwBAgIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly9wa2kuZ29vZy9y +ZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAGoA+Nnn78y6pRjd9XlQWNa7H +TgiZ/r3RNGkmUmYHPQq6Scti9PEajvwRT2iWTHQr02fesqOqBY2ETUwgZQ+lltoN +FvhsO9tvBCOIazpswWC9aJ9xju4tWDQH8NVU6YZZ/XteDSGU9YzJqPjY8q3MDxrz +mqepBCf5o8mw/wJ4a2G6xzUr6Fb6T8McDO22PLRL6u3M4Tzs3A2M1j6bykJYi8wW +IRdAvKLWZu/axBVbzYmqmwkm5zLSDW5nIAJbELCQCZwMH56t2Dvqofxs6BBcCFIZ +USpxu6x6td0V7SvJCCosirSmIatj/9dSSVDQibet8q/7UK4v4ZUN80atnZz1yg== +-----END CERTIFICATE----- From a1d05f93c658b79ece0565241fd3fce882ac99cd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Jun 2020 12:23:50 +0200 Subject: [PATCH 0363/2612] global-functions: add $GetRandomSha256 --- global-functions | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/global-functions b/global-functions index 4bc0d0b..a37ce5d 100644 --- a/global-functions +++ b/global-functions @@ -28,6 +28,7 @@ :global DownloadPackage; :global GetMacVendor; :global GetRandom; +:global GetRandomSha256; :global LogPrintExit; :global MailServerIsUp; :global MkDir; @@ -316,6 +317,17 @@ :return ($Sum % $Max); } +# generate random sha256 string +# returns 64 bytes of 0-9 and a-f +:set GetRandomSha256 do={ + :local FingerPrint; + / certificate add name=GetRandomSha256-template common-name=GetRandomSha256 key-size=prime256v1; + / certificate sign GetRandomSha256-template name=GetRandomSha256 without-paging as-value; + :set FingerPrint [ / certificate get GetRandomSha256 fingerprint ]; + / certificate remove GetRandomSha256; + :return $FingerPrint; +} + # log and print with same text, optionally exit :set LogPrintExit do={ :local Severity [ :tostr $1 ]; From 529dbbe4f811653ffcf176ef7f0242ef892c8fe3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Jun 2020 12:49:52 +0200 Subject: [PATCH 0364/2612] global-functions: rename $GetRandom -> $GetRandomNumber --- global-functions | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/global-functions b/global-functions index a37ce5d..e6b40ba 100644 --- a/global-functions +++ b/global-functions @@ -27,7 +27,7 @@ :global DNSIsResolving; :global DownloadPackage; :global GetMacVendor; -:global GetRandom; +:global GetRandomNumber; :global GetRandomSha256; :global LogPrintExit; :global MailServerIsUp; @@ -307,7 +307,7 @@ # generate random number # Warning: This is a *very* weak algorithm and in *no way* # useful for cryptography or similar! -:set GetRandom do={ +:set GetRandomNumber do={ :local Max ([ :tonum $1 ] + 1); :local Sum 0; @@ -415,9 +415,9 @@ # delay a random amount of seconds :set RandomDelay do={ - :global GetRandom; + :global GetRandomNumber; - :delay ([ $GetRandom $1 ] . "s"); + :delay ([ $GetRandomNumber $1 ] . "s"); } # check if script is run from terminal From 12015af85500a7bf836bb64478f07efc1e4672e3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Jun 2020 12:51:09 +0200 Subject: [PATCH 0365/2612] global-functions: $GetRandomNumber: use $GetRandomSha256 --- global-functions | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/global-functions b/global-functions index e6b40ba..149838b 100644 --- a/global-functions +++ b/global-functions @@ -305,16 +305,22 @@ } # generate random number -# Warning: This is a *very* weak algorithm and in *no way* -# useful for cryptography or similar! :set GetRandomNumber do={ :local Max ([ :tonum $1 ] + 1); - :local Sum 0; - :foreach Interface in=[ /interface find ] do={ - :set Sum ($Sum + [ /interface get $Interface tx-byte ]); + :global GetRandomSha256; + + :local Num; + :local Sha256 [ $GetRandomSha256 ]; + + :for I from=0 to=63 do={ + :local Char [ :pick $Sha256 $I ]; + :if ($Char~"[0-9]") do={ + :set Num ($Num . $Char); + } } - :return ($Sum % $Max); + + :return ([ :tonum [ :pick $Num 0 18 ] ] % $Max); } # generate random sha256 string From 71ad56aaccecb40253e8e697ff36e17b508bb927 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 19 Jun 2020 22:17:42 +0200 Subject: [PATCH 0366/2612] explicitly name the license Copyright (C) 2013-2020 Christian Hesse This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. https://www.gnu.org/licenses/#GPL https://www.gnu.org/licenses/gpl.html https://www.gnu.org/licenses/gpl.md --- COPYING.md | 675 ++++++++++++++++++++++++++++++++ README.md | 16 +- accesslist-duplicates.capsman | 1 + accesslist-duplicates.local | 1 + accesslist-duplicates.template | 1 + bridge-port-to-default | 1 + bridge-port-toggle | 1 + capsman-download-packages | 1 + capsman-rolling-upgrade | 1 + certificate-renew-issued | 1 + check-certificates | 1 + check-health | 1 + check-lte-firmware-upgrade | 1 + check-routeros-update | 1 + cloud-backup | 1 + collect-wireless-mac.capsman | 1 + collect-wireless-mac.local | 1 + collect-wireless-mac.template | 1 + daily-psk.capsman | 1 + daily-psk.local | 1 + daily-psk.template | 1 + dhcp-lease-comment.capsman | 1 + dhcp-lease-comment.local | 1 + dhcp-lease-comment.template | 1 + dhcp-to-dns | 1 + early-errors | 1 + email-backup | 1 + global-config | 1 + global-config-overlay | 1 + global-config.changes | 1 + global-functions | 1 + global-wait | 1 + gps-track | 1 + hotspot-to-wpa | 1 + ip-addr-bridge | 1 + ipv6-update | 1 + learn-mac-based-vlan | 1 + lease-script | 1 + leds-day-mode | 1 + leds-night-mode | 1 + leds-toggle-mode | 1 + manage-umts | 1 + mode-button-event | 1 + mode-button-scheduler | 1 + netwatch-notify | 1 + netwatch-syslog | 1 + packages-update | 1 + ppp-on-up | 1 + rotate-ntp | 1 + sms-action | 1 + sms-forward | 1 + ssh-keys-import | 1 + super-mario-theme | 1 + unattended-lte-firmware-upgrade | 1 + update-gre-address | 1 + update-tunnelbroker | 1 + upload-backup | 1 + 57 files changed, 745 insertions(+), 1 deletion(-) create mode 100644 COPYING.md diff --git a/COPYING.md b/COPYING.md new file mode 100644 index 0000000..2fb2e74 --- /dev/null +++ b/COPYING.md @@ -0,0 +1,675 @@ +### GNU GENERAL PUBLIC LICENSE + +Version 3, 29 June 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. + + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +### Preamble + +The GNU General Public License is a free, copyleft license for +software and other kinds of works. + +The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom +to share and change all versions of a program--to make sure it remains +free software for all its users. We, the Free Software Foundation, use +the GNU General Public License for most of our software; it applies +also to any other work released this way by its authors. You can apply +it to your programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you +have certain responsibilities if you distribute copies of the +software, or if you modify it: responsibilities to respect the freedom +of others. + +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + +Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + +Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the +manufacturer can do so. This is fundamentally incompatible with the +aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for +individuals to use, which is precisely where it is most unacceptable. +Therefore, we have designed this version of the GPL to prohibit the +practice for those products. If such problems arise substantially in +other domains, we stand ready to extend this provision to those +domains in future versions of the GPL, as needed to protect the +freedom of users. + +Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish +to avoid the special danger that patents applied to a free program +could make it effectively proprietary. To prevent this, the GPL +assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and +modification follow. + +### TERMS AND CONDITIONS + +#### 0. Definitions. + +"This License" refers to version 3 of the GNU General Public License. + +"Copyright" also means copyright-like laws that apply to other kinds +of works, such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + +To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of +an exact copy. The resulting work is called a "modified version" of +the earlier work or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based +on the Program. + +To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + +To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user +through a computer network, with no transfer of a copy, is not +conveying. + +An interactive user interface displays "Appropriate Legal Notices" to +the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +#### 1. Source Code. + +The "source code" for a work means the preferred form of the work for +making modifications to it. "Object code" means any non-source form of +a work. + +A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + +The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can +regenerate automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same +work. + +#### 2. Basic Permissions. + +All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, +without conditions so long as your license otherwise remains in force. +You may convey covered works to others for the sole purpose of having +them make modifications exclusively for you, or provide you with +facilities for running those works, provided that you comply with the +terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for +you must do so exclusively on your behalf, under your direction and +control, on terms that prohibit them from making any copies of your +copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under the +conditions stated below. Sublicensing is not allowed; section 10 makes +it unnecessary. + +#### 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + +When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such +circumvention is effected by exercising rights under this License with +respect to the covered work, and you disclaim any intention to limit +operation or modification of the work as a means of enforcing, against +the work's users, your or third parties' legal rights to forbid +circumvention of technological measures. + +#### 4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + +#### 5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these +conditions: + +- a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. +- b) The work must carry prominent notices stating that it is + released under this License and any conditions added under + section 7. This requirement modifies the requirement in section 4 + to "keep intact all notices". +- c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. +- d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + +A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + +#### 6. Conveying Non-Source Forms. + +You may convey a covered work in object code form under the terms of +sections 4 and 5, provided that you also convey the machine-readable +Corresponding Source under the terms of this License, in one of these +ways: + +- a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. +- b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the Corresponding + Source from a network server at no charge. +- c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. +- d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. +- e) Convey the object code using peer-to-peer transmission, + provided you inform other peers where the object code and + Corresponding Source of the work are being offered to the general + public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + +A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, +family, or household purposes, or (2) anything designed or sold for +incorporation into a dwelling. In determining whether a product is a +consumer product, doubtful cases shall be resolved in favor of +coverage. For a particular product received by a particular user, +"normally used" refers to a typical or common use of that class of +product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected +to use, the product. A product is a consumer product regardless of +whether the product has substantial commercial, industrial or +non-consumer uses, unless such uses represent the only significant +mode of use of the product. + +"Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to +install and execute modified versions of a covered work in that User +Product from a modified version of its Corresponding Source. The +information must suffice to ensure that the continued functioning of +the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + +The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or +updates for a work that has been modified or installed by the +recipient, or for the User Product in which it has been modified or +installed. Access to a network may be denied when the modification +itself materially and adversely affects the operation of the network +or violates the rules and protocols for communication across the +network. + +Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + +#### 7. Additional Terms. + +"Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders +of that material) supplement the terms of this License with terms: + +- a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or +- b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or +- c) Prohibiting misrepresentation of the origin of that material, + or requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or +- d) Limiting the use for publicity purposes of names of licensors + or authors of the material; or +- e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or +- f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions + of it) with contractual assumptions of liability to the recipient, + for any liability that these contractual assumptions directly + impose on those licensors and authors. + +All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; the +above requirements apply either way. + +#### 8. Termination. + +You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + +#### 9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or run +a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + +#### 10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + +An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + +#### 11. Patents. + +A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims owned +or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + +In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + +If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + +A patent license is "discriminatory" if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on +the non-exercise of one or more of the rights that are specifically +granted under this License. You may not convey a covered work if you +are a party to an arrangement with a third party that is in the +business of distributing software, under which you make payment to the +third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties +who would receive the covered work from you, a discriminatory patent +license (a) in connection with copies of the covered work conveyed by +you (or copies made from those copies), or (b) primarily for and in +connection with specific products or compilations that contain the +covered work, unless you entered into that arrangement, or that patent +license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + +#### 12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under +this License and any other pertinent obligations, then as a +consequence you may not convey it at all. For example, if you agree to +terms that obligate you to collect a royalty for further conveying +from those to whom you convey the Program, the only way you could +satisfy both those terms and this License would be to refrain entirely +from conveying the Program. + +#### 13. Use with the GNU Affero General Public License. + +Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + +#### 14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions +of the GNU General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in +detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies that a certain numbered version of the GNU General Public +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that numbered version or +of any later version published by the Free Software Foundation. If the +Program does not specify a version number of the GNU General Public +License, you may choose any version ever published by the Free +Software Foundation. + +If the Program specifies that a proxy can decide which future versions +of the GNU General Public License can be used, that proxy's public +statement of acceptance of a version permanently authorizes you to +choose that version for the Program. + +Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + +#### 15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + +#### 16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR +CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT +NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR +LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM +TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER +PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +#### 17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS + +### How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + +To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively state +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper +mail. + +If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands \`show w' and \`show c' should show the +appropriate parts of the General Public License. Of course, your +program's commands might be different; for a GUI interface, you would +use an "about box". + +You should also get your employer (if you work as a programmer) or +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. For more information on this, and how to apply and follow +the GNU GPL, see . + +The GNU General Public License does not permit incorporating your +program into proprietary programs. If your program is a subroutine +library, you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use the +GNU Lesser General Public License instead of this License. But first, +please read . diff --git a/README.md b/README.md index bcc0890..54473c3 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,8 @@ by [MikroTik](https://mikrotik.com/aboutus) for networking tasks. This repository holds a number of [scripts](https://wiki.mikrotik.com/wiki/Manual:Scripting) to manage RouterOS devices or extend their functionality. -*Use at your own risk!* +*Use at your own risk*, pay attention to +[license and warranty](#license-and-warranty)! Requirements ------------ @@ -203,6 +204,19 @@ business please consider to Thanks a lot for your support! +License and warranty +-------------------- + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +[GNU General Public License](COPYING.md) for more details. + Upstream -------- diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman index b441c31..e8d99e6 100644 --- a/accesslist-duplicates.capsman +++ b/accesslist-duplicates.capsman @@ -1,6 +1,7 @@ #!rsc # RouterOS script: accesslist-duplicates.capsman # Copyright (c) 2018-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local index 00d9ae0..c310fea 100644 --- a/accesslist-duplicates.local +++ b/accesslist-duplicates.local @@ -1,6 +1,7 @@ #!rsc # RouterOS script: accesslist-duplicates.local # Copyright (c) 2018-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template index f527810..1edf700 100644 --- a/accesslist-duplicates.template +++ b/accesslist-duplicates.template @@ -1,6 +1,7 @@ #!rsc # RouterOS script: accesslist-duplicates%TEMPL% # Copyright (c) 2018-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/bridge-port-to-default b/bridge-port-to-default index 409dcb9..7051f34 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -1,6 +1,7 @@ #!rsc # RouterOS script: bridge-port-to-default # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # reset bridge ports to default bridge # https://git.eworm.de/cgit/routeros-scripts/about/doc/bridge-port.md diff --git a/bridge-port-toggle b/bridge-port-toggle index a8ad8ad..e3967bd 100644 --- a/bridge-port-toggle +++ b/bridge-port-toggle @@ -1,6 +1,7 @@ #!rsc # RouterOS script: bridge-port-toggle # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # toggle bridge ports between default and alt bridge # https://git.eworm.de/cgit/routeros-scripts/about/doc/bridge-port.md diff --git a/capsman-download-packages b/capsman-download-packages index c17a09d..e65ddc7 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -2,6 +2,7 @@ # RouterOS script: capsman-download-packages # Copyright (c) 2018-2020 Christian Hesse # Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # download and cleanup packages for CAP installation from CAPsMAN # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index a496167..698ff93 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -2,6 +2,7 @@ # RouterOS script: capsman-rolling-upgrade # Copyright (c) 2018-2020 Christian Hesse # Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # upgrade CAPs one after another # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md diff --git a/certificate-renew-issued b/certificate-renew-issued index fe33b93..27eec51 100644 --- a/certificate-renew-issued +++ b/certificate-renew-issued @@ -1,6 +1,7 @@ #!rsc # RouterOS script: certificate-renew-issued # Copyright (c) 2019-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # renew locally issued certificates # https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md diff --git a/check-certificates b/check-certificates index 0964bde..9e65586 100644 --- a/check-certificates +++ b/check-certificates @@ -1,6 +1,7 @@ #!rsc # RouterOS script: check-certificates # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for certificate validity # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md diff --git a/check-health b/check-health index e41984f..3684808 100644 --- a/check-health +++ b/check-health @@ -1,6 +1,7 @@ #!rsc # RouterOS script: check-health # Copyright (c) 2019-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for RouterOS health state # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 218aac0..6aaec79 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -1,6 +1,7 @@ #!rsc # RouterOS script: check-lte-firmware-upgrade # Copyright (c) 2018-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for LTE firmware upgrade, send notification # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md diff --git a/check-routeros-update b/check-routeros-update index 079c918..9109e1d 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -1,6 +1,7 @@ #!rsc # RouterOS script: check-routeros-update # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for RouterOS update, send notification and/or install # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md diff --git a/cloud-backup b/cloud-backup index 89648d5..dd03a98 100644 --- a/cloud-backup +++ b/cloud-backup @@ -1,6 +1,7 @@ #!rsc # RouterOS script: cloud-backup # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # upload backup to MikroTik cloud # https://git.eworm.de/cgit/routeros-scripts/about/doc/cloud-backup.md diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index c89ea19..5979156 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -1,6 +1,7 @@ #!rsc # RouterOS script: collect-wireless-mac.capsman # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index eac8734..3b86d72 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -1,6 +1,7 @@ #!rsc # RouterOS script: collect-wireless-mac.local # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 0f936b3..f644f47 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -1,6 +1,7 @@ #!rsc # RouterOS script: collect-wireless-mac%TEMPL% # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md diff --git a/daily-psk.capsman b/daily-psk.capsman index a457454..f8cbb20 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -2,6 +2,7 @@ # RouterOS script: daily-psk.capsman # Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md diff --git a/daily-psk.local b/daily-psk.local index d4d6a72..a878940 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -2,6 +2,7 @@ # RouterOS script: daily-psk.local # Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md diff --git a/daily-psk.template b/daily-psk.template index e9f061f..5c691e6 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -2,6 +2,7 @@ # RouterOS script: daily-psk%TEMPL% # Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index 51ccca2..7e1dce1 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -1,6 +1,7 @@ #!rsc # RouterOS script: dhcp-lease-comment.capsman # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index 96b98e1..e20a137 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -1,6 +1,7 @@ #!rsc # RouterOS script: dhcp-lease-comment.local # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index 6892f1b..2971036 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -1,6 +1,7 @@ #!rsc # RouterOS script: dhcp-lease-comment%TEMPL% # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-to-dns b/dhcp-to-dns index f883cd0..0a7c1af 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -1,6 +1,7 @@ #!rsc # RouterOS script: dhcp-to-dns # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check DHCP leases and add/remove/update DNS entries # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md diff --git a/early-errors b/early-errors index a48c3cd..015767a 100644 --- a/early-errors +++ b/early-errors @@ -1,6 +1,7 @@ #!rsc # RouterOS script: early-errors # Copyright (c) 2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # send notification with early errors # https://git.eworm.de/cgit/routeros-scripts/about/doc/early-errors.md diff --git a/email-backup b/email-backup index 3a00d04..ff8a678 100644 --- a/email-backup +++ b/email-backup @@ -1,6 +1,7 @@ #!rsc # RouterOS script: email-backup # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # create and email backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/email-backup.md diff --git a/global-config b/global-config index d42a5d1..446950b 100644 --- a/global-config +++ b/global-config @@ -1,6 +1,7 @@ #!rsc # RouterOS script: global-config # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global configuration # https://git.eworm.de/cgit/routeros-scripts/about/ diff --git a/global-config-overlay b/global-config-overlay index 5bb91a9..a3d0ba5 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -1,6 +1,7 @@ #!rsc # RouterOS script: global-config-overlay # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global configuration, custom overlay # https://git.eworm.de/cgit/routeros-scripts/about/ diff --git a/global-config.changes b/global-config.changes index 9d7ec00..5a2bb7a 100644 --- a/global-config.changes +++ b/global-config.changes @@ -1,5 +1,6 @@ # RouterOS global-config changes # Copyright (c) 2019-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # Changes for global-config to be added to notification on script updates :global GlobalConfigChanges { diff --git a/global-functions b/global-functions index 149838b..c3cab0c 100644 --- a/global-functions +++ b/global-functions @@ -2,6 +2,7 @@ # RouterOS script: global-functions # Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global functions # https://git.eworm.de/cgit/routeros-scripts/about/ diff --git a/global-wait b/global-wait index 7e3cc6c..f911593 100644 --- a/global-wait +++ b/global-wait @@ -1,6 +1,7 @@ #!rsc # RouterOS script: global-wait # Copyright (c) 2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # wait for global-functions to finish # https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md diff --git a/gps-track b/gps-track index f839eac..c815fdf 100644 --- a/gps-track +++ b/gps-track @@ -1,6 +1,7 @@ #!rsc # RouterOS script: gps-track # Copyright (c) 2018-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # track gps data by sending json data to http server # https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md diff --git a/hotspot-to-wpa b/hotspot-to-wpa index e862e45..a9fa7d9 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -1,6 +1,7 @@ #!rsc # RouterOS script: hotspot-to-wpa # Copyright (c) 2019-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # add private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/ip-addr-bridge b/ip-addr-bridge index 02781cc..ec403f5 100644 --- a/ip-addr-bridge +++ b/ip-addr-bridge @@ -1,6 +1,7 @@ #!rsc # RouterOS script: ip-addr-bridge # Copyright (c) 2018-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # enable or disable ip addresses based on bridge port state # https://git.eworm.de/cgit/routeros-scripts/about/doc/ip-addr-bridge.md diff --git a/ipv6-update b/ipv6-update index 4e73b8f..ecca490 100644 --- a/ipv6-update +++ b/ipv6-update @@ -1,6 +1,7 @@ #!rsc # RouterOS script: ipv6-update # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update firewall and dns settings on IPv6 prefix change # https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md diff --git a/learn-mac-based-vlan b/learn-mac-based-vlan index 73ffc37..14261c0 100644 --- a/learn-mac-based-vlan +++ b/learn-mac-based-vlan @@ -1,6 +1,7 @@ #!rsc # RouterOS script: learn-mac-based-vlan # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # learn MAC address for MAC-based-VLAN diff --git a/lease-script b/lease-script index 87c0c90..701994e 100644 --- a/lease-script +++ b/lease-script @@ -1,6 +1,7 @@ #!rsc # RouterOS script: lease-script # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run scripts on DHCP lease # https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md diff --git a/leds-day-mode b/leds-day-mode index cd59bab..74d826d 100644 --- a/leds-day-mode +++ b/leds-day-mode @@ -1,6 +1,7 @@ #!rsc # RouterOS script: leds-day-mode # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # enable LEDs # https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md diff --git a/leds-night-mode b/leds-night-mode index 9048a83..d394f49 100644 --- a/leds-night-mode +++ b/leds-night-mode @@ -1,6 +1,7 @@ #!rsc # RouterOS script: leds-night-mode # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # disable LEDs # https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md diff --git a/leds-toggle-mode b/leds-toggle-mode index 5f67979..16a31ae 100644 --- a/leds-toggle-mode +++ b/leds-toggle-mode @@ -1,6 +1,7 @@ #!rsc # RouterOS script: leds-toggle-mode # Copyright (c) 2018-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # toggle LEDs mode # https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md diff --git a/manage-umts b/manage-umts index f1eb861..2813786 100644 --- a/manage-umts +++ b/manage-umts @@ -1,6 +1,7 @@ #!rsc # RouterOS script: manage-umts # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # manage UMTS interface based on ethernet and wireless status diff --git a/mode-button-event b/mode-button-event index 0e1ac0d..246a9fd 100644 --- a/mode-button-event +++ b/mode-button-event @@ -1,6 +1,7 @@ #!rsc # RouterOS script: mode-button-event # Copyright (c) 2018-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run on mode-button event and count button presses # https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md diff --git a/mode-button-scheduler b/mode-button-scheduler index 632d6e3..56b9e24 100644 --- a/mode-button-scheduler +++ b/mode-button-scheduler @@ -1,6 +1,7 @@ #!rsc # RouterOS script: mode-button-scheduler # Copyright (c) 2018-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # act on multiple mode-botton presses from scheduler # https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md diff --git a/netwatch-notify b/netwatch-notify index dca8304..854d5fa 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -1,6 +1,7 @@ #!rsc # RouterOS script: netwatch-notify # Copyright (c) 2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # monitor netwatch and send notifications # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md diff --git a/netwatch-syslog b/netwatch-syslog index 81ef4d5..3f71a7b 100644 --- a/netwatch-syslog +++ b/netwatch-syslog @@ -1,6 +1,7 @@ #!rsc # RouterOS script: netwatch-syslog # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires: dont-require-permissions=yes # diff --git a/packages-update b/packages-update index f4f5407..ff683a2 100644 --- a/packages-update +++ b/packages-update @@ -1,6 +1,7 @@ #!rsc # RouterOS script: packages-update # Copyright (c) 2019-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # download packages and reboot for installation # https://git.eworm.de/cgit/routeros-scripts/about/doc/packages-update.md diff --git a/ppp-on-up b/ppp-on-up index 18229eb..a207e47 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -1,6 +1,7 @@ #!rsc # RouterOS script: ppp-on-up # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run scripts on ppp up # https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md diff --git a/rotate-ntp b/rotate-ntp index 22eca07..fa3909d 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -1,6 +1,7 @@ #!rsc # RouterOS script: rotate-ntp # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # rotate the ntp servers # https://git.eworm.de/cgit/routeros-scripts/about/doc/rotate-ntp.md diff --git a/sms-action b/sms-action index 2384167..ec37581 100644 --- a/sms-action +++ b/sms-action @@ -1,6 +1,7 @@ #!rsc # RouterOS script: sms-action # Copyright (c) 2018-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run action on received SMS # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-action.md diff --git a/sms-forward b/sms-forward index 2c6082c..63b44fe 100644 --- a/sms-forward +++ b/sms-forward @@ -1,6 +1,7 @@ #!rsc # RouterOS script: sms-forward # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # forward SMS to e-mail # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md diff --git a/ssh-keys-import b/ssh-keys-import index 9be92d1..07d5253 100644 --- a/ssh-keys-import +++ b/ssh-keys-import @@ -1,6 +1,7 @@ #!rsc # RouterOS script: ssh-keys-import # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # import ssh keys from file # https://git.eworm.de/cgit/routeros-scripts/about/doc/ssh-keys-import.md diff --git a/super-mario-theme b/super-mario-theme index a7bcb39..7e1a0d7 100644 --- a/super-mario-theme +++ b/super-mario-theme @@ -1,6 +1,7 @@ #!rsc # RouterOS script: super-mario-theme # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # play Super Mario theme # https://git.eworm.de/cgit/routeros-scripts/about/doc/super-mario-theme.md diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index e54c9fb..55d5fa6 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -1,6 +1,7 @@ #!rsc # RouterOS script: unattended-lte-firmware-upgrade # Copyright (c) 2018-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # schedule unattended lte firmware upgrade # https://git.eworm.de/cgit/routeros-scripts/about/doc/unattended-lte-firmware-upgrade.md diff --git a/update-gre-address b/update-gre-address index c0c7e31..3339b02 100644 --- a/update-gre-address +++ b/update-gre-address @@ -1,6 +1,7 @@ #!rsc # RouterOS script: update-gre-address # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update gre interface remote address with dynamic address from # ipsec remote peer diff --git a/update-tunnelbroker b/update-tunnelbroker index 2f7d579..a3c66eb 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -2,6 +2,7 @@ # RouterOS script: update-tunnelbroker # Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update local address of tunnelbroker interface # https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md diff --git a/upload-backup b/upload-backup index 1fc724b..30e7047 100644 --- a/upload-backup +++ b/upload-backup @@ -1,6 +1,7 @@ #!rsc # RouterOS script: upload-backup # Copyright (c) 2013-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # create and upload backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/upload-backup.md From 38760d05b0c5e771bfa1714c0ebde061d0611983 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Jun 2020 13:19:27 +0200 Subject: [PATCH 0367/2612] global-functions: add $IPCalc [admin@MikroTik] > $IPCalc 192.168.88.188/20 Address: 192.168.88.188 Netmask: 255.255.240.0 Network: 192.168.80.0/20 HostMin: 192.168.80.1 HostMax: 192.168.95.254 Broadcast: 192.168.95.255 --- global-functions | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/global-functions b/global-functions index c3cab0c..eaf4532 100644 --- a/global-functions +++ b/global-functions @@ -30,6 +30,7 @@ :global GetMacVendor; :global GetRandomNumber; :global GetRandomSha256; +:global IPCalc; :global LogPrintExit; :global MailServerIsUp; :global MkDir; @@ -335,6 +336,22 @@ :return $FingerPrint; } +# calculate and print netmask, network, min host, max host and broadcast +:set IPCalc do={ + :local Input [ :tostr $1 ]; + :local Address [ :toip [ :pick $Input 0 [ :find $Input "/" ] ] ]; + :local Bits [ :tonum [ :pick $Input ([ :find $Input "/" ] + 1) [ :len $Input ] ] ]; + :local Mask ((255.255.255.255 << (32 - $Bits)) & 255.255.255.255); + + :put ( \ + "Address: " . $Address . "\n\r" . \ + "Netmask: " . $Mask . "\n\r" . \ + "Network: " . ($Address & $Mask) . "/" . $Bits . "\n\r" . \ + "HostMin: " . (($Address & $Mask) | 0.0.0.1) . "\n\r" . \ + "HostMax: " . (($Address | ~$Mask) ^ 0.0.0.1) . "\n\r" . \ + "Broadcast: " . ($Address | ~$Mask)); +} + # log and print with same text, optionally exit :set LogPrintExit do={ :local Severity [ :tostr $1 ]; From baba79e3f5421b82158aa6a5466ae2b8c9caf34d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Jun 2020 16:32:19 +0200 Subject: [PATCH 0368/2612] global-functions: $GetRandomNumber: return 32bit number without limit --- global-functions | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index eaf4532..3a2b19d 100644 --- a/global-functions +++ b/global-functions @@ -308,7 +308,10 @@ # generate random number :set GetRandomNumber do={ - :local Max ([ :tonum $1 ] + 1); + :local Max 4294967296; + :if ([ :typeof $1 ] != "nothing" ) do={ + :set Max ([ :tonum $1 ] + 1); + } :global GetRandomSha256; From 2093661552c1da7ed4b81875eee39bc5e1167698 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 30 Jun 2020 20:06:55 +0200 Subject: [PATCH 0369/2612] global-functions: $GetRandomNumber: limit at 2^32-1 --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 3a2b19d..f529511 100644 --- a/global-functions +++ b/global-functions @@ -308,7 +308,7 @@ # generate random number :set GetRandomNumber do={ - :local Max 4294967296; + :local Max 4294967295; :if ([ :typeof $1 ] != "nothing" ) do={ :set Max ([ :tonum $1 ] + 1); } From 5b03ae4fa2a914c589a83add2a30549fa4847227 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 30 Jun 2020 20:26:37 +0200 Subject: [PATCH 0370/2612] global-functions: do not initialize $Sent* variables The scripts work without initialization, removing this makes sure the value is not overwritten on global functions reload. --- global-functions | 3 --- 1 file changed, 3 deletions(-) diff --git a/global-functions b/global-functions index f529511..c66f39f 100644 --- a/global-functions +++ b/global-functions @@ -13,9 +13,6 @@ # global variables not to be changed by user :global GlobalFunctionsReady false; :global Identity [ / system identity get name ]; -:global SentConfigChangesNotification "-"; -:global SentLteFirmwareUpgradeNotification "-"; -:global SentRouterosUpdateNotification "-"; # global functions :global CertificateAvailable; From 2aaea7c58e88ffa5df1daea1bc4da35a8f10811f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Jul 2020 00:14:08 +0200 Subject: [PATCH 0371/2612] global-functions: $ParseKeyValueStore: key without value for boolean true --- global-functions | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index c66f39f..a2a2ab4 100644 --- a/global-functions +++ b/global-functions @@ -431,8 +431,12 @@ } :local Result [ :toarray "" ]; :foreach KeyValue in=[ :toarray $Source ] do={ - :set KeyValue [ :toarray [ $CharacterReplace $KeyValue "=" "," ] ]; - :set ($Result->($KeyValue->0)) ($KeyValue->1); + :if ([ :find $KeyValue "=" ]) do={ + :set KeyValue [ :toarray [ $CharacterReplace $KeyValue "=" "," ] ]; + :set ($Result->($KeyValue->0)) ($KeyValue->1); + } else={ + :set ($Result->$KeyValue) true; + } } :return $Result; } From 149340ff34c0bf13791c4fafc070f98589c6ce6e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Jul 2020 00:33:05 +0200 Subject: [PATCH 0372/2612] global-functions: $ParseKeyValueStore: allow equals sign in value --- global-functions | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/global-functions b/global-functions index a2a2ab4..b7f1846 100644 --- a/global-functions +++ b/global-functions @@ -423,8 +423,6 @@ # parse key value store :set ParseKeyValueStore do={ - :global CharacterReplace; - :local Source $1; :if ([ :typeof $Source ] != "array") do={ :set Source [ :tostr $1 ]; @@ -432,8 +430,8 @@ :local Result [ :toarray "" ]; :foreach KeyValue in=[ :toarray $Source ] do={ :if ([ :find $KeyValue "=" ]) do={ - :set KeyValue [ :toarray [ $CharacterReplace $KeyValue "=" "," ] ]; - :set ($Result->($KeyValue->0)) ($KeyValue->1); + :set ($Result->[ :pick $KeyValue 0 [ :find $KeyValue "=" ] ]) \ + [ :pick $KeyValue ([ :find $KeyValue "=" ] + 1) [ :len $KeyValue ] ]; } else={ :set ($Result->$KeyValue) true; } From e38f3fb022a0588fff1fab66d68cbf7cba0be693 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Jul 2020 23:55:52 +0200 Subject: [PATCH 0373/2612] global-functions: $ScriptInstallUpdate: support ignore from comment Just add 'ignore' in comment... --- global-functions | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global-functions b/global-functions index b7f1846..f31136f 100644 --- a/global-functions +++ b/global-functions @@ -482,6 +482,7 @@ :global SentConfigChangesNotification; :global LogPrintExit; + :global ParseKeyValueStore; :global SendNotification; :foreach Script in=$Scripts do={ @@ -520,6 +521,8 @@ :foreach IgnoreLoop in=$ScriptUpdatesIgnore do={ :if ($IgnoreLoop = $ScriptVal->"name") do={ :set Ignore 1; } } + :local Comment [ $ParseKeyValueStore ($ScriptVal->"comment") ]; + :if ($Comment->"ignore" = true) do={ :set Ignore 1; } :if ($Ignore = 0) do={ $LogPrintExit debug ("Fetching script from url: " . $ScriptVal->"name") false; From ef2cb11665cb2c855437606fe3b1a3c18310807c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Jul 2020 00:03:21 +0200 Subject: [PATCH 0374/2612] global-functions: $ScriptInstallUpdate: get base url and suffix from comment Just set 'base-url=https://example.com/...' and/or 'url-suffix=\h=branch' in comment to overwrite settings from global configuration. --- global-functions | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index f31136f..e01d807 100644 --- a/global-functions +++ b/global-functions @@ -527,9 +527,13 @@ :if ($Ignore = 0) do={ $LogPrintExit debug ("Fetching script from url: " . $ScriptVal->"name") false; :do { + :local BaseUrl $ScriptUpdatesBaseUrl; + :local UrlSuffix $ScriptUpdatesUrlSuffix; + :if ([ :typeof ($Comment->"base-url") ] = "str") do={ :set BaseUrl ($Comment->"base-url"); } + :if ([ :typeof ($Comment->"url-suffix") ] = "str") do={ :set UrlSuffix ($Comment->"url-suffix"); } + :local Result [ / tool fetch check-certificate=yes-without-crl \ - ($ScriptUpdatesBaseUrl . $ScriptVal->"name" . $ScriptUpdatesUrlSuffix) \ - output=user as-value ]; + ($BaseUrl . $ScriptVal->"name" . $UrlSuffix) output=user as-value ]; :if ($Result->"status" = "finished") do={ :set SourceNew ($Result->"data"); } From 01fe371a0de982963ffeda0da852697726cd336e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Jul 2020 08:08:04 +0200 Subject: [PATCH 0375/2612] dhcp-to-dns: allow to configure 'dhcp' prefix in zone --- dhcp-to-dns | 10 ++++++---- global-config | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index 0a7c1af..4496854 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -9,15 +9,17 @@ :global Domain; :global HostNameInZone; :global Identity; +:global PrefixInZone; :global CharacterReplace; :global LogPrintExit; -:local Zone; +:local Zone $Domain; :if ($HostNameInZone = true) do={ - :set Zone ("dhcp." . $Identity . "." . $Domain); -} else={ - :set Zone ("dhcp." . $Domain); + :set Zone ($Identity . "." . $Zone); +} +:if ($PrefixInZone = true) do={ + :set Zone ("dhcp." . $Zone); } :local Ttl 5m; :local CommentPrefix "managed by dhcp-to-dns for "; diff --git a/global-config b/global-config index 446950b..5f22b6b 100644 --- a/global-config +++ b/global-config @@ -13,6 +13,7 @@ # This is used for DNS and backup file. :global Domain "example.com"; :global HostNameInZone true; +:global PrefixInZone true; # These addresses are used to send e-mails to. The to-address needs # to be filled; cc-address can be empty, one address or a comma From 49d5f52f0b1c0a18489bd0fa64894ed2c54532a2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Jul 2020 15:24:23 +0200 Subject: [PATCH 0376/2612] mode-button-scheduler: drop useless variable --- mode-button-scheduler | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mode-button-scheduler b/mode-button-scheduler index 56b9e24..0090426 100644 --- a/mode-button-scheduler +++ b/mode-button-scheduler @@ -28,8 +28,7 @@ :delay 1s; } - :local Parsed [ :parse $Code ]; - $Parsed; + [ :parse $Code ]; } else={ $LogPrintExit info ("No action defined for " . $Count . " mode-button presses.") false; } From 1c10044b2430c4bd8ec5955ead84fbe282587bef Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Jul 2020 15:19:46 +0200 Subject: [PATCH 0377/2612] netwatch-notify: add support for down hook Adding up-hook does not make sense... Just use netwatch's up-script for that. --- netwatch-notify | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index 854d5fa..350c088 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -18,7 +18,8 @@ :foreach Host in=[ / tool netwatch find where comment~"^notify," ] do={ :local HostVal [ / tool netwatch get $Host ]; - :local HostName ([ $ParseKeyValueStore ($HostVal->"comment") ]->"hostname"); + :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; + :local HostName ($HostInfo->"hostname"); :local Metric { "count"=0; "notified"=false }; :if ([ :typeof ($NetwatchNotify->$HostName) ] = "array") do={ @@ -43,6 +44,10 @@ $SendNotification ("Netwatch Notify: \E2\9D\8C " . $HostName . " down") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :set ($Metric->"notified") true; + :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ + $LogPrintExit info ("Running hook on host " . $HostName . " down: " . ($HostInfo->"down-hook")) false; + [ :parse ($HostInfo->"down-hook") ]; + } } } :set ($NetwatchNotify->$HostName) { "count"=($Metric->"count"); "notified"=($Metric->"notified") }; From a79461aff2b4f18ed8b18f72388cb4c1573bad8e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Jul 2020 15:44:41 +0200 Subject: [PATCH 0378/2612] netwatch-notify: add up hook for consistency Also this works around the permission/policy limitations in netwatch scripts. --- netwatch-notify | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netwatch-notify b/netwatch-notify index 350c088..0df92b5 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -34,6 +34,10 @@ $SendNotification ("Netwatch Notify: \E2\9C\85 " . $HostName . " up") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ "It was down for " . $Count . " checks."); + :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ + $LogPrintExit info ("Running hook on host " . $HostName . " up: " . ($HostInfo->"up-hook")) false; + [ :parse ($HostInfo->"up-hook") ]; + } } :set ($Metric->"notified") false; } else={ From 8dadde23f3eab2918a9d02e58ba4156f0a77d079 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Jul 2020 15:54:02 +0200 Subject: [PATCH 0379/2612] doc/netwatch-notify: document hooks --- doc/netwatch-notify.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 51768ff..f2ce7b4 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -29,6 +29,12 @@ The hosts to be checked have to be added to netwatch with specific comment: / tool netwatch add comment="notify, hostname=example.com" host=[ :resolve "example.com" ] timeout=5s; +It is possible to run an up hook command (`up-hook`) or down hook command +(`down-hook`) when a notification is triggered. This has to be added in +comment: + + / tool netwatch add comment="notify, hostname=poe-device, down-hook=/ interface ethernet poe power-cycle en21;" host=10.0.0.20 timeout=5s; + Also notification settings are required for e-mail and telegram. --- From e1b45f13f5f415a0422d88921b07e2f667d6f396 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Jul 2020 16:04:08 +0200 Subject: [PATCH 0380/2612] early-errors: exclude certificate messages This is most likely SCEP requests before network is up... --- early-errors | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/early-errors b/early-errors index 015767a..a2c5da3 100644 --- a/early-errors +++ b/early-errors @@ -13,7 +13,8 @@ $WaitFullyConnected; -:local Errors [ / log find where (topics~"error" or topics~"critical") !(topics~"e-mail") !(topics~"dns") ]; +:local Errors [ / log find where (topics~"error" or topics~"critical") \ + !(topics~"certificate") !(topics~"dns") !(topics~"e-mail") ]; :local ErrCount [ :len $Errors ]; :if ($ErrCount > 0) do={ :local Message ("The log on " . $Identity . " contains " . $ErrCount . \ From d8b2055fbce578884dfac36fca372101c14cd8af Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Jul 2020 00:01:00 +0200 Subject: [PATCH 0381/2612] global-functions: add $VersionToNum --- global-functions | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/global-functions b/global-functions index e01d807..0a6b709 100644 --- a/global-functions +++ b/global-functions @@ -41,6 +41,7 @@ :global SendTelegram; :global TimeIsSync; :global UrlEncode; +:global VersionToNum; :global WaitDefaultRouteReachable; :global WaitDNSResolving; :global WaitForFile; @@ -760,6 +761,35 @@ :return $Return; } +# convert version string to numeric value +:set VersionToNum do={ + :local Input [ :tostr $1 ]; + :local Multi 0x1000000; + :local Return 0; + + :global CharacterReplace; + + :set Input [ $CharacterReplace [ $CharacterReplace [ $CharacterReplace $Input \ + "." "," ] "beta" ",beta," ] "rc" ",rc," ]; + + :foreach Value in=([ :toarray $Input ], 0) do={ + :local Num [ :tonum $Value ]; + :if ($Multi = 0x100) do={ + :if ([ :typeof $Num ] = "num") do={ + :set Return ($Return + 0xff00); + :set Multi ($Multi / 0x100); + } else={ + :if ($Value = "beta") do={ :set Return ($Return + 0x3f00); } + :if ($Value = "rc") do={ :set Return ($Return + 0x7f00); } + } + } + :if ([ :typeof $Num ] = "num") do={ :set Return ($Return + ($Value * $Multi)); } + :set Multi ($Multi / 0x100); + } + + :return $Return; +} + # wait for default route to be reachable :set WaitDefaultRouteReachable do={ :global DefaultRouteIsReachable; From 2907dbe18f0ac17b9fcae5df56b673d129839d66 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Jul 2020 00:21:47 +0200 Subject: [PATCH 0382/2612] check-routeros-update: support installing patch updates automatically --- check-routeros-update | 14 ++++++++++++++ global-config | 2 ++ 2 files changed, 16 insertions(+) diff --git a/check-routeros-update b/check-routeros-update index 9109e1d..931c32f 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -8,12 +8,14 @@ :global Identity; :global SafeUpdateUrl; +:global SafeUpdatePatch; :global SentRouterosUpdateNotification; :global DeviceInfo; :global LogPrintExit; :global ScriptFromTerminal; :global SendNotification; +:global VersionToNum; :local DoUpdate do={ :if ([ / system script print count-only where name="packages-update" ] > 0) do={ @@ -43,6 +45,18 @@ } :if ($Update->"installed-version" != $Update->"latest-version") do={ + :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; + :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; + + :if ($SafeUpdatePatch = true && $NumInstalled < $NumLatest && \ + ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ + $LogPrintExit info ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; + $SendNotification ("RouterOS update") \ + ("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ + ", updating on " . $Identity . "...") "" "true"; + $DoUpdate; + } + :if ([ :len $SafeUpdateUrl ] > 0) do={ :local Result; :do { diff --git a/global-config b/global-config index 5f22b6b..3976e69 100644 --- a/global-config +++ b/global-config @@ -46,6 +46,8 @@ # The configured channel (bugfix, current, release-candidate) is appended. :global SafeUpdateUrl ""; #:global SafeUpdateUrl "https://example.com/ros/safe-update/"; +# Allow to install patch updates automatically. +:global SafeUpdatePatch false; # These thresholds control when to send health notification # on temperature and voltage. From 22a9a11c738300d2ff29e065e9f2edca1f2f7709 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Jul 2020 08:55:49 +0200 Subject: [PATCH 0383/2612] check-routeros-update: install update only, notification on downgrade --- check-routeros-update | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index 931c32f..ea1fd31 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -44,12 +44,11 @@ $LogPrintExit warning "An empty string is not a valid version." true; } -:if ($Update->"installed-version" != $Update->"latest-version") do={ - :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; - :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; +:local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; +:local NumLatest [ $VersionToNum ($Update->"latest-version") ]; - :if ($SafeUpdatePatch = true && $NumInstalled < $NumLatest && \ - ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ +:if ($NumInstalled < $NumLatest) do={ + :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ $LogPrintExit info ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; $SendNotification ("RouterOS update") \ ("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ @@ -97,3 +96,13 @@ "" "true"; :set SentRouterosUpdateNotification ($Update->"latest-version"); } + +:if ($NumInstalled > $NumLatest) do={ + $SendNotification ("RouterOS version") \ + ("A different RouterOS version " . ($Update->"latest-version") . \ + " is available for " . $Identity . ", but it is a downgrade.\n\n" . \ + [ $DeviceInfo ] . "\n\n" . \ + "https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree") \ + "" "true"; + :set SentRouterosUpdateNotification ($Update->"latest-version"); +} From 0f0d539c67ed98a6d3a6b0ae145c3a20e4f28051 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Jul 2020 09:04:40 +0200 Subject: [PATCH 0384/2612] check-routeros-update: log and print on available downgrade --- check-routeros-update | 2 ++ 1 file changed, 2 insertions(+) diff --git a/check-routeros-update b/check-routeros-update index ea1fd31..5b5872d 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -104,5 +104,7 @@ [ $DeviceInfo ] . "\n\n" . \ "https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree") \ "" "true"; + $LogPrintExit info ("A different RouterOS version " . ($Update->"latest-version") . \ + " is available for downgrade.") false; :set SentRouterosUpdateNotification ($Update->"latest-version"); } From 8b23c1e925d8512df2d84f6518a33e2e9c56d128 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Jul 2020 09:05:06 +0200 Subject: [PATCH 0385/2612] check-routeros-update: send just one notification --- check-routeros-update | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/check-routeros-update b/check-routeros-update index 5b5872d..cc44af1 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -98,6 +98,11 @@ } :if ($NumInstalled > $NumLatest) do={ + :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ + $LogPrintExit info ("Already sent the RouterOS downgrade notification for version " . \ + $Update->"latest-version" . ".") true; + } + $SendNotification ("RouterOS version") \ ("A different RouterOS version " . ($Update->"latest-version") . \ " is available for " . $Identity . ", but it is a downgrade.\n\n" . \ From c5767c8d23fea30371fa9f099310bd34d3d54360 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Jul 2020 09:14:15 +0200 Subject: [PATCH 0386/2612] doc/check-routeros-update: patch updates --- doc/check-routeros-update.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index c94381c..6016a1f 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -13,6 +13,9 @@ Run from a terminal you can start the update process or schedule it. Centrally managing update process of several devices is possibly by specifying versions safe to be updated on a web server. +Also installing patch updates (where just last digit is increased) +automatically is supported. + Requirements and installation ----------------------------- @@ -33,6 +36,7 @@ safe versions from a web server. The configuration goes to * `SafeUpdateUrl`: url to check for safe update, the channel (`long-term`, `stable` or `testing`) is appended +* `SafeUpdatePatch`: install patch updates automatically Usage and invocation -------------------- From b31d1a0f0140a36c0b92b9fd6173db8fa978ef1f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Jul 2020 09:28:16 +0200 Subject: [PATCH 0387/2612] packages-update: do not install downgrade without confirmation --- packages-update | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/packages-update b/packages-update index ff683a2..c0a3c84 100644 --- a/packages-update +++ b/packages-update @@ -10,6 +10,7 @@ :global LogPrintExit; :global ScriptFromTerminal; :global ScriptLock; +:global VersionToNum; $ScriptLock "packages-update"; @@ -23,6 +24,23 @@ $ScriptLock "packages-update"; $LogPrintExit info ("Version " . $Update->"latest-version" . " is already installed.") true; } +:local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; +:local NumLatest [ $VersionToNum ($Update->"latest-version") ]; + +:local DoDowngrade false; +:if ($NumInstalled > $NumLatest) do={ + :if ([ $ScriptFromTerminal "packages-update" ] = true) do={ + :put "Latest version is older than installed one. Want to downgrade? [y/N]"; + :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ + :set DoDowngrade true; + } else={ + :put "Canceled..."; + } + } else={ + $LogPrintExit warning ("Not installing downgrade automatically.") true; + } +} + :foreach Package in=[ / system package find where !bundle ] do={ :local PkgName [ / system package get $Package name ]; if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ @@ -34,16 +52,13 @@ $ScriptLock "packages-update"; / system script run $Script; } -:if ([ $ScriptFromTerminal "packages-update" ] = true) do={ - :if (!([ /system resource get version ] ~ ($Update->"channel"))) do={ - :put "Update channel changed. Want to downgrade? [y/N]"; - :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ - $LogPrintExit info ("Rebooting for downgrade.") false; - :delay 1s; - / system package downgrade; - } - } +:if ($DoDowngrade = true) do={ + $LogPrintExit info ("Rebooting for downgrade.") false; + :delay 1s; + / system package downgrade; +} +:if ([ $ScriptFromTerminal "packages-update" ] = true) do={ :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; :if (([ :terminal inkey timeout=60 ] % 32) = 19) do={ / system scheduler add name="reboot-for-update" start-time=03:00:00 interval=1d \ From d75ef3bd69ab0995680b6cddaf134a65cc1a2a18 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Jul 2020 12:18:37 +0200 Subject: [PATCH 0388/2612] packages-update: add error handling, also run cloud-backup --- packages-update | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages-update b/packages-update index c0a3c84..097b8d4 100644 --- a/packages-update +++ b/packages-update @@ -48,8 +48,12 @@ $ScriptLock "packages-update"; } } -:foreach Script in=[ / system script find where name~"^(email|upload)-backup\$" ] do={ - / system script run $Script; +:foreach Script in=[ / system script find where name~"^(cloud|email|upload)-backup\$" ] do={ + :do { + / system script run $Script; + } on-error={ + $LogPrintExit warning ("Running backup script " . $Script . " failed.") false; + } } :if ($DoDowngrade = true) do={ From 16685dd332cee96a2db55e414e3a6a0c564a47a7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Jul 2020 09:12:44 +0200 Subject: [PATCH 0389/2612] global-functions: $DNSIsResolving: try a domain that is unlikely to be cached --- global-functions | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 0a6b709..687fb6c 100644 --- a/global-functions +++ b/global-functions @@ -224,8 +224,10 @@ # check if DNS is resolving :set DNSIsResolving do={ + :global CharacterReplace; + :do { - :resolve mikrotik.com; + :resolve ([ $CharacterReplace [ / system clock get time ] ":" "" ] . ".mikrotik.com"); :return true; } on-error={ :return false; From 639bfc367b6a7e7085190c911d437f9186e70afc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Jul 2020 09:25:12 +0200 Subject: [PATCH 0390/2612] sms-forward: wait to be fully connected --- sms-forward | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sms-forward b/sms-forward index 63b44fe..bcf29c7 100644 --- a/sms-forward +++ b/sms-forward @@ -11,12 +11,14 @@ :global LogPrintExit; :global MailServerIsUp; :global SendNotification; +:global WaitFullyConnected; :if ([ / tool sms get receive-enabled ] = false) do={ $LogPrintExit warning "Receiving of SMS is not enabled." true; } -# check mail server +$WaitFullyConnected; + :if ($MailServerIsUp = false) do={ $LogPrintExit warning "Mail server is not up." true; } From c4ff95b3aeed3abb588ee94bc02d4c50310f3857 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Jul 2020 10:59:08 +0200 Subject: [PATCH 0391/2612] global-functions: $MailServerIsUp: do immediate check --- global-functions | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 687fb6c..15a5186 100644 --- a/global-functions +++ b/global-functions @@ -400,7 +400,15 @@ / tool netwatch add comment=$MailServer host=$MailHost; } - :if ([ / tool netwatch get [ find where comment=$MailServer ] status ] = "up") do={ + :local NetWatch [ / tool netwatch find where comment=$MailServer ]; + :local NetWatchVal [ / tool netwatch get $NetWatch ]; + :if ($NetWatchVal->"status" = "up") do={ + :return true; + } + + / tool netwatch set interval=($NetWatchVal->"interval") $NetWatch; + :delay ($NetWatchVal->"timeout"); + :if ([ / tool netwatch get $NetWatch status ] = "up") do={ :return true; } From 0b5ab833390a9b392b0b89fda9db0943456dda1a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Jul 2020 14:29:29 +0200 Subject: [PATCH 0392/2612] capsman-download-packages: wait to be fully connected --- capsman-download-packages | 2 ++ doc/capsman-download-packages.md | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/capsman-download-packages b/capsman-download-packages index e65ddc7..88aac0e 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -12,8 +12,10 @@ :global LogPrintExit; :global MkDir; :global ScriptLock; +:global WaitFullyConnected; $ScriptLock "capsman-download-packages"; +$WaitFullyConnected; :local PackagePath [ $CleanFilePath [ / caps-man manager get package-path ] ]; :local InstalledVersion [ / system package update get installed-version ]; diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index add9b83..5acf914 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -19,10 +19,11 @@ Just install the script on CAPsMAN device: $ScriptInstallUpdate capsman-download-packages; -Optionally create a scheduler to run after startup, with a delay to ensure -internet connectivity is given: +Optionally install [global-wait](global-wait.md) and add a scheduler to run +after startup: - / system scheduler add name=capsman-download-packages on-event=":delay 2m; / system script run capsman-download-packages;" start-time=startup; + $ScriptInstallUpdate global-wait; + / system scheduler add name=capsman-download-packages on-event="/ system script { run global-wait; run capsman-download-packages; }" start-time=startup; Only packages available in older version are downloaded. For initial setup place the required packages to CAPsMAN package path (see @@ -54,6 +55,7 @@ See also -------- * [Run rolling CAP upgrades from CAPsMAN](capsman-rolling-upgrade.md) +* [Wait for configuration und functions](global-wait.md) --- [◀ Go back to main README](../README.md) From 23563cb9aa7bfc0f70f410abf056cd86ccca5fa4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Jul 2020 16:16:46 +0200 Subject: [PATCH 0393/2612] notify about early-errors --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 3976e69..4c4424e 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 16; +:global GlobalConfigVersion 17; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index a3d0ba5..21f1fa4 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 16; +:global GlobalConfigVersion 17; # The global-config script is updated by $ScriptInstallUpdate, # global-config-overlay becomes an overlay for your changes. diff --git a/global-config.changes b/global-config.changes index 5a2bb7a..763562d 100644 --- a/global-config.changes +++ b/global-config.changes @@ -20,4 +20,5 @@ 14="Dropped script 'script-updates', use '\$ScriptInstallUpdate' exclusively!"; 15="New documentation is online! https://git.eworm.de/cgit/routeros-scripts/about/#available-scripts"; 16="Happy with RouterOS Scripts and have a GitHub and/or GitLab account? Please star!"; + 17="Introduced script 'early-errors'"; }; diff --git a/global-functions b/global-functions index 15a5186..710c84f 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 16; +:global ExpectedConfigVersion 17; # global variables not to be changed by user :global GlobalFunctionsReady false; From 883920aeae9f25dcb56a0b47054d12ab57dd8833 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Jul 2020 16:17:33 +0200 Subject: [PATCH 0394/2612] notify about $IPCalc --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 4c4424e..ffc5fd3 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 17; +:global GlobalConfigVersion 18; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 21f1fa4..4045a0e 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 17; +:global GlobalConfigVersion 18; # The global-config script is updated by $ScriptInstallUpdate, # global-config-overlay becomes an overlay for your changes. diff --git a/global-config.changes b/global-config.changes index 763562d..0932ac8 100644 --- a/global-config.changes +++ b/global-config.changes @@ -21,4 +21,5 @@ 15="New documentation is online! https://git.eworm.de/cgit/routeros-scripts/about/#available-scripts"; 16="Happy with RouterOS Scripts and have a GitHub and/or GitLab account? Please star!"; 17="Introduced script 'early-errors'"; + 18=("Added a simple IP calculation function, try: \$IPCalc " . [ / ip address get ([ find ]->0) address ]); }; diff --git a/global-functions b/global-functions index 710c84f..c6932b2 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 17; +:global ExpectedConfigVersion 18; # global variables not to be changed by user :global GlobalFunctionsReady false; From aec63407e873e4a6f7299bdb0bf1c740be45f2b1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Jul 2020 16:18:23 +0200 Subject: [PATCH 0395/2612] notify about options in script comments --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index ffc5fd3..9c5f9ca 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 18; +:global GlobalConfigVersion 19; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 4045a0e..d50ffc3 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 18; +:global GlobalConfigVersion 19; # The global-config script is updated by $ScriptInstallUpdate, # global-config-overlay becomes an overlay for your changes. diff --git a/global-config.changes b/global-config.changes index 0932ac8..12c5a38 100644 --- a/global-config.changes +++ b/global-config.changes @@ -22,4 +22,5 @@ 16="Happy with RouterOS Scripts and have a GitHub and/or GitLab account? Please star!"; 17="Introduced script 'early-errors'"; 18=("Added a simple IP calculation function, try: \$IPCalc " . [ / ip address get ([ find ]->0) address ]); + 19="Commenting scripts with 'ignore', 'base-url=...' and 'url-suffix=...' is honored on update"; }; diff --git a/global-functions b/global-functions index c6932b2..920f2a4 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 18; +:global ExpectedConfigVersion 19; # global variables not to be changed by user :global GlobalFunctionsReady false; From 4a52d51a36742755cbb3e865ad2e68b39a1a3c5c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Jul 2020 16:24:29 +0200 Subject: [PATCH 0396/2612] notify about hooks in netwatch-notify --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 9c5f9ca..2aab1cb 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 19; +:global GlobalConfigVersion 20; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index d50ffc3..b0ace3d 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 19; +:global GlobalConfigVersion 20; # The global-config script is updated by $ScriptInstallUpdate, # global-config-overlay becomes an overlay for your changes. diff --git a/global-config.changes b/global-config.changes index 12c5a38..95e9e6b 100644 --- a/global-config.changes +++ b/global-config.changes @@ -23,4 +23,5 @@ 17="Introduced script 'early-errors'"; 18=("Added a simple IP calculation function, try: \$IPCalc " . [ / ip address get ([ find ]->0) address ]); 19="Commenting scripts with 'ignore', 'base-url=...' and 'url-suffix=...' is honored on update"; + 20="Added support for hooks to 'netwatch-notify'"; }; diff --git a/global-functions b/global-functions index 920f2a4..05be101 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 19; +:global ExpectedConfigVersion 20; # global variables not to be changed by user :global GlobalFunctionsReady false; From d1b6ca3d0b531f310a21b947837f7771649b9e17 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Jul 2020 16:25:46 +0200 Subject: [PATCH 0397/2612] notify about auto patch updates in check-routeros-update --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 2aab1cb..bd82a19 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 20; +:global GlobalConfigVersion 21; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index b0ace3d..d143efa 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 20; +:global GlobalConfigVersion 21; # The global-config script is updated by $ScriptInstallUpdate, # global-config-overlay becomes an overlay for your changes. diff --git a/global-config.changes b/global-config.changes index 95e9e6b..4e6fcfc 100644 --- a/global-config.changes +++ b/global-config.changes @@ -24,4 +24,5 @@ 18=("Added a simple IP calculation function, try: \$IPCalc " . [ / ip address get ([ find ]->0) address ]); 19="Commenting scripts with 'ignore', 'base-url=...' and 'url-suffix=...' is honored on update"; 20="Added support for hooks to 'netwatch-notify'"; + 21="Added support for installing patch updates automatically by 'check-routeros-update'"; }; diff --git a/global-functions b/global-functions index 05be101..57ae336 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 20; +:global ExpectedConfigVersion 21; # global variables not to be changed by user :global GlobalFunctionsReady false; From f4d6e07dbb6c1406b56c77116a52d11ff8b363b1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Jul 2020 16:32:17 +0200 Subject: [PATCH 0398/2612] global-config: dropped $ScriptUpdatesIgnore, use ignore flag in comment --- INITIAL-COMMANDS.md | 3 ++- README.md | 4 ++++ global-config | 6 ++---- global-config-overlay | 8 +------- global-config.changes | 1 + global-functions | 18 +++++++++++++----- 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 4541430..c985f9c 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -17,8 +17,9 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } + / system script set comment="ignore" global-config-overlay; / system script { run global-config; run global-config-overlay; run global-functions; } - / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }" + / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }"; $CertificateNameByCN "ISRG Root X1"; $CertificateNameByCN "Let's Encrypt Authority X3"; $CertificateNameByCN "DST Root CA X3"; diff --git a/README.md b/README.md index 54473c3..99fbdc5 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,10 @@ Now let's download the main scripts and add them in configuration on the fly. [admin@MikroTik] > :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } +Mark `global-config-overlay` not to be overwritten by future updates. + + [admin@MikroTik] > / system script set comment="ignore" global-config-overlay + The configuration needs to be tweaked for your needs. Make sure not to send your mails to `mail@example.com`! Edit `global-config-overlay`, copy configuration from `global-config`. diff --git a/global-config b/global-config index bd82a19..0e4ae63 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 21; +:global GlobalConfigVersion 22; # This is used for DNS and backup file. :global Domain "example.com"; @@ -111,9 +111,7 @@ #:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/master/"; #:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/master/"; :global ScriptUpdatesUrlSuffix ""; -:global ScriptUpdatesIgnore { - "global-config" -} + # This project is developed in private spare time and usage is free of charge # for you. If you like the scripts and think this is of value for you or your # business please consider a donation: diff --git a/global-config-overlay b/global-config-overlay index d143efa..22d3ab5 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,13 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 21; - -# The global-config script is updated by $ScriptInstallUpdate, -# global-config-overlay becomes an overlay for your changes. -:global ScriptUpdatesIgnore { - "global-config-overlay" -} +:global GlobalConfigVersion 22; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 4e6fcfc..f6a0c40 100644 --- a/global-config.changes +++ b/global-config.changes @@ -25,4 +25,5 @@ 19="Commenting scripts with 'ignore', 'base-url=...' and 'url-suffix=...' is honored on update"; 20="Added support for hooks to 'netwatch-notify'"; 21="Added support for installing patch updates automatically by 'check-routeros-update'"; + 22="Dropped '\$ScriptUpdatesIgnore' from global configuration, auto-migrating to ignore flag in comment" }; diff --git a/global-functions b/global-functions index 57ae336..db27774 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 21; +:global ExpectedConfigVersion 22; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -529,11 +529,19 @@ } :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ - :foreach IgnoreLoop in=$ScriptUpdatesIgnore do={ - :if ($IgnoreLoop = $ScriptVal->"name") do={ :set Ignore 1; } - } :local Comment [ $ParseKeyValueStore ($ScriptVal->"comment") ]; - :if ($Comment->"ignore" = true) do={ :set Ignore 1; } + :if ($Comment->"ignore" = true) do={ + :set Ignore 1; + } else={ + # TODO: remove at later time + :foreach IgnoreLoop in=$ScriptUpdatesIgnore do={ + :if ($IgnoreLoop = $ScriptVal->"name") do={ + :set Ignore 1; + $LogPrintExit info ("Migrating script " . $ScriptVal->"name" . " to ignore flag in comment.") false; + / system script set comment="ignore" ($ScriptVal->"name"); + } + } + } :if ($Ignore = 0) do={ $LogPrintExit debug ("Fetching script from url: " . $ScriptVal->"name") false; From e19f40f1eb4bd6dd94f433f13b0e2dd3c56c6b6c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Jul 2020 16:45:40 +0200 Subject: [PATCH 0399/2612] README: be more explicit on file name --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 99fbdc5..9f5cc32 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ Mark `global-config-overlay` not to be overwritten by future updates. The configuration needs to be tweaked for your needs. Make sure not to send your mails to `mail@example.com`! Edit `global-config-overlay`, copy -configuration from `global-config`. +configuration from `global-config` (the one without `-overlay`). [admin@MikroTik] > / system script edit global-config-overlay source From 9740b1f26993bafe09834e19a0275036e2f5c22a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Jul 2020 21:28:35 +0200 Subject: [PATCH 0400/2612] global-functions: $ScriptInstallUpdate: update wording for notification --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index db27774..2dc7830 100644 --- a/global-functions +++ b/global-functions @@ -635,7 +635,7 @@ "https://git.eworm.de/cgit/routeros-scripts/about/#donate"); } - $SendNotification "Configuration warning!" $NotificationMessage; + $SendNotification "News and configuration changes" $NotificationMessage; :set SentConfigChangesNotification $ExpectedConfigVersion; } } From 6bce0a4b6a3d1ee48a1e4b4f40652ae490fb288c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Jul 2020 12:22:55 +0200 Subject: [PATCH 0401/2612] add 'log-forward', drop 'early-errors' --- README.md | 2 +- doc/early-errors.md | 39 ++++------------------------------- doc/log-forward.md | 42 ++++++++++++++++++++++++++++++++++++++ early-errors | 26 ++---------------------- global-config | 5 ++++- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- log-forward | 47 +++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 103 insertions(+), 63 deletions(-) create mode 100644 doc/log-forward.md create mode 100644 log-forward diff --git a/README.md b/README.md index 9f5cc32..cb6d7b8 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,6 @@ Available Scripts * [Use wireless network with daily psk](doc/daily-psk.md) * [Comment DHCP leases with info from access list](doc/dhcp-lease-comment.md) * [Create DNS records for DHCP leases](doc/dhcp-to-dns.md) -* [Send notification with early errors](doc/early-errors.md) * [Send backup via e-mail](doc/email-backup.md) * [Wait for configuration und functions](doc/global-wait.md) * [Send GPS position to server](doc/gps-track.md) @@ -168,6 +167,7 @@ Available Scripts * [Manage IP addresses with bridge status](doc/ip-addr-bridge.md) * [Run other scripts on DHCP lease](doc/lease-script.md) * [Manage LEDs dark mode](doc/leds-mode.md) +* [Forward log messages via notification](doc/log-forward.md) * [Mode botton with multiple presses](doc/mode-button.md) * [Notify on host up and down](doc/netwatch-notify.md) * [Manage remote logging](doc/netwatch-syslog.md) diff --git a/doc/early-errors.md b/doc/early-errors.md index f6209b7..a16da7d 100644 --- a/doc/early-errors.md +++ b/doc/early-errors.md @@ -3,40 +3,9 @@ Send notification with early errors [◀ Go back to main README](../README.md) -Description ------------ +This script has been replace. Please migrate to +[Forward log messages via notification](log-forward.md). -RouterOS supports sending log messages via e-mail or to a syslog server. -However this does not work early after boot if network connectivity is not -yet established. For example log messages about reboot without proper -shutdown may be missed: - -> router rebooted without proper shutdown, probably power outage - -The script collects log messages with severity `error` and sends a -notification. - -Requirements and installation ------------------------------ - -Just install this script and [global-wait](global-wait.md): - - $ScriptInstallUpdate early-errors,global-wait; - -... and add a scheduler: - - / system scheduler add name=early-erros on-event="/ system script { run global-wait; run early-errors; }" start-time=startup; - -Configuration -------------- - -The notifications just require notification settings for e-mail and telegram. - -See also --------- - -* [Wait for configuration und functions](global-wait.md) - ---- -[◀ Go back to main README](../README.md) +--- +[◀ Go back to main README](../README.md) [▲ Go back to top](#top) diff --git a/doc/log-forward.md b/doc/log-forward.md new file mode 100644 index 0000000..bc7213a --- /dev/null +++ b/doc/log-forward.md @@ -0,0 +1,42 @@ +Forward log messages via notification +===================================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +RouterOS supports sending log messages via e-mail or to a syslog server. +This has some limitation, however: + +* does not work early after boot if network connectivity is not + yet established +* lots of messages generate a flood of mails +* Telegram is not supported + +The script is intended to be run periodically. It collects log messages +and forwards them via notification. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate log-forward; + +... and add a scheduler: + + / system scheduler add interval=1m name=log-forward on-event="/ system script run log-forward;" start-time=startup; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, there is just one parameters: + +* `LogForwardFilter`: define topics *not* to be forwarded + +Also notification settings are required for e-mail and telegram. + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/early-errors b/early-errors index a2c5da3..4f411f4 100644 --- a/early-errors +++ b/early-errors @@ -1,28 +1,6 @@ #!rsc # RouterOS script: early-errors -# Copyright (c) 2020 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# send notification with early errors -# https://git.eworm.de/cgit/routeros-scripts/about/doc/early-errors.md -:global Identity; +:global LogPrintExit; -:global SendNotification; -:global WaitFullyConnected; - -$WaitFullyConnected; - -:local Errors [ / log find where (topics~"error" or topics~"critical") \ - !(topics~"certificate") !(topics~"dns") !(topics~"e-mail") ]; -:local ErrCount [ :len $Errors ]; -:if ($ErrCount > 0) do={ - :local Message ("The log on " . $Identity . " contains " . $ErrCount . \ - " errors after " . [ / system resource get uptime ] . " uptime.\n"); - :foreach Log in=$Errors do={ - :local LogVal [ / log get $Log ]; - :set Message ($Message . "\n" . [ :tostr ($LogVal->"topics") ] . \ - " " . ($LogVal->"message")); - } - $SendNotification ("\E2\9A\A0 Early errors") ($Message); -} +$LogPrintExit warning ("This script has been replaced. Please migrate to 'log-forward'.") true; diff --git a/global-config b/global-config index 0e4ae63..87ac2c7 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 22; +:global GlobalConfigVersion 23; # This is used for DNS and backup file. :global Domain "example.com"; @@ -42,6 +42,9 @@ :global BackupUploadUser "mikrotik"; :global BackupUploadPass "v3ry-s3cr3t"; +# This defines a filter on log topics not to be forwarded. +:global LogForwardFilter "(debug|info|script)"; + # Specify an address to enable auto update to version assumed safe. # The configured channel (bugfix, current, release-candidate) is appended. :global SafeUpdateUrl ""; diff --git a/global-config-overlay b/global-config-overlay index 22d3ab5..676db65 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 22; +:global GlobalConfigVersion 23; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index f6a0c40..d3ff78f 100644 --- a/global-config.changes +++ b/global-config.changes @@ -26,4 +26,5 @@ 20="Added support for hooks to 'netwatch-notify'"; 21="Added support for installing patch updates automatically by 'check-routeros-update'"; 22="Dropped '\$ScriptUpdatesIgnore' from global configuration, auto-migrating to ignore flag in comment" + 23="Added 'log-forward' with configurable filter, which replaces 'early-errors'"; }; diff --git a/global-functions b/global-functions index 2dc7830..fe51031 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 22; +:global ExpectedConfigVersion 23; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/log-forward b/log-forward new file mode 100644 index 0000000..8f7bc1f --- /dev/null +++ b/log-forward @@ -0,0 +1,47 @@ +#!rsc +# RouterOS script: log-forward +# Copyright (c) 2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# forward log messages via notification +# https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md + +:global Identity; +:global LogForwardFilter; +:global LogForwardLast; + +:global LogPrintExit; +:global MailServerIsUp; +:global SendNotification; +:global WaitFullyConnected; + +$WaitFullyConnected; + +:if ($MailServerIsUp = false) do={ + $LogPrintExit warning ("Mail server is not up.") true; +} + +:local Count 0; +:local Messages ""; +:local MessageVal; + +:foreach Message in=[ / log find where !(topics~$LogForwardFilter) ] do={ + :set MessageVal [ / log get $Message ]; + + :if ($LogForwardLast = $MessageVal) do={ + :set Messages ""; + :set Count 0; + } else={ + :set Messages ($Messages . "\n" . $MessageVal->"time" . " " . \ + [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message"); + :set Count ($Count + 1); + } +} + +:if ($Count > 0) do={ + $SendNotification ("\E2\9A\A0 Log Forwarding") \ + ("The log on " . $Identity . " contains these " . $Count . " messages after " . \ + [ / system resource get uptime ] . " uptime.\n" . $Messages); + + :set LogForwardLast $MessageVal; +} From 96d473cfe8128908a4948d93d674823f75601b49 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Jul 2020 14:43:26 +0200 Subject: [PATCH 0402/2612] log-forward: remember the last id only --- log-forward | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/log-forward b/log-forward index 8f7bc1f..068ffb0 100644 --- a/log-forward +++ b/log-forward @@ -28,7 +28,7 @@ $WaitFullyConnected; :foreach Message in=[ / log find where !(topics~$LogForwardFilter) ] do={ :set MessageVal [ / log get $Message ]; - :if ($LogForwardLast = $MessageVal) do={ + :if ($LogForwardLast = ($MessageVal->".id")) do={ :set Messages ""; :set Count 0; } else={ @@ -43,5 +43,5 @@ $WaitFullyConnected; ("The log on " . $Identity . " contains these " . $Count . " messages after " . \ [ / system resource get uptime ] . " uptime.\n" . $Messages); - :set LogForwardLast $MessageVal; + :set LogForwardLast ($MessageVal->".id"); } From efd0b0d2742d1ee0ee8d8ef8362b6b12a81542ea Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Jul 2020 20:52:24 +0200 Subject: [PATCH 0403/2612] check-health: new symbol for high temperature --- check-health | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-health b/check-health index 3684808..7b7a0b1 100644 --- a/check-health +++ b/check-health @@ -59,7 +59,7 @@ } :if ($CheckHealthLast->$Temperature <= $CheckHealthTemperature->$Temperature && \ $CheckHealthCurrent->$Temperature > $CheckHealthTemperature->$Temperature) do={ - $SendNotification ("Health warning: \E2\9D\8C " . $Temperature) \ + $SendNotification ("Health warning: \F0\9F\94\A5 " . $Temperature) \ ("The " . $Temperature . " on " . $Identity . " is above threshold: " . \ $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); } From 5d7d2e9ac696cb6659aefb912406f9bc8d3673b3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Jul 2020 21:01:15 +0200 Subject: [PATCH 0404/2612] check-health: add symbol for voltage --- check-health | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-health b/check-health index 7b7a0b1..7192b46 100644 --- a/check-health +++ b/check-health @@ -26,7 +26,7 @@ [ :typeof ($CheckHealthCurrent->$Voltage) ] = "num") do={ :if ($CheckHealthLast->$Voltage * (100 + $CheckHealthVoltagePercent) < $CheckHealthCurrent->$Voltage * 100 || \ $CheckHealthLast->$Voltage * 100 > $CheckHealthCurrent->$Voltage * (100 + $CheckHealthVoltagePercent)) do={ - $SendNotification ("Health warning: " . $Voltage) \ + $SendNotification ("Health warning: \E2\9A\A1 " . $Voltage) \ ("The " . $Voltage . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ "old value: " . [ $FormatVoltage ($CheckHealthLast->$Voltage) ] . "\n" . \ "new value: " . [ $FormatVoltage ($CheckHealthCurrent->$Voltage) ]); From 1aed883cd5aa5cbe075887f49cc770455d6545b6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Jul 2020 10:56:24 +0200 Subject: [PATCH 0405/2612] INITIAL-COMMANDS: declare $CertificateNameByCN --- INITIAL-COMMANDS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index c985f9c..e9889d2 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -20,6 +20,7 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai / system script set comment="ignore" global-config-overlay; / system script { run global-config; run global-config-overlay; run global-functions; } / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }"; + :global CertificateNameByCN; $CertificateNameByCN "ISRG Root X1"; $CertificateNameByCN "Let's Encrypt Authority X3"; $CertificateNameByCN "DST Root CA X3"; From 371e96911d507a1ac3147ec131de7bc5dce595cb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Jul 2020 14:53:35 +0200 Subject: [PATCH 0406/2612] sms-forward: add symbol --- sms-forward | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sms-forward b/sms-forward index bcf29c7..d435421 100644 --- a/sms-forward +++ b/sms-forward @@ -46,7 +46,7 @@ $WaitFullyConnected; } :if ([ :len $Messages ] > 0) do={ - $SendNotification ("SMS Forwarding from " . $Phone) \ + $SendNotification ("\F0\9F\93\A8 SMS Forwarding from " . $Phone) \ ("These message(s) were received by " . $Identity . \ " from " . $Phone . ":" . $Messages); :foreach Sms in=$Delete do={ From 806d9bd4fbcb141555b01e32b79aa3db7c91ce34 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Jul 2020 17:48:21 +0200 Subject: [PATCH 0407/2612] check-health: move symbol before text --- check-health | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/check-health b/check-health index 7192b46..3710bd2 100644 --- a/check-health +++ b/check-health @@ -26,7 +26,7 @@ [ :typeof ($CheckHealthCurrent->$Voltage) ] = "num") do={ :if ($CheckHealthLast->$Voltage * (100 + $CheckHealthVoltagePercent) < $CheckHealthCurrent->$Voltage * 100 || \ $CheckHealthLast->$Voltage * 100 > $CheckHealthCurrent->$Voltage * (100 + $CheckHealthVoltagePercent)) do={ - $SendNotification ("Health warning: \E2\9A\A1 " . $Voltage) \ + $SendNotification ("\E2\9A\A1 Health warning: " . $Voltage) \ ("The " . $Voltage . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ "old value: " . [ $FormatVoltage ($CheckHealthLast->$Voltage) ] . "\n" . \ "new value: " . [ $FormatVoltage ($CheckHealthCurrent->$Voltage) ]); @@ -39,12 +39,12 @@ [ :typeof ($CheckHealthCurrent->($PSU . "-state")) ] = "str") do={ :if ($CheckHealthLast->($PSU . "-state") = "ok" && \ $CheckHealthCurrent->($PSU . "-state") != "ok") do={ - $SendNotification ("Health warning: \E2\9D\8C " . $PSU . " state") \ + $SendNotification ("\E2\9D\8C Health warning: " . $PSU . " state") \ ("The power supply unit '" . $PSU . "' on " . $Identity . " failed!"); } :if ($CheckHealthLast->($PSU . "-state") != "ok" && \ $CheckHealthCurrent->($PSU . "-state") = "ok") do={ - $SendNotification ("Health recovery: \E2\9C\85 " . $PSU . " state") \ + $SendNotification ("\E2\9C\85 Health recovery: " . $PSU . " state") \ ("The power supply unit '" . $PSU . "' on " . $Identity . " recovered!"); } } @@ -59,13 +59,13 @@ } :if ($CheckHealthLast->$Temperature <= $CheckHealthTemperature->$Temperature && \ $CheckHealthCurrent->$Temperature > $CheckHealthTemperature->$Temperature) do={ - $SendNotification ("Health warning: \F0\9F\94\A5 " . $Temperature) \ + $SendNotification ("\F0\9F\94\A5 Health warning: " . $Temperature) \ ("The " . $Temperature . " on " . $Identity . " is above threshold: " . \ $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); } :if ($CheckHealthLast->$Temperature > $CheckHealthTemperature->$Temperature && \ $CheckHealthCurrent->$Temperature <= $CheckHealthTemperature->$Temperature) do={ - $SendNotification ("Health recovery: \E2\9C\85 " . $Temperature) \ + $SendNotification ("\E2\9C\85 Health recovery: " . $Temperature) \ ("The " . $Temperature . " on " . $Identity . " dropped below threshold: " . \ $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); } From 5859b0406ee11f07af2cfe97ab9e2a9a7c30ffa8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Jul 2020 17:51:21 +0200 Subject: [PATCH 0408/2612] netwatch-notify: move symbol before text --- netwatch-notify | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 0df92b5..5b0c629 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -31,7 +31,7 @@ :local Count ($Metric->"count"); :set ($Metric->"count") 0; :if ($Metric->"notified" = true) do={ - $SendNotification ("Netwatch Notify: \E2\9C\85 " . $HostName . " up") \ + $SendNotification ("\E2\9C\85 Netwatch Notify: " . $HostName . " up") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ "It was down for " . $Count . " checks."); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ @@ -45,7 +45,7 @@ $LogPrintExit info ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ $Metric->"count" . " checks.") false; :if ($Metric->"count" >= 5 && $Metric->"notified" != true) do={ - $SendNotification ("Netwatch Notify: \E2\9D\8C " . $HostName . " down") \ + $SendNotification ("\E2\9D\8C Netwatch Notify: " . $HostName . " down") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :set ($Metric->"notified") true; :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ From 910641b6fa9548e0b06f64aad82082506b03c89e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Jul 2020 20:34:27 +0200 Subject: [PATCH 0409/2612] global-functions: introduce $IfThenElse --- global-functions | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/global-functions b/global-functions index fe51031..e20017b 100644 --- a/global-functions +++ b/global-functions @@ -27,6 +27,7 @@ :global GetMacVendor; :global GetRandomNumber; :global GetRandomSha256; +:global IfThenElse; :global IPCalc; :global LogPrintExit; :global MailServerIsUp; @@ -339,6 +340,14 @@ :return $FingerPrint; } +# mimic conditional/ternary operator (condition ? consequent : alternative) +:set IfThenElse do={ + :if ([ :tostr $1 ] = "true" || [ :tobool $1 ] = true) do={ + :return $2; + } + :return $3; +} + # calculate and print netmask, network, min host, max host and broadcast :set IPCalc do={ :local Input [ :tostr $1 ]; From 4c61cd0b650d6bab1aafb32f1d1100fa4bb2f7fe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Jul 2020 21:06:13 +0200 Subject: [PATCH 0410/2612] global-functions: $DeviceInfo: use $IfThenElse --- global-functions | 52 +++++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/global-functions b/global-functions index e20017b..17796fa 100644 --- a/global-functions +++ b/global-functions @@ -186,41 +186,31 @@ :global GlobalConfigVersion; :global Identity; + :global IfThenElse; + :local Resource [ / system resource get ]; :local RouterBoard [ / system routerboard get ]; :local Update [ / system package update get ]; - :local Info ( \ - "Hostname: " . $Identity . "\n" . \ - "Board name: " . $Resource->"board-name" . "\n" . \ - "Architecture: " . $Resource->"architecture-name"); - :if ($RouterBoard->"routerboard" = true) do={ - :local Revision ""; - :if ([ :len ($RouterBoard->"revision") ] > 0) do={ - :set Revision (" " . $RouterBoard->"revision"); - } - :set Info ($Info . "\n" . \ - "Model: " . $RouterBoard->"model" . $Revision . "\n" . \ - "Serial number: " . $RouterBoard->"serial-number"); - } - :set Info ($Info . "\n" . \ - "RouterOS:\n" . \ - " Channel: " . $Update->"channel" . "\n" . \ - " Installed: " . $Update->"installed-version"); - :if ([ :typeof ($Update->"latest-version") ] != "nothing" && \ - $Update->"installed-version" != $Update->"latest-version") do={ - :set Info ($Info . "\n" . \ - " Available: " . $Update->"latest-version"); - } - :set Info ($Info . "\n" . \ - "RouterOS-Scripts Configuration Version:\n" . \ - " Current: " . $GlobalConfigVersion); - :if ($GlobalConfigVersion != $ExpectedConfigVersion) do={ - :set Info ($Info . "\n" . \ - " Expected: " . $ExpectedConfigVersion); - } - - :return $Info; + :return ( \ + "Hostname: " . $Identity . \ + "\nBoard name: " . $Resource->"board-name" . \ + "\nArchitecture: " . $Resource->"architecture-name" . \ + [ $IfThenElse ($RouterBoard->"routerboard" = true) \ + ("\nModel: " . $RouterBoard->"model" . \ + [ $IfThenElse ([ :len ($RouterBoard->"revision") ] > 0) \ + (" " . $RouterBoard->"revision") ] . \ + "\nSerial number: " . $RouterBoard->"serial-number") ] . \ + "\nRouterOS:" . \ + "\n Channel: " . $Update->"channel" . \ + "\n Installed: " . $Update->"installed-version" . \ + [ $IfThenElse ([ :typeof ($Update->"latest-version") ] != "nothing" && \ + $Update->"installed-version" != $Update->"latest-version") \ + ("\n Available: " . $Update->"latest-version") ] . \ + "\nRouterOS-Scripts Configuration Version:" . \ + "\n Current: " . $GlobalConfigVersion . \ + [ $IfThenElse ($GlobalConfigVersion != $ExpectedConfigVersion) \ + ("\n Expected: " . $ExpectedConfigVersion) ]); } # check if DNS is resolving From 6dfd8ed41a18a10dd6c640bb0dfc37f1a561ee8c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Jul 2020 21:18:12 +0200 Subject: [PATCH 0411/2612] check-certificates: use $IfThenElse --- check-certificates | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/check-certificates b/check-certificates index 9e65586..1402e49 100644 --- a/check-certificates +++ b/check-certificates @@ -12,6 +12,7 @@ :global CertificateAvailable :global CertificateNameByCN; +:global IfThenElse; :global LogPrintExit; :global ParseKeyValueStore; :global SendNotification; @@ -104,12 +105,7 @@ :if ([ / certificate scep-server print count-only where ca-cert=($CertVal->"ca") ] > 0) do={ $LogPrintExit debug ("Certificate \"" . ($CertVal->"name") . "\" is handled by SCEP, skipping.") false; } else={ - :local ExpiresAfter [ $FormatExpire ($CertVal->"expires-after") ]; - :local State "is about to expire"; - :if (($CertVal->"expired") = true) do={ - :set ExpiresAfter "expired"; - :set State "expired"; - } + :local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ]; $SendNotification ("Certificate warning!") \ ("A certificate on " . $Identity . " " . $State . ".\n\n" . \ @@ -118,7 +114,7 @@ "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ - "Expires in: " . $ExpiresAfter); + "Expires in: " . [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ]); $LogPrintExit warning ("The certificate " . ($CertVal->"name") . " " . $State . \ ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; } From e709af4c4d824560999c9bbd36f7e3504c28e9f6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Jul 2020 21:27:44 +0200 Subject: [PATCH 0412/2612] dhcp-to-dns: use $IfThenElse --- dhcp-to-dns | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index 4496854..352b53f 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -12,15 +12,12 @@ :global PrefixInZone; :global CharacterReplace; +:global IfThenElse; :global LogPrintExit; -:local Zone $Domain; -:if ($HostNameInZone = true) do={ - :set Zone ($Identity . "." . $Zone); -} -:if ($PrefixInZone = true) do={ - :set Zone ("dhcp." . $Zone); -} +:local Zone \ + ([ $IfThenElse ($PrefixInZone = true) "dhcp." ] . \ + [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); :local Ttl 5m; :local CommentPrefix "managed by dhcp-to-dns for "; @@ -45,10 +42,9 @@ :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ :local LeaseVal [ / ip dhcp-server lease get $Lease ]; :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); - :local HostName [ $CharacterReplace ($LeaseVal->"host-name") " " "" ]; - :if ($HostName = "") do={ - :set HostName [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ]; - } + :local HostName [ $IfThenElse ([ :len ($LeaseVal->"host-name") ] = 0) \ + [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ] \ + [ $CharacterReplace ($LeaseVal->"host-name") " " "" ] ]; :local Fqdn ($HostName . "." . $Zone); :local DnsRecord [ / ip dns static find where name=$Fqdn ]; From febf0ee5e465d81ced6b86fb5af6d9e6bc1f4e4e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 00:10:31 +0200 Subject: [PATCH 0413/2612] check-routeros-update: move symbol before text --- check-routeros-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-routeros-update b/check-routeros-update index cc44af1..62ad64a 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -88,7 +88,7 @@ $Update->"latest-version" . ".") true; } - $SendNotification ("RouterOS update \E2\9C\A8") \ + $SendNotification ("\E2\9C\A8 RouterOS update") \ ("A new RouterOS version " . ($Update->"latest-version") . \ " is available for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ From 7862ce5f1995e2c61fe93d6916d6f00c81694230 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 07:36:02 +0200 Subject: [PATCH 0414/2612] global-functions: introduce $SymbolByUnicodeName --- global-functions | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/global-functions b/global-functions index 17796fa..ba9142f 100644 --- a/global-functions +++ b/global-functions @@ -40,6 +40,7 @@ :global SendEMail; :global SendNotification; :global SendTelegram; +:global SymbolByUnicodeName; :global TimeIsSync; :global UrlEncode; :global VersionToNum; @@ -731,6 +732,21 @@ } } +# return UTF-8 symbol for unicode name +:set SymbolByUnicodeName do={ + :local Symbols { + "cross-mark"="\E2\9D\8C"; + "fire"="\F0\9F\94\A5"; + "high-voltage-sign"="\E2\9A\A1"; + "incoming-envelope"="\F0\9F\93\A8"; + "sparkles"="\E2\9C\A8"; + "warning-sign"="\E2\9A\A0"; + "white-heavy-check-mark"="\E2\9C\85" + } + + :return ($Symbols->$1); +} + # check if system time is sync :set TimeIsSync do={ :if ([ / system ntp client get enabled ] = true) do={ From 17e9635ca1cf676499bb2cff9470da04faa3504b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 07:41:47 +0200 Subject: [PATCH 0415/2612] check-health: use $SymbolByUnicodeName --- check-health | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/check-health b/check-health index 3710bd2..a63483e 100644 --- a/check-health +++ b/check-health @@ -13,6 +13,7 @@ :global LogPrintExit; :global SendNotification; +:global SymbolByUnicodeName; :local FormatVoltage do={ :local Voltage [ :tonum $1 ]; @@ -26,7 +27,7 @@ [ :typeof ($CheckHealthCurrent->$Voltage) ] = "num") do={ :if ($CheckHealthLast->$Voltage * (100 + $CheckHealthVoltagePercent) < $CheckHealthCurrent->$Voltage * 100 || \ $CheckHealthLast->$Voltage * 100 > $CheckHealthCurrent->$Voltage * (100 + $CheckHealthVoltagePercent)) do={ - $SendNotification ("\E2\9A\A1 Health warning: " . $Voltage) \ + $SendNotification ([ $SymbolByUnicodeName "high-voltage-sign" ] . " Health warning: " . $Voltage) \ ("The " . $Voltage . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ "old value: " . [ $FormatVoltage ($CheckHealthLast->$Voltage) ] . "\n" . \ "new value: " . [ $FormatVoltage ($CheckHealthCurrent->$Voltage) ]); @@ -39,12 +40,12 @@ [ :typeof ($CheckHealthCurrent->($PSU . "-state")) ] = "str") do={ :if ($CheckHealthLast->($PSU . "-state") = "ok" && \ $CheckHealthCurrent->($PSU . "-state") != "ok") do={ - $SendNotification ("\E2\9D\8C Health warning: " . $PSU . " state") \ + $SendNotification ([ $SymbolByUnicodeName "cross-mark" ] . " Health warning: " . $PSU . " state") \ ("The power supply unit '" . $PSU . "' on " . $Identity . " failed!"); } :if ($CheckHealthLast->($PSU . "-state") != "ok" && \ $CheckHealthCurrent->($PSU . "-state") = "ok") do={ - $SendNotification ("\E2\9C\85 Health recovery: " . $PSU . " state") \ + $SendNotification ([ $SymbolByUnicodeName "white-heavy-check-mark" ] . " Health recovery: " . $PSU . " state") \ ("The power supply unit '" . $PSU . "' on " . $Identity . " recovered!"); } } @@ -59,13 +60,13 @@ } :if ($CheckHealthLast->$Temperature <= $CheckHealthTemperature->$Temperature && \ $CheckHealthCurrent->$Temperature > $CheckHealthTemperature->$Temperature) do={ - $SendNotification ("\F0\9F\94\A5 Health warning: " . $Temperature) \ + $SendNotification ([ $SymbolByUnicodeName "fire" ] . " Health warning: " . $Temperature) \ ("The " . $Temperature . " on " . $Identity . " is above threshold: " . \ $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); } :if ($CheckHealthLast->$Temperature > $CheckHealthTemperature->$Temperature && \ $CheckHealthCurrent->$Temperature <= $CheckHealthTemperature->$Temperature) do={ - $SendNotification ("\E2\9C\85 Health recovery: " . $Temperature) \ + $SendNotification ([ $SymbolByUnicodeName "white-heavy-check-mark" ] . " Health recovery: " . $Temperature) \ ("The " . $Temperature . " on " . $Identity . " dropped below threshold: " . \ $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); } From 33899b990432b266c500a35a7f0837d1357f8f3f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 07:43:49 +0200 Subject: [PATCH 0416/2612] check-routeros-update: use $SymbolByUnicodeName --- check-routeros-update | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/check-routeros-update b/check-routeros-update index 62ad64a..8b1b54f 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -15,6 +15,7 @@ :global LogPrintExit; :global ScriptFromTerminal; :global SendNotification; +:global SymbolByUnicodeName; :global VersionToNum; :local DoUpdate do={ @@ -88,7 +89,7 @@ $Update->"latest-version" . ".") true; } - $SendNotification ("\E2\9C\A8 RouterOS update") \ + $SendNotification ([ $SymbolByUnicodeName "sparkles" ] . " RouterOS update") \ ("A new RouterOS version " . ($Update->"latest-version") . \ " is available for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ From 1b55c9b5a2662ac187591c1f81dd541d88e70e9b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 07:47:28 +0200 Subject: [PATCH 0417/2612] log-forward: use $SymbolByUnicodeName --- log-forward | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-forward b/log-forward index 068ffb0..1bba504 100644 --- a/log-forward +++ b/log-forward @@ -13,6 +13,7 @@ :global LogPrintExit; :global MailServerIsUp; :global SendNotification; +:global SymbolByUnicodeName; :global WaitFullyConnected; $WaitFullyConnected; @@ -39,7 +40,7 @@ $WaitFullyConnected; } :if ($Count > 0) do={ - $SendNotification ("\E2\9A\A0 Log Forwarding") \ + $SendNotification ([ $SymbolByUnicodeName "warning-sign" ] . " Log Forwarding") \ ("The log on " . $Identity . " contains these " . $Count . " messages after " . \ [ / system resource get uptime ] . " uptime.\n" . $Messages); From 4a5185ae28a120cc576d5566c54f093f80284db8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 07:49:42 +0200 Subject: [PATCH 0418/2612] netwatch-notify: use $SymbolByUnicodeName --- netwatch-notify | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 5b0c629..44f0657 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -11,6 +11,7 @@ :global ParseKeyValueStore; :global LogPrintExit; :global SendNotification; +:global SymbolByUnicodeName; :if ([ :typeof $NetwatchNotify ] = "nothing") do={ :set NetwatchNotify [ :toarray "" ]; @@ -31,7 +32,7 @@ :local Count ($Metric->"count"); :set ($Metric->"count") 0; :if ($Metric->"notified" = true) do={ - $SendNotification ("\E2\9C\85 Netwatch Notify: " . $HostName . " up") \ + $SendNotification ([ $SymbolByUnicodeName "white-heavy-check-mark" ] . " Netwatch Notify: " . $HostName . " up") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ "It was down for " . $Count . " checks."); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ @@ -45,7 +46,7 @@ $LogPrintExit info ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ $Metric->"count" . " checks.") false; :if ($Metric->"count" >= 5 && $Metric->"notified" != true) do={ - $SendNotification ("\E2\9D\8C Netwatch Notify: " . $HostName . " down") \ + $SendNotification ([ $SymbolByUnicodeName "cross-mark" ] . " Netwatch Notify: " . $HostName . " down") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :set ($Metric->"notified") true; :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ From 0e7b2d3ac735ca4922dc87671138297623ebd4bc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 07:50:51 +0200 Subject: [PATCH 0419/2612] sms-forward: use $SymbolByUnicodeName --- sms-forward | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sms-forward b/sms-forward index d435421..88b39b9 100644 --- a/sms-forward +++ b/sms-forward @@ -11,6 +11,7 @@ :global LogPrintExit; :global MailServerIsUp; :global SendNotification; +:global SymbolByUnicodeName; :global WaitFullyConnected; :if ([ / tool sms get receive-enabled ] = false) do={ @@ -46,7 +47,7 @@ $WaitFullyConnected; } :if ([ :len $Messages ] > 0) do={ - $SendNotification ("\F0\9F\93\A8 SMS Forwarding from " . $Phone) \ + $SendNotification ([ $SymbolByUnicodeName "incoming-envelope" ] . " SMS Forwarding from " . $Phone) \ ("These message(s) were received by " . $Identity . \ " from " . $Phone . ":" . $Messages); :foreach Sms in=$Delete do={ From 075859c8986827b21c313affa896de814e3ae763 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 08:07:12 +0200 Subject: [PATCH 0420/2612] global-functions: introduce and use $SymbolForNotification --- check-health | 12 ++++++------ check-routeros-update | 4 ++-- global-config | 5 ++++- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 15 ++++++++++++++- log-forward | 4 ++-- netwatch-notify | 6 +++--- sms-forward | 4 ++-- 9 files changed, 35 insertions(+), 18 deletions(-) diff --git a/check-health b/check-health index a63483e..33ad59f 100644 --- a/check-health +++ b/check-health @@ -13,7 +13,7 @@ :global LogPrintExit; :global SendNotification; -:global SymbolByUnicodeName; +:global SymbolForNotification; :local FormatVoltage do={ :local Voltage [ :tonum $1 ]; @@ -27,7 +27,7 @@ [ :typeof ($CheckHealthCurrent->$Voltage) ] = "num") do={ :if ($CheckHealthLast->$Voltage * (100 + $CheckHealthVoltagePercent) < $CheckHealthCurrent->$Voltage * 100 || \ $CheckHealthLast->$Voltage * 100 > $CheckHealthCurrent->$Voltage * (100 + $CheckHealthVoltagePercent)) do={ - $SendNotification ([ $SymbolByUnicodeName "high-voltage-sign" ] . " Health warning: " . $Voltage) \ + $SendNotification ([ $SymbolForNotification "high-voltage-sign" ] . "Health warning: " . $Voltage) \ ("The " . $Voltage . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ "old value: " . [ $FormatVoltage ($CheckHealthLast->$Voltage) ] . "\n" . \ "new value: " . [ $FormatVoltage ($CheckHealthCurrent->$Voltage) ]); @@ -40,12 +40,12 @@ [ :typeof ($CheckHealthCurrent->($PSU . "-state")) ] = "str") do={ :if ($CheckHealthLast->($PSU . "-state") = "ok" && \ $CheckHealthCurrent->($PSU . "-state") != "ok") do={ - $SendNotification ([ $SymbolByUnicodeName "cross-mark" ] . " Health warning: " . $PSU . " state") \ + $SendNotification ([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $PSU . " state") \ ("The power supply unit '" . $PSU . "' on " . $Identity . " failed!"); } :if ($CheckHealthLast->($PSU . "-state") != "ok" && \ $CheckHealthCurrent->($PSU . "-state") = "ok") do={ - $SendNotification ([ $SymbolByUnicodeName "white-heavy-check-mark" ] . " Health recovery: " . $PSU . " state") \ + $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $PSU . " state") \ ("The power supply unit '" . $PSU . "' on " . $Identity . " recovered!"); } } @@ -60,13 +60,13 @@ } :if ($CheckHealthLast->$Temperature <= $CheckHealthTemperature->$Temperature && \ $CheckHealthCurrent->$Temperature > $CheckHealthTemperature->$Temperature) do={ - $SendNotification ([ $SymbolByUnicodeName "fire" ] . " Health warning: " . $Temperature) \ + $SendNotification ([ $SymbolForNotification "fire" ] . "Health warning: " . $Temperature) \ ("The " . $Temperature . " on " . $Identity . " is above threshold: " . \ $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); } :if ($CheckHealthLast->$Temperature > $CheckHealthTemperature->$Temperature && \ $CheckHealthCurrent->$Temperature <= $CheckHealthTemperature->$Temperature) do={ - $SendNotification ([ $SymbolByUnicodeName "white-heavy-check-mark" ] . " Health recovery: " . $Temperature) \ + $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Temperature) \ ("The " . $Temperature . " on " . $Identity . " dropped below threshold: " . \ $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); } diff --git a/check-routeros-update b/check-routeros-update index 8b1b54f..ee018c0 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -15,7 +15,7 @@ :global LogPrintExit; :global ScriptFromTerminal; :global SendNotification; -:global SymbolByUnicodeName; +:global SymbolForNotification; :global VersionToNum; :local DoUpdate do={ @@ -89,7 +89,7 @@ $Update->"latest-version" . ".") true; } - $SendNotification ([ $SymbolByUnicodeName "sparkles" ] . " RouterOS update") \ + $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ ("A new RouterOS version " . ($Update->"latest-version") . \ " is available for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ diff --git a/global-config b/global-config index 87ac2c7..4e5fd4a 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 23; +:global GlobalConfigVersion 24; # This is used for DNS and backup file. :global Domain "example.com"; @@ -28,6 +28,9 @@ #:global TelegramTokenId "123456:ABCDEF-GHI"; #:global TelegramChatId "12345678"; +# Toggle this to disable symbols in notifications. +:global NotificationsWithSymbols true; + # This defines what backups to generate and what password to use. :global BackupSendBinary false; :global BackupSendExport true; diff --git a/global-config-overlay b/global-config-overlay index 676db65..001128d 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 23; +:global GlobalConfigVersion 24; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index d3ff78f..82d67d7 100644 --- a/global-config.changes +++ b/global-config.changes @@ -27,4 +27,5 @@ 21="Added support for installing patch updates automatically by 'check-routeros-update'"; 22="Dropped '\$ScriptUpdatesIgnore' from global configuration, auto-migrating to ignore flag in comment" 23="Added 'log-forward' with configurable filter, which replaces 'early-errors'"; + 24="Made symbols in notifications configurable."; }; diff --git a/global-functions b/global-functions index ba9142f..0eb0e4c 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 23; +:global ExpectedConfigVersion 24; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -41,6 +41,7 @@ :global SendNotification; :global SendTelegram; :global SymbolByUnicodeName; +:global SymbolForNotification; :global TimeIsSync; :global UrlEncode; :global VersionToNum; @@ -747,6 +748,18 @@ :return ($Symbols->$1); } +# return symbol for notification +:set SymbolForNotification do={ + :global NotificationsWithSymbols; + + :global SymbolByUnicodeName; + + :if ($NotificationsWithSymbols != true) do={ + :return ""; + } + :return ([ $SymbolByUnicodeName $1 ] . " "); +} + # check if system time is sync :set TimeIsSync do={ :if ([ / system ntp client get enabled ] = true) do={ diff --git a/log-forward b/log-forward index 1bba504..0500072 100644 --- a/log-forward +++ b/log-forward @@ -13,7 +13,7 @@ :global LogPrintExit; :global MailServerIsUp; :global SendNotification; -:global SymbolByUnicodeName; +:global SymbolForNotification; :global WaitFullyConnected; $WaitFullyConnected; @@ -40,7 +40,7 @@ $WaitFullyConnected; } :if ($Count > 0) do={ - $SendNotification ([ $SymbolByUnicodeName "warning-sign" ] . " Log Forwarding") \ + $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Log Forwarding") \ ("The log on " . $Identity . " contains these " . $Count . " messages after " . \ [ / system resource get uptime ] . " uptime.\n" . $Messages); diff --git a/netwatch-notify b/netwatch-notify index 44f0657..0f464a9 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -11,7 +11,7 @@ :global ParseKeyValueStore; :global LogPrintExit; :global SendNotification; -:global SymbolByUnicodeName; +:global SymbolForNotification; :if ([ :typeof $NetwatchNotify ] = "nothing") do={ :set NetwatchNotify [ :toarray "" ]; @@ -32,7 +32,7 @@ :local Count ($Metric->"count"); :set ($Metric->"count") 0; :if ($Metric->"notified" = true) do={ - $SendNotification ([ $SymbolByUnicodeName "white-heavy-check-mark" ] . " Netwatch Notify: " . $HostName . " up") \ + $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $HostName . " up") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ "It was down for " . $Count . " checks."); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ @@ -46,7 +46,7 @@ $LogPrintExit info ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ $Metric->"count" . " checks.") false; :if ($Metric->"count" >= 5 && $Metric->"notified" != true) do={ - $SendNotification ([ $SymbolByUnicodeName "cross-mark" ] . " Netwatch Notify: " . $HostName . " down") \ + $SendNotification ([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :set ($Metric->"notified") true; :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ diff --git a/sms-forward b/sms-forward index 88b39b9..8f38a4a 100644 --- a/sms-forward +++ b/sms-forward @@ -11,7 +11,7 @@ :global LogPrintExit; :global MailServerIsUp; :global SendNotification; -:global SymbolByUnicodeName; +:global SymbolForNotification; :global WaitFullyConnected; :if ([ / tool sms get receive-enabled ] = false) do={ @@ -47,7 +47,7 @@ $WaitFullyConnected; } :if ([ :len $Messages ] > 0) do={ - $SendNotification ([ $SymbolByUnicodeName "incoming-envelope" ] . " SMS Forwarding from " . $Phone) \ + $SendNotification ([ $SymbolForNotification "incoming-envelope" ] . "SMS Forwarding from " . $Phone) \ ("These message(s) were received by " . $Identity . \ " from " . $Phone . ":" . $Messages); :foreach Sms in=$Delete do={ From e0fe98a27410f415e296bba69c4587847ddd4781 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 11:22:40 +0200 Subject: [PATCH 0421/2612] cloud-backup: add symbol in notification --- cloud-backup | 3 ++- global-functions | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cloud-backup b/cloud-backup index dd03a98..b85a467 100644 --- a/cloud-backup +++ b/cloud-backup @@ -12,6 +12,7 @@ :global DeviceInfo; :global LogPrintExit; :global SendNotification; +:global SymbolForNotification; :do { # we are not interested in output, but print without count-only is @@ -26,7 +27,7 @@ } :local Cloud [ / system backup cloud get ([ find ]->0) ]; - $SendNotification "Cloud backup" \ + $SendNotification ([ $SymbolForNotification "floppy-disk" ] . "Cloud backup") \ ("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Name: " . $Cloud->"name" . "\n" . \ diff --git a/global-functions b/global-functions index 0eb0e4c..5304e53 100644 --- a/global-functions +++ b/global-functions @@ -738,6 +738,7 @@ :local Symbols { "cross-mark"="\E2\9D\8C"; "fire"="\F0\9F\94\A5"; + "floppy-disk"="\F0\9F\92\BE"; "high-voltage-sign"="\E2\9A\A1"; "incoming-envelope"="\F0\9F\93\A8"; "sparkles"="\E2\9C\A8"; From d1cba3fc057a71cc2ad4d88450e492f58669ce7f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 11:23:17 +0200 Subject: [PATCH 0422/2612] upload-backup: add symbol in notification --- upload-backup | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/upload-backup b/upload-backup index 30e7047..6ad85ad 100644 --- a/upload-backup +++ b/upload-backup @@ -19,6 +19,7 @@ :global DeviceInfo; :global LogPrintExit; :global SendNotification; +:global SymbolForNotification; :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ @@ -58,7 +59,7 @@ } } -$SendNotification "Backup & Config Upload" \ +$SendNotification ([ $SymbolForNotification "floppy-disk" ] . "Backup & Config Upload") \ ("Backup and config export upload for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ From b91edc9e3993eb65e8bc07f8f7f35a1995ffae66 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 11:40:24 +0200 Subject: [PATCH 0423/2612] global-functions: $ScriptInstallUpdate: add symbol in notification --- global-functions | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 5304e53..a59ac11 100644 --- a/global-functions +++ b/global-functions @@ -496,6 +496,7 @@ :global LogPrintExit; :global ParseKeyValueStore; :global SendNotification; + :global SymbolForNotification; :foreach Script in=$Scripts do={ :if ([ / system script print count-only where name=$Script ] = 0) do={ @@ -636,7 +637,8 @@ "https://git.eworm.de/cgit/routeros-scripts/about/#donate"); } - $SendNotification "News and configuration changes" $NotificationMessage; + $SendNotification ([ $SymbolForNotification "pushpin" ] . "News and configuration changes") \ + $NotificationMessage; :set SentConfigChangesNotification $ExpectedConfigVersion; } } @@ -741,6 +743,7 @@ "floppy-disk"="\F0\9F\92\BE"; "high-voltage-sign"="\E2\9A\A1"; "incoming-envelope"="\F0\9F\93\A8"; + "pushpin"="\F0\9F\93\8C"; "sparkles"="\E2\9C\A8"; "warning-sign"="\E2\9A\A0"; "white-heavy-check-mark"="\E2\9C\85" From 3e1746f43e624ebfa9e10fc46ab9d170956612cc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 11:52:54 +0200 Subject: [PATCH 0424/2612] check-certificates: add symbol in notification --- check-certificates | 5 +++-- global-functions | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/check-certificates b/check-certificates index 1402e49..5dfb596 100644 --- a/check-certificates +++ b/check-certificates @@ -16,6 +16,7 @@ :global LogPrintExit; :global ParseKeyValueStore; :global SendNotification; +:global SymbolForNotification; :global TimeIsSync; :global UrlEncode; :global WaitForFile; @@ -85,7 +86,7 @@ / certificate set $CertNew name=($CertVal->"name"); } - $SendNotification ("Certificate renewed") \ + $SendNotification ([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed") \ ("A certificate on " . $Identity . " has been renewed.\n\n" . \ "Name: " . ($CertVal->"name") . "\n" . \ "CommonName: " . ($CertNewVal->"common-name") . "\n" . \ @@ -107,7 +108,7 @@ } else={ :local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ]; - $SendNotification ("Certificate warning!") \ + $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Certificate warning!") \ ("A certificate on " . $Identity . " " . $State . ".\n\n" . \ "Name: " . ($CertVal->"name") . "\n" . \ "CommonName: " . ($CertVal->"common-name") . "\n" . \ diff --git a/global-functions b/global-functions index a59ac11..8149d4b 100644 --- a/global-functions +++ b/global-functions @@ -743,6 +743,7 @@ "floppy-disk"="\F0\9F\92\BE"; "high-voltage-sign"="\E2\9A\A1"; "incoming-envelope"="\F0\9F\93\A8"; + "lock-with-ink-pen"="\F0\9F\94\8F"; "pushpin"="\F0\9F\93\8C"; "sparkles"="\E2\9C\A8"; "warning-sign"="\E2\9A\A0"; From 8eaf24e27415ad56138cf2ec93eb850509e42b0c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 12:00:59 +0200 Subject: [PATCH 0425/2612] upload-backup: change symbol to warning sign on failure --- upload-backup | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/upload-backup b/upload-backup index 6ad85ad..8d7dd28 100644 --- a/upload-backup +++ b/upload-backup @@ -17,6 +17,7 @@ :global CharacterReplace; :global DeviceInfo; +:global IfThenElse; :global LogPrintExit; :global SendNotification; :global SymbolForNotification; @@ -30,6 +31,7 @@ :local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; :local BackupFile "none"; :local ConfigFile "none"; +:local Failed 0; # binary backup :if ($BackupSendBinary = true) do={ @@ -42,6 +44,7 @@ } on-error={ $LogPrintExit error ("Uploading backup file failed!") false; :set BackupFile "failed"; + :set Failed 1; } } @@ -56,10 +59,11 @@ } on-error={ $LogPrintExit error ("Uploading configuration export failed!") false; :set ConfigFile "failed"; + :set Failed 1; } } -$SendNotification ([ $SymbolForNotification "floppy-disk" ] . "Backup & Config Upload") \ +$SendNotification ([ $SymbolForNotification [ $IfThenElse ($Failed > 0) "warning-sign" "floppy-disk" ] ] . "Backup & Config Upload") \ ("Backup and config export upload for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ From 35c28df68dc8e04338d52fc966c97347cc612f0d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 12:25:44 +0200 Subject: [PATCH 0426/2612] check-routeros-update: add symbol in all notifications --- check-routeros-update | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index ee018c0..b1e40e4 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -51,7 +51,7 @@ :if ($NumInstalled < $NumLatest) do={ :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ $LogPrintExit info ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; - $SendNotification ("RouterOS update") \ + $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ ("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ ", updating on " . $Identity . "...") "" "true"; $DoUpdate; @@ -68,7 +68,7 @@ } :if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={ $LogPrintExit info ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; - $SendNotification ("RouterOS update") \ + $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ ("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ ", updating on " . $Identity . "...") "" "true"; $DoUpdate; @@ -104,7 +104,7 @@ $Update->"latest-version" . ".") true; } - $SendNotification ("RouterOS version") \ + $SendNotification ([ $SymbolForNotification "warning-sign" ] . "RouterOS version") \ ("A different RouterOS version " . ($Update->"latest-version") . \ " is available for " . $Identity . ", but it is a downgrade.\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ From 00e99a13fbbe0fe5be2b148365e0afffa905718a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 12:26:55 +0200 Subject: [PATCH 0427/2612] check-lte-firmware-upgrade: add symbol in notification --- check-lte-firmware-upgrade | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 6aaec79..b4ca5d3 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -11,6 +11,7 @@ :global LogPrintExit; :global SendNotification; +:global SymbolForNotification; :foreach Interface in=[ / interface lte find ] do={ :local IntName [ / interface lte get $Interface name ]; @@ -22,7 +23,7 @@ ($Firmware->"latest") . ".") false; } else={ :if (($Firmware->"installed") != ($Firmware->"latest")) do={ - $SendNotification ("LTE firmware upgrade") \ + $SendNotification ([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade") \ ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ "Installed: " . ($Firmware->"installed") . "\n" . \ From b27d875111271743be939368935ab28d93eae042 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jul 2020 20:52:52 +0200 Subject: [PATCH 0428/2612] log-forward: lock script to run just once --- log-forward | 3 +++ 1 file changed, 3 insertions(+) diff --git a/log-forward b/log-forward index 0500072..40afbe6 100644 --- a/log-forward +++ b/log-forward @@ -12,10 +12,13 @@ :global LogPrintExit; :global MailServerIsUp; +:global ScriptLock; :global SendNotification; :global SymbolForNotification; :global WaitFullyConnected; +$ScriptLock "log-forward"; + $WaitFullyConnected; :if ($MailServerIsUp = false) do={ From 1bac1b4d3d91c366842437cc477274b7c7d40d3f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 18 Jul 2020 00:01:51 +0200 Subject: [PATCH 0429/2612] netwatch-notify: ignore disabled hosts --- netwatch-notify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index 0f464a9..898ca99 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -17,7 +17,7 @@ :set NetwatchNotify [ :toarray "" ]; } -:foreach Host in=[ / tool netwatch find where comment~"^notify," ] do={ +:foreach Host in=[ / tool netwatch find where comment~"^notify," disabled=no ] do={ :local HostVal [ / tool netwatch get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; :local HostName ($HostInfo->"hostname"); From 3b28440b05449f567834e740029a5ac9d0e8ce46 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 25 Jul 2020 13:39:15 +0200 Subject: [PATCH 0430/2612] global-functions: drop $GetRandomSha256, introduce $GetRandom20CharHex Do do generate certificate, but use scep-server otp. --- global-functions | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/global-functions b/global-functions index 8149d4b..3895550 100644 --- a/global-functions +++ b/global-functions @@ -25,8 +25,8 @@ :global DNSIsResolving; :global DownloadPackage; :global GetMacVendor; +:global GetRandom20CharHex; :global GetRandomNumber; -:global GetRandomSha256; :global IfThenElse; :global IPCalc; :global LogPrintExit; @@ -299,6 +299,13 @@ } } +# generate random 20 chars hex (0-9 and a-f) +:set GetRandom20CharHex do={ + :local Random ([ / certificate scep-server otp generate minutes-valid=0 as-value ]->"password"); + / certificate scep-server otp remove [ find where password=$Random ]; + :return $Random; +} + # generate random number :set GetRandomNumber do={ :local Max 4294967295; @@ -306,13 +313,13 @@ :set Max ([ :tonum $1 ] + 1); } - :global GetRandomSha256; + :global GetRandom20CharHex; :local Num; - :local Sha256 [ $GetRandomSha256 ]; + :local 40CharHex ([ $GetRandom20CharHex ] . [ $GetRandom20CharHex ]); - :for I from=0 to=63 do={ - :local Char [ :pick $Sha256 $I ]; + :for I from=0 to=39 do={ + :local Char [ :pick $40CharHex $I ]; :if ($Char~"[0-9]") do={ :set Num ($Num . $Char); } @@ -321,17 +328,6 @@ :return ([ :tonum [ :pick $Num 0 18 ] ] % $Max); } -# generate random sha256 string -# returns 64 bytes of 0-9 and a-f -:set GetRandomSha256 do={ - :local FingerPrint; - / certificate add name=GetRandomSha256-template common-name=GetRandomSha256 key-size=prime256v1; - / certificate sign GetRandomSha256-template name=GetRandomSha256 without-paging as-value; - :set FingerPrint [ / certificate get GetRandomSha256 fingerprint ]; - / certificate remove GetRandomSha256; - :return $FingerPrint; -} - # mimic conditional/ternary operator (condition ? consequent : alternative) :set IfThenElse do={ :if ([ :tostr $1 ] = "true" || [ :tobool $1 ] = true) do={ From 354be9c222339d0d2dcaa5a5460f272f0c0b44a6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 2 Aug 2020 23:10:41 +0200 Subject: [PATCH 0431/2612] doc/dhcp-to-dns: document $PrefixInZone --- doc/dhcp-to-dns.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 9f8cb8b..0c112b3 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -33,6 +33,7 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `Domain`: the domain used for dns records * `HostNameInZone`: whether or not to add the dhcp/dns server's hostname +* `PrefixInZone`: whether or not to add prefix `dhcp` See also -------- From 2e1acc25059b9cc671a96ad648ef854a5bb29202 Mon Sep 17 00:00:00 2001 From: netztrip Date: Sun, 2 Aug 2020 23:31:21 +0200 Subject: [PATCH 0432/2612] dhcp-to-dns: add support for dhcp server name in fqdn --- dhcp-to-dns | 3 ++- doc/dhcp-to-dns.md | 1 + global-config | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index 352b53f..4e2c7f2 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -10,6 +10,7 @@ :global HostNameInZone; :global Identity; :global PrefixInZone; +:global ServerNameInZone; :global CharacterReplace; :global IfThenElse; @@ -46,7 +47,7 @@ [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ] \ [ $CharacterReplace ($LeaseVal->"host-name") " " "" ] ]; - :local Fqdn ($HostName . "." . $Zone); + :local Fqdn ($HostName . "." . [ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); :local DnsRecord [ / ip dns static find where name=$Fqdn ]; :if ([ :len $DnsRecord ] > 0) do={ :local DnsIp [ / ip dns static get $DnsRecord address ]; diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 0c112b3..699b6a5 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -34,6 +34,7 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `Domain`: the domain used for dns records * `HostNameInZone`: whether or not to add the dhcp/dns server's hostname * `PrefixInZone`: whether or not to add prefix `dhcp` +* `ServerNameInZone`: whether or not to add DHCP server name See also -------- diff --git a/global-config b/global-config index 4e5fd4a..0228082 100644 --- a/global-config +++ b/global-config @@ -14,6 +14,7 @@ :global Domain "example.com"; :global HostNameInZone true; :global PrefixInZone true; +:global ServerNameInZone false; # These addresses are used to send e-mails to. The to-address needs # to be filled; cc-address can be empty, one address or a comma From 457110e2620808d630b50825d255268c7fe3f2e3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Aug 2020 22:11:01 +0200 Subject: [PATCH 0433/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index a15a72a..46b798b 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -10,6 +10,7 @@ Thanks a lot for your contributions! These persons contributed code. See the git history for details! * [Michael Gisbers](mailto:michael@gisbers.de) +* [netztrip](mailto:dave-tvg@netztrip.de) (@netztrip) ## Donations From 6575cb332113945b591dae7f4b424773936e2c64 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Aug 2020 22:15:30 +0200 Subject: [PATCH 0434/2612] notify about support for dhcp server name in fqdn --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 0228082..90686a1 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 24; +:global GlobalConfigVersion 25; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 001128d..c1f55da 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 24; +:global GlobalConfigVersion 25; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 82d67d7..452fa4b 100644 --- a/global-config.changes +++ b/global-config.changes @@ -28,4 +28,5 @@ 22="Dropped '\$ScriptUpdatesIgnore' from global configuration, auto-migrating to ignore flag in comment" 23="Added 'log-forward' with configurable filter, which replaces 'early-errors'"; 24="Made symbols in notifications configurable."; + 25="Added support for DHCP server name in DNS FQDN via '\$ServerNameInZone'"; }; diff --git a/global-functions b/global-functions index 3895550..e6e51c0 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 24; +:global ExpectedConfigVersion 25; # global variables not to be changed by user :global GlobalFunctionsReady false; From f1236065ad145a5414d41e86013f6fd19b4ec911 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 13 Aug 2020 13:07:40 +0200 Subject: [PATCH 0435/2612] fix typo: botton -> button --- README.md | 2 +- doc/leds-mode.md | 2 +- doc/mode-button.md | 2 +- mode-button-scheduler | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cb6d7b8..03b7bbd 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ Available Scripts * [Run other scripts on DHCP lease](doc/lease-script.md) * [Manage LEDs dark mode](doc/leds-mode.md) * [Forward log messages via notification](doc/log-forward.md) -* [Mode botton with multiple presses](doc/mode-button.md) +* [Mode button with multiple presses](doc/mode-button.md) * [Notify on host up and down](doc/netwatch-notify.md) * [Manage remote logging](doc/netwatch-syslog.md) * [Manage system update](doc/packages-update.md) diff --git a/doc/leds-mode.md b/doc/leds-mode.md index e0f7cf3..b525220 100644 --- a/doc/leds-mode.md +++ b/doc/leds-mode.md @@ -43,7 +43,7 @@ to toggle mode. See also -------- -* [Mode botton with multiple presses](mode-button.md) +* [Mode button with multiple presses](mode-button.md) --- [◀ Go back to main README](../README.md) diff --git a/doc/mode-button.md b/doc/mode-button.md index 0e5fa47..0007481 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -1,4 +1,4 @@ -Mode botton with multiple presses +Mode button with multiple presses ================================= [◀ Go back to main README](../README.md) diff --git a/mode-button-scheduler b/mode-button-scheduler index 0090426..fe04b40 100644 --- a/mode-button-scheduler +++ b/mode-button-scheduler @@ -3,7 +3,7 @@ # Copyright (c) 2018-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# act on multiple mode-botton presses from scheduler +# act on multiple mode-button presses from scheduler # https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md :global ModeButton; From eaffb1dbd27689015d7bcfaa9ab19f81a75fef24 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 21 Aug 2020 23:09:39 +0200 Subject: [PATCH 0436/2612] check-certificates: fix usage of function --- check-certificates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index 5dfb596..7a587e1 100644 --- a/check-certificates +++ b/check-certificates @@ -26,7 +26,7 @@ :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; } -:if ($TimeIsSync = false) do={ +:if ([ $TimeIsSync ] = false) do={ $LogPrintExit warning ("Time is not yet synchronized.") true; } From b68b997c1ea0882f89df4425ed39c6ce0dc653aa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 21 Aug 2020 23:13:47 +0200 Subject: [PATCH 0437/2612] check-certificates: wait to be fully connected --- check-certificates | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/check-certificates b/check-certificates index 7a587e1..a0e5bce 100644 --- a/check-certificates +++ b/check-certificates @@ -17,18 +17,16 @@ :global ParseKeyValueStore; :global SendNotification; :global SymbolForNotification; -:global TimeIsSync; :global UrlEncode; :global WaitForFile; +:global WaitFullyConnected; :local FormatExpire do={ :global CharacterReplace; :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; } -:if ([ $TimeIsSync ] = false) do={ - $LogPrintExit warning ("Time is not yet synchronized.") true; -} +$WaitFullyConnected; :foreach Cert in=[ / certificate find where !revoked !ca !scep-url expires-after<3w ] do={ :local CertVal [ / certificate get $Cert ]; From cc375704f35be7fa454335c20087daec030381db Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 21 Aug 2020 23:25:53 +0200 Subject: [PATCH 0438/2612] global-functions: $TimeIsSync: return false if ntp client enabled but not synced --- global-functions | 1 + 1 file changed, 1 insertion(+) diff --git a/global-functions b/global-functions index e6e51c0..95437c6 100644 --- a/global-functions +++ b/global-functions @@ -773,6 +773,7 @@ :return true; } } + :return false; } :if ([ / ip cloud get update-time ] = true && \ From 7febb6a0f418c07239fa8fcaa61ce4b5ef75f448 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 21 Aug 2020 23:30:36 +0200 Subject: [PATCH 0439/2612] global-functions: $TimeIsSync: return false if cloud enabled but not ready --- global-functions | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 95437c6..7f3e51b 100644 --- a/global-functions +++ b/global-functions @@ -776,9 +776,11 @@ :return false; } - :if ([ / ip cloud get update-time ] = true && \ - [ :typeof [ / ip cloud get public-address ] ] = "ip") do={ - :return true; + :if ([ / ip cloud get ddns-enabled ] = true && [ / ip cloud get update-time ] = true) do={ + :if ([ :typeof [ / ip cloud get public-address ] ] = "ip") do={ + :return true; + } + :return false; } :return false; From 8c988ac55a7dc1bd61ea9a6433bb4f0910a8c0ab Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 21 Aug 2020 23:35:29 +0200 Subject: [PATCH 0440/2612] global-functions: $TimeIsSync: warn on missing time source --- global-functions | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global-functions b/global-functions index 7f3e51b..4014e76 100644 --- a/global-functions +++ b/global-functions @@ -763,6 +763,8 @@ # check if system time is sync :set TimeIsSync do={ + :global LogPrintExit; + :if ([ / system ntp client get enabled ] = true) do={ :do { :if ([ / system ntp client get status ] = "synchronized") do={ @@ -783,6 +785,7 @@ :return false; } + $LogPrintExit warning ("No time source configured!") false; :return false; } From d65874e142b5815a2fa32518bc710d2f4c78b5d8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 21 Aug 2020 23:39:36 +0200 Subject: [PATCH 0441/2612] global-functions: $TimeIsSync: return gracefully... Situation will not improve... But chances are that RTC is available with correct time, for example from host inside CHR vm. So return gracefully. --- global-functions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 4014e76..7483f11 100644 --- a/global-functions +++ b/global-functions @@ -785,8 +785,8 @@ :return false; } - $LogPrintExit warning ("No time source configured!") false; - :return false; + $LogPrintExit warning ("No time source configured! Returning gracefully...") false; + :return true; } # url encoding From e58d8e43739744d88f04918ff0e74fabf0bcc37c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Aug 2020 14:02:40 +0200 Subject: [PATCH 0442/2612] netwatch-notify: make check count threshold configurable Signed-off-by: Christian Hesse --- doc/netwatch-notify.md | 4 ++++ netwatch-notify | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index f2ce7b4..3fe1bca 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -35,6 +35,10 @@ comment: / tool netwatch add comment="notify, hostname=poe-device, down-hook=/ interface ethernet poe power-cycle en21;" host=10.0.0.20 timeout=5s; +The count threshould (default is 5 checks) is configurable as well: + + / tool netwatch add comment="notify, hostname=example.com, count=10" host=104.18.144.11 timeout=5s; + Also notification settings are required for e-mail and telegram. --- diff --git a/netwatch-notify b/netwatch-notify index 898ca99..b52c4d1 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -8,8 +8,9 @@ :global NetwatchNotify; -:global ParseKeyValueStore; +:global IfThenElse; :global LogPrintExit; +:global ParseKeyValueStore; :global SendNotification; :global SymbolForNotification; @@ -45,7 +46,8 @@ :set ($Metric->"count") ($Metric->"count" + 1); $LogPrintExit info ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ $Metric->"count" . " checks.") false; - :if ($Metric->"count" >= 5 && $Metric->"notified" != true) do={ + :if ($Metric->"count" >= [ $IfThenElse ([ :typeof ($HostVal->"count") ] != "nothing") ($HostVal->"count") 5 ] && \ + $Metric->"notified" != true) do={ $SendNotification ([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :set ($Metric->"notified") true; From 92ca31a41df332171d1f2dcf08c75db570b12234 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Aug 2020 14:18:32 +0200 Subject: [PATCH 0443/2612] netwatch-notify: be more verbose on host downtime Signed-off-by: Christian Hesse --- netwatch-notify | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index b52c4d1..e47f715 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -35,15 +35,17 @@ :if ($Metric->"notified" = true) do={ $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $HostName . " up") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ - "It was down for " . $Count . " checks."); + "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ $LogPrintExit info ("Running hook on host " . $HostName . " up: " . ($HostInfo->"up-hook")) false; [ :parse ($HostInfo->"up-hook") ]; } } :set ($Metric->"notified") false; + :set ($Metric->"since"); } else={ :set ($Metric->"count") ($Metric->"count" + 1); + :set ($Metric->"since") ($HostVal->"since"); $LogPrintExit info ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ $Metric->"count" . " checks.") false; :if ($Metric->"count" >= [ $IfThenElse ([ :typeof ($HostVal->"count") ] != "nothing") ($HostVal->"count") 5 ] && \ @@ -57,5 +59,8 @@ } } } - :set ($NetwatchNotify->$HostName) { "count"=($Metric->"count"); "notified"=($Metric->"notified") }; + :set ($NetwatchNotify->$HostName) { + "count"=($Metric->"count"); + "notified"=($Metric->"notified"); + "since"=($Metric->"since") }; } From ff5cdc30193ba69944f6772f213e63ea00678861 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Aug 2020 09:23:56 +0200 Subject: [PATCH 0444/2612] [ ... print count-only ...] -> [ :len [ ... find ... ] ] Using 'print count-only' always prints a number to terminal, even if the value is evaluated in a condition or assigned to a variable. This can be quite annoying. Behavior will not chance (SUP-25503), so replacing the code... --- INITIAL-COMMANDS.md | 2 +- capsman-download-packages | 4 ++-- capsman-rolling-upgrade | 2 +- check-certificates | 2 +- check-routeros-update | 6 +++--- cloud-backup | 4 ++-- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- daily-psk.capsman | 2 +- daily-psk.local | 2 +- daily-psk.template | 4 ++-- dhcp-to-dns | 4 ++-- global-functions | 24 ++++++++++++------------ hotspot-to-wpa | 2 +- ip-addr-bridge | 4 ++-- learn-mac-based-vlan | 2 +- lease-script | 2 +- ppp-on-up | 2 +- sms-forward | 2 +- 20 files changed, 38 insertions(+), 38 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index e9889d2..597ddb6 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -10,7 +10,7 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt.pem"; :delay 1s; / certificate import file-name=letsencrypt.pem passphrase=""; - :if ([ / certificate print count-only where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] != 3) do={ + :if ([ :len [ / certificate find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] ] != 3) do={ :error "Something is wrong with your certificates!"; } / file remove "letsencrypt.pem"; diff --git a/capsman-download-packages b/capsman-download-packages index 88aac0e..a314163 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -21,7 +21,7 @@ $WaitFullyConnected; :local InstalledVersion [ / system package update get installed-version ]; :local Updated false; -:if ([ / file print count-only where name=$PackagePath type="directory" ] = 0) do={ +:if ([ :len [ / file find where name=$PackagePath type="directory" ] ] = 0) do={ $MkDir $PackagePath; $LogPrintExit info ("Created directory at package path (" . $PackagePath . \ "). Please place your packages!") false; @@ -43,7 +43,7 @@ $WaitFullyConnected; } :if ($Updated = true) do={ - :if ([ / system script print count-only where name="capsman-rolling-upgrade" ] > 0) do={ + :if ([ :len [ / system script find where name="capsman-rolling-upgrade" ] ] > 0) do={ / system script run capsman-rolling-upgrade; } else={ / caps-man remote-cap upgrade [ find where version!=$InstalledVersion ]; diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index 698ff93..61552f5 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -14,7 +14,7 @@ $ScriptLock "capsman-rolling-upgrade"; :local InstalledVersion [ / system package update get installed-version ]; -:local RemoteCapCount [ /caps-man remote-cap print count-only ]; +:local RemoteCapCount [ :len [ / caps-man remote-cap find ] ]; :if ($RemoteCapCount > 0) do={ :local Delay (600 / $RemoteCapCount); :if ($Delay > 120) do={ :set Delay 120; } diff --git a/check-certificates b/check-certificates index a0e5bce..5ac8a18 100644 --- a/check-certificates +++ b/check-certificates @@ -101,7 +101,7 @@ $WaitFullyConnected; :foreach Cert in=[ / certificate find where !revoked !scep-url expires-after<2w fingerprint~"." ] do={ :local CertVal [ / certificate get $Cert ]; - :if ([ / certificate scep-server print count-only where ca-cert=($CertVal->"ca") ] > 0) do={ + :if ([ :len [ / certificate scep-server find where ca-cert=($CertVal->"ca") ] ] > 0) do={ $LogPrintExit debug ("Certificate \"" . ($CertVal->"name") . "\" is handled by SCEP, skipping.") false; } else={ :local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ]; diff --git a/check-routeros-update b/check-routeros-update index b1e40e4..073ed96 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -19,7 +19,7 @@ :global VersionToNum; :local DoUpdate do={ - :if ([ / system script print count-only where name="packages-update" ] > 0) do={ + :if ([ :len [ / system script find where name="packages-update" ] ] > 0) do={ / system script run packages-update; } else={ / system package update install without-paging; @@ -27,14 +27,14 @@ :error "Waiting for system to reboot."; } -:if ([ / system package print count-only where name="wireless" disabled=no ] > 0) do={ +:if ([ :len [ / system package find where name="wireless" disabled=no ] ] > 0) do={ :if ([ / interface wireless cap get enabled ] = true && \ [ / caps-man manager get enabled ] = false) do={ $LogPrintExit error "System is managed by CAPsMAN, not checking." true; } } -:if ([ / system scheduler print count-only where name="reboot-for-update" ] > 0) do={ +:if ([ :len [ / system scheduler find where name="reboot-for-update" ] ] > 0) do={ :error "A reboot for update is already scheduled."; } diff --git a/cloud-backup b/cloud-backup index b85a467..1511062 100644 --- a/cloud-backup +++ b/cloud-backup @@ -15,10 +15,10 @@ :global SymbolForNotification; :do { - # we are not interested in output, but print without count-only is + # we are not interested in output, but print is # required to fetch information from cloud / system backup cloud print as-value; - :if ([ / system backup cloud print count-only ] > 0) do={ + :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={ diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 5979156..e44f387 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -17,7 +17,7 @@ $ScriptLock "collect-wireless-mac.capsman"; -:if ([ / caps-man access-list print count-only where comment="--- collected above ---" disabled ] = 0) do={ +:if ([ :len [ / caps-man access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ / caps-man access-list add comment="--- collected above ---" disabled=yes; $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; } diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 3b86d72..8d23317 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -17,7 +17,7 @@ $ScriptLock "collect-wireless-mac.local"; -:if ([ / interface wireless access-list print count-only where comment="--- collected above ---" disabled ] = 0) do={ +:if ([ :len [ / interface wireless access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ / interface wireless access-list add comment="--- collected above ---" disabled=yes; $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; } diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index f644f47..655fd47 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -18,7 +18,7 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; -:if ([ / %PATH% access-list print count-only where comment="--- collected above ---" disabled ] = 0) do={ +:if ([ :len [ / %PATH% access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ / %PATH% access-list add comment="--- collected above ---" disabled=yes; $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; } diff --git a/daily-psk.capsman b/daily-psk.capsman index f8cbb20..5ae2f5e 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -64,7 +64,7 @@ $WaitFullyConnected; $LogPrintExit info ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; / caps-man access-list set $AccList private-passphrase=$NewPsk; - :if ([ / caps-man interface print count-only where configuration=$Configuration ] > 0) do={ + :if ([ :len [ / caps-man interface find where configuration=$Configuration ] ] > 0) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ $LogPrintExit debug ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; diff --git a/daily-psk.local b/daily-psk.local index a878940..4cc728c 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -64,7 +64,7 @@ $WaitFullyConnected; $LogPrintExit info ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; / interface wireless access-list set $AccList private-pre-shared-key=$NewPsk; - :if ([ / interface wireless print count-only where name=$IntName disabled=no ] = 1) do={ + :if ([ :len [ / interface wireless find where name=$IntName disabled=no ] ] = 1) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ $LogPrintExit debug ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; diff --git a/daily-psk.template b/daily-psk.template index 5c691e6..3c23139 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -69,8 +69,8 @@ $WaitFullyConnected; / interface wireless access-list set $AccList private-pre-shared-key=$NewPsk; / caps-man access-list set $AccList private-passphrase=$NewPsk; - :if ([ / interface wireless print count-only where name=$IntName disabled=no ] = 1) do={ - :if ([ / caps-man interface print count-only where configuration=$Configuration ] > 0) do={ + :if ([ :len [ / interface wireless find where name=$IntName disabled=no ] ] = 1) do={ + :if ([ :len [ / caps-man interface find where configuration=$Configuration ] ] > 0) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ $LogPrintExit debug ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; diff --git a/dhcp-to-dns b/dhcp-to-dns index 4e2c7f2..3a95eb6 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -22,7 +22,7 @@ :local Ttl 5m; :local CommentPrefix "managed by dhcp-to-dns for "; -:if ([ / ip dns static print count-only where comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled ] = 0) do={ +:if ([ :len [ / ip dns static find where comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled ] ] = 0) do={ / ip dns static add comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled=yes; $LogPrintExit warning "Added disabled static dns record with comment '--- dhcp-to-dns above ---'." false; } @@ -31,7 +31,7 @@ :foreach DnsRecord in=[ / ip dns static find where comment ~ $CommentPrefix ] do={ :local DnsRecordVal [ / ip dns static get $DnsRecord ]; :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; - :if ([ / ip dhcp-server lease print count-only where mac-address=$MacAddress address=($DnsRecordVal->"address") dynamic=yes status=bound ] > 0) do={ + :if ([ :len [ / ip dhcp-server lease find where mac-address=$MacAddress address=($DnsRecordVal->"address") dynamic=yes status=bound ] ] > 0) do={ $LogPrintExit debug ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; } else={ :local Found false; diff --git a/global-functions b/global-functions index 7483f11..67c4882 100644 --- a/global-functions +++ b/global-functions @@ -66,7 +66,7 @@ "is configured to download certificate CRLs to system!") false; } - :if ([ / certificate print count-only where common-name=$CommonName ] = 0) do={ + :if ([ :len [ / certificate find where common-name=$CommonName ] ] = 0) do={ $LogPrintExit info ("Certificate with CommonName \"" . $CommonName . "\" not available.") false; :if ([ $CertificateDownload $CommonName ] = false) do={ :return false; @@ -76,7 +76,7 @@ :local CertVal; :local Issuer $CommonName; :do { - :if ([ / certificate print count-only where common-name=$Issuer ] = 0) do={ + :if ([ :len [ / certificate find where common-name=$Issuer ] ] = 0) do={ $LogPrintExit info ("Certificate chain for \"" . $CommonName . \ "\" is incomplete, missing \"" . $Issuer . "\".") false; :if ([ $CertificateDownload $CommonName ] = false) do={ @@ -176,7 +176,7 @@ # default route is reachable :set DefaultRouteIsReachable do={ - :if ([ / ip route print count-only where dst-address=0.0.0.0/0 !unreachable active !routing-mark ] > 0) do={ + :if ([ :len [ / ip route find where dst-address=0.0.0.0/0 !unreachable active !routing-mark ] ] > 0) do={ :return true; } :return false; @@ -249,7 +249,7 @@ } :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; - :if ([ / file print count-only where name=$PkgDest type="package" ] > 0) do={ + :if ([ :len [ / file find where name=$PkgDest type="package" ] ] > 0) do={ $LogPrintExit info ("Package file alreasy exists.") false; :return true; } @@ -383,7 +383,7 @@ :global LogPrintExit; - :if ([ / tool netwatch print count-only where comment=$MailServer ] = 0) do={ + :if ([ :len [ / tool netwatch find where comment=$MailServer ] ] = 0) do={ $LogPrintExit warning ("Adding netwatch entry for mail server.") false; :local MailHost $MailServer; :if ([ :typeof [ :toip $MailHost ] ] != "ip" ) do={ @@ -418,7 +418,7 @@ :global WaitForFile; - :if ([ / file print count-only where name=$Dir type="directory" ] = 0) do={ + :if ([ :len [ / file find where name=$Dir type="directory" ] ] = 0) do={ :local WwwVal [ / ip service get www ]; / ip service set www address=127.0.0.1/32 disabled=no port=80; / tool fetch http://127.0.0.1/ dst-path=($Dir . "/tmp"); @@ -495,7 +495,7 @@ :global SymbolForNotification; :foreach Script in=$Scripts do={ - :if ([ / system script print count-only where name=$Script ] = 0) do={ + :if ([ :len [ / system script find where name=$Script ] ] = 0) do={ $LogPrintExit info ("Adding new script: " . $Script) false; / system script add name=$Script source="#!rsc"; } @@ -569,7 +569,7 @@ / system script set owner=($ScriptVal->"name") source=$SourceNew \ dont-require-permissions=$DontRequirePermissions $Script; :if ($ScriptVal->"name" = "global-config" && \ - [ / system script print count-only where name="global-config-overlay" ] > 0) do={ + [ :len [ / system script find where name="global-config-overlay" ] ] > 0) do={ $LogPrintExit info ("Reloading global configuration and overlay.") false; / system script { run global-config; run global-config-overlay; } } @@ -593,7 +593,7 @@ :global GlobalConfigChanges; :local ChangeLogCode; :local ConfigScript "global-config"; - :if ([ /system script print count-only where name="global-config-overlay" ] > 0) do={ + :if ([ :len [ / system script find where name="global-config-overlay" ] ] > 0) do={ :set ConfigScript "global-config-overlay"; } :local NotificationMessage ("Current configuration on " . $Identity . \ @@ -645,7 +645,7 @@ :local Script [ :tostr $1 ]; - :if ([ / system script job print count-only where script=$Script ] > 1) do={ + :if ([ :len [ / system script job find where script=$Script ] ] > 1) do={ $LogPrintExit info ("Script " . $Script . " started more than once... Aborting.") true; } } @@ -868,7 +868,7 @@ :local FileName [ $CleanFilePath [ :tostr $1 ] ]; :local I 0; - :while ([ file print count-only where name=$FileName ] = 0) do={ + :while ([ :len [ / file find where name=$FileName ] ] = 0) do={ :if ($I > 20) do={ :return false; } @@ -895,7 +895,7 @@ :global TimeIsSync; :while ([ $TimeIsSync ] = false) do={ - :if ([ / system script print count-only where name="rotate-ntp" ] > 0 && \ + :if ([ :len [ / system script find where name="rotate-ntp" ] ] > 0 && \ [ :tostr [ / system resource get uptime ] ] ~ "[369]:00\$") do={ :do { / system script run rotate-ntp; diff --git a/hotspot-to-wpa b/hotspot-to-wpa index a9fa7d9..8603d56 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -13,7 +13,7 @@ :local Date [ / system clock get date ]; :local PassWord [ / ip hotspot user get [ find where name=$UserName ] password ]; -:if ([ / caps-man access-list print count-only where comment="--- hotspot-to-wpa above ---" disabled ] = 0) do={ +:if ([ :len [ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ / caps-man access-list add comment="--- hotspot-to-wpa above ---" disabled=yes; $LogPrintExit warning "Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'." false; } diff --git a/ip-addr-bridge b/ip-addr-bridge index ec403f5..9bc7ef8 100644 --- a/ip-addr-bridge +++ b/ip-addr-bridge @@ -8,8 +8,8 @@ :foreach Bridge in=[ / interface bridge find ] do={ :local BrName [ / interface bridge get $Bridge name ]; - :if ([ / interface bridge port print count-only where bridge=$BrName ] > 0) do={ - :if ([ / interface bridge port print count-only where bridge=$BrName and inactive=no ] = 0) do={ + :if ([ :len [ / interface bridge port find where bridge=$BrName ] ] > 0) do={ + :if ([ :len [ / interface bridge port find where bridge=$BrName and inactive=no ] ] = 0) do={ / ip address disable [ find where !dynamic interface=$BrName ]; } else={ / ip address enable [ find where !dynamic interface=$BrName ]; diff --git a/learn-mac-based-vlan b/learn-mac-based-vlan index 14261c0..690bec4 100644 --- a/learn-mac-based-vlan +++ b/learn-mac-based-vlan @@ -7,7 +7,7 @@ :local NewVlanId 33; -:if ( [ / interface ethernet switch mac-based-vlan print count-only where src-mac-address=$leaseActMAC ] = 0 ) do={ +:if ([ :len [ / interface ethernet switch mac-based-vlan find where src-mac-address=$leaseActMAC ] ] = 0 ) do={ :log info ("MAC-based-VLAN: learning MAC address " . $leaseActMAC . " for VLAN " . $NewVlanId . "."); / interface ethernet switch mac-based-vlan add src-mac-address=$leaseActMAC new-customer-vid=$NewVlanId; } diff --git a/lease-script b/lease-script index 701994e..2b097c4 100644 --- a/lease-script +++ b/lease-script @@ -42,7 +42,7 @@ :delay ((1 + $leaseBound) . "s"); :foreach Script in=$Scripts do={ - :if ([ / system script print count-only where name=$Script ] > 0) do={ + :if ([ :len [ / system script find where name=$Script ] ] > 0) do={ :log debug ("Running script from lease-script: " . $Script); / system script run $Script; } diff --git a/ppp-on-up b/ppp-on-up index a207e47..5de980d 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -24,7 +24,7 @@ } :foreach Script in=$Scripts do={ - :if ([ / system script print count-only where name=$Script ] > 0) do={ + :if ([ :len [ / system script find where name=$Script ] ] > 0) do={ :log debug ("Running script from ppp-on-up: " . $Script); / system script run $Script; } diff --git a/sms-forward b/sms-forward index 8f38a4a..13ba8bd 100644 --- a/sms-forward +++ b/sms-forward @@ -27,7 +27,7 @@ $WaitFullyConnected; :local Settings [ / tool sms get ]; # forward SMS in a loop -:while ([ / tool sms inbox print count-only ] > 0) do={ +:while ([ :len [ / tool sms inbox find ] ] > 0) do={ :local Phone [ / tool sms inbox get ([ find ]->0) phone ]; :local Messages ""; :local Delete [ :toarray "" ]; From 8cbb0536868739e9833b3ba1f50f3f2a5095ed63 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 1 Sep 2020 11:18:13 +0200 Subject: [PATCH 0445/2612] email-backup: wait for file --- email-backup | 3 +++ 1 file changed, 3 insertions(+) diff --git a/email-backup b/email-backup index ff8a678..9c4259b 100644 --- a/email-backup +++ b/email-backup @@ -17,6 +17,7 @@ :global CharacterReplace; :global DeviceInfo; :global LogPrintExit; +:global WaitForFile; :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ @@ -32,6 +33,7 @@ # binary backup :if ($BackupSendBinary = true) do={ / system backup save encryption=aes-sha256 name=$FileName password=$BackupPassword; + $WaitForFile ($FileName . ".backup"); :set BackupFile ($FileName . ".backup"); :set Attach ($Attach, $BackupFile); } @@ -39,6 +41,7 @@ # create configuration export :if ($BackupSendExport = true) do={ / export terse file=$FileName; + $WaitForFile ($FileName . ".rsc"); :set ConfigFile ($FileName . ".rsc"); :set Attach ($Attach, $ConfigFile); } From b9c699b29f366c77757639858d57c0331853537e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 1 Sep 2020 11:19:20 +0200 Subject: [PATCH 0446/2612] upload-backup: wait for file --- upload-backup | 3 +++ 1 file changed, 3 insertions(+) diff --git a/upload-backup b/upload-backup index 8d7dd28..b2b67a0 100644 --- a/upload-backup +++ b/upload-backup @@ -21,6 +21,7 @@ :global LogPrintExit; :global SendNotification; :global SymbolForNotification; +:global WaitForFile; :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ @@ -36,6 +37,7 @@ # binary backup :if ($BackupSendBinary = true) do={ / system backup save encryption=aes-sha256 name=$FileName password=$BackupPassword; + $WaitForFile ($FileName . ".backup"); :do { / tool fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \ @@ -51,6 +53,7 @@ # create configuration export :if ($BackupSendExport = true) do={ / export terse file=$FileName; + $WaitForFile ($FileName . ".rsc"); :do { / tool fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \ From 25d8d5d855c351bb8dfd7b2adbc3d53dd12778dc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 1 Sep 2020 11:31:51 +0200 Subject: [PATCH 0447/2612] email-backup: remove extra curly bracket --- email-backup | 1 - 1 file changed, 1 deletion(-) diff --git a/email-backup b/email-backup index 9c4259b..994a56a 100644 --- a/email-backup +++ b/email-backup @@ -55,4 +55,3 @@ "Backup file: " . $BackupFile . "\n" . \ "Config file: " . $ConfigFile) \ file=$Attach; -} From d320fa93f2c6bd283d86060a4778ef43d46d457b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 1 Sep 2020 11:32:27 +0200 Subject: [PATCH 0448/2612] upload-backup: remove extra curly bracket --- upload-backup | 1 - 1 file changed, 1 deletion(-) diff --git a/upload-backup b/upload-backup index b2b67a0..95d31b3 100644 --- a/upload-backup +++ b/upload-backup @@ -71,4 +71,3 @@ $SendNotification ([ $SymbolForNotification [ $IfThenElse ($Failed > 0) "warning [ $DeviceInfo ] . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ "Config file: " . $ConfigFile) "" "true"; -} From fae28357c7cd739f7d0b96c81b4933bdfcd4466a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 1 Sep 2020 23:15:57 +0200 Subject: [PATCH 0449/2612] global-functions: $DefaultRouteIsReachable: exclude blackhole --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 67c4882..26c180b 100644 --- a/global-functions +++ b/global-functions @@ -176,7 +176,7 @@ # default route is reachable :set DefaultRouteIsReachable do={ - :if ([ :len [ / ip route find where dst-address=0.0.0.0/0 !unreachable active !routing-mark ] ] > 0) do={ + :if ([ :len [ / ip route find where dst-address=0.0.0.0/0 active !blackhole !routing-mark !unreachable ] ] > 0) do={ :return true; } :return false; From 5c7cde6227499cca1ea53891098098c7e727312c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 1 Sep 2020 23:39:34 +0200 Subject: [PATCH 0450/2612] bridge-port-to-default: better check for non-empty value --- bridge-port-to-default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge-port-to-default b/bridge-port-to-default index 7051f34..55d383a 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -11,7 +11,7 @@ :global LogPrintExit; :global ParseKeyValueStore; -:foreach BridgePort in=[ / interface bridge port find where comment~"." ] do={ +:foreach BridgePort in=[ / interface bridge port find where !(comment=[]) ] do={ :local BridgePortVal [ / interface bridge port get $BridgePort ]; :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ :if ($Config = $BridgePortTo) do={ From cabafc7853a00fe26ea309e82dd6035bd299f9b4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 1 Sep 2020 23:40:03 +0200 Subject: [PATCH 0451/2612] check-certificates: better check for non-empty value --- check-certificates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index 5ac8a18..d8e535a 100644 --- a/check-certificates +++ b/check-certificates @@ -98,7 +98,7 @@ $WaitFullyConnected; } } -:foreach Cert in=[ / certificate find where !revoked !scep-url expires-after<2w fingerprint~"." ] do={ +:foreach Cert in=[ / certificate find where !revoked !scep-url expires-after<2w !(fingerprint=[]) ] do={ :local CertVal [ / certificate get $Cert ]; :if ([ :len [ / certificate scep-server find where ca-cert=($CertVal->"ca") ] ] > 0) do={ From b3c1450f1caf72a3e207eef2a4f36e8a738f8a2e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 3 Sep 2020 13:06:20 +0200 Subject: [PATCH 0452/2612] doc/check-certificates: hint on running on startup --- doc/check-certificates.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 51ecd14..6e4a851 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -42,6 +42,10 @@ Just run the script: / system scheduler add interval=1d name=check-certificates on-event="/ system script run check-certificates;" start-time=startup; +Alternatively running on startup may be desired: + + / system scheduler add name=check-certificates-startup on-event="/ system script { run global-wait; run check-certificates; }" start-time=startup; + See also -------- From d434a2f2d72f0f7c02160cffec4abcb0437b365b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 6 Sep 2020 22:31:55 +0200 Subject: [PATCH 0453/2612] check-certificates: do not notify with missing validity period --- check-certificates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index d8e535a..6152e2d 100644 --- a/check-certificates +++ b/check-certificates @@ -98,7 +98,7 @@ $WaitFullyConnected; } } -:foreach Cert in=[ / certificate find where !revoked !scep-url expires-after<2w !(fingerprint=[]) ] do={ +:foreach Cert in=[ / certificate find where !revoked !scep-url !(expires-after=[]) expires-after<2w !(fingerprint=[]) ] do={ :local CertVal [ / certificate get $Cert ]; :if ([ :len [ / certificate scep-server find where ca-cert=($CertVal->"ca") ] ] > 0) do={ From 0c111a2ebe4ffbd070e34c47c836f42cd75c32f8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 8 Sep 2020 17:16:51 +0200 Subject: [PATCH 0454/2612] doc/mode-button: add code to check for support --- doc/mode-button.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/mode-button.md b/doc/mode-button.md index 0007481..6469e54 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -14,6 +14,20 @@ The hardware needs to have a mode button, see can configure the reset button to act the same, see `/ system routerboard reset-button`. +Copy this code to terminal to check: + +``` +:if ([ :len [ /system routerboard mode-button print as-value ] ] > 0) do={ + :put "Mode button is supported."; +} else={ + :if ([ :len [ /system routerboard reset-button print as-value ] ] > 0) do={ + :put "Mode button is not supported, but reset button is."; + } else={ + :put "Neither mode button nor reset button is supported."; + } +} +``` + Requirements and installation ----------------------------- From 1b68e42bc6116e16cbf284de1086c6d1a18f07f2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 14 Sep 2020 22:56:52 +0200 Subject: [PATCH 0455/2612] global-functions: queue Telegram notifications on failure and re-send This introduces function $FlushTelegramQueue, which flushes queue of Telegram notifications. Notifications are appended to the queue if sending failed. --- global-functions | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 26c180b..1cacde6 100644 --- a/global-functions +++ b/global-functions @@ -24,6 +24,7 @@ :global DeviceInfo; :global DNSIsResolving; :global DownloadPackage; +:global FlushTelegramQueue; :global GetMacVendor; :global GetRandom20CharHex; :global GetRandomNumber; @@ -280,6 +281,36 @@ :return false; } +# flush telegram queue +:set FlushTelegramQueue do={ + :global TelegramQueue; + :global TelegramTokenId; + + :global LogPrintExit; + + :local AllDone true; + :local QueueLen [ :len $TelegramQueue ]; + :foreach Id,Message in=$TelegramQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :do { + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ + http-data=("chat_id=" . ($Message->"chatid") . \ + "&disable_notification=" . ($Message->"silent") . \ + "&text=" . ($Message->"text")); + :set ($TelegramQueue->$Id); + } on-error={ + $LogPrintExit debug ("Sending queued Telegram message failed.") false; + :set AllDone false; + } + } + } + + :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ + / system scheduler remove FlushTelegramQueue; + } +} + # get MAC vendor :set GetMacVendor do={ :local Mac [ :tostr $1 ]; @@ -701,9 +732,10 @@ :local Silent [ :tostr $3 ]; :global Identity; - :global TelegramTokenId; :global TelegramChatId; :global TelegramChatIdOverride; + :global TelegramQueue; + :global TelegramTokenId; :global CertificateAvailable; :global LogPrintExit; @@ -718,6 +750,7 @@ :return false; } + :local Text [ $UrlEncode ("[" . $Identity . "] " . $Subject . "\n\n" . $Message) ]; :do { :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ $LogPrintExit warning ("Downloading required certificate failed.") true; @@ -725,9 +758,18 @@ / tool fetch check-certificate=yes-without-crl output=none http-method=post \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ http-data=("chat_id=" . $ChatId . "&disable_notification=" . $Silent . \ - "&text=" . [ $UrlEncode ("[" . $Identity . "] " . $Subject . "\n\n" . $Message) ]); + "&text=" . $Text); } on-error={ - $LogPrintExit warning ("Failed sending telegram notification!") false; + $LogPrintExit warning ("Failed sending telegram notification! Queuing...") false; + + :if ([ :typeof $TelegramQueue ] = "nothing") do={ + :set TelegramQueue [ :toarray "" ]; + } + :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; text=$Text; silent=$Silent }; + :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ + / system scheduler add name=FlushTelegramQueue interval=1m start-time=startup \ + on-event=":global FlushTelegramQueue; \$FlushTelegramQueue;"; + } } } From a03c8773da9a41b6c2db295d7187aae323a1b4bb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 14 Sep 2020 23:22:02 +0200 Subject: [PATCH 0456/2612] global-functions: $FlushTelegramQueue: give hint on queued message --- global-functions | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 1cacde6..21fa1f3 100644 --- a/global-functions +++ b/global-functions @@ -287,6 +287,8 @@ :global TelegramTokenId; :global LogPrintExit; + :global SymbolForNotification; + :global UrlEncode; :local AllDone true; :local QueueLen [ :len $TelegramQueue ]; @@ -297,7 +299,9 @@ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ http-data=("chat_id=" . ($Message->"chatid") . \ "&disable_notification=" . ($Message->"silent") . \ - "&text=" . ($Message->"text")); + "&text=" . ($Message->"text") . "\n\n" . \ + [ $UrlEncode ([ $SymbolForNotification "alarm-clock" ] . "This message was " . \ + "queued since " . ($Message->"since") . " and may be obsolete.") ]); :set ($TelegramQueue->$Id); } on-error={ $LogPrintExit debug ("Sending queued Telegram message failed.") false; @@ -765,7 +769,8 @@ :if ([ :typeof $TelegramQueue ] = "nothing") do={ :set TelegramQueue [ :toarray "" ]; } - :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; text=$Text; silent=$Silent }; + :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; text=$Text; \ + silent=$Silent; since=([ / system clock get date ] . " " . [ / system clock get time ]) }; :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ / system scheduler add name=FlushTelegramQueue interval=1m start-time=startup \ on-event=":global FlushTelegramQueue; \$FlushTelegramQueue;"; @@ -776,6 +781,7 @@ # return UTF-8 symbol for unicode name :set SymbolByUnicodeName do={ :local Symbols { + "alarm-clock"="\E2\8F\B0"; "cross-mark"="\E2\9D\8C"; "fire"="\F0\9F\94\A5"; "floppy-disk"="\F0\9F\92\BE"; From 52f4f484e5ae93a5648ce8121040edde0912c8eb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 14 Sep 2020 23:56:59 +0200 Subject: [PATCH 0457/2612] global-functions: $FlushTelegramQueue: destroy empty queue --- global-functions | 1 + 1 file changed, 1 insertion(+) diff --git a/global-functions b/global-functions index 21fa1f3..dd8a52c 100644 --- a/global-functions +++ b/global-functions @@ -312,6 +312,7 @@ :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ / system scheduler remove FlushTelegramQueue; + :set TelegramQueue; } } From 6c3bcdecb296acaf11281da609ce1c32f3be611b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 17 Sep 2020 21:21:04 +0200 Subject: [PATCH 0458/2612] global-functions: add missing colon --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index dd8a52c..69add43 100644 --- a/global-functions +++ b/global-functions @@ -240,7 +240,7 @@ :global LogPrintExit; :global WaitForFile; - :if ([ :len $PkgName ] = 0) do={ return false; } + :if ([ :len $PkgName ] = 0) do={ :return false; } :if ([ :len $PkgVer ] = 0) do={ :set PkgVer [ / system package update get installed-version ]; } :if ([ :len $PkgArch ] = 0) do={ :set PkgArch [ / system resource get architecture-name ]; } From 49737af6d191ec636030b1d408d3fb318ff9c9d0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Sep 2020 11:00:27 +0200 Subject: [PATCH 0459/2612] extend magic pattern with "by RouterOS" This matches the string included in export. --- accesslist-duplicates.capsman | 2 +- accesslist-duplicates.local | 2 +- accesslist-duplicates.template | 2 +- bridge-port-to-default | 2 +- bridge-port-toggle | 2 +- capsman-download-packages | 2 +- capsman-rolling-upgrade | 2 +- certificate-renew-issued | 2 +- check-certificates | 2 +- check-health | 2 +- check-lte-firmware-upgrade | 2 +- check-routeros-update | 2 +- cloud-backup | 2 +- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- daily-psk.capsman | 2 +- daily-psk.local | 2 +- daily-psk.template | 2 +- dhcp-lease-comment.capsman | 2 +- dhcp-lease-comment.local | 2 +- dhcp-lease-comment.template | 2 +- dhcp-to-dns | 2 +- early-errors | 2 +- email-backup | 2 +- global-config | 2 +- global-config-overlay | 2 +- global-functions | 8 ++++---- global-wait | 2 +- gps-track | 2 +- hotspot-to-wpa | 2 +- ip-addr-bridge | 2 +- ipv6-update | 2 +- learn-mac-based-vlan | 2 +- lease-script | 2 +- leds-day-mode | 2 +- leds-night-mode | 2 +- leds-toggle-mode | 2 +- log-forward | 2 +- manage-umts | 2 +- mode-button-event | 2 +- mode-button-scheduler | 2 +- netwatch-notify | 2 +- netwatch-syslog | 2 +- packages-update | 2 +- ppp-on-up | 2 +- rotate-ntp | 2 +- script-updates | 2 +- sms-action | 2 +- sms-forward | 2 +- ssh-keys-import | 2 +- super-mario-theme | 2 +- unattended-lte-firmware-upgrade | 2 +- update-gre-address | 2 +- update-tunnelbroker | 2 +- upload-backup | 2 +- 56 files changed, 59 insertions(+), 59 deletions(-) diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman index e8d99e6..30cd809 100644 --- a/accesslist-duplicates.capsman +++ b/accesslist-duplicates.capsman @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: accesslist-duplicates.capsman # Copyright (c) 2018-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local index c310fea..4ac98f2 100644 --- a/accesslist-duplicates.local +++ b/accesslist-duplicates.local @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: accesslist-duplicates.local # Copyright (c) 2018-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template index 1edf700..c38dd47 100644 --- a/accesslist-duplicates.template +++ b/accesslist-duplicates.template @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: accesslist-duplicates%TEMPL% # Copyright (c) 2018-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/bridge-port-to-default b/bridge-port-to-default index 55d383a..4db04e8 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: bridge-port-to-default # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/bridge-port-toggle b/bridge-port-toggle index e3967bd..1aa6b75 100644 --- a/bridge-port-toggle +++ b/bridge-port-toggle @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: bridge-port-toggle # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/capsman-download-packages b/capsman-download-packages index a314163..8a5b465 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: capsman-download-packages # Copyright (c) 2018-2020 Christian Hesse # Michael Gisbers diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index 61552f5..2868214 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: capsman-rolling-upgrade # Copyright (c) 2018-2020 Christian Hesse # Michael Gisbers diff --git a/certificate-renew-issued b/certificate-renew-issued index 27eec51..50cabe7 100644 --- a/certificate-renew-issued +++ b/certificate-renew-issued @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: certificate-renew-issued # Copyright (c) 2019-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/check-certificates b/check-certificates index 6152e2d..ced2a69 100644 --- a/check-certificates +++ b/check-certificates @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: check-certificates # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/check-health b/check-health index 33ad59f..86df9ea 100644 --- a/check-health +++ b/check-health @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: check-health # Copyright (c) 2019-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index b4ca5d3..d31ed37 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: check-lte-firmware-upgrade # Copyright (c) 2018-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/check-routeros-update b/check-routeros-update index 073ed96..13262f3 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: check-routeros-update # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/cloud-backup b/cloud-backup index 1511062..eb3267d 100644 --- a/cloud-backup +++ b/cloud-backup @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: cloud-backup # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index e44f387..a9a331e 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: collect-wireless-mac.capsman # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 8d23317..d6be32d 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: collect-wireless-mac.local # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 655fd47..18d4185 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: collect-wireless-mac%TEMPL% # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/daily-psk.capsman b/daily-psk.capsman index 5ae2f5e..a60f41d 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: daily-psk.capsman # Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers diff --git a/daily-psk.local b/daily-psk.local index 4cc728c..0d098a0 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: daily-psk.local # Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers diff --git a/daily-psk.template b/daily-psk.template index 3c23139..f462fe2 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: daily-psk%TEMPL% # Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index 7e1dce1..6cd026a 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: dhcp-lease-comment.capsman # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index e20a137..f55931c 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: dhcp-lease-comment.local # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index 2971036..b594324 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: dhcp-lease-comment%TEMPL% # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/dhcp-to-dns b/dhcp-to-dns index 3a95eb6..ddda171 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: dhcp-to-dns # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/early-errors b/early-errors index 4f411f4..e6160e8 100644 --- a/early-errors +++ b/early-errors @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: early-errors :global LogPrintExit; diff --git a/email-backup b/email-backup index 994a56a..8f4fdc1 100644 --- a/email-backup +++ b/email-backup @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: email-backup # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/global-config b/global-config index 90686a1..b3c5879 100644 --- a/global-config +++ b/global-config @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: global-config # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/global-config-overlay b/global-config-overlay index c1f55da..358e5ae 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: global-config-overlay # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/global-functions b/global-functions index 69add43..ad07a9c 100644 --- a/global-functions +++ b/global-functions @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: global-functions # Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers @@ -533,11 +533,11 @@ :foreach Script in=$Scripts do={ :if ([ :len [ / system script find where name=$Script ] ] = 0) do={ $LogPrintExit info ("Adding new script: " . $Script) false; - / system script add name=$Script source="#!rsc"; + / system script add name=$Script source="#!rsc by RouterOS\n"; } } - :foreach Script in=[ / system script find where source~"^#!rsc" ] do={ + :foreach Script in=[ / system script find where source~"^#!rsc( by RouterOS)\?\n" ] do={ :local Ignore 0; :local ScriptVal [ / system script get $Script ]; :local ScriptFile [ / file find where name=("script-updates/" . $ScriptVal->"name") ]; @@ -597,7 +597,7 @@ } :if ([ :len $SourceNew ] > 0) do={ - :if ([ :pick $SourceNew 0 5 ] = "#!rsc") do={ + :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ :if ($SourceNew != $ScriptVal->"source") do={ :local DontRequirePermissions \ ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); diff --git a/global-wait b/global-wait index f911593..fe19151 100644 --- a/global-wait +++ b/global-wait @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: global-wait # Copyright (c) 2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/gps-track b/gps-track index c815fdf..53718e2 100644 --- a/gps-track +++ b/gps-track @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: gps-track # Copyright (c) 2018-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/hotspot-to-wpa b/hotspot-to-wpa index 8603d56..7951ed0 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: hotspot-to-wpa # Copyright (c) 2019-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/ip-addr-bridge b/ip-addr-bridge index 9bc7ef8..9d2a281 100644 --- a/ip-addr-bridge +++ b/ip-addr-bridge @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: ip-addr-bridge # Copyright (c) 2018-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/ipv6-update b/ipv6-update index ecca490..4fdda3d 100644 --- a/ipv6-update +++ b/ipv6-update @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: ipv6-update # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/learn-mac-based-vlan b/learn-mac-based-vlan index 690bec4..d497714 100644 --- a/learn-mac-based-vlan +++ b/learn-mac-based-vlan @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: learn-mac-based-vlan # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/lease-script b/lease-script index 2b097c4..fe4bd11 100644 --- a/lease-script +++ b/lease-script @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: lease-script # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/leds-day-mode b/leds-day-mode index 74d826d..b2f37d3 100644 --- a/leds-day-mode +++ b/leds-day-mode @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: leds-day-mode # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/leds-night-mode b/leds-night-mode index d394f49..a4e48fa 100644 --- a/leds-night-mode +++ b/leds-night-mode @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: leds-night-mode # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/leds-toggle-mode b/leds-toggle-mode index 16a31ae..e817b1b 100644 --- a/leds-toggle-mode +++ b/leds-toggle-mode @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: leds-toggle-mode # Copyright (c) 2018-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/log-forward b/log-forward index 40afbe6..59a47c1 100644 --- a/log-forward +++ b/log-forward @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: log-forward # Copyright (c) 2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/manage-umts b/manage-umts index 2813786..663c1dc 100644 --- a/manage-umts +++ b/manage-umts @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: manage-umts # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/mode-button-event b/mode-button-event index 246a9fd..7039852 100644 --- a/mode-button-event +++ b/mode-button-event @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: mode-button-event # Copyright (c) 2018-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/mode-button-scheduler b/mode-button-scheduler index fe04b40..6c1f554 100644 --- a/mode-button-scheduler +++ b/mode-button-scheduler @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: mode-button-scheduler # Copyright (c) 2018-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/netwatch-notify b/netwatch-notify index e47f715..61bb348 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: netwatch-notify # Copyright (c) 2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/netwatch-syslog b/netwatch-syslog index 3f71a7b..374173a 100644 --- a/netwatch-syslog +++ b/netwatch-syslog @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: netwatch-syslog # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/packages-update b/packages-update index 097b8d4..976a8a0 100644 --- a/packages-update +++ b/packages-update @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: packages-update # Copyright (c) 2019-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/ppp-on-up b/ppp-on-up index 5de980d..925cb6e 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: ppp-on-up # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/rotate-ntp b/rotate-ntp index fa3909d..159cdfe 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: rotate-ntp # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/script-updates b/script-updates index 1da4987..be79f58 100644 --- a/script-updates +++ b/script-updates @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: script-updates :global LogPrintExit; diff --git a/sms-action b/sms-action index ec37581..2008a8a 100644 --- a/sms-action +++ b/sms-action @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: sms-action # Copyright (c) 2018-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/sms-forward b/sms-forward index 13ba8bd..753cb0a 100644 --- a/sms-forward +++ b/sms-forward @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: sms-forward # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/ssh-keys-import b/ssh-keys-import index 07d5253..d4795d7 100644 --- a/ssh-keys-import +++ b/ssh-keys-import @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: ssh-keys-import # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/super-mario-theme b/super-mario-theme index 7e1a0d7..6b2ea74 100644 --- a/super-mario-theme +++ b/super-mario-theme @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: super-mario-theme # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index 55d5fa6..e84188b 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: unattended-lte-firmware-upgrade # Copyright (c) 2018-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/update-gre-address b/update-gre-address index 3339b02..c4d1dda 100644 --- a/update-gre-address +++ b/update-gre-address @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: update-gre-address # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/update-tunnelbroker b/update-tunnelbroker index a3c66eb..a503df0 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: update-tunnelbroker # Copyright (c) 2013-2020 Christian Hesse # Michael Gisbers diff --git a/upload-backup b/upload-backup index 95d31b3..3c09b58 100644 --- a/upload-backup +++ b/upload-backup @@ -1,4 +1,4 @@ -#!rsc +#!rsc by RouterOS # RouterOS script: upload-backup # Copyright (c) 2013-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md From 1367a59c27706c4a2e47f0f3536ef851031468e7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Sep 2020 13:08:29 +0200 Subject: [PATCH 0460/2612] daily-psk: add symbol in notification --- daily-psk.capsman | 3 ++- daily-psk.local | 3 ++- daily-psk.template | 3 ++- global-functions | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/daily-psk.capsman b/daily-psk.capsman index a60f41d..33208f5 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -14,6 +14,7 @@ :global LogPrintExit; :global SendNotification; +:global SymbolForNotification; :global UrlEncode; :global WaitForFile; :global WaitFullyConnected; @@ -87,7 +88,7 @@ $WaitFullyConnected; :set Attach ""; } - $SendNotification ("daily PSK " . $Ssid) \ + $SendNotification ([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid) \ ("This is the daily PSK on " . $Identity . ":\n\n" . \ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ diff --git a/daily-psk.local b/daily-psk.local index 0d098a0..13a878e 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -14,6 +14,7 @@ :global LogPrintExit; :global SendNotification; +:global SymbolForNotification; :global UrlEncode; :global WaitForFile; :global WaitFullyConnected; @@ -87,7 +88,7 @@ $WaitFullyConnected; :set Attach ""; } - $SendNotification ("daily PSK " . $Ssid) \ + $SendNotification ([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid) \ ("This is the daily PSK on " . $Identity . ":\n\n" . \ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ diff --git a/daily-psk.template b/daily-psk.template index f462fe2..fd5bd2b 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -15,6 +15,7 @@ :global LogPrintExit; :global SendNotification; +:global SymbolForNotification; :global UrlEncode; :global WaitForFile; :global WaitFullyConnected; @@ -93,7 +94,7 @@ $WaitFullyConnected; :set Attach ""; } - $SendNotification ("daily PSK " . $Ssid) \ + $SendNotification ([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid) \ ("This is the daily PSK on " . $Identity . ":\n\n" . \ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ diff --git a/global-functions b/global-functions index ad07a9c..84d8d75 100644 --- a/global-functions +++ b/global-functions @@ -783,6 +783,7 @@ :set SymbolByUnicodeName do={ :local Symbols { "alarm-clock"="\E2\8F\B0"; + "calendar"="\F0\9F\93\85"; "cross-mark"="\E2\9D\8C"; "fire"="\F0\9F\94\A5"; "floppy-disk"="\F0\9F\92\BE"; From 956244d53b19ecd1c7e1d54ac4b9350db83cff12 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Sep 2020 13:11:33 +0200 Subject: [PATCH 0461/2612] collect-wireless-mac: add symbol in notification --- collect-wireless-mac.capsman | 3 ++- collect-wireless-mac.local | 3 ++- collect-wireless-mac.template | 3 ++- global-functions | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index a9a331e..7abae6a 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -14,6 +14,7 @@ :global LogPrintExit; :global ScriptLock; :global SendNotification; +:global SymbolForNotification; $ScriptLock "collect-wireless-mac.capsman"; @@ -51,7 +52,7 @@ $ScriptLock "collect-wireless-mac.capsman"; "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); $LogPrintExit info $Message false; / caps-man access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; - $SendNotification ($Mac . " connected to " . $Ssid) \ + $SendNotification ([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid) \ ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ "Controller: " . $Identity . "\n" . \ "Interface: " . $Interface . "\n" . \ diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index d6be32d..080d036 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -14,6 +14,7 @@ :global LogPrintExit; :global ScriptLock; :global SendNotification; +:global SymbolForNotification; $ScriptLock "collect-wireless-mac.local"; @@ -51,7 +52,7 @@ $ScriptLock "collect-wireless-mac.local"; "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); $LogPrintExit info $Message false; / interface wireless access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; - $SendNotification ($Mac . " connected to " . $Ssid) \ + $SendNotification ([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid) \ ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ "Controller: " . $Identity . "\n" . \ "Interface: " . $Interface . "\n" . \ diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 18d4185..a7e2b4a 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -15,6 +15,7 @@ :global LogPrintExit; :global ScriptLock; :global SendNotification; +:global SymbolForNotification; $ScriptLock "collect-wireless-mac%TEMPL%"; @@ -53,7 +54,7 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); $LogPrintExit info $Message false; / %PATH% access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; - $SendNotification ($Mac . " connected to " . $Ssid) \ + $SendNotification ([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid) \ ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ "Controller: " . $Identity . "\n" . \ "Interface: " . $Interface . "\n" . \ diff --git a/global-functions b/global-functions index 84d8d75..f46aff3 100644 --- a/global-functions +++ b/global-functions @@ -790,6 +790,7 @@ "high-voltage-sign"="\E2\9A\A1"; "incoming-envelope"="\F0\9F\93\A8"; "lock-with-ink-pen"="\F0\9F\94\8F"; + "mobile-phone"="\F0\9F\93\B1"; "pushpin"="\F0\9F\93\8C"; "sparkles"="\E2\9C\A8"; "warning-sign"="\E2\9A\A0"; From 9f3e39206c0c03978bfbe59f9a61974b964167b7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 19 Sep 2020 22:33:15 +0200 Subject: [PATCH 0462/2612] dhcp-to-dns: also act on static leases Since commit 0560f828 we act on bound leases only. That keeps offline clients away, so act on static leases as well. --- dhcp-to-dns | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index ddda171..4ea4f59 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -31,7 +31,7 @@ :foreach DnsRecord in=[ / ip dns static find where comment ~ $CommentPrefix ] do={ :local DnsRecordVal [ / ip dns static get $DnsRecord ]; :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; - :if ([ :len [ / ip dhcp-server lease find where mac-address=$MacAddress address=($DnsRecordVal->"address") dynamic=yes status=bound ] ] > 0) do={ + :if ([ :len [ / ip dhcp-server lease find where mac-address=$MacAddress address=($DnsRecordVal->"address") status=bound ] ] > 0) do={ $LogPrintExit debug ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; } else={ :local Found false; @@ -40,7 +40,7 @@ } } -:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ +:foreach Lease in=[ / ip dhcp-server lease find where status=bound ] do={ :local LeaseVal [ / ip dhcp-server lease get $Lease ]; :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); :local HostName [ $IfThenElse ([ :len ($LeaseVal->"host-name") ] = 0) \ @@ -52,13 +52,13 @@ :if ([ :len $DnsRecord ] > 0) do={ :local DnsIp [ / ip dns static get $DnsRecord address ]; - :local DupMacLeases [ / ip dhcp-server lease find where mac-address=($LeaseVal->"mac-address") dynamic=yes status=bound ]; + :local DupMacLeases [ / ip dhcp-server lease find where mac-address=($LeaseVal->"mac-address") status=bound ]; :if ([ :len $DupMacLeases ] > 1) do={ :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; } :if ([ :len ($LeaseVal->"host-name") ] > 0) do={ - :set ($LeaseVal->"address") [ / ip dhcp-server lease get ([ find where host-name=($LeaseVal->"host-name") dynamic=yes status=bound ]->0) address ]; + :set ($LeaseVal->"address") [ / ip dhcp-server lease get ([ find where host-name=($LeaseVal->"host-name") status=bound ]->0) address ]; } :if ($DnsIp = $LeaseVal->"address") do={ From 1a28a417f4e10ba38d5ae8a6c5df6d059901bbbf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 20 Sep 2020 21:50:33 +0200 Subject: [PATCH 0463/2612] lease-script: give correct hint in message --- lease-script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lease-script b/lease-script index fe4bd11..8230c6e 100644 --- a/lease-script +++ b/lease-script @@ -12,7 +12,7 @@ [ :typeof $leaseActMAC ] = "nothing" || \ [ :typeof $leaseServerName ] = "nothing" || \ [ :typeof $leaseBound ] = "nothing") do={ - $LogPrintExit error "This script is supposed to run from ip dhcp-client." true; + $LogPrintExit error "This script is supposed to run from ip dhcp-server." true; } :local Scripts; From addd4d7d9071b620aea57726a489b5863d2ed1dd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 21 Sep 2020 21:25:17 +0200 Subject: [PATCH 0464/2612] netwatch-syslog: find the correct netwatch entry --- netwatch-syslog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-syslog b/netwatch-syslog index 374173a..fee22cc 100644 --- a/netwatch-syslog +++ b/netwatch-syslog @@ -10,7 +10,7 @@ :local Remote [ /system logging action get ([ find where target=remote ]->0) remote ]; -if ([ / tool netwatch get [ find where host=$Remote ] status ] = "up") do={ +if ([ / tool netwatch get [ find where host=$Remote up-script="netwatch-syslog" down-script="netwatch-syslog" ] status ] = "up") do={ / system logging set disabled=no [ find where action=remote disabled=yes ]; } else={ / system logging set disabled=yes [ find where action=remote disabled=no ]; From 9bec6914cce7914150b8589025b2bc9c12a670e4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 25 Sep 2020 22:17:26 +0200 Subject: [PATCH 0465/2612] netwatch-notify: notify on configurable check count threshold --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index b3c5879..a611e2b 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 25; +:global GlobalConfigVersion 26; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 358e5ae..6c21a06 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 25; +:global GlobalConfigVersion 26; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 452fa4b..1bd7ff3 100644 --- a/global-config.changes +++ b/global-config.changes @@ -29,4 +29,5 @@ 23="Added 'log-forward' with configurable filter, which replaces 'early-errors'"; 24="Made symbols in notifications configurable."; 25="Added support for DHCP server name in DNS FQDN via '\$ServerNameInZone'"; + 26="Made check count threshold in 'netwatch-notify' configurable."; }; diff --git a/global-functions b/global-functions index f46aff3..e5cae34 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 25; +:global ExpectedConfigVersion 26; # global variables not to be changed by user :global GlobalFunctionsReady false; From 9f16e0644b8add83968f0646e278ce19c9d6b215 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 25 Sep 2020 22:19:16 +0200 Subject: [PATCH 0466/2612] global-functions: notify on Telegram queue --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index a611e2b..9d1547c 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 26; +:global GlobalConfigVersion 27; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 6c21a06..870367b 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 26; +:global GlobalConfigVersion 27; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 1bd7ff3..2fa393b 100644 --- a/global-config.changes +++ b/global-config.changes @@ -30,4 +30,5 @@ 24="Made symbols in notifications configurable."; 25="Added support for DHCP server name in DNS FQDN via '\$ServerNameInZone'"; 26="Made check count threshold in 'netwatch-notify' configurable."; + 27="Added queue for Telegram notifications to resend later on error."; }; diff --git a/global-functions b/global-functions index e5cae34..22a35ef 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 26; +:global ExpectedConfigVersion 27; # global variables not to be changed by user :global GlobalFunctionsReady false; From c3ea55523371403f07f116cb44eebfdf444c5628 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 25 Sep 2020 22:20:34 +0200 Subject: [PATCH 0467/2612] dhcp-to-dns: notify on acting on all bound leases --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 9d1547c..18754a8 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 27; +:global GlobalConfigVersion 28; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 870367b..48dbb9c 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 27; +:global GlobalConfigVersion 28; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 2fa393b..e260565 100644 --- a/global-config.changes +++ b/global-config.changes @@ -31,4 +31,5 @@ 25="Added support for DHCP server name in DNS FQDN via '\$ServerNameInZone'"; 26="Made check count threshold in 'netwatch-notify' configurable."; 27="Added queue for Telegram notifications to resend later on error."; + 28="Made 'dhcp-to-dns' act on all bound leases, not just dynamic ones."; }; diff --git a/global-functions b/global-functions index 22a35ef..adb9733 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 27; +:global ExpectedConfigVersion 28; # global variables not to be changed by user :global GlobalFunctionsReady false; From 697e32a30640c7bb8c132aaed44968081e6e3872 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 25 Sep 2020 22:21:59 +0200 Subject: [PATCH 0468/2612] log-forward: add filter on log message text --- doc/log-forward.md | 3 ++- global-config | 5 ++++- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- log-forward | 3 ++- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/doc/log-forward.md b/doc/log-forward.md index bc7213a..afb695e 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -31,9 +31,10 @@ Just install the script: Configuration ------------- -The configuration goes to `global-config-overlay`, there is just one parameters: +The configuration goes to `global-config-overlay`, these are the parameters: * `LogForwardFilter`: define topics *not* to be forwarded +* `LogForwardFilterMessage`: define message text *not* to be forwarded Also notification settings are required for e-mail and telegram. diff --git a/global-config b/global-config index 18754a8..446628f 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 28; +:global GlobalConfigVersion 29; # This is used for DNS and backup file. :global Domain "example.com"; @@ -48,6 +48,9 @@ # This defines a filter on log topics not to be forwarded. :global LogForwardFilter "(debug|info|script)"; +# ... and the same for log message text. +:global LogForwardFilterMessage "^\$"; +#:global LogForwardFilterMessage "(^\$|message text|...)"; # Specify an address to enable auto update to version assumed safe. # The configured channel (bugfix, current, release-candidate) is appended. diff --git a/global-config-overlay b/global-config-overlay index 48dbb9c..93c55ae 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 28; +:global GlobalConfigVersion 29; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index e260565..605ceac 100644 --- a/global-config.changes +++ b/global-config.changes @@ -32,4 +32,5 @@ 26="Made check count threshold in 'netwatch-notify' configurable."; 27="Added queue for Telegram notifications to resend later on error."; 28="Made 'dhcp-to-dns' act on all bound leases, not just dynamic ones."; + 29="Added filter on log message text for 'log-forward'."; }; diff --git a/global-functions b/global-functions index adb9733..2d25b34 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 28; +:global ExpectedConfigVersion 29; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/log-forward b/log-forward index 59a47c1..dc2ad05 100644 --- a/log-forward +++ b/log-forward @@ -8,6 +8,7 @@ :global Identity; :global LogForwardFilter; +:global LogForwardFilterMessage; :global LogForwardLast; :global LogPrintExit; @@ -29,7 +30,7 @@ $WaitFullyConnected; :local Messages ""; :local MessageVal; -:foreach Message in=[ / log find where !(topics~$LogForwardFilter) ] do={ +:foreach Message in=[ / log find where !(topics~$LogForwardFilter) !(message~$LogForwardFilterMessage) ] do={ :set MessageVal [ / log get $Message ]; :if ($LogForwardLast = ($MessageVal->".id")) do={ From 9ea6b159b697359ace83f45d1cbd12cb6b0d6dd5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 27 Sep 2020 20:38:09 +0200 Subject: [PATCH 0469/2612] global-functions: $SendTelegram: truncate messages if too long Telegram messages have a maximum length of 4096 characters. Truncate if too long, keep some spare characters for status messages. --- global-functions | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 2d25b34..5aab671 100644 --- a/global-functions +++ b/global-functions @@ -744,6 +744,7 @@ :global CertificateAvailable; :global LogPrintExit; + :global SymbolForNotification; :global UrlEncode; :local ChatId $TelegramChatId; @@ -755,7 +756,13 @@ :return false; } - :local Text [ $UrlEncode ("[" . $Identity . "] " . $Subject . "\n\n" . $Message) ]; + :local Text ("[" . $Identity . "] " . $Subject . "\n\n" . $Message); + :if ([ :len $Text ] > 3968) do={ + :set Text ([ :pick $Text 0 3840 ] . "...\n\n" . [ $SymbolForNotification "warning-sign" ] . \ + "The Telegram message was too long and has been truncated."); + } + :set Text [ $UrlEncode $Text ]; + :do { :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ $LogPrintExit warning ("Downloading required certificate failed.") true; From b0db9c7d52ff9b4aa5b046f737ed055211e0edca Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Sep 2020 19:53:32 +0200 Subject: [PATCH 0470/2612] global-functions: $SendTelegram: scissors symbol for truncation --- global-functions | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 5aab671..e6eb93b 100644 --- a/global-functions +++ b/global-functions @@ -758,7 +758,7 @@ :local Text ("[" . $Identity . "] " . $Subject . "\n\n" . $Message); :if ([ :len $Text ] > 3968) do={ - :set Text ([ :pick $Text 0 3840 ] . "...\n\n" . [ $SymbolForNotification "warning-sign" ] . \ + :set Text ([ :pick $Text 0 3840 ] . "...\n\n" . [ $SymbolForNotification "scissors" ] . \ "The Telegram message was too long and has been truncated."); } :set Text [ $UrlEncode $Text ]; @@ -799,6 +799,7 @@ "lock-with-ink-pen"="\F0\9F\94\8F"; "mobile-phone"="\F0\9F\93\B1"; "pushpin"="\F0\9F\93\8C"; + "scissors"="\E2\9C\82"; "sparkles"="\E2\9C\A8"; "warning-sign"="\E2\9A\A0"; "white-heavy-check-mark"="\E2\9C\85" From d53cf3e8e76d5f9205742090875694da8542443f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Sep 2020 19:56:45 +0200 Subject: [PATCH 0471/2612] log-forward: fix usage of function --- log-forward | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log-forward b/log-forward index dc2ad05..7da8a4a 100644 --- a/log-forward +++ b/log-forward @@ -22,7 +22,7 @@ $ScriptLock "log-forward"; $WaitFullyConnected; -:if ($MailServerIsUp = false) do={ +:if ([ $MailServerIsUp ] = false) do={ $LogPrintExit warning ("Mail server is not up.") true; } From 42289b6239a6d4f622b91ca81048c25d0832722f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Sep 2020 19:57:04 +0200 Subject: [PATCH 0472/2612] sms-forward: fix usage of function --- sms-forward | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sms-forward b/sms-forward index 753cb0a..bd750b6 100644 --- a/sms-forward +++ b/sms-forward @@ -20,7 +20,7 @@ $WaitFullyConnected; -:if ($MailServerIsUp = false) do={ +:if ([ $MailServerIsUp ] = false) do={ $LogPrintExit warning "Mail server is not up." true; } From 744542e92539eb6ad39c84eca05258f82e1dd47a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Sep 2020 20:20:19 +0200 Subject: [PATCH 0473/2612] log-forward: add rate limit to prevent flooding --- log-forward | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/log-forward b/log-forward index 7da8a4a..27aa19c 100644 --- a/log-forward +++ b/log-forward @@ -10,6 +10,7 @@ :global LogForwardFilter; :global LogForwardFilterMessage; :global LogForwardLast; +:global LogForwardRateLimit; :global LogPrintExit; :global MailServerIsUp; @@ -20,6 +21,15 @@ $ScriptLock "log-forward"; +:if ([ :typeof $LogForwardRateLimit ] = "nothing") do={ + :set LogForwardRateLimit 0; +} + +:if ($LogForwardRateLimit > 30) do={ + :set LogForwardRateLimit ($LogForwardRateLimit - 1); + $LogPrintExit info ("Rate limit in action, not forwarding logs!") true; +} + $WaitFullyConnected; :if ([ $MailServerIsUp ] = false) do={ @@ -48,5 +58,10 @@ $WaitFullyConnected; ("The log on " . $Identity . " contains these " . $Count . " messages after " . \ [ / system resource get uptime ] . " uptime.\n" . $Messages); + :set LogForwardRateLimit ($LogForwardRateLimit + 10); :set LogForwardLast ($MessageVal->".id"); +} else={ + :if ($LogForwardRateLimit > 0) do={ + :set LogForwardRateLimit ($LogForwardRateLimit - 1); + } } From a0d170924450341fd1229a40e7095763c1440dfe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Sep 2020 20:26:29 +0200 Subject: [PATCH 0474/2612] log-forward: notify on rate limit --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 446628f..c828a97 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 29; +:global GlobalConfigVersion 30; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 93c55ae..f76fac3 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 29; +:global GlobalConfigVersion 30; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 605ceac..8253c15 100644 --- a/global-config.changes +++ b/global-config.changes @@ -33,4 +33,5 @@ 27="Added queue for Telegram notifications to resend later on error."; 28="Made 'dhcp-to-dns' act on all bound leases, not just dynamic ones."; 29="Added filter on log message text for 'log-forward'."; + 30="Implemented simple rate limit for 'log-forward' to prevent flooding."; }; diff --git a/global-functions b/global-functions index e6eb93b..ad5651e 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 29; +:global ExpectedConfigVersion 30; # global variables not to be changed by user :global GlobalFunctionsReady false; From 38a3ef955293d51971f11149f37de75ebb1a630d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Oct 2020 14:17:43 +0200 Subject: [PATCH 0475/2612] global-functions: $MailServerIsUp: return gracefully on missing configuration --- global-functions | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/global-functions b/global-functions index ad5651e..ba957a1 100644 --- a/global-functions +++ b/global-functions @@ -417,8 +417,19 @@ :set MailServerIsUp do={ :local MailServer [ / tool e-mail get address ]; + :global EmailGeneralTo; + :global LogPrintExit; + :if ([ :len $EmailGeneralTo ] = 0) do={ + :return true; + } else={ + :if ($MailServer = "0.0.0.0") do={ + $LogPrintExit warning ("No mail server is configured! Returning gracefully...") false; + :return true; + } + } + :if ([ :len [ / tool netwatch find where comment=$MailServer ] ] = 0) do={ $LogPrintExit warning ("Adding netwatch entry for mail server.") false; :local MailHost $MailServer; From 2be4a2ce9888f1c78f516bac5587e6a5e0e18655 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Oct 2020 15:28:19 +0200 Subject: [PATCH 0476/2612] cloud-backup: send notification on error and do exit --- cloud-backup | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cloud-backup b/cloud-backup index eb3267d..f6f2d28 100644 --- a/cloud-backup +++ b/cloud-backup @@ -34,5 +34,7 @@ "Size: " . $Cloud->"size" . "\n" . \ "Download key: " . $Cloud->"secret-download-key") "" "true"; } on-error={ - $LogPrintExit error ("Failed uploading backup for " . $Identity . " to cloud.") false; + $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Cloud backup failed") \ + ("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]); + $LogPrintExit error ("Failed uploading backup for " . $Identity . " to cloud!") true; } From 1cb7194ec518369bd3d03ea28c12d9b4eee6cc7b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Oct 2020 15:29:18 +0200 Subject: [PATCH 0477/2612] upload-backup: exit with error on error The error has been logged before, so just make sure to exit with error. --- upload-backup | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/upload-backup b/upload-backup index 3c09b58..7fd092e 100644 --- a/upload-backup +++ b/upload-backup @@ -71,3 +71,7 @@ $SendNotification ([ $SymbolForNotification [ $IfThenElse ($Failed > 0) "warning [ $DeviceInfo ] . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ "Config file: " . $ConfigFile) "" "true"; + +:if ($Failed = 1) do={ + :error "An error occured!"; +} From 8425290d1d7361d089407212a9f35959f821d1fb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Oct 2020 23:18:48 +0200 Subject: [PATCH 0478/2612] upload-backup: hint failure in subject --- upload-backup | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/upload-backup b/upload-backup index 7fd092e..27eab0c 100644 --- a/upload-backup +++ b/upload-backup @@ -66,8 +66,10 @@ } } -$SendNotification ([ $SymbolForNotification [ $IfThenElse ($Failed > 0) "warning-sign" "floppy-disk" ] ] . "Backup & Config Upload") \ - ("Backup and config export upload for " . $Identity . ".\n\n" . \ +$SendNotification [ $IfThenElse ($Failed > 0) \ + ([ $SymbolForNotification "warning-sign" ] . "Backup & Config upload with failure") \ + ([ $SymbolForNotification "floppy-disk" ] . "Backup & Config upload") ] \ + ("Backup and config export upload for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ "Config file: " . $ConfigFile) "" "true"; From bc5133fb41d53b11b6fd0d0893bad949f003b663 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Oct 2020 16:19:31 +0200 Subject: [PATCH 0479/2612] global-functions: $LogPrintExit: explicitly set severity --- global-functions | 1 + 1 file changed, 1 insertion(+) diff --git a/global-functions b/global-functions index ba957a1..d51f1d3 100644 --- a/global-functions +++ b/global-functions @@ -402,6 +402,7 @@ :if ($Severity = "info" ) do={ :log info $Message; } } else={ :log warning $Message; + :set Severity "warning"; } :if ($Severity != "debug" || $PrintDebug = true) do={ From 3dc10ca2b86f929799048ceb68af30c19f39702d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Oct 2020 23:55:10 +0200 Subject: [PATCH 0480/2612] packages-update: fix variable usage --- packages-update | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages-update b/packages-update index 976a8a0..38636c5 100644 --- a/packages-update +++ b/packages-update @@ -52,7 +52,8 @@ $ScriptLock "packages-update"; :do { / system script run $Script; } on-error={ - $LogPrintExit warning ("Running backup script " . $Script . " failed.") false; + :local ScriptName [ / system script get $Script name ]; + $LogPrintExit warning ("Running backup script " . $ScriptName . " failed.") false; } } From ffad79b8fc25b8d486a68991d8b619cf01733908 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Oct 2020 00:02:02 +0200 Subject: [PATCH 0481/2612] packages-update: be more verbose --- packages-update | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages-update b/packages-update index 38636c5..8e18e77 100644 --- a/packages-update +++ b/packages-update @@ -49,11 +49,12 @@ $ScriptLock "packages-update"; } :foreach Script in=[ / system script find where name~"^(cloud|email|upload)-backup\$" ] do={ + :local ScriptName [ / system script get $Script name ]; :do { + $LogPrintExit info ("Running backup script " . $ScriptName . " before update.") false; / system script run $Script; } on-error={ - :local ScriptName [ / system script get $Script name ]; - $LogPrintExit warning ("Running backup script " . $ScriptName . " failed.") false; + $LogPrintExit warning ("Running backup script " . $ScriptName . " before update failed!") false; } } From 9bd56d8aca25f84d018d423721161c9f438bfccd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Oct 2020 16:04:41 +0200 Subject: [PATCH 0482/2612] packages-update: improve backup failure handling --- packages-update | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages-update b/packages-update index 8e18e77..7c88eac 100644 --- a/packages-update +++ b/packages-update @@ -55,6 +55,16 @@ $ScriptLock "packages-update"; / system script run $Script; } on-error={ $LogPrintExit warning ("Running backup script " . $ScriptName . " before update failed!") false; + :if ([ $ScriptFromTerminal "packages-update" ] = true) do={ + :put "Do you want to continue anyway? [y/N]"; + :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ + $LogPrintExit info ("User requested to continue anyway.") false; + } else={ + $LogPrintExit info ("Canceled update...") true; + } + } else={ + $LogPrintExit info ("Canceled non-interactive update.") true; + } } } From 8e6403b1bedd837485d86641aed2013abc4cc7f0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 9 Oct 2020 16:00:09 +0200 Subject: [PATCH 0483/2612] global-functions: $WaitTimeSync: calculate with modulo operation The uptime is returned in time, with supports arithmetic modulo operation. This is three minutes in nano seconds, so multiplied 180 with 10^9. --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index d51f1d3..366804a 100644 --- a/global-functions +++ b/global-functions @@ -967,7 +967,7 @@ :while ([ $TimeIsSync ] = false) do={ :if ([ :len [ / system script find where name="rotate-ntp" ] ] > 0 && \ - [ :tostr [ / system resource get uptime ] ] ~ "[369]:00\$") do={ + ([ / system resource get uptime ] % (180 * 1000000000)) = 0s) do={ :do { / system script run rotate-ntp; } on-error={ From 8ddc964cb51430a99285d002fe15a3dcb6a7bdb8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 10 Oct 2020 19:59:53 +0200 Subject: [PATCH 0484/2612] global-functions: $IPCalc: return data in array --- global-functions | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/global-functions b/global-functions index 366804a..2716355 100644 --- a/global-functions +++ b/global-functions @@ -379,13 +379,26 @@ :local Bits [ :tonum [ :pick $Input ([ :find $Input "/" ] + 1) [ :len $Input ] ] ]; :local Mask ((255.255.255.255 << (32 - $Bits)) & 255.255.255.255); + :local Return { + "address"=$Address; + "netmask"=$Mask; + "networkaddress"=($Address & $Mask); + "networkbits"=$Bits; + "network"=(($Address & $Mask) . "/" . $Bits); + "hostmin"=(($Address & $Mask) | 0.0.0.1); + "hostmax"=(($Address | ~$Mask) ^ 0.0.0.1); + "broadcast"=($Address | ~$Mask); + } + :put ( \ - "Address: " . $Address . "\n\r" . \ - "Netmask: " . $Mask . "\n\r" . \ - "Network: " . ($Address & $Mask) . "/" . $Bits . "\n\r" . \ - "HostMin: " . (($Address & $Mask) | 0.0.0.1) . "\n\r" . \ - "HostMax: " . (($Address | ~$Mask) ^ 0.0.0.1) . "\n\r" . \ - "Broadcast: " . ($Address | ~$Mask)); + "Address: " . $Return->"address" . "\n\r" . \ + "Netmask: " . $Return->"netmask" . "\n\r" . \ + "Network: " . $Return->"network" . "\n\r" . \ + "HostMin: " . $Return->"hostmin" . "\n\r" . \ + "HostMax: " . $Return->"hostmax" . "\n\r" . \ + "Broadcast: " . $Return->"broadcast"); + + :return $Return; } # log and print with same text, optionally exit From fc994402241d97d084669d63f1c8c2accc2550c7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Oct 2020 08:43:42 +0200 Subject: [PATCH 0485/2612] global-functions: $UrlEncode: encode new line & carriage return --- global-functions | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/global-functions b/global-functions index 2716355..10c5bd9 100644 --- a/global-functions +++ b/global-functions @@ -879,10 +879,11 @@ :local Return ""; :if ([ :len $Input ] > 0) do={ - :local Chars " !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~"; - :local Subs { "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27"; "%28"; "%29"; - "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; "%3F"; "%40"; - "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; "%7E" }; + :local Chars "\n\r !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~"; + :local Subs { "%0A"; "%0D"; "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27"; + "%28"; "%29"; "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; + "%3F"; "%40"; "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; + "%7E" }; :for I from=0 to=([ :len $Input ] - 1) do={ :local Char [ :pick $Input $I ]; From 6b1d9e8f40cf708bbc51be40bb7345ee3cf676b7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Oct 2020 09:00:55 +0200 Subject: [PATCH 0486/2612] global-functions: $FlushTelegramQueue, $SendTelegram: move hint --- global-functions | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/global-functions b/global-functions index 10c5bd9..1188c76 100644 --- a/global-functions +++ b/global-functions @@ -287,8 +287,6 @@ :global TelegramTokenId; :global LogPrintExit; - :global SymbolForNotification; - :global UrlEncode; :local AllDone true; :local QueueLen [ :len $TelegramQueue ]; @@ -299,9 +297,7 @@ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ http-data=("chat_id=" . ($Message->"chatid") . \ "&disable_notification=" . ($Message->"silent") . \ - "&text=" . ($Message->"text") . "\n\n" . \ - [ $UrlEncode ([ $SymbolForNotification "alarm-clock" ] . "This message was " . \ - "queued since " . ($Message->"since") . " and may be obsolete.") ]); + "&text=" . ($Message->"text")); :set ($TelegramQueue->$Id); } on-error={ $LogPrintExit debug ("Sending queued Telegram message failed.") false; @@ -802,8 +798,11 @@ :if ([ :typeof $TelegramQueue ] = "nothing") do={ :set TelegramQueue [ :toarray "" ]; } - :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; text=$Text; \ - silent=$Silent; since=([ / system clock get date ] . " " . [ / system clock get time ]) }; + :set Text ($Text . [ $UrlEncode ("\n\n" . [ $SymbolForNotification "alarm-clock" ] . \ + "This message was queued since " . [ / system clock get date ] . " " . \ + [ / system clock get time ] . " and may be obsolete.") ]); + :set ($TelegramQueue->[ :len $TelegramQueue ]) { + chatid=$ChatId; text=$Text; silent=$Silent; }; :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ / system scheduler add name=FlushTelegramQueue interval=1m start-time=startup \ on-event=":global FlushTelegramQueue; \$FlushTelegramQueue;"; From 3e0039c2666ae4cf2d45284e7a583f4ea2a0a85c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 12 Oct 2020 23:58:20 +0200 Subject: [PATCH 0487/2612] global-functions: $SendTelegram: use fixed-width font... ... but give configuration to opt-out. --- global-config | 4 +++- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 41 +++++++++++++++++++++++++++++++++-------- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/global-config b/global-config index c828a97..269ac6b 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 30; +:global GlobalConfigVersion 31; # This is used for DNS and backup file. :global Domain "example.com"; @@ -28,6 +28,8 @@ :global TelegramChatId ""; #:global TelegramTokenId "123456:ABCDEF-GHI"; #:global TelegramChatId "12345678"; +# This is whether or not to send Telegram messages with fixed-width font. +:global TelegramFixedWidthFont true; # Toggle this to disable symbols in notifications. :global NotificationsWithSymbols true; diff --git a/global-config-overlay b/global-config-overlay index f76fac3..0bc7cbb 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 30; +:global GlobalConfigVersion 31; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 8253c15..4120695 100644 --- a/global-config.changes +++ b/global-config.changes @@ -34,4 +34,5 @@ 28="Made 'dhcp-to-dns' act on all bound leases, not just dynamic ones."; 29="Added filter on log message text for 'log-forward'."; 30="Implemented simple rate limit for 'log-forward' to prevent flooding."; + 31="Switched Telegram notifications to fixed-width font, with opt-out."; }; diff --git a/global-functions b/global-functions index 1188c76..3ffe737 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 30; +:global ExpectedConfigVersion 31; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -297,7 +297,7 @@ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ http-data=("chat_id=" . ($Message->"chatid") . \ "&disable_notification=" . ($Message->"silent") . \ - "&text=" . ($Message->"text")); + "&parse_mode=" . ($Message->"parsemode") . "&text=" . ($Message->"text")); :set ($TelegramQueue->$Id); } on-error={ $LogPrintExit debug ("Sending queued Telegram message failed.") false; @@ -760,14 +760,31 @@ :global Identity; :global TelegramChatId; :global TelegramChatIdOverride; + :global TelegramFixedWidthFont; :global TelegramQueue; :global TelegramTokenId; :global CertificateAvailable; + :global CharacterReplace; + :global IfThenElse; :global LogPrintExit; :global SymbolForNotification; :global UrlEncode; + :local EscapeMD do={ + :global TelegramFixedWidthFont; + + :if ($TelegramFixedWidthFont != true) do={ + :return $1; + } + + :local Return $1; + :foreach Char in={ "."; "!" } do={ + :set Return [ $CharacterReplace $Return $Char ("\\" . $Char) ]; + } + :return $Return; + } + :local ChatId $TelegramChatId; :if ([ :len $TelegramChatIdOverride ] > 0) do={ :set ChatId $TelegramChatIdOverride; @@ -778,9 +795,17 @@ } :local Text ("[" . $Identity . "] " . $Subject . "\n\n" . $Message); + :local ParseMode; + :if ($TelegramFixedWidthFont = true) do={ + :set Text ("```\n" . [ $CharacterReplace [ $CharacterReplace $Text \ + ("\\") ("\\\\") ] ("`") ("\\`") ] . "\n```"); + :set ParseMode "MarkdownV2"; + } :if ([ :len $Text ] > 3968) do={ - :set Text ([ :pick $Text 0 3840 ] . "...\n\n" . [ $SymbolForNotification "scissors" ] . \ - "The Telegram message was too long and has been truncated."); + :set Text ([ :pick $Text 0 3840 ] . "..." . \ + [ $IfThenElse ($TelegramFixedWidthFont = true) ("\n```") "" ] . \ + "\n\n" . [ $SymbolForNotification "scissors" ] . \ + [ $EscapeMD "The Telegram message was too long and has been truncated!" ]); } :set Text [ $UrlEncode $Text ]; @@ -791,7 +816,7 @@ / tool fetch check-certificate=yes-without-crl output=none http-method=post \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ http-data=("chat_id=" . $ChatId . "&disable_notification=" . $Silent . \ - "&text=" . $Text); + "&parse_mode=" . $ParseMode . "&text=" . $Text); } on-error={ $LogPrintExit warning ("Failed sending telegram notification! Queuing...") false; @@ -799,10 +824,10 @@ :set TelegramQueue [ :toarray "" ]; } :set Text ($Text . [ $UrlEncode ("\n\n" . [ $SymbolForNotification "alarm-clock" ] . \ - "This message was queued since " . [ / system clock get date ] . " " . \ - [ / system clock get time ] . " and may be obsolete.") ]); + [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ + " " . [ / system clock get time ] . " and may be obsolete.") ]) ]); :set ($TelegramQueue->[ :len $TelegramQueue ]) { - chatid=$ChatId; text=$Text; silent=$Silent; }; + chatid=$ChatId; parsemode=$ParseMode; text=$Text; silent=$Silent }; :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ / system scheduler add name=FlushTelegramQueue interval=1m start-time=startup \ on-event=":global FlushTelegramQueue; \$FlushTelegramQueue;"; From e11e6b465812863fd2049274fd199f6dfa93c1a4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Oct 2020 13:23:32 +0200 Subject: [PATCH 0488/2612] check-lte-firmware-upgrade: show manufacturer & model --- check-lte-firmware-upgrade | 3 +++ 1 file changed, 3 insertions(+) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index d31ed37..0e4cb3d 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -9,6 +9,7 @@ :global Identity; :global SentLteFirmwareUpgradeNotification; +:global CharacterReplace; :global LogPrintExit; :global SendNotification; :global SymbolForNotification; @@ -23,9 +24,11 @@ ($Firmware->"latest") . ".") false; } else={ :if (($Firmware->"installed") != ($Firmware->"latest")) do={ + :local Info [ / interface lte info $Interface once as-value ]; $SendNotification ([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade") \ ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ + "Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \ "Installed: " . ($Firmware->"installed") . "\n" . \ "Available: " . ($Firmware->"latest")) "" "true"; :set SentLteFirmwareUpgradeNotification ($Firmware->"latest"); From 370d7c1a580cd59f2f6bc79b984a30c9fcf3b720 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Oct 2020 18:52:01 +0200 Subject: [PATCH 0489/2612] unattended-lte-firmware-upgrade: convert to function --- unattended-lte-firmware-upgrade | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index e84188b..d9bffad 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -17,14 +17,17 @@ :if (($Firmware->"installed") != ($Firmware->"latest")) do={ :log info ("Scheduling LTE firmware upgrade for interface " . $IntName . "."); - / system script add name=($IntName . "-firmware-upgrade") source=("# unattended-lte-firmware-upgrade\n" . \ - "/ system scheduler remove " . $IntName . "-firmware-upgrade;\n" . \ - "/ system script remove " . $IntName . "-firmware-upgrade;\n" . \ - "/ interface lte firmware-upgrade " . $IntName . " upgrade=yes;\n" . \ - ":log info (\"LTE firmware upgrade finished, waiting for installation before reset.\");\n" . \ - ":delay 150s;\n" . \ - "/ interface lte at-chat " . $IntName . " input=\"AT+RESET\";"); - / system scheduler add name=($IntName . "-firmware-upgrade") \ - on-event=("/ system script run " . $IntName . "-firmware-upgrade;") interval=1m; + :global LTEFirmwareUpgrade do={ + :global LTEFirmwareUpgrade; + :set LTEFirmwareUpgrade; + / system scheduler remove ($1 . "-firmware-upgrade"); + / interface lte firmware-upgrade $1 upgrade=yes; + :log info ("LTE firmware upgrade finished, waiting for installation before reset."); + :delay 150s; + / interface lte at-chat $1 input="AT+RESET"; + :log info ("Reset device, waiting to finish and reconnect."); + } + / system scheduler add name=($IntName . "-firmware-upgrade") start-time=startup interval=2s \ + on-event=(":global LTEFirmwareUpgrade; \$LTEFirmwareUpgrade \"" . $IntName . "\";"); } } From 0009c7fc656726af809b0015622d226467a5dbf7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Oct 2020 20:46:30 +0200 Subject: [PATCH 0490/2612] cloud-backup: add unit for size, add KiB --- cloud-backup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloud-backup b/cloud-backup index f6f2d28..e1386f0 100644 --- a/cloud-backup +++ b/cloud-backup @@ -31,7 +31,7 @@ ("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Name: " . $Cloud->"name" . "\n" . \ - "Size: " . $Cloud->"size" . "\n" . \ + "Size: " . $Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)\n" . \ "Download key: " . $Cloud->"secret-download-key") "" "true"; } on-error={ $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Cloud backup failed") \ From c40c792806df3385f64905f7d989bb08c884d916 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 14 Oct 2020 21:53:11 +0200 Subject: [PATCH 0491/2612] global-functions: $SendTelegram: clean up --- global-functions | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/global-functions b/global-functions index 3ffe737..2dafe4b 100644 --- a/global-functions +++ b/global-functions @@ -774,14 +774,26 @@ :local EscapeMD do={ :global TelegramFixedWidthFont; + :global CharacterReplace; + :if ($TelegramFixedWidthFont != true) do={ :return $1; } :local Return $1; - :foreach Char in={ "."; "!" } do={ + :local Chars { + "fixed"={ "\\"; "`" }; + "hint"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">"; + "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; + } + :foreach Char in=($Chars->$2) do={ :set Return [ $CharacterReplace $Return $Char ("\\" . $Char) ]; } + + :if ($2 = "fixed") do={ + :return ("```\n" . $Return . "\n```"); + } + :return $Return; } @@ -795,19 +807,15 @@ } :local Text ("[" . $Identity . "] " . $Subject . "\n\n" . $Message); - :local ParseMode; - :if ($TelegramFixedWidthFont = true) do={ - :set Text ("```\n" . [ $CharacterReplace [ $CharacterReplace $Text \ - ("\\") ("\\\\") ] ("`") ("\\`") ] . "\n```"); - :set ParseMode "MarkdownV2"; - } :if ([ :len $Text ] > 3968) do={ - :set Text ([ :pick $Text 0 3840 ] . "..." . \ - [ $IfThenElse ($TelegramFixedWidthFont = true) ("\n```") "" ] . \ + :set Text ([ $EscapeMD ([ :pick $Text 0 3840 ] . "...") "fixed" ] . \ "\n\n" . [ $SymbolForNotification "scissors" ] . \ - [ $EscapeMD "The Telegram message was too long and has been truncated!" ]); + [ $EscapeMD "The Telegram message was too long and has been truncated!" "hint" ]); + } else={ + :set Text [ $EscapeMD $Text "fixed" ]; } :set Text [ $UrlEncode $Text ]; + :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; :do { :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ @@ -825,7 +833,7 @@ } :set Text ($Text . [ $UrlEncode ("\n\n" . [ $SymbolForNotification "alarm-clock" ] . \ [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ - " " . [ / system clock get time ] . " and may be obsolete.") ]) ]); + " " . [ / system clock get time ] . " and may be obsolete.") "hint" ]) ]); :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; parsemode=$ParseMode; text=$Text; silent=$Silent }; :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ From b7690777464a46ecb9a21fff260a2830f3b7fb8f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 15 Oct 2020 22:45:27 +0200 Subject: [PATCH 0492/2612] global-config: do not define mail addresses by default --- README.md | 6 +++--- global-config | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 03b7bbd..33b61cd 100644 --- a/README.md +++ b/README.md @@ -96,9 +96,9 @@ Mark `global-config-overlay` not to be overwritten by future updates. [admin@MikroTik] > / system script set comment="ignore" global-config-overlay -The configuration needs to be tweaked for your needs. Make sure not to send -your mails to `mail@example.com`! Edit `global-config-overlay`, copy -configuration from `global-config` (the one without `-overlay`). +The configuration needs to be tweaked for your needs. Edit +`global-config-overlay`, copy configuration from `global-config` (the one +without `-overlay`). [admin@MikroTik] > / system script edit global-config-overlay source diff --git a/global-config b/global-config index 269ac6b..759356c 100644 --- a/global-config +++ b/global-config @@ -19,8 +19,10 @@ # These addresses are used to send e-mails to. The to-address needs # to be filled; cc-address can be empty, one address or a comma # separated list of addresses. -:global EmailGeneralTo "mail@example.com"; -:global EmailGeneralCc "another@example.com"; +:global EmailGeneralTo ""; +:global EmailGeneralCc ""; +#:global EmailGeneralTo "mail@example.com"; +#:global EmailGeneralCc "another@example.com,third@example.com"; # You can send Telegram notifications. Register a bot # and add the token and chat ids here. From 1c4531d5369ac1b8e502539faf65274a60c268d2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 15 Oct 2020 22:50:12 +0200 Subject: [PATCH 0493/2612] README: link to global-config --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 33b61cd..172de54 100644 --- a/README.md +++ b/README.md @@ -97,8 +97,8 @@ Mark `global-config-overlay` not to be overwritten by future updates. [admin@MikroTik] > / system script set comment="ignore" global-config-overlay The configuration needs to be tweaked for your needs. Edit -`global-config-overlay`, copy configuration from `global-config` (the one -without `-overlay`). +`global-config-overlay`, copy configuration from +[`global-config`](global-config) (the one without `-overlay`). [admin@MikroTik] > / system script edit global-config-overlay source From 8b2df7abd071b75b19df8564cece0a23c18c7894 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 16 Oct 2020 08:24:19 +0200 Subject: [PATCH 0494/2612] mode-button: merge mode-button-event & mode-button-scheduler --- doc/mode-button.md | 12 +++++----- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- mode-button | 54 +++++++++++++++++++++++++++++++++++++++++++ mode-button-event | 20 +--------------- mode-button-scheduler | 30 +----------------------- 8 files changed, 66 insertions(+), 57 deletions(-) create mode 100644 mode-button diff --git a/doc/mode-button.md b/doc/mode-button.md index 6469e54..a44b571 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -6,7 +6,7 @@ Mode button with multiple presses Description ----------- -These scripts extend the functionality of mode button. Instead of just one +This script extend the functionality of mode button. Instead of just one you can trigger several actions by pressing the mode button several times. The hardware needs to have a mode button, see @@ -31,17 +31,17 @@ Copy this code to terminal to check: Requirements and installation ----------------------------- -Just install the scripts: +Just install the script: - $ScriptInstallUpdate mode-button-event,mode-button-scheduler; + $ScriptInstallUpdate mode-button; -Then configure the mode button to run `mode-button-event`: +Then configure the mode button to run `mode-button`: - / system routerboard mode-button set enabled=yes on-event="/ system script run mode-button-event;"; + / system routerboard mode-button set enabled=yes on-event="/ system script run mode-button;"; To use the reset button instead: - / system routerboard reset-button set enabled=yes on-event="/ system script run mode-button-event;"; + / system routerboard reset-button set enabled=yes on-event="/ system script run mode-button;"; Configuration ------------- diff --git a/global-config b/global-config index 759356c..c90c4cb 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 31; +:global GlobalConfigVersion 32; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 0bc7cbb..246c013 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 31; +:global GlobalConfigVersion 32; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 4120695..aadc588 100644 --- a/global-config.changes +++ b/global-config.changes @@ -35,4 +35,5 @@ 29="Added filter on log message text for 'log-forward'."; 30="Implemented simple rate limit for 'log-forward' to prevent flooding."; 31="Switched Telegram notifications to fixed-width font, with opt-out."; + 32="Merged mode (& reset) button scripts in single new script 'mode-button'."; }; diff --git a/global-functions b/global-functions index 2dafe4b..38c6cde 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 31; +:global ExpectedConfigVersion 32; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/mode-button b/mode-button new file mode 100644 index 0000000..242cb46 --- /dev/null +++ b/mode-button @@ -0,0 +1,54 @@ +#!rsc by RouterOS +# RouterOS script: mode-button +# Copyright (c) 2018-2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# act on multiple mode and reset button presses +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md + +:global ModeButton; + +:global LogPrintExit; + +:set ($ModeButton->"count") ($ModeButton->"count" + 1); + +:local Scheduler [ / system scheduler find where name="ModeButtonScheduler" ]; + +:if ([ :len $Scheduler ] = 0) do={ + $LogPrintExit info ("Creating scheduler ModeButtonScheduler, counting presses...") false; + :global ModeButtonScheduler do={ + :global ModeButton; + + :global LogPrintExit; + :global ModeButtonScheduler; + + :local Count ($ModeButton->"count"); + :local Code ($ModeButton->[ :tostr $Count ]); + + :set ($ModeButton->"count") 0; + :set ModeButtonScheduler; + / system scheduler remove ModeButtonScheduler; + + :if ([ :len $Code ] > 0) do={ + $LogPrintExit info ("Acting on " . $Count . " mode-button presses: " . $Code) false; + + :if ([ / system routerboard settings get silent-boot ] = false) do={ + :for I from=1 to=$Count do={ + :beep length=200ms; + :delay 200ms; + } + } else={ + :delay 1s; + } + + [ :parse $Code ]; + } else={ + $LogPrintExit info ("No action defined for " . $Count . " mode-button presses.") false; + } + } + / system scheduler add name="ModeButtonScheduler" \ + on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s; +} else={ + $LogPrintExit debug ("Updating scheduler ModeButtonScheduler...") false; + / system scheduler set $Scheduler start-time=[ /system clock get time ]; +} diff --git a/mode-button-event b/mode-button-event index 7039852..b31ddc3 100644 --- a/mode-button-event +++ b/mode-button-event @@ -1,24 +1,6 @@ #!rsc by RouterOS # RouterOS script: mode-button-event -# Copyright (c) 2018-2020 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# run on mode-button event and count button presses -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md - -:global ModeButton; :global LogPrintExit; -:set ($ModeButton->"count") ($ModeButton->"count" + 1); - -:local Scheduler [ / system scheduler find where name="mode-button-scheduler" ]; - -:if ([ :len $Scheduler ] = 0) do={ - $LogPrintExit info ("Creating mode-button scheduler, counting presses...") false; - / system scheduler add name="mode-button-scheduler" \ - on-event="/ system script run mode-button-scheduler;" interval=3s; -} else={ - $LogPrintExit debug ("Updating mode-button-scheduler...") false; - / system scheduler set $Scheduler start-time=[ /system clock get time ]; -} +$LogPrintExit warning ("This script's functionality has been merged into 'mode-button'.") true; diff --git a/mode-button-scheduler b/mode-button-scheduler index 6c1f554..8844e49 100644 --- a/mode-button-scheduler +++ b/mode-button-scheduler @@ -1,34 +1,6 @@ #!rsc by RouterOS # RouterOS script: mode-button-scheduler -# Copyright (c) 2018-2020 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# act on multiple mode-button presses from scheduler -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md - -:global ModeButton; :global LogPrintExit; -:local Count ($ModeButton->"count"); -:local Code ($ModeButton->[ :tostr $Count ]); - -:set ($ModeButton->"count") 0; -/ system scheduler remove mode-button-scheduler; - -:if ([ :len $Code ] > 0) do={ - $LogPrintExit info ("Acting on " . $Count . " mode-button presses: " . $Code) false; - - :if ([ / system routerboard settings get silent-boot ] = false) do={ - :for I from=1 to=$Count do={ - :beep length=200ms; - :delay 200ms; - } - } else={ - :delay 1s; - } - - [ :parse $Code ]; -} else={ - $LogPrintExit info ("No action defined for " . $Count . " mode-button presses.") false; -} +$LogPrintExit warning ("This script's functionality has been merged into 'mode-button'.") true; From 3e72d1ec0bcb1a2d6276fff9408db01f16e7f5d8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 16 Oct 2020 21:35:44 +0200 Subject: [PATCH 0495/2612] check-health: give error on messing health values --- check-health | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/check-health b/check-health index 86df9ea..c27178d 100644 --- a/check-health +++ b/check-health @@ -22,6 +22,10 @@ :local CheckHealthCurrent [ / system health get ]; +:if ([ :len $CheckHealthCurrent ] = 0) do={ + $LogPrintExit error ("Your device does not provide any health values.") true; +} + :foreach Voltage in={ "battery"; "psu1-voltage"; "psu2-voltage"; "voltage" } do={ :if ([ :typeof ($CheckHealthLast->$Voltage) ] = "num" && \ [ :typeof ($CheckHealthCurrent->$Voltage) ] = "num") do={ From 6d9eb99e08fb0a1ac8dc03213edfd5f590655ee4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 16 Oct 2020 22:51:51 +0200 Subject: [PATCH 0496/2612] check-health: add deviation on temperature recovery threshold This helps against notification flooding. --- check-health | 19 +++++++++++++------ global-config | 4 +++- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/check-health b/check-health index c27178d..ff4cf36 100644 --- a/check-health +++ b/check-health @@ -8,6 +8,8 @@ :global CheckHealthLast; :global CheckHealthTemperature; +:global CheckHealthTemperatureDeviation; +:global CheckHealthTemperatureNotified; :global CheckHealthVoltagePercent; :global Identity; @@ -26,6 +28,10 @@ $LogPrintExit error ("Your device does not provide any health values.") true; } +:if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ + :set CheckHealthTemperatureNotified [ :toarray "" ]; +} + :foreach Voltage in={ "battery"; "psu1-voltage"; "psu2-voltage"; "voltage" } do={ :if ([ :typeof ($CheckHealthLast->$Voltage) ] = "num" && \ [ :typeof ($CheckHealthCurrent->$Voltage) ] = "num") do={ @@ -56,23 +62,24 @@ } :foreach Temperature in={ "temperature"; "cpu-temperature"; "board-temperature1"; "board-temperature2" } do={ - :if ([ :typeof ($CheckHealthLast->$Temperature) ] = "num" && \ - [ :typeof ($CheckHealthCurrent->$Temperature) ] = "num") do={ + :if ([ :typeof ($CheckHealthCurrent->$Temperature) ] = "num") do={ :if ([ :typeof ($CheckHealthTemperature->$Temperature) ] != "num" ) do={ $LogPrintExit warning ("No threshold given for " . $Temperature . ", assuming 50C.") false; :set ($CheckHealthTemperature->$Temperature) 50; } - :if ($CheckHealthLast->$Temperature <= $CheckHealthTemperature->$Temperature && \ - $CheckHealthCurrent->$Temperature > $CheckHealthTemperature->$Temperature) do={ + :if ($CheckHealthCurrent->$Temperature > $CheckHealthTemperature->$Temperature && \ + $CheckHealthTemperatureNotified->$Temperature != true) do={ $SendNotification ([ $SymbolForNotification "fire" ] . "Health warning: " . $Temperature) \ ("The " . $Temperature . " on " . $Identity . " is above threshold: " . \ $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); + :set ($CheckHealthTemperatureNotified->$Temperature) true; } - :if ($CheckHealthLast->$Temperature > $CheckHealthTemperature->$Temperature && \ - $CheckHealthCurrent->$Temperature <= $CheckHealthTemperature->$Temperature) do={ + :if ($CheckHealthCurrent->$Temperature <= ($CheckHealthTemperature->$Temperature - $CheckHealthTemperatureDeviation) && \ + $CheckHealthTemperatureNotified->$Temperature = true) do={ $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Temperature) \ ("The " . $Temperature . " on " . $Identity . " dropped below threshold: " . \ $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); + :set ($CheckHealthTemperatureNotified->$Temperature) false; } } } diff --git a/global-config b/global-config index c90c4cb..8721f8d 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 32; +:global GlobalConfigVersion 33; # This is used for DNS and backup file. :global Domain "example.com"; @@ -71,6 +71,8 @@ board-temperature1=50; board-temperature2=50; } +# This is deviation on recovery threshold against notification flooding. +:global CheckHealthTemperatureDeviation 2; :global CheckHealthVoltagePercent 10; # This controls what configuration is activated by bridge-port-to-default. diff --git a/global-config-overlay b/global-config-overlay index 246c013..984e577 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 32; +:global GlobalConfigVersion 33; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index aadc588..04f8a53 100644 --- a/global-config.changes +++ b/global-config.changes @@ -36,4 +36,5 @@ 30="Implemented simple rate limit for 'log-forward' to prevent flooding."; 31="Switched Telegram notifications to fixed-width font, with opt-out."; 32="Merged mode (& reset) button scripts in single new script 'mode-button'."; + 33="Added configurable deviation on health temperature recovery threshold against notification flooding."; }; diff --git a/global-functions b/global-functions index 38c6cde..10f14f6 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 32; +:global ExpectedConfigVersion 33; # global variables not to be changed by user :global GlobalFunctionsReady false; From a4b237044d9928109bc925fe565a262ed30dbfcd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 17 Oct 2020 13:40:01 +0200 Subject: [PATCH 0497/2612] sms-forward: lock against multiple invocations --- sms-forward | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sms-forward b/sms-forward index bd750b6..bd1f9d6 100644 --- a/sms-forward +++ b/sms-forward @@ -10,10 +10,13 @@ :global LogPrintExit; :global MailServerIsUp; +:global ScriptLock; :global SendNotification; :global SymbolForNotification; :global WaitFullyConnected; +$ScriptLock "sms-forward"; + :if ([ / tool sms get receive-enabled ] = false) do={ $LogPrintExit warning "Receiving of SMS is not enabled." true; } From 211edb93c0dc0a1c469694d5e137b5a10ac7438b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 17 Oct 2020 23:05:08 +0200 Subject: [PATCH 0498/2612] check-health: do not hardcode names, use as available --- check-health | 77 +++++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/check-health b/check-health index ff4cf36..fc8f097 100644 --- a/check-health +++ b/check-health @@ -32,54 +32,57 @@ :set CheckHealthTemperatureNotified [ :toarray "" ]; } -:foreach Voltage in={ "battery"; "psu1-voltage"; "psu2-voltage"; "voltage" } do={ - :if ([ :typeof ($CheckHealthLast->$Voltage) ] = "num" && \ - [ :typeof ($CheckHealthCurrent->$Voltage) ] = "num") do={ - :if ($CheckHealthLast->$Voltage * (100 + $CheckHealthVoltagePercent) < $CheckHealthCurrent->$Voltage * 100 || \ - $CheckHealthLast->$Voltage * 100 > $CheckHealthCurrent->$Voltage * (100 + $CheckHealthVoltagePercent)) do={ - $SendNotification ([ $SymbolForNotification "high-voltage-sign" ] . "Health warning: " . $Voltage) \ - ("The " . $Voltage . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ - "old value: " . [ $FormatVoltage ($CheckHealthLast->$Voltage) ] . "\n" . \ - "new value: " . [ $FormatVoltage ($CheckHealthCurrent->$Voltage) ]); +:foreach Name,Voltage in=$CheckHealthCurrent do={ + :if ($Name ~ "(battery|voltage)" && \ + [ :typeof ($CheckHealthLast->$Name) ] = "num" && \ + [ :typeof $Voltage ] = "num") do={ + :if ($CheckHealthLast->$Name * (100 + $CheckHealthVoltagePercent) < $Voltage * 100 || \ + $CheckHealthLast->$Name * 100 > $Voltage * (100 + $CheckHealthVoltagePercent)) do={ + $SendNotification ([ $SymbolForNotification "high-voltage-sign" ] . "Health warning: " . $Name) \ + ("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ + "old value: " . [ $FormatVoltage ($CheckHealthLast->$Name) ] . "\n" . \ + "new value: " . [ $FormatVoltage $Voltage ]); } } } -:foreach PSU in={ "psu1"; "psu2" } do={ - :if ([ :typeof ($CheckHealthLast->($PSU . "-state")) ] = "str" && \ - [ :typeof ($CheckHealthCurrent->($PSU . "-state")) ] = "str") do={ - :if ($CheckHealthLast->($PSU . "-state") = "ok" && \ - $CheckHealthCurrent->($PSU . "-state") != "ok") do={ - $SendNotification ([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $PSU . " state") \ - ("The power supply unit '" . $PSU . "' on " . $Identity . " failed!"); +:foreach Name,PSU in=$CheckHealthCurrent do={ + :if ($Name ~ "psu.*-state" && \ + [ :typeof ($CheckHealthLast->$Name) ] = "str" && \ + [ :typeof $PSU ] = "str") do={ + :if ($CheckHealthLast->$Name = "ok" && \ + $PSU != "ok") do={ + $SendNotification ([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name) \ + ("The power supply unit '" . $Name . "' on " . $Identity . " failed!"); } - :if ($CheckHealthLast->($PSU . "-state") != "ok" && \ - $CheckHealthCurrent->($PSU . "-state") = "ok") do={ - $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $PSU . " state") \ - ("The power supply unit '" . $PSU . "' on " . $Identity . " recovered!"); + :if ($CheckHealthLast->$Name != "ok" && \ + $PSU = "ok") do={ + $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name) \ + ("The power supply unit '" . $Name . "' on " . $Identity . " recovered!"); } } } -:foreach Temperature in={ "temperature"; "cpu-temperature"; "board-temperature1"; "board-temperature2" } do={ - :if ([ :typeof ($CheckHealthCurrent->$Temperature) ] = "num") do={ - :if ([ :typeof ($CheckHealthTemperature->$Temperature) ] != "num" ) do={ - $LogPrintExit warning ("No threshold given for " . $Temperature . ", assuming 50C.") false; - :set ($CheckHealthTemperature->$Temperature) 50; +:foreach Name,Temperature in=$CheckHealthCurrent do={ + :if ($Name ~ "temperature" && \ + [ :typeof $Temperature ] = "num") do={ + :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ + $LogPrintExit warning ("No threshold given for " . $Name . ", assuming 50C.") false; + :set ($CheckHealthTemperature->$Name) 50; } - :if ($CheckHealthCurrent->$Temperature > $CheckHealthTemperature->$Temperature && \ - $CheckHealthTemperatureNotified->$Temperature != true) do={ - $SendNotification ([ $SymbolForNotification "fire" ] . "Health warning: " . $Temperature) \ - ("The " . $Temperature . " on " . $Identity . " is above threshold: " . \ - $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); - :set ($CheckHealthTemperatureNotified->$Temperature) true; + :if ($Temperature > $CheckHealthTemperature->$Name && \ + $CheckHealthTemperatureNotified->$Name != true) do={ + $SendNotification ([ $SymbolForNotification "fire" ] . "Health warning: " . $Name) \ + ("The " . $Name . " on " . $Identity . " is above threshold: " . \ + $Temperature . "\C2\B0" . "C"); + :set ($CheckHealthTemperatureNotified->$Name) true; } - :if ($CheckHealthCurrent->$Temperature <= ($CheckHealthTemperature->$Temperature - $CheckHealthTemperatureDeviation) && \ - $CheckHealthTemperatureNotified->$Temperature = true) do={ - $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Temperature) \ - ("The " . $Temperature . " on " . $Identity . " dropped below threshold: " . \ - $CheckHealthCurrent->$Temperature . "\C2\B0" . "C"); - :set ($CheckHealthTemperatureNotified->$Temperature) false; + :if ($Temperature <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ + $CheckHealthTemperatureNotified->$Name = true) do={ + $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name) \ + ("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ + $Temperature . "\C2\B0" . "C"); + :set ($CheckHealthTemperatureNotified->$Name) false; } } } From 4a85deb45c5f6a0231180e57ade1c2d600262f4b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 18 Oct 2020 20:13:58 +0200 Subject: [PATCH 0499/2612] log-forward: improve wording for single message --- log-forward | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/log-forward b/log-forward index 27aa19c..fdabbf8 100644 --- a/log-forward +++ b/log-forward @@ -12,6 +12,7 @@ :global LogForwardLast; :global LogForwardRateLimit; +:global IfThenElse; :global LogPrintExit; :global MailServerIsUp; :global ScriptLock; @@ -55,8 +56,9 @@ $WaitFullyConnected; :if ($Count > 0) do={ $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Log Forwarding") \ - ("The log on " . $Identity . " contains these " . $Count . " messages after " . \ - [ / system resource get uptime ] . " uptime.\n" . $Messages); + ("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) \ + "this message" ("these " . $Count . " messages") ] . " after " . \ + [ / system resource get uptime ] . " uptime.\n" . $Messages); :set LogForwardRateLimit ($LogForwardRateLimit + 10); :set LogForwardLast ($MessageVal->".id"); From 4af1f5dec2cb8c7b94b3fff141cab63b2adae725 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 19 Oct 2020 13:45:02 +0200 Subject: [PATCH 0500/2612] sms-forward: improve wording for single/multiple message(s) --- sms-forward | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sms-forward b/sms-forward index bd1f9d6..28d60a1 100644 --- a/sms-forward +++ b/sms-forward @@ -8,6 +8,7 @@ :global Identity; +:global IfThenElse; :global LogPrintExit; :global MailServerIsUp; :global ScriptLock; @@ -50,9 +51,10 @@ $WaitFullyConnected; } :if ([ :len $Messages ] > 0) do={ + :local Count [ :len $Delete ]; $SendNotification ([ $SymbolForNotification "incoming-envelope" ] . "SMS Forwarding from " . $Phone) \ - ("These message(s) were received by " . $Identity . \ - " from " . $Phone . ":" . $Messages); + ("Received " . [ $IfThenElse ($Count = 1) "this message" ("these " . $Count . " messages") ] . \ + " by " . $Identity . " from " . $Phone . ":" . $Messages); :foreach Sms in=$Delete do={ / tool sms inbox remove $Sms; } From dd39049d36a4ec34c6bc11936c3f680cd31b24c9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 22 Oct 2020 22:18:22 +0200 Subject: [PATCH 0501/2612] mode-button: use user-led for visual feeback The user-led needs to be configured with type=off, it is ignored with other configuration. --- mode-button | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mode-button b/mode-button index 242cb46..3aee63e 100644 --- a/mode-button +++ b/mode-button @@ -32,13 +32,15 @@ :if ([ :len $Code ] > 0) do={ $LogPrintExit info ("Acting on " . $Count . " mode-button presses: " . $Code) false; - :if ([ / system routerboard settings get silent-boot ] = false) do={ - :for I from=1 to=$Count do={ + :for I from=1 to=$Count do={ + / system leds set type=on [ find where leds="user-led" type=off ]; + :if ([ / system routerboard settings get silent-boot ] = false) do={ :beep length=200ms; + } else={ :delay 200ms; } - } else={ - :delay 1s; + / system leds set type=off [ find where leds="user-led" type=on ]; + :delay 200ms; } [ :parse $Code ]; From ebbc40e3a090fb91e6107b7546abf4caf32e4989 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Oct 2020 12:01:29 +0200 Subject: [PATCH 0502/2612] mode-button: support inverted blink --- mode-button | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mode-button b/mode-button index 3aee63e..a555044 100644 --- a/mode-button +++ b/mode-button @@ -19,11 +19,14 @@ :global ModeButtonScheduler do={ :global ModeButton; + :global IfThenElse; :global LogPrintExit; :global ModeButtonScheduler; :local Count ($ModeButton->"count"); :local Code ($ModeButton->[ :tostr $Count ]); + :local LEDState [ / system leds get [ find where leds="user-led" ] type ]; + :local LEDInvert [ $IfThenElse ($LEDState = "on") "off" "on" ]; :set ($ModeButton->"count") 0; :set ModeButtonScheduler; @@ -33,13 +36,13 @@ $LogPrintExit info ("Acting on " . $Count . " mode-button presses: " . $Code) false; :for I from=1 to=$Count do={ - / system leds set type=on [ find where leds="user-led" type=off ]; + / system leds set type=$LEDInvert [ find where leds="user-led" type=$LEDState ]; :if ([ / system routerboard settings get silent-boot ] = false) do={ :beep length=200ms; } else={ :delay 200ms; } - / system leds set type=off [ find where leds="user-led" type=on ]; + / system leds set type=$LEDState [ find where leds="user-led" type=$LEDInvert ]; :delay 200ms; } From ae5570325b8509ad8c637e8e6ebc81f1d8528cd0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Oct 2020 14:13:40 +0200 Subject: [PATCH 0503/2612] ospf-to-leds: introduce script to visualize ospf state via leds --- README.md | 1 + doc/ospf-to-leds.md | 34 ++++++++++++++++++++++++++++++++++ global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- ospf-to-leds | 24 ++++++++++++++++++++++++ 7 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 doc/ospf-to-leds.md create mode 100644 ospf-to-leds diff --git a/README.md b/README.md index 172de54..2c12b45 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,7 @@ Available Scripts * [Mode button with multiple presses](doc/mode-button.md) * [Notify on host up and down](doc/netwatch-notify.md) * [Manage remote logging](doc/netwatch-syslog.md) +* [Visualize OSPF state via LEDs](doc/ospf-to-leds.md) * [Manage system update](doc/packages-update.md) * [Run scripts on ppp connection](doc/ppp-on-up.md) * [Rotate NTP servers](doc/rotate-ntp.md) diff --git a/doc/ospf-to-leds.md b/doc/ospf-to-leds.md new file mode 100644 index 0000000..72fab6b --- /dev/null +++ b/doc/ospf-to-leds.md @@ -0,0 +1,34 @@ +Visualize OSPF state via LEDs +============================= + +[◀ Go back to main README](../README.md) + +Description +----------- + +Physical interfaces have their state LEDs, software-defined connectivity +does not. This script helps to visualize whether or not an OSPF instance +is running. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate ospf-to-leds; + +... and add a scheduler to run the script periodically: + + / system scheduler add interval=20s name=ospf-to-leds on-event="/ system script run ospf-to-leds;" start-time=startup; + +Configuration +------------- + +The configuration goes to OSPF instance's comment. To visualize state for +instance `default` via LED `user-led` set this: + + / routing ospf instance set default comment="ospf-to-leds, leds=user-led"; + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/global-config b/global-config index 8721f8d..68d12e7 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 33; +:global GlobalConfigVersion 34; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 984e577..99295e6 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 33; +:global GlobalConfigVersion 34; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 04f8a53..7d14e85 100644 --- a/global-config.changes +++ b/global-config.changes @@ -37,4 +37,5 @@ 31="Switched Telegram notifications to fixed-width font, with opt-out."; 32="Merged mode (& reset) button scripts in single new script 'mode-button'."; 33="Added configurable deviation on health temperature recovery threshold against notification flooding."; + 34="Introduced script 'ospf-to-leds' to visualize OSPF instance state via LEDs."; }; diff --git a/global-functions b/global-functions index 10f14f6..ab3247a 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 33; +:global ExpectedConfigVersion 34; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/ospf-to-leds b/ospf-to-leds new file mode 100644 index 0000000..61b90ce --- /dev/null +++ b/ospf-to-leds @@ -0,0 +1,24 @@ +#!rsc by RouterOS +# RouterOS script: ospf-to-leds +# Copyright (c) 2020 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# visualize ospf instance state via leds +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ospf-to-leds.md + +:global LogPrintExit; +:global ParseKeyValueStore; + +:foreach Instance in=[ / routing ospf instance find where comment~"^ospf-to-leds," ] do={ + :local InstanceVal [ / routing ospf instance get $Instance ]; + :local LED ([ $ParseKeyValueStore ($InstanceVal->"comment") ]->"leds"); + :local LEDType [ / system leds get [ find where leds=$LED ] type ]; + + $LogPrintExit debug ("OSPF instance " . $InstanceVal->"name" . " is " . $InstanceVal->"state" . ".") false; + :if ($InstanceVal->"state" = "running" && $LEDType = "off") do={ + / system leds set type=on [ find where leds=$LED ]; + } + :if ($InstanceVal->"state" = "down" && $LEDType = "on") do={ + / system leds set type=off [ find where leds=$LED ]; + } +} From cbb1e624b24c6c6b2a5c55eb4bc8b3ca2ec9febe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Oct 2020 15:25:01 +0200 Subject: [PATCH 0504/2612] bridge-port-to-default: be more robust This was unreliable with inconsistent configuration... --- bridge-port-to-default | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/bridge-port-to-default b/bridge-port-to-default index 4db04e8..e4d4947 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -8,6 +8,7 @@ :global BridgePortTo; +:global IfThenElse; :global LogPrintExit; :global ParseKeyValueStore; @@ -15,23 +16,32 @@ :local BridgePortVal [ / interface bridge port get $BridgePort ]; :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ :if ($Config = $BridgePortTo) do={ + :local DHCPClient [ / ip dhcp-client find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; + :if ($BridgeDefault = "dhcp-client") do={ - :if ($BridgePortVal->"disabled" = false) do={ + :if ([ :len $DHCPClient ] != 1) do={ + $LogPrintExit warning ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ + " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; + } + :local DHCPClientDisabled [ / ip dhcp-client get $DHCPClient disabled ]; + + :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ $LogPrintExit info ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; / interface bridge port disable $BridgePort; - / ip dhcp-client enable [ find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" disabled=yes ]; + / ip dhcp-client enable $DHCPClient; } } else={ - :if ($BridgePortVal->"disabled" = true) do={ - $LogPrintExit info ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", disabling dhcp client.") false; - / ip dhcp-client disable [ find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" disabled=no ]; - / interface bridge port enable $BridgePort; - } - :if ($BridgeDefault != $BridgePortVal->"bridge") do={ - $LogPrintExit info ("Changing interface " . $BridgePortVal->"interface" . " to " . $BridgePortTo . " bridge " . $BridgeDefault) false; - / interface bridge port set bridge=$BridgeDefault $BridgePort; + :if ($BridgePortVal->"disabled" = true || $BridgeDefault != $BridgePortVal->"bridge") do={ + $LogPrintExit info ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ + " bridge " . $BridgeDefault . ", disabling dhcp client.") false; + :if ([ :len $DHCPClient ] = 1) do={ + / ip dhcp-client disable $DHCPClient; + :delay 200ms; + } + / interface bridge port set disabled=no bridge=$BridgeDefault $BridgePort; } else={ - $LogPrintExit debug ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . " bridge " . $BridgeDefault) false; + $LogPrintExit debug ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ + " bridge " . $BridgeDefault . ".") false; } } } From 3b65b7e83544e042b8c965aa191cf1a315a52e5f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Oct 2020 16:01:21 +0200 Subject: [PATCH 0505/2612] mode-button: fix delay The `:beep` command is async... So an additional delay is required unconditionally. --- mode-button | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mode-button b/mode-button index a555044..f3d7be7 100644 --- a/mode-button +++ b/mode-button @@ -39,9 +39,8 @@ / system leds set type=$LEDInvert [ find where leds="user-led" type=$LEDState ]; :if ([ / system routerboard settings get silent-boot ] = false) do={ :beep length=200ms; - } else={ - :delay 200ms; } + :delay 200ms; / system leds set type=$LEDState [ find where leds="user-led" type=$LEDInvert ]; :delay 200ms; } From 55e114c190318274f06a9749810470e6c4e8dfea Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Oct 2020 20:32:45 +0200 Subject: [PATCH 0506/2612] mode-button: act on led with no interface setting only --- mode-button | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode-button b/mode-button index f3d7be7..2493208 100644 --- a/mode-button +++ b/mode-button @@ -36,12 +36,12 @@ $LogPrintExit info ("Acting on " . $Count . " mode-button presses: " . $Code) false; :for I from=1 to=$Count do={ - / system leds set type=$LEDInvert [ find where leds="user-led" type=$LEDState ]; + / system leds set type=$LEDInvert [ find where leds="user-led" type=$LEDState interface=[] ]; :if ([ / system routerboard settings get silent-boot ] = false) do={ :beep length=200ms; } :delay 200ms; - / system leds set type=$LEDState [ find where leds="user-led" type=$LEDInvert ]; + / system leds set type=$LEDState [ find where leds="user-led" type=$LEDInvert interface=[] ]; :delay 200ms; } From 2e4658e49a5a2e575ff6b9c0fdadb66f65142d94 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Oct 2020 21:24:59 +0200 Subject: [PATCH 0507/2612] mode-button: act on led with type on or off only --- mode-button | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/mode-button b/mode-button index 2493208..c189ad2 100644 --- a/mode-button +++ b/mode-button @@ -19,14 +19,21 @@ :global ModeButtonScheduler do={ :global ModeButton; - :global IfThenElse; :global LogPrintExit; :global ModeButtonScheduler; + :local LEDInvert do={ + :global IfThenElse; + + :local LED [ / system leds find where leds="user-led" type~"^(on|off)\$" interface=[] ]; + :if ([ :len $LED ] = 0) do={ + :return false; + } + / system leds set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED; + } + :local Count ($ModeButton->"count"); :local Code ($ModeButton->[ :tostr $Count ]); - :local LEDState [ / system leds get [ find where leds="user-led" ] type ]; - :local LEDInvert [ $IfThenElse ($LEDState = "on") "off" "on" ]; :set ($ModeButton->"count") 0; :set ModeButtonScheduler; @@ -36,12 +43,12 @@ $LogPrintExit info ("Acting on " . $Count . " mode-button presses: " . $Code) false; :for I from=1 to=$Count do={ - / system leds set type=$LEDInvert [ find where leds="user-led" type=$LEDState interface=[] ]; + $LEDInvert; :if ([ / system routerboard settings get silent-boot ] = false) do={ :beep length=200ms; } :delay 200ms; - / system leds set type=$LEDState [ find where leds="user-led" type=$LEDInvert interface=[] ]; + $LEDInvert; :delay 200ms; } From fee2523a226e28e08dd2e2264ff857650a886702 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Oct 2020 21:33:38 +0200 Subject: [PATCH 0508/2612] mode-button: make LED configurable --- doc/mode-button.md | 3 ++- global-config | 4 +++- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- mode-button | 4 +++- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/doc/mode-button.md b/doc/mode-button.md index a44b571..8d037e5 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -46,9 +46,10 @@ To use the reset button instead: Configuration ------------- -The configuration goes to `global-config-overlay`, the only parameter is: +The configuration goes to `global-config-overlay`, these are the parameters: * `ModeButton`: an array with defined actions +* `ModeButtonLED`: led to give visual feedback Usage and invocation -------------------- diff --git a/global-config b/global-config index 68d12e7..fc8d010 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 34; +:global GlobalConfigVersion 35; # This is used for DNS and backup file. :global Domain "example.com"; @@ -105,6 +105,8 @@ 5="/ system script run bridge-port-toggle;"; # add more here... }; +# This led gives visual feedback if type is 'on' or 'off'. +:global ModeButtonLED "user-led"; # Run commands on SMS action. :global SmsAction { diff --git a/global-config-overlay b/global-config-overlay index 99295e6..250f697 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 34; +:global GlobalConfigVersion 35; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 7d14e85..8082344 100644 --- a/global-config.changes +++ b/global-config.changes @@ -38,4 +38,5 @@ 32="Merged mode (& reset) button scripts in single new script 'mode-button'."; 33="Added configurable deviation on health temperature recovery threshold against notification flooding."; 34="Introduced script 'ospf-to-leds' to visualize OSPF instance state via LEDs."; + 35="Implemented visual feedback for 'mode-button' with configurable LED."; }; diff --git a/global-functions b/global-functions index ab3247a..f8716fe 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 34; +:global ExpectedConfigVersion 35; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/mode-button b/mode-button index c189ad2..217c0cc 100644 --- a/mode-button +++ b/mode-button @@ -23,9 +23,11 @@ :global ModeButtonScheduler; :local LEDInvert do={ + :global ModeButtonLED; + :global IfThenElse; - :local LED [ / system leds find where leds="user-led" type~"^(on|off)\$" interface=[] ]; + :local LED [ / system leds find where leds=$ModeButtonLED type~"^(on|off)\$" interface=[] ]; :if ([ :len $LED ] = 0) do={ :return false; } From 7f356d76bf5c76d98d3fc93c6471720b49750daf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Oct 2020 00:30:40 +0100 Subject: [PATCH 0509/2612] global-functions: $SymbolForNotification: support multiple symbols... ... with comma-separated list. --- global-functions | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index f8716fe..f4b3ca6 100644 --- a/global-functions +++ b/global-functions @@ -874,7 +874,11 @@ :if ($NotificationsWithSymbols != true) do={ :return ""; } - :return ([ $SymbolByUnicodeName $1 ] . " "); + :local Return ""; + :foreach Symbol in=[ :toarray $1 ] do={ + :set Return ($Return . [ $SymbolByUnicodeName $Symbol ]); + } + :return ($Return . " "); } # check if system time is sync From 98c132105dc88b13989c12d5bf9572022c7e986b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 1 Nov 2020 21:48:03 +0100 Subject: [PATCH 0510/2612] check-routeros-update: support installing updates automatically if seen in neighbor list --- check-routeros-update | 12 +++++++++++- doc/check-routeros-update.md | 3 ++- global-config | 4 +++- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 6 files changed, 19 insertions(+), 5 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index 13262f3..e020153 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -7,8 +7,9 @@ # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md :global Identity; -:global SafeUpdateUrl; +:global SafeUpdateNeighbor; :global SafeUpdatePatch; +:global SafeUpdateUrl; :global SentRouterosUpdateNotification; :global DeviceInfo; @@ -57,6 +58,15 @@ $DoUpdate; } + :if ($SafeUpdateNeighbor = true && [ :len [ / ip neighbor find where \ + version=($Update->"latest-version" . " (" . $Update->"channel" . ")") ] ] > 0) do={ + $LogPrintExit info ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; + $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ + ("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \ + ", updating on " . $Identity . "...") "" "true"; + $DoUpdate; + } + :if ([ :len $SafeUpdateUrl ] > 0) do={ :local Result; :do { diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 6016a1f..bd25ab1 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -34,9 +34,10 @@ Configuration is required only if you want to control update process with safe versions from a web server. The configuration goes to `global-config-overlay`, this is the parameter: +* `SafeUpdateNeighbor`: install updates automatically if seen in neighbor list +* `SafeUpdatePatch`: install patch updates automatically * `SafeUpdateUrl`: url to check for safe update, the channel (`long-term`, `stable` or `testing`) is appended -* `SafeUpdatePatch`: install patch updates automatically Usage and invocation -------------------- diff --git a/global-config b/global-config index fc8d010..01e62c1 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 35; +:global GlobalConfigVersion 36; # This is used for DNS and backup file. :global Domain "example.com"; @@ -62,6 +62,8 @@ #:global SafeUpdateUrl "https://example.com/ros/safe-update/"; # Allow to install patch updates automatically. :global SafeUpdatePatch false; +# Allow to install updates automatically if seen in neighbor list. +:global SafeUpdateNeighbor false; # These thresholds control when to send health notification # on temperature and voltage. diff --git a/global-config-overlay b/global-config-overlay index 250f697..2777519 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 35; +:global GlobalConfigVersion 36; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 8082344..85529eb 100644 --- a/global-config.changes +++ b/global-config.changes @@ -39,4 +39,5 @@ 33="Added configurable deviation on health temperature recovery threshold against notification flooding."; 34="Introduced script 'ospf-to-leds' to visualize OSPF instance state via LEDs."; 35="Implemented visual feedback for 'mode-button' with configurable LED."; + 36="Added support for installing updates automatically if seen in neighbor list."; }; diff --git a/global-functions b/global-functions index f4b3ca6..030a9f2 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 35; +:global ExpectedConfigVersion 36; # global variables not to be changed by user :global GlobalFunctionsReady false; From d547f68df12638c42dd78592613cd0886fc064ae Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 1 Nov 2020 21:57:13 +0100 Subject: [PATCH 0511/2612] doc/global-wait: warn about scheduler --- doc/global-wait.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/global-wait.md b/doc/global-wait.md index 9fcaa96..60d7211 100644 --- a/doc/global-wait.md +++ b/doc/global-wait.md @@ -12,6 +12,9 @@ script at system startup may result in race condition where configuration and/or function are not yet available. This script is supposed to wait for everything being prepared. +Do **not** add this script `global-wait` to the `global-scripts` scheduler! +It would inhibit the initialization of configuration and functions. + Requirements and installation ----------------------------- From df66309281544675ee998f6fb20fa711b67c26e9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 1 Nov 2020 21:57:36 +0100 Subject: [PATCH 0512/2612] doc/global-wait: link more use cases --- doc/global-wait.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/global-wait.md b/doc/global-wait.md index 60d7211..bdceddf 100644 --- a/doc/global-wait.md +++ b/doc/global-wait.md @@ -31,6 +31,9 @@ See also -------- * [Manage ports in bridge](bridge-port.md) +* [Download packages for CAP upgrade from CAPsMAN](capsman-download-packages.md) +* [Renew certificates and notify on expiration](check-certificates.md) +* [Use wireless network with daily psk](daily-psk.md) --- [◀ Go back to main README](../README.md) From f2e16a92d1675de790de591788e62ed3f586fc3a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 1 Nov 2020 22:20:02 +0100 Subject: [PATCH 0513/2612] README: optional scheduler to update scripts automatically --- INITIAL-COMMANDS.md | 4 ++++ README.md | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 597ddb6..6c167ef 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -26,6 +26,10 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai $CertificateNameByCN "DST Root CA X3"; } +Optional to update the scripts automatically: + + / system scheduler add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; + --- [◀ Go back to main README](README.md) [▲ Go back to top](#top) diff --git a/README.md b/README.md index 2c12b45..9aa0bb8 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,11 @@ And finally load configuration and functions and add the scheduler. [admin@MikroTik] > / system script { run global-config; run global-config-overlay; run global-functions; } [admin@MikroTik] > / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }" +The last step is optional: Add this scheduler **only** if you want the scripts +to be updated automatically! + + [admin@MikroTik] > / system scheduler add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;" + Updating scripts ---------------- From 243b23dc196fc055714639ab3b84f9ff9cf13511 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Nov 2020 22:48:33 +0100 Subject: [PATCH 0514/2612] global-functions: $DNSIsResolving: use a domain with low ttl --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 030a9f2..06acf9f 100644 --- a/global-functions +++ b/global-functions @@ -221,7 +221,7 @@ :global CharacterReplace; :do { - :resolve ([ $CharacterReplace [ / system clock get time ] ":" "" ] . ".mikrotik.com"); + :resolve "low-ttl.eworm.de"; :return true; } on-error={ :return false; From 24eb2c15a974a4e04f2fe8ab8aff504e1ee15019 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 12 Nov 2020 23:18:51 +0100 Subject: [PATCH 0515/2612] log-forward: do not forward e-mail logs This could cause infinite loop if the mail server does not recover... --- global-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config b/global-config index 01e62c1..d0a34fa 100644 --- a/global-config +++ b/global-config @@ -51,7 +51,7 @@ :global BackupUploadPass "v3ry-s3cr3t"; # This defines a filter on log topics not to be forwarded. -:global LogForwardFilter "(debug|info|script)"; +:global LogForwardFilter "(debug|info|e-mail|script)"; # ... and the same for log message text. :global LogForwardFilterMessage "^\$"; #:global LogForwardFilterMessage "(^\$|message text|...)"; From d2fab050ba02a0d9234663fa6434c364e6049f4c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Nov 2020 20:56:48 +0100 Subject: [PATCH 0516/2612] log-forward: do not forward own e-mail logs Revert the last change, instead just ignore messages that were generated by log-forward, with "Log Forwarding" in subject. --- global-config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-config b/global-config index d0a34fa..09eda44 100644 --- a/global-config +++ b/global-config @@ -51,9 +51,9 @@ :global BackupUploadPass "v3ry-s3cr3t"; # This defines a filter on log topics not to be forwarded. -:global LogForwardFilter "(debug|info|e-mail|script)"; +:global LogForwardFilter "(debug|info|script)"; # ... and the same for log message text. -:global LogForwardFilterMessage "^\$"; +:global LogForwardFilterMessage "^\$|^Error sending e-mail <.* Log Forwarding>:"; #:global LogForwardFilterMessage "(^\$|message text|...)"; # Specify an address to enable auto update to version assumed safe. From d519b70e650498669c569926b5b591dec7ab5944 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Nov 2020 22:02:00 +0100 Subject: [PATCH 0517/2612] global-functions: $CertificateDownload: be more verbose --- global-functions | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 06acf9f..c6439b5 100644 --- a/global-functions +++ b/global-functions @@ -119,7 +119,8 @@ $CertificateNameByCN [ / certificate get $Cert common-name ]; } } on-error={ - $LogPrintExit warning ("Failed imprting certificate!") false; + $LogPrintExit warning ("Failed imprting certificate with " . \ + "CommonName \"" . $CommonName . "\"!") false; :return false; } :return true; From 27b494b13965349e7ac83e6abe921a59f1b5d96c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Nov 2020 22:07:24 +0100 Subject: [PATCH 0518/2612] global-functions: $MailServerIsUp: decrease log severity to info --- global-functions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index c6439b5..08ef0a1 100644 --- a/global-functions +++ b/global-functions @@ -436,13 +436,13 @@ :return true; } else={ :if ($MailServer = "0.0.0.0") do={ - $LogPrintExit warning ("No mail server is configured! Returning gracefully...") false; + $LogPrintExit info ("No mail server is configured! Returning gracefully...") false; :return true; } } :if ([ :len [ / tool netwatch find where comment=$MailServer ] ] = 0) do={ - $LogPrintExit warning ("Adding netwatch entry for mail server.") false; + $LogPrintExit info ("Adding netwatch entry for mail server.") false; :local MailHost $MailServer; :if ([ :typeof [ :toip $MailHost ] ] != "ip" ) do={ :do { From 7b3960a0e1f6cc13219d0021a86ddfbc48faf82b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Nov 2020 22:12:03 +0100 Subject: [PATCH 0519/2612] global-functions: $TimeIsSync: decrease log severity to info --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 08ef0a1..de810cd 100644 --- a/global-functions +++ b/global-functions @@ -906,7 +906,7 @@ :return false; } - $LogPrintExit warning ("No time source configured! Returning gracefully...") false; + $LogPrintExit info ("No time source configured! Returning gracefully...") false; :return true; } From b8efaafe6efe80f6201bb40e779738fc6d3ffb97 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Nov 2020 22:15:23 +0100 Subject: [PATCH 0520/2612] global-functions: $SendTelegram: decrease log severity to info The message is queued, not lost... --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index de810cd..a4a3630 100644 --- a/global-functions +++ b/global-functions @@ -827,7 +827,7 @@ http-data=("chat_id=" . $ChatId . "&disable_notification=" . $Silent . \ "&parse_mode=" . $ParseMode . "&text=" . $Text); } on-error={ - $LogPrintExit warning ("Failed sending telegram notification! Queuing...") false; + $LogPrintExit info ("Failed sending telegram notification! Queuing...") false; :if ([ :typeof $TelegramQueue ] = "nothing") do={ :set TelegramQueue [ :toarray "" ]; From 8b07119f388adc20de9118837e29ed78ff95c675 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Nov 2020 22:17:55 +0100 Subject: [PATCH 0521/2612] check-health: decrease log severity to info --- check-health | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-health b/check-health index fc8f097..7d52204 100644 --- a/check-health +++ b/check-health @@ -67,7 +67,7 @@ :if ($Name ~ "temperature" && \ [ :typeof $Temperature ] = "num") do={ :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ - $LogPrintExit warning ("No threshold given for " . $Name . ", assuming 50C.") false; + $LogPrintExit info ("No threshold given for " . $Name . ", assuming 50C.") false; :set ($CheckHealthTemperature->$Name) 50; } :if ($Temperature > $CheckHealthTemperature->$Name && \ From 19ed080244341601ab71fa2f600343a612df5248 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Nov 2020 22:34:31 +0100 Subject: [PATCH 0522/2612] check-routeros-update: decrease log severity to info --- check-routeros-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-routeros-update b/check-routeros-update index e020153..b8e87d9 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -43,7 +43,7 @@ :local Update [ / system package update get ]; :if ([ :len ($Update->"latest-version") ] = 0) do={ - $LogPrintExit warning "An empty string is not a valid version." true; + $LogPrintExit info "An empty string is not a valid version." true; } :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; From 348cc2e3f395346b15941ff380c47e4675918808 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Nov 2020 22:43:41 +0100 Subject: [PATCH 0523/2612] check-certificates: decrease log severity to info --- check-certificates | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-certificates b/check-certificates index ced2a69..d5c08b9 100644 --- a/check-certificates +++ b/check-certificates @@ -33,7 +33,7 @@ $WaitFullyConnected; :do { :if ([ :len $CertRenewUrl ] = 0) do={ - $LogPrintExit warning ("No CertRenewUrl given.") true; + $LogPrintExit info ("No CertRenewUrl given.") true; } :foreach Type in={ ".pem"; ".p12" } do={ @@ -114,7 +114,7 @@ $WaitFullyConnected; "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ "Expires in: " . [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ]); - $LogPrintExit warning ("The certificate " . ($CertVal->"name") . " " . $State . \ + $LogPrintExit info ("The certificate " . ($CertVal->"name") . " " . $State . \ ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; } } From 966e7b6fd3291c01eb9ab5639c92bc1ea95f8e5d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Nov 2020 22:46:26 +0100 Subject: [PATCH 0524/2612] log-forward: do not exclude topic 'script' We have justified severity for some log message, so do no longer exclude topic 'script'. --- global-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config b/global-config index 09eda44..9bbbc29 100644 --- a/global-config +++ b/global-config @@ -51,7 +51,7 @@ :global BackupUploadPass "v3ry-s3cr3t"; # This defines a filter on log topics not to be forwarded. -:global LogForwardFilter "(debug|info|script)"; +:global LogForwardFilter "(debug|info)"; # ... and the same for log message text. :global LogForwardFilterMessage "^\$|^Error sending e-mail <.* Log Forwarding>:"; #:global LogForwardFilterMessage "(^\$|message text|...)"; From cf5220278de066e0721cb85ebffb5aebbc3cfa86 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 17 Nov 2020 14:22:29 +0100 Subject: [PATCH 0525/2612] netwatch-notify: unbreak custom count --- netwatch-notify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index 61bb348..6c2a18c 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -48,7 +48,7 @@ :set ($Metric->"since") ($HostVal->"since"); $LogPrintExit info ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ $Metric->"count" . " checks.") false; - :if ($Metric->"count" >= [ $IfThenElse ([ :typeof ($HostVal->"count") ] != "nothing") ($HostVal->"count") 5 ] && \ + :if ($Metric->"count" >= [ $IfThenElse ([ :typeof ($HostInfo->"count") ] != "nothing") ($HostInfo->"count") 5 ] && \ $Metric->"notified" != true) do={ $SendNotification ([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); From e1d9b08b9af23a20b612e92b150aded8ee1b1b68 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 17 Nov 2020 21:08:37 +0100 Subject: [PATCH 0526/2612] doc/netwatch-notify: remove timeout from examples --- doc/netwatch-notify.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 3fe1bca..557ae88 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -27,17 +27,17 @@ Configuration The hosts to be checked have to be added to netwatch with specific comment: - / tool netwatch add comment="notify, hostname=example.com" host=[ :resolve "example.com" ] timeout=5s; + / tool netwatch add comment="notify, hostname=example.com" host=[ :resolve "example.com" ]; It is possible to run an up hook command (`up-hook`) or down hook command (`down-hook`) when a notification is triggered. This has to be added in comment: - / tool netwatch add comment="notify, hostname=poe-device, down-hook=/ interface ethernet poe power-cycle en21;" host=10.0.0.20 timeout=5s; + / tool netwatch add comment="notify, hostname=poe-device, down-hook=/ interface ethernet poe power-cycle en21;" host=10.0.0.20; The count threshould (default is 5 checks) is configurable as well: - / tool netwatch add comment="notify, hostname=example.com, count=10" host=104.18.144.11 timeout=5s; + / tool netwatch add comment="notify, hostname=example.com, count=10" host=104.18.144.11; Also notification settings are required for e-mail and telegram. From 6c14412aa936d24a7a6c124b390bbd95fdc66cd7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 17 Nov 2020 15:03:01 +0100 Subject: [PATCH 0527/2612] netwatch-notify: implemented simple dependency model --- doc/netwatch-notify.md | 13 +++++++++++-- netwatch-notify | 8 ++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 557ae88..66c5c75 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -8,8 +8,9 @@ Description This script sends notifications about host UP and DOWN events. In comparison to just netwatch (`/ tool netwatch`) and its `up-script` and `down-script` -this script implements a simple state machine. Host down events are triggered -only if the host is down for several checks to avoid false alerts. +this script implements a simple state machine and dependency model. Host +down events are triggered only if the host is down for several checks and +optional parent host is not down to avoid false alerts. Requirements and installation ----------------------------- @@ -39,6 +40,14 @@ The count threshould (default is 5 checks) is configurable as well: / tool netwatch add comment="notify, hostname=example.com, count=10" host=104.18.144.11; +If the host is behind another checked host add a dependency, this will +suppress notification if the parent host is down: + + / tool netwatch add comment="notify, hostname=gateway" host=93.184.216.1; + / tool netwatch add comment="notify, hostname=example.com, parent=gateway" host=93.184.216.34; + +Note that a configured parent increases the check count threshould by one. + Also notification settings are required for e-mail and telegram. --- diff --git a/netwatch-notify b/netwatch-notify index 6c2a18c..2462e9b 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -48,8 +48,12 @@ :set ($Metric->"since") ($HostVal->"since"); $LogPrintExit info ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ $Metric->"count" . " checks.") false; - :if ($Metric->"count" >= [ $IfThenElse ([ :typeof ($HostInfo->"count") ] != "nothing") ($HostInfo->"count") 5 ] && \ - $Metric->"notified" != true) do={ + :local Count [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; + :local ParentNotified [ $IfThenElse (($NetwatchNotify->($HostInfo->"parent")->"notified") = true) true false ]; + :if ([ :len ($HostInfo->"parent") ] > 0) do={ + :set Count ($Count + 1); + } + :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ $SendNotification ([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :set ($Metric->"notified") true; From d5125b816aeef0f86e48bdf5dbd1dccfe0164c9f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 17 Nov 2020 15:14:27 +0100 Subject: [PATCH 0528/2612] netwatch-notify: be more verbose in logs --- netwatch-notify | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 2462e9b..4c3586c 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -46,13 +46,15 @@ } else={ :set ($Metric->"count") ($Metric->"count" + 1); :set ($Metric->"since") ($HostVal->"since"); - $LogPrintExit info ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ - $Metric->"count" . " checks.") false; :local Count [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; :local ParentNotified [ $IfThenElse (($NetwatchNotify->($HostInfo->"parent")->"notified") = true) true false ]; :if ([ :len ($HostInfo->"parent") ] > 0) do={ :set Count ($Count + 1); } + $LogPrintExit info ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ + $Metric->"count" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ + ($Metric->"notified" = true) ("already notified.") ($Count - $Metric->"count" . " to go.") ] \ + ("parent host " . $HostInfo->"parent" . " is down.") ]) false; :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ $SendNotification ([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); From e7855b4611f754fcde4f5adaff0e1a6006ddaaac Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 17 Nov 2020 21:37:23 +0100 Subject: [PATCH 0529/2612] netwatch-notify: support parents in a chain --- netwatch-notify | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 4c3586c..1cfd4a6 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -42,19 +42,28 @@ } } :set ($Metric->"notified") false; + :set ($Metric->"parent") ($HostInfo->"parent"); :set ($Metric->"since"); } else={ :set ($Metric->"count") ($Metric->"count" + 1); + :set ($Metric->"parent") ($HostInfo->"parent"); :set ($Metric->"since") ($HostVal->"since"); :local Count [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; - :local ParentNotified [ $IfThenElse (($NetwatchNotify->($HostInfo->"parent")->"notified") = true) true false ]; - :if ([ :len ($HostInfo->"parent") ] > 0) do={ + :local Parent ($HostInfo->"parent"); + :if ([ :len $Parent ] > 0) do={ :set Count ($Count + 1); } + :local ParentNotified false; + :while ($ParentNotified = false && [ :len $Parent ] > 0) do={ + :set ParentNotified [ $IfThenElse (($NetwatchNotify->$Parent->"notified") = true) true false ]; + :if ($ParentNotified = false) do={ + :set Parent ($NetwatchNotify->$Parent->"parent"); + } + } $LogPrintExit info ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ $Metric->"count" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ ($Metric->"notified" = true) ("already notified.") ($Count - $Metric->"count" . " to go.") ] \ - ("parent host " . $HostInfo->"parent" . " is down.") ]) false; + ("parent host " . $Parent . " is down.") ]) false; :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ $SendNotification ([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down") \ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); @@ -68,5 +77,6 @@ :set ($NetwatchNotify->$HostName) { "count"=($Metric->"count"); "notified"=($Metric->"notified"); + "parent"=($Metric->"parent"); "since"=($Metric->"since") }; } From 23923619dd0d92e4af65060e7b51b058fc1842aa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 17 Nov 2020 22:02:41 +0100 Subject: [PATCH 0530/2612] netwatch-notify: increase count for every parent in chain --- doc/netwatch-notify.md | 3 ++- netwatch-notify | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 66c5c75..11371ff 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -46,7 +46,8 @@ suppress notification if the parent host is down: / tool netwatch add comment="notify, hostname=gateway" host=93.184.216.1; / tool netwatch add comment="notify, hostname=example.com, parent=gateway" host=93.184.216.34; -Note that a configured parent increases the check count threshould by one. +Note that every configured parent in a chain increases the check count +threshould by one. Also notification settings are required for e-mail and telegram. diff --git a/netwatch-notify b/netwatch-notify index 1cfd4a6..9a12c5a 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -50,9 +50,11 @@ :set ($Metric->"since") ($HostVal->"since"); :local Count [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; :local Parent ($HostInfo->"parent"); - :if ([ :len $Parent ] > 0) do={ + :while ([ :len $Parent ] > 0) do={ :set Count ($Count + 1); + :set Parent ($NetwatchNotify->$Parent->"parent"); } + :set Parent ($HostInfo->"parent"); :local ParentNotified false; :while ($ParentNotified = false && [ :len $Parent ] > 0) do={ :set ParentNotified [ $IfThenElse (($NetwatchNotify->$Parent->"notified") = true) true false ]; From 62ef70e5dd0da2eee841359b8aa0305088880e58 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 17 Nov 2020 15:03:01 +0100 Subject: [PATCH 0531/2612] netwatch-notify: notify about changes --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 9bbbc29..591bdda 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 36; +:global GlobalConfigVersion 37; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 2777519..a0c6361 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 36; +:global GlobalConfigVersion 37; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 85529eb..5c400a5 100644 --- a/global-config.changes +++ b/global-config.changes @@ -40,4 +40,5 @@ 34="Introduced script 'ospf-to-leds' to visualize OSPF instance state via LEDs."; 35="Implemented visual feedback for 'mode-button' with configurable LED."; 36="Added support for installing updates automatically if seen in neighbor list."; + 37="Implemented simple dependency model in 'netwatch-notify'."; }; diff --git a/global-functions b/global-functions index a4a3630..b0b27c2 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 36; +:global ExpectedConfigVersion 37; # global variables not to be changed by user :global GlobalFunctionsReady false; From 7adfd1b6703eeec91e829e386a65a60ec77e9c90 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 19 Nov 2020 16:14:25 +0100 Subject: [PATCH 0532/2612] check-health: properly handle voltage value below one Before this produced division by zero... --- check-health | 3 +++ 1 file changed, 3 insertions(+) diff --git a/check-health b/check-health index 7d52204..d1b45d5 100644 --- a/check-health +++ b/check-health @@ -19,6 +19,9 @@ :local FormatVoltage do={ :local Voltage [ :tonum $1 ]; + :if ($Voltage < 10) do={ + :return ("0." . $Voltage . "V"); + } :return (($Voltage / 10) . "." . ($Voltage % ($Voltage / 10 * 10)) . "V"); } From 88f9948c722ad003864470f85abf85c3e419e3c5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 19 Nov 2020 20:24:09 +0100 Subject: [PATCH 0533/2612] check-health: handle formatting by picking from string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mathematical way is more elegant, but just picking the char from string is shorter. 😜 --- check-health | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/check-health b/check-health index d1b45d5..8dfbc16 100644 --- a/check-health +++ b/check-health @@ -19,10 +19,7 @@ :local FormatVoltage do={ :local Voltage [ :tonum $1 ]; - :if ($Voltage < 10) do={ - :return ("0." . $Voltage . "V"); - } - :return (($Voltage / 10) . "." . ($Voltage % ($Voltage / 10 * 10)) . "V"); + :return (($Voltage / 10) . "." . [ :pick $Voltage ([ :len $Voltage ] - 1) ] . "V"); } :local CheckHealthCurrent [ / system health get ]; From b97d5308b11297151f76b4410394077b5829f242 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 19 Nov 2020 21:23:27 +0100 Subject: [PATCH 0534/2612] check-health: guard against temperature spikes Looks like devices out there suffer sensor issue or bug where temperature value spikes and drops immediately: https://forum.mikrotik.com/viewtopic.php?t=111030 https://forum.mikrotik.com/viewtopic.php?t=111109 https://forum.mikrotik.com/viewtopic.php?t=151242 ... and possibly more. Let's ignore these spikes, but at the same time increase the current value to bring it into line - in case it's real. --- check-health | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/check-health b/check-health index 8dfbc16..c30eee1 100644 --- a/check-health +++ b/check-health @@ -70,6 +70,12 @@ $LogPrintExit info ("No threshold given for " . $Name . ", assuming 50C.") false; :set ($CheckHealthTemperature->$Name) 50; } + :if ($Temperature > $CheckHealthLast->$Name + 20) do={ + $LogPrintExit info ("The " . $Name . " spikes from " . $CheckHealthLast->$Name . \ + "\C2\B0" . "C to " . $Temperature . "\C2\B0" . "C, ignoring.") false; + :set Temperature ($CheckHealthLast->$Name); + :set ($CheckHealthCurrent->$Name) ($CheckHealthLast->$Name + 3); + } :if ($Temperature > $CheckHealthTemperature->$Name && \ $CheckHealthTemperatureNotified->$Name != true) do={ $SendNotification ([ $SymbolForNotification "fire" ] . "Health warning: " . $Name) \ From 13f7ba11da598e903b6d4835f34c89a56a26ec45 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Nov 2020 12:01:15 +0100 Subject: [PATCH 0535/2612] check-health: do not write unicode to log --- check-health | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-health b/check-health index c30eee1..1e7c1b4 100644 --- a/check-health +++ b/check-health @@ -72,7 +72,7 @@ } :if ($Temperature > $CheckHealthLast->$Name + 20) do={ $LogPrintExit info ("The " . $Name . " spikes from " . $CheckHealthLast->$Name . \ - "\C2\B0" . "C to " . $Temperature . "\C2\B0" . "C, ignoring.") false; + "C to " . $Temperature . "C, ignoring.") false; :set Temperature ($CheckHealthLast->$Name); :set ($CheckHealthCurrent->$Name) ($CheckHealthLast->$Name + 3); } From af50ed590923af80ad4e996a199a13dd1ca90e5e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 21 Nov 2020 21:03:56 +0100 Subject: [PATCH 0536/2612] check-health: use second measure against temperature spikes The old spike detection was still prone to false alerts. Let's do a second measurement and ignore on difference. This results in more measurements being ignored, but temperature is changing slowly only and it should not hurt. --- check-health | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/check-health b/check-health index 1e7c1b4..bb75fa0 100644 --- a/check-health +++ b/check-health @@ -70,11 +70,10 @@ $LogPrintExit info ("No threshold given for " . $Name . ", assuming 50C.") false; :set ($CheckHealthTemperature->$Name) 50; } - :if ($Temperature > $CheckHealthLast->$Name + 20) do={ - $LogPrintExit info ("The " . $Name . " spikes from " . $CheckHealthLast->$Name . \ - "C to " . $Temperature . "C, ignoring.") false; + :if ($Temperature != [ / system health get $Name ]) do={ + $LogPrintExit debug ("The second measurement for " . $Name . " differs, ignoring.") false; :set Temperature ($CheckHealthLast->$Name); - :set ($CheckHealthCurrent->$Name) ($CheckHealthLast->$Name + 3); + :set ($CheckHealthCurrent->$Name) $Temperature; } :if ($Temperature > $CheckHealthTemperature->$Name && \ $CheckHealthTemperatureNotified->$Name != true) do={ From 0545fbd8995551650caf54686165fb050a3d1ea8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 24 Nov 2020 13:53:15 +0100 Subject: [PATCH 0537/2612] check-health: re-measure until we have a valid value --- check-health | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/check-health b/check-health index bb75fa0..bc7e064 100644 --- a/check-health +++ b/check-health @@ -70,10 +70,10 @@ $LogPrintExit info ("No threshold given for " . $Name . ", assuming 50C.") false; :set ($CheckHealthTemperature->$Name) 50; } - :if ($Temperature != [ / system health get $Name ]) do={ - $LogPrintExit debug ("The second measurement for " . $Name . " differs, ignoring.") false; - :set Temperature ($CheckHealthLast->$Name); - :set ($CheckHealthCurrent->$Name) $Temperature; + :local Validate [ / system health get $Name ]; + :while ($Temperature != $Validate) do={ + :set Temperature $Validate; + :set Validate [ / system health get $Name ]; } :if ($Temperature > $CheckHealthTemperature->$Name && \ $CheckHealthTemperatureNotified->$Name != true) do={ From 056d273c112ca2f2c767f4aa48fd39ebb4517531 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 23 Nov 2020 13:45:00 +0100 Subject: [PATCH 0538/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 46b798b..6cf5ade 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -21,6 +21,7 @@ Add yourself to the list, * Linux-Schmie.de Michael Gisbers * Christoph Boss (@Kampfwurst) * Klaus Michael RÃŧbsam +* Marek ÄŒÃĄbÃĄk --- [◀ Go back to main README](README.md) From 6b19cf2578fb840d286e6539fa82acbacbf6cca5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Nov 2020 10:32:17 +0100 Subject: [PATCH 0539/2612] log-forward: add parenthesis in filter expression Looks like this works without parenthesis in RouterOS, let's add it anyway. --- global-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config b/global-config index 591bdda..b681163 100644 --- a/global-config +++ b/global-config @@ -53,7 +53,7 @@ # This defines a filter on log topics not to be forwarded. :global LogForwardFilter "(debug|info)"; # ... and the same for log message text. -:global LogForwardFilterMessage "^\$|^Error sending e-mail <.* Log Forwarding>:"; +:global LogForwardFilterMessage "(^\$|^Error sending e-mail <.* Log Forwarding>:)"; #:global LogForwardFilterMessage "(^\$|message text|...)"; # Specify an address to enable auto update to version assumed safe. From c93d1c4944fff937598ec2825869a02030362a9a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Nov 2020 17:32:12 +0100 Subject: [PATCH 0540/2612] global-functions: $SendTelegram: disable web page preview --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index b0b27c2..a058d69 100644 --- a/global-functions +++ b/global-functions @@ -825,7 +825,7 @@ / tool fetch check-certificate=yes-without-crl output=none http-method=post \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ http-data=("chat_id=" . $ChatId . "&disable_notification=" . $Silent . \ - "&parse_mode=" . $ParseMode . "&text=" . $Text); + "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text); } on-error={ $LogPrintExit info ("Failed sending telegram notification! Queuing...") false; From 54e164e542bcd5b220ed3cbb3ad866d53f052efe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Nov 2020 22:02:39 +0100 Subject: [PATCH 0541/2612] global-functions: $SendTelegram: try to get the line breaks right --- global-functions | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index a058d69..ee13de8 100644 --- a/global-functions +++ b/global-functions @@ -776,9 +776,10 @@ :global TelegramFixedWidthFont; :global CharacterReplace; + :global IfThenElse; :if ($TelegramFixedWidthFont != true) do={ - :return $1; + :return ($1 . [ $IfThenElse ($2 = "fixed") "\n" "" ]); } :local Return $1; @@ -810,7 +811,7 @@ :local Text ("[" . $Identity . "] " . $Subject . "\n\n" . $Message); :if ([ :len $Text ] > 3968) do={ :set Text ([ $EscapeMD ([ :pick $Text 0 3840 ] . "...") "fixed" ] . \ - "\n\n" . [ $SymbolForNotification "scissors" ] . \ + "\n" . [ $SymbolForNotification "scissors" ] . \ [ $EscapeMD "The Telegram message was too long and has been truncated!" "hint" ]); } else={ :set Text [ $EscapeMD $Text "fixed" ]; @@ -832,7 +833,7 @@ :if ([ :typeof $TelegramQueue ] = "nothing") do={ :set TelegramQueue [ :toarray "" ]; } - :set Text ($Text . [ $UrlEncode ("\n\n" . [ $SymbolForNotification "alarm-clock" ] . \ + :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ " " . [ / system clock get time ] . " and may be obsolete.") "hint" ]) ]); :set ($TelegramQueue->[ :len $TelegramQueue ]) { From d7725540f884bf7486274f0e002cf2ba1b41306e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Nov 2020 22:06:03 +0100 Subject: [PATCH 0542/2612] global-functions: $SendTelegram: change internal wording --- global-functions | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/global-functions b/global-functions index ee13de8..9c5e76e 100644 --- a/global-functions +++ b/global-functions @@ -779,12 +779,12 @@ :global IfThenElse; :if ($TelegramFixedWidthFont != true) do={ - :return ($1 . [ $IfThenElse ($2 = "fixed") "\n" "" ]); + :return ($1 . [ $IfThenElse ($2 = "body") "\n" "" ]); } :local Return $1; :local Chars { - "fixed"={ "\\"; "`" }; + "body"={ "\\"; "`" }; "hint"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">"; "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; } @@ -792,7 +792,7 @@ :set Return [ $CharacterReplace $Return $Char ("\\" . $Char) ]; } - :if ($2 = "fixed") do={ + :if ($2 = "body") do={ :return ("```\n" . $Return . "\n```"); } @@ -810,11 +810,11 @@ :local Text ("[" . $Identity . "] " . $Subject . "\n\n" . $Message); :if ([ :len $Text ] > 3968) do={ - :set Text ([ $EscapeMD ([ :pick $Text 0 3840 ] . "...") "fixed" ] . \ + :set Text ([ $EscapeMD ([ :pick $Text 0 3840 ] . "...") "body" ] . \ "\n" . [ $SymbolForNotification "scissors" ] . \ [ $EscapeMD "The Telegram message was too long and has been truncated!" "hint" ]); } else={ - :set Text [ $EscapeMD $Text "fixed" ]; + :set Text [ $EscapeMD $Text "body" ]; } :set Text [ $UrlEncode $Text ]; :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; From 7e0558e85dcf06161d0b9c554688d4fc4d1b3101 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Nov 2020 22:21:28 +0100 Subject: [PATCH 0543/2612] global-functions: $SendTelegram: prepare to add clickable link Formatting with fixed width font stopped links from being clickable. --- global-functions | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 9c5e76e..384f438 100644 --- a/global-functions +++ b/global-functions @@ -756,6 +756,7 @@ :set SendTelegram do={ :local Subject [ :tostr $1 ]; :local Message [ :tostr $2 ]; + :local Link; :local Silent [ :tostr $3 ]; :global Identity; @@ -808,14 +809,18 @@ :return false; } + :local LenLink [ :len $Link ]; :local Text ("[" . $Identity . "] " . $Subject . "\n\n" . $Message); - :if ([ :len $Text ] > 3968) do={ - :set Text ([ $EscapeMD ([ :pick $Text 0 3840 ] . "...") "body" ] . \ + :if ([ :len $Text ] > (3968 - $LenLink)) do={ + :set Text ([ $EscapeMD ([ :pick $Text 0 (3840 - $LenLink) ] . "...") "body" ] . \ "\n" . [ $SymbolForNotification "scissors" ] . \ [ $EscapeMD "The Telegram message was too long and has been truncated!" "hint" ]); } else={ :set Text [ $EscapeMD $Text "body" ]; } + :if ($LenLink > 0) do={ + :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD $Link "hint" ]); + } :set Text [ $UrlEncode $Text ]; :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; @@ -855,6 +860,7 @@ "floppy-disk"="\F0\9F\92\BE"; "high-voltage-sign"="\E2\9A\A1"; "incoming-envelope"="\F0\9F\93\A8"; + "link"="\F0\9F\94\97"; "lock-with-ink-pen"="\F0\9F\94\8F"; "mobile-phone"="\F0\9F\93\B1"; "pushpin"="\F0\9F\93\8C"; From b078ce2f0f8544936274506e55ee4ecc5c5425cb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Nov 2020 22:24:56 +0100 Subject: [PATCH 0544/2612] global-functions: $SendTelegram: split off & move down truncation message --- global-functions | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 384f438..ac7cec1 100644 --- a/global-functions +++ b/global-functions @@ -809,18 +809,22 @@ :return false; } + :local Truncated false; :local LenLink [ :len $Link ]; :local Text ("[" . $Identity . "] " . $Subject . "\n\n" . $Message); :if ([ :len $Text ] > (3968 - $LenLink)) do={ - :set Text ([ $EscapeMD ([ :pick $Text 0 (3840 - $LenLink) ] . "...") "body" ] . \ - "\n" . [ $SymbolForNotification "scissors" ] . \ - [ $EscapeMD "The Telegram message was too long and has been truncated!" "hint" ]); + :set Text [ $EscapeMD ([ :pick $Text 0 (3840 - $LenLink) ] . "...") "body" ]; + :set Truncated true; } else={ :set Text [ $EscapeMD $Text "body" ]; } :if ($LenLink > 0) do={ :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD $Link "hint" ]); } + :if ($Truncated = true) do={ + :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ + [ $EscapeMD "The Telegram message was too long and has been truncated!" "hint" ]); + } :set Text [ $UrlEncode $Text ]; :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; From 46866e2ff232c86b62419810667a3a394a2b4b65 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Nov 2020 22:34:08 +0100 Subject: [PATCH 0545/2612] global-functions: $SendEMail: handle signature with $IfThenElse --- global-functions | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/global-functions b/global-functions index ac7cec1..be04150 100644 --- a/global-functions +++ b/global-functions @@ -719,6 +719,7 @@ :global EmailGeneralCc; :global LogPrintExit; + :global IfThenElse; :if ([ :len $EmailGeneralTo ] = 0) do={ :return false; @@ -726,12 +727,11 @@ :do { :local Signature [ / system note get note ]; - :if ([ :len $Signature ] > 0) do={ - :set Signature ("\n-- \n" . $Signature); - } / tool e-mail send to=$EmailGeneralTo cc=$EmailGeneralCc \ subject=("[" . $Identity . "] " . $Subject) \ - body=($Message . $Signature) file=$Attach; + body=($Message . \ + [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]) \ + file=$Attach; } on-error={ $LogPrintExit warning ("Failed sending notification mail!") false; } From d09baddac30b8221ed34db41b9f0536daf83a084 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Nov 2020 22:36:14 +0100 Subject: [PATCH 0546/2612] global-functions: $SendEMail: prepare to add link For e-mail just in plain text... --- global-functions | 2 ++ 1 file changed, 2 insertions(+) diff --git a/global-functions b/global-functions index be04150..de62a59 100644 --- a/global-functions +++ b/global-functions @@ -712,6 +712,7 @@ :set SendEMail do={ :local Subject [ :tostr $1 ]; :local Message [ :tostr $2 ]; + :local Link; :local Attach [ :tostr $3 ]; :global Identity; @@ -730,6 +731,7 @@ / tool e-mail send to=$EmailGeneralTo cc=$EmailGeneralCc \ subject=("[" . $Identity . "] " . $Subject) \ body=($Message . \ + [ $IfThenElse ([ :len $Link ] > 0) ("\n\n" . $Link) "" ] . \ [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]) \ file=$Attach; } on-error={ From ca4e25283fa7a3c72d4b678cd0e5781f71cfed7e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Nov 2020 23:02:15 +0100 Subject: [PATCH 0547/2612] global-functions: clickable links in telegram notifications --- check-certificates | 2 +- check-lte-firmware-upgrade | 2 +- check-routeros-update | 15 ++++++--------- cloud-backup | 2 +- daily-psk.capsman | 4 ++-- daily-psk.local | 4 ++-- daily-psk.template | 4 ++-- global-functions | 24 +++++++++++++----------- upload-backup | 2 +- 9 files changed, 29 insertions(+), 30 deletions(-) diff --git a/check-certificates b/check-certificates index d5c08b9..f3a8e99 100644 --- a/check-certificates +++ b/check-certificates @@ -91,7 +91,7 @@ $WaitFullyConnected; "Fingerprint: " . ($CertNewVal->"fingerprint") . "\n" . \ "Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ - "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]) "" "true"; + "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]) "" "" "true"; $LogPrintExit info ("The certificate " . ($CertVal->"name") . " has been renewed.") false; } on-error={ $LogPrintExit debug ("Could not renew certificate " . ($CertVal->"name") . ".") false; diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 0e4cb3d..08b27ce 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -30,7 +30,7 @@ "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ "Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \ "Installed: " . ($Firmware->"installed") . "\n" . \ - "Available: " . ($Firmware->"latest")) "" "true"; + "Available: " . ($Firmware->"latest")) "" "" "true"; :set SentLteFirmwareUpgradeNotification ($Firmware->"latest"); } } diff --git a/check-routeros-update b/check-routeros-update index b8e87d9..a4dfe9d 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -48,13 +48,14 @@ :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; +:local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); :if ($NumInstalled < $NumLatest) do={ :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ $LogPrintExit info ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ ("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ - ", updating on " . $Identity . "...") "" "true"; + ", updating on " . $Identity . "...") $Link "" "true"; $DoUpdate; } @@ -63,7 +64,7 @@ $LogPrintExit info ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ ("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \ - ", updating on " . $Identity . "...") "" "true"; + ", updating on " . $Identity . "...") $Link "" "true"; $DoUpdate; } @@ -80,7 +81,7 @@ $LogPrintExit info ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ ("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ - ", updating on " . $Identity . "...") "" "true"; + ", updating on " . $Identity . "...") $Link "" "true"; $DoUpdate; } } @@ -102,9 +103,7 @@ $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ ("A new RouterOS version " . ($Update->"latest-version") . \ " is available for " . $Identity . ".\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - "https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree") \ - "" "true"; + [ $DeviceInfo ]) $Link "" "true"; :set SentRouterosUpdateNotification ($Update->"latest-version"); } @@ -117,9 +116,7 @@ $SendNotification ([ $SymbolForNotification "warning-sign" ] . "RouterOS version") \ ("A different RouterOS version " . ($Update->"latest-version") . \ " is available for " . $Identity . ", but it is a downgrade.\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - "https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree") \ - "" "true"; + [ $DeviceInfo ]) $Link "" "true"; $LogPrintExit info ("A different RouterOS version " . ($Update->"latest-version") . \ " is available for downgrade.") false; :set SentRouterosUpdateNotification ($Update->"latest-version"); diff --git a/cloud-backup b/cloud-backup index e1386f0..46777b9 100644 --- a/cloud-backup +++ b/cloud-backup @@ -32,7 +32,7 @@ [ $DeviceInfo ] . "\n\n" . \ "Name: " . $Cloud->"name" . "\n" . \ "Size: " . $Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)\n" . \ - "Download key: " . $Cloud->"secret-download-key") "" "true"; + "Download key: " . $Cloud->"secret-download-key") "" "" "true"; } on-error={ $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Cloud backup failed") \ ("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]); diff --git a/daily-psk.capsman b/daily-psk.capsman index 33208f5..2f7e8f2 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -93,8 +93,8 @@ $WaitFullyConnected; "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ "Date: " . $Date . "\n\n" . \ - "A client device specific rule must not exist!\n\n" . \ - $Url) $Attach; + "A client device specific rule must not exist!") \ + $Url $Attach; } } } diff --git a/daily-psk.local b/daily-psk.local index 13a878e..d51d5f6 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -93,8 +93,8 @@ $WaitFullyConnected; "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ "Date: " . $Date . "\n\n" . \ - "A client device specific rule must not exist!\n\n" . \ - $Url) $Attach; + "A client device specific rule must not exist!") \ + $Url $Attach; } } } diff --git a/daily-psk.template b/daily-psk.template index fd5bd2b..acc8edd 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -99,8 +99,8 @@ $WaitFullyConnected; "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ "Date: " . $Date . "\n\n" . \ - "A client device specific rule must not exist!\n\n" . \ - $Url) $Attach; + "A client device specific rule must not exist!") \ + $Url $Attach; } } } diff --git a/global-functions b/global-functions index de62a59..f42d8f9 100644 --- a/global-functions +++ b/global-functions @@ -682,17 +682,18 @@ "\n\nChanges are not available."); } + :local Link; :if ($IDonate != true) do={ :set NotificationMessage ($NotificationMessage . \ "\n\n==== donation hint ====\n" . \ "This project is developed in private spare time and usage is " . \ "free of charge for you. If you like the scripts and think this is " . \ - "of value for you or your business please consider a donation:\n" . \ - "https://git.eworm.de/cgit/routeros-scripts/about/#donate"); + "of value for you or your business please consider a donation."); + :set Link "https://git.eworm.de/cgit/routeros-scripts/about/#donate"; } $SendNotification ([ $SymbolForNotification "pushpin" ] . "News and configuration changes") \ - $NotificationMessage; + $NotificationMessage $Link; :set SentConfigChangesNotification $ExpectedConfigVersion; } } @@ -712,8 +713,8 @@ :set SendEMail do={ :local Subject [ :tostr $1 ]; :local Message [ :tostr $2 ]; - :local Link; - :local Attach [ :tostr $3 ]; + :local Link [ :tostr $3 ]; + :local Attach [ :tostr $4 ]; :global Identity; :global EmailGeneralTo; @@ -744,22 +745,23 @@ :set SendNotification do={ :local Subject [ :tostr $1 ]; :local Message [ :tostr $2 ]; - :local Attach [ :tostr $3 ]; - :local Silent [ :tostr $4 ]; + :local Link [ :tostr $3 ]; + :local Attach [ :tostr $4 ]; + :local Silent [ :tostr $5 ]; :global SendEMail; :global SendTelegram; - $SendEMail $Subject $Message $Attach; - $SendTelegram $Subject $Message $Silent; + $SendEMail $Subject $Message $Link $Attach; + $SendTelegram $Subject $Message $Link $Silent; } # send notification via telegram :set SendTelegram do={ :local Subject [ :tostr $1 ]; :local Message [ :tostr $2 ]; - :local Link; - :local Silent [ :tostr $3 ]; + :local Link [ :tostr $3 ]; + :local Silent [ :tostr $4 ]; :global Identity; :global TelegramChatId; diff --git a/upload-backup b/upload-backup index 27eab0c..5d4dd8e 100644 --- a/upload-backup +++ b/upload-backup @@ -72,7 +72,7 @@ $SendNotification [ $IfThenElse ($Failed > 0) \ ("Backup and config export upload for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ - "Config file: " . $ConfigFile) "" "true"; + "Config file: " . $ConfigFile) "" "" "true"; :if ($Failed = 1) do={ :error "An error occured!"; From e2e831dbf94aed1fd628fbef6758449bbf4bca6b Mon Sep 17 00:00:00 2001 From: Michael Gisbers Date: Sun, 29 Nov 2020 22:23:25 +0100 Subject: [PATCH 0548/2612] global-functions: $CertificateDownload: fix typo Signed-off-by: Michael Gisbers Signed-off-by: Christian Hesse --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index f42d8f9..5e4ef8b 100644 --- a/global-functions +++ b/global-functions @@ -119,7 +119,7 @@ $CertificateNameByCN [ / certificate get $Cert common-name ]; } } on-error={ - $LogPrintExit warning ("Failed imprting certificate with " . \ + $LogPrintExit warning ("Failed importing certificate with " . \ "CommonName \"" . $CommonName . "\"!") false; :return false; } From cef0e8c0791298e00cf8c4e359fdb3628d8c4ff5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 30 Nov 2020 22:37:26 +0100 Subject: [PATCH 0549/2612] global-functions: $SendTelegram: give amount of truncated text --- global-functions | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 5e4ef8b..5e643d9 100644 --- a/global-functions +++ b/global-functions @@ -816,7 +816,8 @@ :local Truncated false; :local LenLink [ :len $Link ]; :local Text ("[" . $Identity . "] " . $Subject . "\n\n" . $Message); - :if ([ :len $Text ] > (3968 - $LenLink)) do={ + :local LenText [ :len $Text ]; + :if ($LenText > (3968 - $LenLink)) do={ :set Text [ $EscapeMD ([ :pick $Text 0 (3840 - $LenLink) ] . "...") "body" ]; :set Truncated true; } else={ @@ -827,7 +828,8 @@ } :if ($Truncated = true) do={ :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ - [ $EscapeMD "The Telegram message was too long and has been truncated!" "hint" ]); + [ $EscapeMD ("The Telegram message was too long and has been truncated, cut off " . \ + (($LenText - [ :len $Text ]) * 100 / $LenText) . "%!") "hint" ]); } :set Text [ $UrlEncode $Text ]; :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; From adf35f3b16d0630785d5aa00420c03da6d5ba7ea Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 10 Dec 2020 09:37:37 +0100 Subject: [PATCH 0550/2612] global-functions: $FlushTelegramQueue: do not fail if run without scheduler --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 5e643d9..fadd2c6 100644 --- a/global-functions +++ b/global-functions @@ -308,7 +308,7 @@ } :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ - / system scheduler remove FlushTelegramQueue; + / system scheduler remove [ find where name="FlushTelegramQueue" ]; :set TelegramQueue; } } From 158c27e293eccc07a235883443277a15abee9b64 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 10 Dec 2020 09:53:43 +0100 Subject: [PATCH 0551/2612] global-functions: $FlushTelegramQueue: log warning on empty queue... ... if scheduler exists. --- global-functions | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/global-functions b/global-functions index fadd2c6..0530564 100644 --- a/global-functions +++ b/global-functions @@ -291,6 +291,11 @@ :local AllDone true; :local QueueLen [ :len $TelegramQueue ]; + + :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] > 0 && $QueueLen = 0) do={ + $LogPrintExit warning ("Flushing Telegram messages from scheduler, but queue is empty.") false; + } + :foreach Id,Message in=$TelegramQueue do={ :if ([ :typeof $Message ] = "array" ) do={ :do { From 16d3709030dc14451928a45e948706023cbd6455 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 14 Dec 2020 23:39:50 +0100 Subject: [PATCH 0552/2612] log-forward: add 'if any' in log message --- log-forward | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log-forward b/log-forward index fdabbf8..831ffe1 100644 --- a/log-forward +++ b/log-forward @@ -28,7 +28,7 @@ $ScriptLock "log-forward"; :if ($LogForwardRateLimit > 30) do={ :set LogForwardRateLimit ($LogForwardRateLimit - 1); - $LogPrintExit info ("Rate limit in action, not forwarding logs!") true; + $LogPrintExit info ("Rate limit in action, not forwarding logs, if any!") true; } $WaitFullyConnected; From 50199a57a002320f286f93674781dde089bd07b9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 17 Dec 2020 21:58:53 +0100 Subject: [PATCH 0553/2612] certs: add new Let's Encrypt certificates https://letsencrypt.org/certificates/ --- certs/E1.pem | 31 ++++++++++++++++++++ certs/R3.pem | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 certs/E1.pem create mode 100644 certs/R3.pem diff --git a/certs/E1.pem b/certs/E1.pem new file mode 100644 index 0000000..d33bedd --- /dev/null +++ b/certs/E1.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIICxjCCAk2gAwIBAgIRALO93/inhFu86QOgQTWzSkUwCgYIKoZIzj0EAwMwTzEL +MAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNo +IEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDIwHhcNMjAwOTA0MDAwMDAwWhcN +MjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3MgRW5j +cnlwdDELMAkGA1UEAxMCRTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQkXC2iKv0c +S6Zdl3MnMayyoGli72XoprDwrEuf/xwLcA/TmC9N/A8AmzfwdAVXMpcuBe8qQyWj ++240JxP2T35p0wKZXuskR5LBJJvmsSGPwSSB/GjMH2m6WPUZIvd0xhajggEIMIIB +BDAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB +MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFFrz7Sv8NsI3eblSMOpUb89V +yy6sMB8GA1UdIwQYMBaAFHxClq7eS0g7+pL4nozPbYupcjeVMDIGCCsGAQUFBwEB +BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gyLmkubGVuY3Iub3JnLzAnBgNVHR8E +IDAeMBygGqAYhhZodHRwOi8veDIuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYG +Z4EMAQIBMA0GCysGAQQBgt8TAQEBMAoGCCqGSM49BAMDA2cAMGQCMHt01VITjWH+ +Dbo/AwCd89eYhNlXLr3pD5xcSAQh8suzYHKOl9YST8pE9kLJ03uGqQIwWrGxtO3q +YJkgsTgDyj2gJrjubi1K9sZmHzOa25JK1fUpE8ZwYii6I4zPPS/Lgul/ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- diff --git a/certs/R3.pem b/certs/R3.pem new file mode 100644 index 0000000..933f1d9 --- /dev/null +++ b/certs/R3.pem @@ -0,0 +1,81 @@ +-----BEGIN CERTIFICATE----- +MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw +WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP +R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx +sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm +NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg +Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG +/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB +Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA +FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw +AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw +Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB +gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W +PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl +ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz +CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm +lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 +avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 +yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O +yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids +hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ +HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv +MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX +nLRbwHOoq7hHwg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- From 9f6b877aef96b95a839a9dbcb18b221352c0d37d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 17 Dec 2020 22:00:13 +0100 Subject: [PATCH 0554/2612] README: also import Let's Encrypt certificate "R3" --- README.md | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 9aa0bb8..7856935 100644 --- a/README.md +++ b/README.md @@ -48,36 +48,51 @@ download the certificates. If you intend to download the scripts from a different location (for example from github.com) install the corresponding certificate chain. - [admin@MikroTik] > / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt.pem" + [admin@MikroTik] > / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem" status: finished - downloaded: 3KiBC-z pause] - total: 3KiB + downloaded: 4KiBC-z pause] + total: 4KiB + duration: 1s + + [admin@MikroTik] > / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt-X3.pem" + status: finished + downloaded: 5KiBC-z pause] + total: 5KiB duration: 1s Note that the commands above do *not* verify server certificate, so if you want to be safe download with your workstations's browser and transfer the files to your MikroTik device. -* [ISRG Root X1](https://letsencrypt.org/certs/isrgrootx1.pem.txt) -* [Let's Encrypt Authority X3](https://letsencrypt.org/certs/letsencryptauthorityx3.pem.txt) +* [ISRG Root X1](https://letsencrypt.org/certs/isrgrootx1.pem) +* [Let's Encrypt Authority X3](https://letsencrypt.org/certs/letsencryptauthorityx3.pem) +* Let's Encrypt [R3](https://letsencrypt.org/certs/lets-encrypt-r3.pem) Then we import the certificates. - [admin@MikroTik] > / certificate import file-name=letsencrypt.pem passphrase="" + [admin@MikroTik] > / certificate import file-name=letsencrypt-R3.pem passphrase="" certificates-imported: 3 private-keys-imported: 0 files-imported: 1 decryption-failures: 0 keys-with-no-certificate: 0 -For basic verification we rename the certifiactes and print their count. Make -sure the certificate count is **three**. + [admin@MikroTik] > / certificate import file-name=letsencrypt-X3.pem passphrase="" + certificates-imported: 1 + private-keys-imported: 0 + files-imported: 1 + decryption-failures: 0 + keys-with-no-certificate: 0 +For basic verification we rename the certifiactes and print their count. Make +sure the certificate count is **four**. + + [admin@MikroTik] > / certificate set name="R3" [ find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" ] [admin@MikroTik] > / certificate set name="ISRG-Root-X1" [ find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ] [admin@MikroTik] > / certificate set name="Let-s-Encrypt-Authority-X3" [ find where fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" ] [admin@MikroTik] > / certificate set name="DST-Root-CA-X3" [ find where fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] - [admin@MikroTik] > / certificate print count-only where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" - 3 + [admin@MikroTik] > / certificate print count-only where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" + 4 Always make sure there are no certificates installed you do not know or want! From c51a630a21b601695ec334b7fa22ffe791a94a25 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 17 Dec 2020 22:01:01 +0100 Subject: [PATCH 0555/2612] INITIAL-COMMANDS: also import Let's Encrypt certificate "R3" --- INITIAL-COMMANDS.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 6c167ef..bf26ff1 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -7,13 +7,16 @@ These command are inteneded for initial setup. If you are not aware of the procedure please follow [the long way in detail](README.md#the-long-way-in-detail). { - / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt.pem"; + / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem"; + / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt-X3.pem"; :delay 1s; - / certificate import file-name=letsencrypt.pem passphrase=""; - :if ([ :len [ / certificate find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] ] != 3) do={ + / certificate import file-name=letsencrypt-R3.pem passphrase=""; + / certificate import file-name=letsencrypt-X3.pem passphrase=""; + :if ([ :len [ / certificate find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] ] != 4) do={ :error "Something is wrong with your certificates!"; } - / file remove "letsencrypt.pem"; + / file remove "letsencrypt-R3.pem"; + / file remove "letsencrypt-X3.pem"; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } @@ -21,6 +24,7 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai / system script { run global-config; run global-config-overlay; run global-functions; } / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }"; :global CertificateNameByCN; + $CertificateNameByCN "R3"; $CertificateNameByCN "ISRG Root X1"; $CertificateNameByCN "Let's Encrypt Authority X3"; $CertificateNameByCN "DST Root CA X3"; From 62598b66531f7fe794300a298ee09849b317edab Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 17 Dec 2020 22:47:12 +0100 Subject: [PATCH 0556/2612] import Let's Encrypt certificate "R3" --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 6 ++++++ global-functions | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index b681163..6c94b1b 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 37; +:global GlobalConfigVersion 38; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index a0c6361..46da208 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 37; +:global GlobalConfigVersion 38; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 5c400a5..306a866 100644 --- a/global-config.changes +++ b/global-config.changes @@ -2,6 +2,11 @@ # Copyright (c) 2019-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +:global CertificateAvailable; + +# import new Let's Encrypt intermediate certificate 'R3' +$CertificateAvailable "R3"; + # Changes for global-config to be added to notification on script updates :global GlobalConfigChanges { 1="Moved variables from 'global-config' to 'global-functions' for independence"; @@ -41,4 +46,5 @@ 35="Implemented visual feedback for 'mode-button' with configurable LED."; 36="Added support for installing updates automatically if seen in neighbor list."; 37="Implemented simple dependency model in 'netwatch-notify'."; + 38="Imported new Let's Encrypt intermediate certificate 'R3'."; }; diff --git a/global-functions b/global-functions index 0530564..6b29157 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 37; +:global ExpectedConfigVersion 38; # global variables not to be changed by user :global GlobalFunctionsReady false; From e9210acfdb9c2c66ff422bbb341a4f8ab71a796d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Dec 2020 00:02:56 +0100 Subject: [PATCH 0557/2612] ipv6-update: add missing colon --- ipv6-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv6-update b/ipv6-update index 4fdda3d..bbe5b2d 100644 --- a/ipv6-update +++ b/ipv6-update @@ -22,7 +22,7 @@ # give the interfaces a moment to receive their addresses :delay 2s; -if ($OldPrefix != $PdPrefix) do={ +:if ($OldPrefix != $PdPrefix) do={ :log info ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix); / ipv6 firewall address-list set address=$PdPrefix $AddrList; From 744a03896c3276ca0bee9af5735851bb64a7f542 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Dec 2020 09:59:13 +0100 Subject: [PATCH 0558/2612] ipv6-update: automatically add ipv6 address list entry --- doc/ipv6-update.md | 3 +++ ipv6-update | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md index 93ada42..5295bd5 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -40,6 +40,9 @@ firewall rules, comment has to be "`ipv6-pool-`" and actual pool name: / ipv6 firewall address-list add address=2003:cf:2f0f:de00::/56 comment=ipv6-pool-isp list=extern; +As this entry is mandatory it is created automatically if it does not exist, +with the comment also set for list. + Static DNS records need a special comment to be updated. Again it has to start with "`ipv6-pool-`" and actual pool name, followed by a comma, "`interface=`" and the name of interface this address is connected to: diff --git a/ipv6-update b/ipv6-update index bbe5b2d..56dbd16 100644 --- a/ipv6-update +++ b/ipv6-update @@ -17,6 +17,11 @@ :local Pool [ / ipv6 pool get [ find where prefix=$PdPrefix ] name ]; :local AddrList [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ]; +:if ([ :len $AddrList ] = 0) do={ + :log info ("Missing ipv6 address list entry for ipv6-pool-" . $Pool . ", adding."); + / ipv6 firewall address-list add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool); + :set AddrList [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ]; +} :local OldPrefix [ / ipv6 firewall address-list get $AddrList address ]; # give the interfaces a moment to receive their addresses From 503dc3c32ccd7c75086bec878fd9149a8632c82c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Dec 2020 10:01:50 +0100 Subject: [PATCH 0559/2612] ipv6-update: move the delay down We have to wait for the interfaces, no need to delay address list entry. --- ipv6-update | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ipv6-update b/ipv6-update index 56dbd16..1baa0a4 100644 --- a/ipv6-update +++ b/ipv6-update @@ -24,13 +24,13 @@ } :local OldPrefix [ / ipv6 firewall address-list get $AddrList address ]; -# give the interfaces a moment to receive their addresses -:delay 2s; - :if ($OldPrefix != $PdPrefix) do={ :log info ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix); / ipv6 firewall address-list set address=$PdPrefix $AddrList; + # give the interfaces a moment to receive their addresses + :delay 2s; + :foreach Record in=[ / ip dns static find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ :local RecordVal [ / ip dns static get $Record ]; :local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ]; From cb72eccc6cf66cab0412f7bd696aa079fffc5180 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Dec 2020 10:11:18 +0100 Subject: [PATCH 0560/2612] ipv6-update: update interface specific address list entries --- doc/ipv6-update.md | 6 ++++++ ipv6-update | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md index 5295bd5..f736433 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -43,6 +43,12 @@ firewall rules, comment has to be "`ipv6-pool-`" and actual pool name: As this entry is mandatory it is created automatically if it does not exist, with the comment also set for list. +Address list entries for specific interfaces can be updated as well. The +interface needs to get its address from pool `isp` and the address list entry +has to be associated to an interface in comment: + + / ipv6 firewall address-list add address=2003:cf:2f0f:de01::/64 comment="ipv6-pool-isp, interface=br-local" list=local; + Static DNS records need a special comment to be updated. Again it has to start with "`ipv6-pool-`" and actual pool name, followed by a comma, "`interface=`" and the name of interface this address is connected to: diff --git a/ipv6-update b/ipv6-update index 1baa0a4..2224a11 100644 --- a/ipv6-update +++ b/ipv6-update @@ -31,6 +31,18 @@ # give the interfaces a moment to receive their addresses :delay 2s; + :foreach ListEntry in=[ / ipv6 firewall address-list find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ + :local ListEntryVal [ / ipv6 firewall address-list get $ListEntry ]; + :local Comment [ $ParseKeyValueStore ($ListEntryVal->"comment") ]; + + :local Address [ / ipv6 address find where from-pool=$Pool interface=($Comment->"interface") ]; + :if ([ :len $Address ] = 1) do={ + :set Address [ / ipv6 address get $Address address ]; + :log info ("Updating IPv6 address list with new IPv6 prefix " . $Address . " from interface " . ($Comment->"interface")); + / ipv6 firewall address-list set address=$Address $ListEntry; + } + } + :foreach Record in=[ / ip dns static find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ :local RecordVal [ / ip dns static get $Record ]; :local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ]; From 3657830582c4e5b4c75050bc2145adee52fbef28 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Dec 2020 15:31:03 +0100 Subject: [PATCH 0561/2612] ipv6-update: notify about interface specific address list entries --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 6c94b1b..2b1586e 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 38; +:global GlobalConfigVersion 39; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 46da208..93bd84b 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 38; +:global GlobalConfigVersion 39; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 306a866..343f5bf 100644 --- a/global-config.changes +++ b/global-config.changes @@ -47,4 +47,5 @@ $CertificateAvailable "R3"; 36="Added support for installing updates automatically if seen in neighbor list."; 37="Implemented simple dependency model in 'netwatch-notify'."; 38="Imported new Let's Encrypt intermediate certificate 'R3'."; + 39="Added support for interface specific address list entries in 'ipv6-update'."; }; diff --git a/global-functions b/global-functions index 6b29157..51396bf 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 38; +:global ExpectedConfigVersion 39; # global variables not to be changed by user :global GlobalFunctionsReady false; From 010e2d6b05f9aaed3adccd72ae1903664a373e96 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Dec 2020 16:02:31 +0100 Subject: [PATCH 0562/2612] check-certificates: make the certificate renewal time configurable --- check-certificates | 3 ++- global-config | 3 ++- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/check-certificates b/check-certificates index f3a8e99..4531c3d 100644 --- a/check-certificates +++ b/check-certificates @@ -7,6 +7,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md :global CertRenewPass; +:global CertRenewTime; :global CertRenewUrl; :global Identity; @@ -28,7 +29,7 @@ $WaitFullyConnected; -:foreach Cert in=[ / certificate find where !revoked !ca !scep-url expires-after<3w ] do={ +:foreach Cert in=[ / certificate find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ :local CertVal [ / certificate get $Cert ]; :do { diff --git a/global-config b/global-config index 2b1586e..c1f5ec5 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 39; +:global GlobalConfigVersion 40; # This is used for DNS and backup file. :global Domain "example.com"; @@ -142,6 +142,7 @@ # Use this for certificate auto-renew :global CertRenewUrl ""; #:global CertRenewUrl "https://example.com/certificates/"; +:global CertRenewTime 3w; :global CertRenewPass { "v3ry-s3cr3t"; "4n0th3r-s3cr3t"; diff --git a/global-config-overlay b/global-config-overlay index 93bd84b..aa22167 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 39; +:global GlobalConfigVersion 40; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 343f5bf..80fa5d8 100644 --- a/global-config.changes +++ b/global-config.changes @@ -48,4 +48,5 @@ $CertificateAvailable "R3"; 37="Implemented simple dependency model in 'netwatch-notify'."; 38="Imported new Let's Encrypt intermediate certificate 'R3'."; 39="Added support for interface specific address list entries in 'ipv6-update'."; + 40="Made the certificate renewal time configurable."; }; diff --git a/global-functions b/global-functions index 51396bf..b2337bc 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 39; +:global ExpectedConfigVersion 40; # global variables not to be changed by user :global GlobalFunctionsReady false; From c4c139d5a6f43dcc364f75a06af81f0b259dfbe8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Dec 2020 16:15:44 +0100 Subject: [PATCH 0563/2612] README: drop Let's Encrypt Authority X3 --- README.md | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 7856935..448cb10 100644 --- a/README.md +++ b/README.md @@ -54,18 +54,11 @@ certificate chain. total: 4KiB duration: 1s - [admin@MikroTik] > / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt-X3.pem" - status: finished - downloaded: 5KiBC-z pause] - total: 5KiB - duration: 1s - Note that the commands above do *not* verify server certificate, so if you want to be safe download with your workstations's browser and transfer the files to your MikroTik device. * [ISRG Root X1](https://letsencrypt.org/certs/isrgrootx1.pem) -* [Let's Encrypt Authority X3](https://letsencrypt.org/certs/letsencryptauthorityx3.pem) * Let's Encrypt [R3](https://letsencrypt.org/certs/lets-encrypt-r3.pem) Then we import the certificates. @@ -77,22 +70,14 @@ Then we import the certificates. decryption-failures: 0 keys-with-no-certificate: 0 - [admin@MikroTik] > / certificate import file-name=letsencrypt-X3.pem passphrase="" - certificates-imported: 1 - private-keys-imported: 0 - files-imported: 1 - decryption-failures: 0 - keys-with-no-certificate: 0 - For basic verification we rename the certifiactes and print their count. Make -sure the certificate count is **four**. +sure the certificate count is **three**. [admin@MikroTik] > / certificate set name="R3" [ find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" ] [admin@MikroTik] > / certificate set name="ISRG-Root-X1" [ find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ] - [admin@MikroTik] > / certificate set name="Let-s-Encrypt-Authority-X3" [ find where fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" ] [admin@MikroTik] > / certificate set name="DST-Root-CA-X3" [ find where fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] - [admin@MikroTik] > / certificate print count-only where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" - 4 + [admin@MikroTik] > / certificate print count-only where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" + 3 Always make sure there are no certificates installed you do not know or want! From 25d54542340c52678bd3f510559b73302576832a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Dec 2020 16:17:52 +0100 Subject: [PATCH 0564/2612] INITIAL-COMMANDS: drop Let's Encrypt Authority X3 --- INITIAL-COMMANDS.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index bf26ff1..9a5d6c8 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -8,15 +8,12 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai { / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem"; - / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/Let%27s%20Encrypt%20Authority%20X3.pem" dst-path="letsencrypt-X3.pem"; :delay 1s; / certificate import file-name=letsencrypt-R3.pem passphrase=""; - / certificate import file-name=letsencrypt-X3.pem passphrase=""; - :if ([ :len [ / certificate find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] ] != 4) do={ + :if ([ :len [ / certificate find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] ] != 3) do={ :error "Something is wrong with your certificates!"; } / file remove "letsencrypt-R3.pem"; - / file remove "letsencrypt-X3.pem"; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } @@ -26,7 +23,6 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai :global CertificateNameByCN; $CertificateNameByCN "R3"; $CertificateNameByCN "ISRG Root X1"; - $CertificateNameByCN "Let's Encrypt Authority X3"; $CertificateNameByCN "DST Root CA X3"; } From 05a9531dac25c1ab0cc9fc8533818647ef5f6f6c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Dec 2020 16:09:00 +0100 Subject: [PATCH 0565/2612] certs: remove Let's Encrypt Authority X3 --- certs/Let's Encrypt Authority X3.pem | 83 ---------------------------- 1 file changed, 83 deletions(-) delete mode 100644 certs/Let's Encrypt Authority X3.pem diff --git a/certs/Let's Encrypt Authority X3.pem b/certs/Let's Encrypt Authority X3.pem deleted file mode 100644 index 7df773f..0000000 --- a/certs/Let's Encrypt Authority X3.pem +++ /dev/null @@ -1,83 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFjTCCA3WgAwIBAgIRANOxciY0IzLc9AUoUSrsnGowDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTYxMDA2MTU0MzU1 -WhcNMjExMDA2MTU0MzU1WjBKMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg -RW5jcnlwdDEjMCEGA1UEAxMaTGV0J3MgRW5jcnlwdCBBdXRob3JpdHkgWDMwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc0wzwWuUuR7dyXTeDs2hjMOrX -NSYZJeG9vjXxcJIvt7hLQQWrqZ41CFjssSrEaIcLo+N15Obzp2JxunmBYB/XkZqf -89B4Z3HIaQ6Vkc/+5pnpYDxIzH7KTXcSJJ1HG1rrueweNwAcnKx7pwXqzkrrvUHl -Npi5y/1tPJZo3yMqQpAMhnRnyH+lmrhSYRQTP2XpgofL2/oOVvaGifOFP5eGr7Dc -Gu9rDZUWfcQroGWymQQ2dYBrrErzG5BJeC+ilk8qICUpBMZ0wNAxzY8xOJUWuqgz -uEPxsR/DMH+ieTETPS02+OP88jNquTkxxa/EjQ0dZBYzqvqEKbbUC8DYfcOTAgMB -AAGjggFnMIIBYzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADBU -BgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEBATAwMC4GCCsGAQUFBwIB -FiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMB0GA1UdDgQWBBSo -SmpjBH3duubRObemRWXv86jsoTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js -LnJvb3QteDEubGV0c2VuY3J5cHQub3JnMHIGCCsGAQUFBwEBBGYwZDAwBggrBgEF -BQcwAYYkaHR0cDovL29jc3Aucm9vdC14MS5sZXRzZW5jcnlwdC5vcmcvMDAGCCsG -AQUFBzAChiRodHRwOi8vY2VydC5yb290LXgxLmxldHNlbmNyeXB0Lm9yZy8wHwYD -VR0jBBgwFoAUebRZ5nu25eQBc4AIiMgaWPbpm24wDQYJKoZIhvcNAQELBQADggIB -ABnPdSA0LTqmRf/Q1eaM2jLonG4bQdEnqOJQ8nCqxOeTRrToEKtwT++36gTSlBGx -A/5dut82jJQ2jxN8RI8L9QFXrWi4xXnA2EqA10yjHiR6H9cj6MFiOnb5In1eWsRM -UM2v3e9tNsCAgBukPHAg1lQh07rvFKm/Bz9BCjaxorALINUfZ9DD64j2igLIxle2 -DPxW8dI/F2loHMjXZjqG8RkqZUdoxtID5+90FgsGIfkMpqgRS05f4zPbCEHqCXl1 -eO5HyELTgcVlLXXQDgAWnRzut1hFJeczY1tjQQno6f6s+nMydLN26WuU4s3UYvOu -OsUxRlJu7TSRHqDC3lSE5XggVkzdaPkuKGQbGpny+01/47hfXXNB7HntWNZ6N2Vw -p7G6OfY+YQrZwIaQmhrIqJZuigsrbe3W+gdn5ykE9+Ky0VgVUsfxo52mwFYs1JKY -2PGDuWx8M6DlS6qQkvHaRUo0FMd8TsSlbF0/v965qGFKhSDeQoMpYnwcmQilRh/0 -ayLThlHLN81gSkJjVrPI0Y8xCVPB4twb1PFUd2fPM3sA1tJ83sZ5v8vgFv2yofKR -PB0t6JzUA81mSqM3kxl5e+IZwhYAyO0OTg3/fs8HqGTNKd9BqoUwSRBzp06JMg5b -rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ -MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT -DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow -PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD -Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O -rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq -OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b -xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw -7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD -aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV -HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG -SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 -ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr -AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz -R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 -JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo -Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ ------END CERTIFICATE----- From 40dc2415d3c414d77f31084936040d586d8c8acb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Dec 2020 17:04:22 +0100 Subject: [PATCH 0566/2612] global-functions: $ScriptInstallUpdate: make Let's Encrypt certificate semi-mandatory ... and remove the migration from changes. --- global-config.changes | 5 ----- global-functions | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/global-config.changes b/global-config.changes index 80fa5d8..3c06553 100644 --- a/global-config.changes +++ b/global-config.changes @@ -2,11 +2,6 @@ # Copyright (c) 2019-2020 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -:global CertificateAvailable; - -# import new Let's Encrypt intermediate certificate 'R3' -$CertificateAvailable "R3"; - # Changes for global-config to be added to notification on script updates :global GlobalConfigChanges { 1="Moved variables from 'global-config' to 'global-functions' for independence"; diff --git a/global-functions b/global-functions index b2337bc..9ee2d00 100644 --- a/global-functions +++ b/global-functions @@ -552,11 +552,16 @@ :global ScriptUpdatesUrlSuffix; :global SentConfigChangesNotification; + :global CertificateAvailable; :global LogPrintExit; :global ParseKeyValueStore; :global SendNotification; :global SymbolForNotification; + :if ([ $CertificateAvailable "R3" ] = false) do={ + $LogPrintExit warning ("Downloading certificate failed, trying without.") false; + } + :foreach Script in=$Scripts do={ :if ([ :len [ / system script find where name=$Script ] ] = 0) do={ $LogPrintExit info ("Adding new script: " . $Script) false; From 0360a0ef901659b7a63ba9fcdf70883b8f098e72 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Dec 2020 17:50:37 +0100 Subject: [PATCH 0567/2612] global-functions: $ScriptInstallUpdate: implement migration mechanism Reset $SentConfigChangesNotification and rerun $ScriptInstallUpdate to test... :set SentConfigChangesNotification $ScriptInstallUpdate --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 6 ++++++ global-functions | 9 ++++++++- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index c1f5ec5..379701a 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 40; +:global GlobalConfigVersion 41; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index aa22167..a7cd500 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 40; +:global GlobalConfigVersion 41; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 3c06553..2d53160 100644 --- a/global-config.changes +++ b/global-config.changes @@ -44,4 +44,10 @@ 38="Imported new Let's Encrypt intermediate certificate 'R3'."; 39="Added support for interface specific address list entries in 'ipv6-update'."; 40="Made the certificate renewal time configurable."; + 41="Implemented migration mechanism for script updates."; +}; + +# Migration steps to be applied on script updates +:global GlobalConfigMigration { + 41=":global SendNotification; \$SendNotification (\"Migration mechanism\") (\"Congratulations!\nSuccessfully tested the new migration mechanism.\");"; }; diff --git a/global-functions b/global-functions index 9ee2d00..e1a7d3d 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 40; +:global ExpectedConfigVersion 41; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -659,6 +659,7 @@ :if ($SentConfigChangesNotification!=$ExpectedConfigVersion && \ $GlobalConfigVersion < $ExpectedConfigVersion) do={ :global GlobalConfigChanges; + :global GlobalConfigMigration; :local ChangeLogCode; :local ConfigScript "global-config"; :if ([ :len [ / system script find where name="global-config-overlay" ] ] > 0) do={ @@ -684,8 +685,14 @@ :set NotificationMessage ($NotificationMessage . \ "\n * " . $GlobalConfigChanges->[ :tostr $I ]); $LogPrintExit info ("Change: " . $GlobalConfigChanges->[ :tostr $I ]) false; + :local Migration ($GlobalConfigMigration->[ :tostr $I ]); + :if ([ :typeof $Migration ] = "str") do={ + $LogPrintExit info ("Applying migration: " . $Migration) false; + [ :parse $Migration ]; + } } :set GlobalConfigChanges; + :set GlobalConfigMigration; } on-error={ $LogPrintExit warning ("Failed fetching changes!") false; :set NotificationMessage ($NotificationMessage . \ From caddcbabe27848bdac05afd885d918ea4a0e8bae Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 17 Dec 2020 22:52:27 +0100 Subject: [PATCH 0568/2612] global-functions: $ScriptInstallUpdate: drop ignore migration Anybody had enough time to migrate, no? --- global-functions | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/global-functions b/global-functions index e1a7d3d..8b0e6cb 100644 --- a/global-functions +++ b/global-functions @@ -548,7 +548,6 @@ :global IDonate; :global ScriptUpdatesBaseUrl; :global ScriptUpdatesFetch; - :global ScriptUpdatesIgnore; :global ScriptUpdatesUrlSuffix; :global SentConfigChangesNotification; @@ -598,15 +597,6 @@ :local Comment [ $ParseKeyValueStore ($ScriptVal->"comment") ]; :if ($Comment->"ignore" = true) do={ :set Ignore 1; - } else={ - # TODO: remove at later time - :foreach IgnoreLoop in=$ScriptUpdatesIgnore do={ - :if ($IgnoreLoop = $ScriptVal->"name") do={ - :set Ignore 1; - $LogPrintExit info ("Migrating script " . $ScriptVal->"name" . " to ignore flag in comment.") false; - / system script set comment="ignore" ($ScriptVal->"name"); - } - } } :if ($Ignore = 0) do={ From 605c313e46bdffb0f572c64bd4f3e1336d8c9896 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 20 Dec 2020 23:30:18 +0100 Subject: [PATCH 0569/2612] global-functions: $ScriptInstallUpdate: simplify code --- global-functions | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/global-functions b/global-functions index 8b0e6cb..192e326 100644 --- a/global-functions +++ b/global-functions @@ -569,7 +569,6 @@ } :foreach Script in=[ / system script find where source~"^#!rsc( by RouterOS)\?\n" ] do={ - :local Ignore 0; :local ScriptVal [ / system script get $Script ]; :local ScriptFile [ / file find where name=("script-updates/" . $ScriptVal->"name") ]; :local SourceNew; @@ -595,11 +594,7 @@ :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ :local Comment [ $ParseKeyValueStore ($ScriptVal->"comment") ]; - :if ($Comment->"ignore" = true) do={ - :set Ignore 1; - } - - :if ($Ignore = 0) do={ + :if (!($Comment->"ignore" = true)) do={ $LogPrintExit debug ("Fetching script from url: " . $ScriptVal->"name") false; :do { :local BaseUrl $ScriptUpdatesBaseUrl; From 97ade535d9789b35652f294bff4f489d868a1130 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 30 Dec 2020 00:45:11 +0100 Subject: [PATCH 0570/2612] certs: add plain text info about certificates Also order certificates, so we have: * intermediate * root * alternative root, if any Let's add 'ISRG Root X1' for 'E1' as there will be a valid cross-signed chain 'E1' -> 'ISRG Root X2' -> 'ISRG Root X1'. --- certs/DigiCert ECC Secure Server CA.pem | 122 +++++++++ certs/E1.pem | 212 ++++++++++++++++ certs/GTS CA 1O1.pem | 183 ++++++++++++-- ...addy Secure Certificate Authority - G2.pem | 173 +++++++++++-- certs/R3.pem | 233 ++++++++++++++++++ ...ield Secure Certificate Authority - G2.pem | 173 +++++++++++-- 6 files changed, 1028 insertions(+), 68 deletions(-) diff --git a/certs/DigiCert ECC Secure Server CA.pem b/certs/DigiCert ECC Secure Server CA.pem index 184ca1d..3eca7fc 100644 --- a/certs/DigiCert ECC Secure Server CA.pem +++ b/certs/DigiCert ECC Secure Server CA.pem @@ -1,3 +1,65 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0a:cb:28:ba:46:5e:e5:39:08:76:74:70:f3:cd:c6:12 + Signature Algorithm: sha384WithRSAEncryption + Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA + Validity + Not Before: Mar 8 12:00:00 2013 GMT + Not After : Mar 8 12:00:00 2023 GMT + Subject: C = US, O = DigiCert Inc, CN = DigiCert ECC Secure Server CA + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:e2:08:42:ea:77:d8:24:de:a0:2c:64:a4:13:ce: + 40:9c:23:72:a9:02:0a:0e:37:3f:21:36:b8:8d:53: + 14:f6:d5:91:95:4b:f3:96:02:8d:71:1e:c4:d8:cb: + a7:9f:5e:ef:a0:e6:7f:5a:92:11:96:53:6f:eb:c0: + cb:3f:ae:fd:5b:3f:47:24:e7:9a:07:2e:96:be:a8: + 2f:bb:57:18:af:71:a4:bd:78:3a:1e:e8:5b:3c:6b: + 64:11:2b:cc:34:2b:8c + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl3.digicert.com/DigiCertGlobalRootCA.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.digicert.com/CPS + + X509v3 Subject Key Identifier: + A3:9D:E6:1F:F9:DA:39:4F:C0:6E:E8:91:CB:95:A5:DA:31:E2:0A:9F + X509v3 Authority Key Identifier: + keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 + + Signature Algorithm: sha384WithRSAEncryption + c7:8a:a0:43:4b:ec:74:c9:c5:ab:d5:1f:30:35:36:6e:98:56: + 7b:48:ac:05:63:ae:7b:9a:57:24:57:cc:6f:fa:de:ab:6d:9c: + c7:b6:ba:ec:ce:e7:ca:73:64:db:df:04:37:0a:00:49:b3:3f: + 9f:26:ad:91:8c:20:e8:1f:88:0e:2a:fb:66:37:c8:30:e8:d2: + c2:24:a7:45:48:2d:ea:01:50:4a:31:94:13:df:8d:5f:da:2a: + bb:49:3c:61:f3:79:c8:9c:66:92:1a:96:2a:f4:7b:36:58:a3: + 2c:41:10:74:1a:d3:ed:48:b6:d2:bb:8a:06:45:71:33:10:30: + 7a:7a:98:21:dd:24:b9:ec:9c:b5:92:07:ad:83:c6:c4:6a:f8: + 77:e6:35:be:13:0f:27:64:b2:43:bf:83:e9:77:56:db:08:87: + 94:47:14:f5:5f:28:af:a3:68:4c:83:8f:60:f7:96:80:79:85: + 6a:76:26:9d:95:0c:20:03:8d:3e:ee:7a:28:65:64:66:a4:d9: + 83:ea:99:74:cd:6e:4d:7d:1c:eb:8d:b2:c5:af:16:1b:4e:c8: + f3:55:ea:88:38:11:34:1d:11:af:3f:07:a8:4f:6a:d2:74:11: + 2f:2a:fc:73:b7:5f:c2:15:43:05:6c:d6:7d:da:02:bd:22:9b: + 4f:d3:f9:77 -----BEGIN CERTIFICATE----- MIIDrDCCApSgAwIBAgIQCssoukZe5TkIdnRw883GEjANBgkqhkiG9w0BAQwFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 @@ -20,6 +82,66 @@ mCHdJLnsnLWSB62DxsRq+HfmNb4TDydkskO/g+l3VtsIh5RHFPVfKK+jaEyDj2D3 loB5hWp2Jp2VDCADjT7ueihlZGak2YPqmXTNbk19HOuNssWvFhtOyPNV6og4ETQd Ea8/B6hPatJ0ES8q/HO3X8IVQwVs1n3aAr0im0/T+Xc= -----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 08:3b:e0:56:90:42:46:b1:a1:75:6a:c9:59:91:c7:4a + Signature Algorithm: sha1WithRSAEncryption + Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA + Validity + Not Before: Nov 10 00:00:00 2006 GMT + Not After : Nov 10 00:00:00 2031 GMT + Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:e2:3b:e1:11:72:de:a8:a4:d3:a3:57:aa:50:a2: + 8f:0b:77:90:c9:a2:a5:ee:12:ce:96:5b:01:09:20: + cc:01:93:a7:4e:30:b7:53:f7:43:c4:69:00:57:9d: + e2:8d:22:dd:87:06:40:00:81:09:ce:ce:1b:83:bf: + df:cd:3b:71:46:e2:d6:66:c7:05:b3:76:27:16:8f: + 7b:9e:1e:95:7d:ee:b7:48:a3:08:da:d6:af:7a:0c: + 39:06:65:7f:4a:5d:1f:bc:17:f8:ab:be:ee:28:d7: + 74:7f:7a:78:99:59:85:68:6e:5c:23:32:4b:bf:4e: + c0:e8:5a:6d:e3:70:bf:77:10:bf:fc:01:f6:85:d9: + a8:44:10:58:32:a9:75:18:d5:d1:a2:be:47:e2:27: + 6a:f4:9a:33:f8:49:08:60:8b:d4:5f:b4:3a:84:bf: + a1:aa:4a:4c:7d:3e:cf:4f:5f:6c:76:5e:a0:4b:37: + 91:9e:dc:22:e6:6d:ce:14:1a:8e:6a:cb:fe:cd:b3: + 14:64:17:c7:5b:29:9e:32:bf:f2:ee:fa:d3:0b:42: + d4:ab:b7:41:32:da:0c:d4:ef:f8:81:d5:bb:8d:58: + 3f:b5:1b:e8:49:28:a2:70:da:31:04:dd:f7:b2:16: + f2:4c:0a:4e:07:a8:ed:4a:3d:5e:b5:7f:a3:90:c3: + af:27 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 + X509v3 Authority Key Identifier: + keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 + + Signature Algorithm: sha1WithRSAEncryption + cb:9c:37:aa:48:13:12:0a:fa:dd:44:9c:4f:52:b0:f4:df:ae: + 04:f5:79:79:08:a3:24:18:fc:4b:2b:84:c0:2d:b9:d5:c7:fe: + f4:c1:1f:58:cb:b8:6d:9c:7a:74:e7:98:29:ab:11:b5:e3:70: + a0:a1:cd:4c:88:99:93:8c:91:70:e2:ab:0f:1c:be:93:a9:ff: + 63:d5:e4:07:60:d3:a3:bf:9d:5b:09:f1:d5:8e:e3:53:f4:8e: + 63:fa:3f:a7:db:b4:66:df:62:66:d6:d1:6e:41:8d:f2:2d:b5: + ea:77:4a:9f:9d:58:e2:2b:59:c0:40:23:ed:2d:28:82:45:3e: + 79:54:92:26:98:e0:80:48:a8:37:ef:f0:d6:79:60:16:de:ac: + e8:0e:cd:6e:ac:44:17:38:2f:49:da:e1:45:3e:2a:b9:36:53: + cf:3a:50:06:f7:2e:e8:c4:57:49:6c:61:21:18:d5:04:ad:78: + 3c:2c:3a:80:6b:a7:eb:af:15:14:e9:d8:89:c1:b9:38:6c:e2: + 91:6c:8a:ff:64:b9:77:25:57:30:c0:1b:24:a3:e1:dc:e9:df: + 47:7c:b5:b4:24:08:05:30:ec:2d:bd:0b:bf:45:bf:50:b9:a9: + f3:eb:98:01:12:ad:c8:88:c6:98:34:5f:8d:0a:3c:c6:e9:d5: + 95:95:6d:de -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 diff --git a/certs/E1.pem b/certs/E1.pem index d33bedd..4c3c212 100644 --- a/certs/E1.pem +++ b/certs/E1.pem @@ -1,3 +1,58 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + b3:bd:df:f8:a7:84:5b:bc:e9:03:a0:41:35:b3:4a:45 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X2 + Validity + Not Before: Sep 4 00:00:00 2020 GMT + Not After : Sep 15 16:00:00 2025 GMT + Subject: C = US, O = Let's Encrypt, CN = E1 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:24:5c:2d:a2:2a:fd:1c:4b:a6:5d:97:73:27:31: + ac:b2:a0:69:62:ef:65:e8:a6:b0:f0:ac:4b:9f:ff: + 1c:0b:70:0f:d3:98:2f:4d:fc:0f:00:9b:37:f0:74: + 05:57:32:97:2e:05:ef:2a:43:25:a3:fb:6e:34:27: + 13:f6:4f:7e:69:d3:02:99:5e:eb:24:47:92:c1:24: + 9b:e6:b1:21:8f:c1:24:81:fc:68:cc:1f:69:ba:58: + f5:19:22:f7:74:c6:16 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + 5A:F3:ED:2B:FC:36:C2:37:79:B9:52:30:EA:54:6F:CF:55:CB:2E:AC + X509v3 Authority Key Identifier: + keyid:7C:42:96:AE:DE:4B:48:3B:FA:92:F8:9E:8C:CF:6D:8B:A9:72:37:95 + + Authority Information Access: + CA Issuers - URI:http://x2.i.lencr.org/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://x2.c.lencr.org/ + + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.1 + Policy: 1.3.6.1.4.1.44947.1.1.1 + + Signature Algorithm: ecdsa-with-SHA384 + 30:64:02:30:7b:74:d5:52:13:8d:61:fe:0d:ba:3f:03:00:9d: + f3:d7:98:84:d9:57:2e:bd:e9:0f:9c:5c:48:04:21:f2:cb:b3: + 60:72:8e:97:d6:12:4f:ca:44:f6:42:c9:d3:7b:86:a9:02:30: + 5a:b1:b1:b4:ed:ea:60:99:20:b1:38:03:ca:3d:a0:26:b8:ee: + 6e:2d:4a:f6:c6:66:1f:33:9a:db:92:4a:d5:f5:29:13:c6:70: + 62:28:ba:23:8c:cf:3d:2f:cb:82:e9:7f -----BEGIN CERTIFICATE----- MIICxjCCAk2gAwIBAgIRALO93/inhFu86QOgQTWzSkUwCgYIKoZIzj0EAwMwTzEL MAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNo @@ -15,6 +70,44 @@ Z4EMAQIBMA0GCysGAQQBgt8TAQEBMAoGCCqGSM49BAMDA2cAMGQCMHt01VITjWH+ Dbo/AwCd89eYhNlXLr3pD5xcSAQh8suzYHKOl9YST8pE9kLJ03uGqQIwWrGxtO3q YJkgsTgDyj2gJrjubi1K9sZmHzOa25JK1fUpE8ZwYii6I4zPPS/Lgul/ -----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 41:d2:9d:d1:72:ea:ee:a7:80:c1:2c:6c:e9:2f:87:52 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X2 + Validity + Not Before: Sep 4 00:00:00 2020 GMT + Not After : Sep 17 16:00:00 2040 GMT + Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X2 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:cd:9b:d5:9f:80:83:0a:ec:09:4a:f3:16:4a:3e: + 5c:cf:77:ac:de:67:05:0d:1d:07:b6:dc:16:fb:5a: + 8b:14:db:e2:71:60:c4:ba:45:95:11:89:8e:ea:06: + df:f7:2a:16:1c:a4:b9:c5:c5:32:e0:03:e0:1e:82: + 18:38:8b:d7:45:d8:0a:6a:6e:e6:00:77:fb:02:51: + 7d:22:d8:0a:6e:9a:5b:77:df:f0:fa:41:ec:39:dc: + 75:ca:68:07:0c:1f:ea + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 7C:42:96:AE:DE:4B:48:3B:FA:92:F8:9E:8C:CF:6D:8B:A9:72:37:95 + Signature Algorithm: ecdsa-with-SHA384 + 30:65:02:30:7b:79:4e:46:50:84:c2:44:87:46:1b:45:70:ff: + 58:99:de:f4:fd:a4:d2:55:a6:20:2d:74:d6:34:bc:41:a3:50: + 5f:01:27:56:b4:be:27:75:06:af:12:2e:75:98:8d:fc:02:31: + 00:8b:f5:77:6c:d4:c8:65:aa:e0:0b:2c:ee:14:9d:27:37:a4: + f9:53:a5:51:e4:29:83:d7:f8:90:31:5b:42:9f:0a:f5:fe:ae: + 00:68:e7:8c:49:0f:b6:6f:5b:5b:15:f2:e7 -----BEGIN CERTIFICATE----- MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg @@ -29,3 +122,122 @@ zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 /q4AaOeMSQ+2b1tbFfLn -----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 82:10:cf:b0:d2:40:e3:59:44:63:e0:bb:63:82:8b:00 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 + Validity + Not Before: Jun 4 11:04:38 2015 GMT + Not After : Jun 4 11:04:38 2035 GMT + Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:ad:e8:24:73:f4:14:37:f3:9b:9e:2b:57:28:1c: + 87:be:dc:b7:df:38:90:8c:6e:3c:e6:57:a0:78:f7: + 75:c2:a2:fe:f5:6a:6e:f6:00:4f:28:db:de:68:86: + 6c:44:93:b6:b1:63:fd:14:12:6b:bf:1f:d2:ea:31: + 9b:21:7e:d1:33:3c:ba:48:f5:dd:79:df:b3:b8:ff: + 12:f1:21:9a:4b:c1:8a:86:71:69:4a:66:66:6c:8f: + 7e:3c:70:bf:ad:29:22:06:f3:e4:c0:e6:80:ae:e2: + 4b:8f:b7:99:7e:94:03:9f:d3:47:97:7c:99:48:23: + 53:e8:38:ae:4f:0a:6f:83:2e:d1:49:57:8c:80:74: + b6:da:2f:d0:38:8d:7b:03:70:21:1b:75:f2:30:3c: + fa:8f:ae:dd:da:63:ab:eb:16:4f:c2:8e:11:4b:7e: + cf:0b:e8:ff:b5:77:2e:f4:b2:7b:4a:e0:4c:12:25: + 0c:70:8d:03:29:a0:e1:53:24:ec:13:d9:ee:19:bf: + 10:b3:4a:8c:3f:89:a3:61:51:de:ac:87:07:94:f4: + 63:71:ec:2e:e2:6f:5b:98:81:e1:89:5c:34:79:6c: + 76:ef:3b:90:62:79:e6:db:a4:9a:2f:26:c5:d0:10: + e1:0e:de:d9:10:8e:16:fb:b7:f7:a8:f7:c7:e5:02: + 07:98:8f:36:08:95:e7:e2:37:96:0d:36:75:9e:fb: + 0e:72:b1:1d:9b:bc:03:f9:49:05:d8:81:dd:05:b4: + 2a:d6:41:e9:ac:01:76:95:0a:0f:d8:df:d5:bd:12: + 1f:35:2f:28:17:6c:d2:98:c1:a8:09:64:77:6e:47: + 37:ba:ce:ac:59:5e:68:9d:7f:72:d6:89:c5:06:41: + 29:3e:59:3e:dd:26:f5:24:c9:11:a7:5a:a3:4c:40: + 1f:46:a1:99:b5:a7:3a:51:6e:86:3b:9e:7d:72:a7: + 12:05:78:59:ed:3e:51:78:15:0b:03:8f:8d:d0:2f: + 05:b2:3e:7b:4a:1c:4b:73:05:12:fc:c6:ea:e0:50: + 13:7c:43:93:74:b3:ca:74:e7:8e:1f:01:08:d0:30: + d4:5b:71:36:b4:07:ba:c1:30:30:5c:48:b7:82:3b: + 98:a6:7d:60:8a:a2:a3:29:82:cc:ba:bd:83:04:1b: + a2:83:03:41:a1:d6:05:f1:1b:c2:b6:f0:a8:7c:86: + 3b:46:a8:48:2a:88:dc:76:9a:76:bf:1f:6a:a5:3d: + 19:8f:eb:38:f3:64:de:c8:2b:0d:0a:28:ff:f7:db: + e2:15:42:d4:22:d0:27:5d:e1:79:fe:18:e7:70:88: + ad:4e:e6:d9:8b:3a:c6:dd:27:51:6e:ff:bc:64:f5: + 33:43:4f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E + Signature Algorithm: sha256WithRSAEncryption + 55:1f:58:a9:bc:b2:a8:50:d0:0c:b1:d8:1a:69:20:27:29:08: + ac:61:75:5c:8a:6e:f8:82:e5:69:2f:d5:f6:56:4b:b9:b8:73: + 10:59:d3:21:97:7e:e7:4c:71:fb:b2:d2:60:ad:39:a8:0b:ea: + 17:21:56:85:f1:50:0e:59:eb:ce:e0:59:e9:ba:c9:15:ef:86: + 9d:8f:84:80:f6:e4:e9:91:90:dc:17:9b:62:1b:45:f0:66:95: + d2:7c:6f:c2:ea:3b:ef:1f:cf:cb:d6:ae:27:f1:a9:b0:c8:ae: + fd:7d:7e:9a:fa:22:04:eb:ff:d9:7f:ea:91:2b:22:b1:17:0e: + 8f:f2:8a:34:5b:58:d8:fc:01:c9:54:b9:b8:26:cc:8a:88:33: + 89:4c:2d:84:3c:82:df:ee:96:57:05:ba:2c:bb:f7:c4:b7:c7: + 4e:3b:82:be:31:c8:22:73:73:92:d1:c2:80:a4:39:39:10:33: + 23:82:4c:3c:9f:86:b2:55:98:1d:be:29:86:8c:22:9b:9e:e2: + 6b:3b:57:3a:82:70:4d:dc:09:c7:89:cb:0a:07:4d:6c:e8:5d: + 8e:c9:ef:ce:ab:c7:bb:b5:2b:4e:45:d6:4a:d0:26:cc:e5:72: + ca:08:6a:a5:95:e3:15:a1:f7:a4:ed:c9:2c:5f:a5:fb:ff:ac: + 28:02:2e:be:d7:7b:bb:e3:71:7b:90:16:d3:07:5e:46:53:7c: + 37:07:42:8c:d3:c4:96:9c:d5:99:b5:2a:e0:95:1a:80:48:ae: + 4c:39:07:ce:cc:47:a4:52:95:2b:ba:b8:fb:ad:d2:33:53:7d: + e5:1d:4d:6d:d5:a1:b1:c7:42:6f:e6:40:27:35:5c:a3:28:b7: + 07:8d:e7:8d:33:90:e7:23:9f:fb:50:9c:79:6c:46:d5:b4:15: + b3:96:6e:7e:9b:0c:96:3a:b8:52:2d:3f:d6:5b:e1:fb:08:c2: + 84:fe:24:a8:a3:89:da:ac:6a:e1:18:2a:b1:a8:43:61:5b:d3: + 1f:dc:3b:8d:76:f2:2d:e8:8d:75:df:17:33:6c:3d:53:fb:7b: + cb:41:5f:ff:dc:a2:d0:61:38:e1:96:b8:ac:5d:8b:37:d7:75: + d5:33:c0:99:11:ae:9d:41:c1:72:75:84:be:02:41:42:5f:67: + 24:48:94:d1:9b:27:be:07:3f:b9:b8:4f:81:74:51:e1:7a:b7: + ed:9d:23:e2:be:e0:d5:28:04:13:3c:31:03:9e:dd:7a:6c:8f: + c6:07:18:c6:7f:de:47:8e:3f:28:9e:04:06:cf:a5:54:34:77: + bd:ec:89:9b:e9:17:43:df:5b:db:5f:fe:8e:1e:57:a2:cd:40: + 9d:7e:62:22:da:de:18:27 +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- diff --git a/certs/GTS CA 1O1.pem b/certs/GTS CA 1O1.pem index dc3aff5..ccdba4d 100644 --- a/certs/GTS CA 1O1.pem +++ b/certs/GTS CA 1O1.pem @@ -1,25 +1,77 @@ ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 -MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL -v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 -eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq -tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd -C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa -zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB -mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH -V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n -bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG -3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs -J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO -291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS -ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd -AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 -TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== ------END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 01:e3:b4:9a:a1:8d:8a:a9:81:25:69:50:b8 + Signature Algorithm: sha256WithRSAEncryption + Issuer: OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign + Validity + Not Before: Jun 15 00:00:42 2017 GMT + Not After : Dec 15 00:00:42 2021 GMT + Subject: C = US, O = Google Trust Services, CN = GTS CA 1O1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:d0:18:cf:45:d4:8b:cd:d3:9c:e4:40:ef:7e:b4: + dd:69:21:1b:c9:cf:3c:8e:4c:75:b9:0f:31:19:84: + 3d:9e:3c:29:ef:50:0d:10:93:6f:05:80:80:9f:2a: + a0:bd:12:4b:02:e1:3d:9f:58:16:24:fe:30:9f:0b: + 74:77:55:93:1d:4b:f7:4d:e1:92:82:10:f6:51:ac: + 0c:c3:b2:22:94:0f:34:6b:98:10:49:e7:0b:9d:83: + 39:dd:20:c6:1c:2d:ef:d1:18:61:65:e7:23:83:20: + a8:23:12:ff:d2:24:7f:d4:2f:e7:44:6a:5b:4d:d7: + 50:66:b0:af:9e:42:63:05:fb:e0:1c:c4:63:61:af: + 9f:6a:33:ff:62:97:bd:48:d9:d3:7c:14:67:dc:75: + dc:2e:69:e8:f8:6d:78:69:d0:b7:10:05:b8:f1:31: + c2:3b:24:fd:1a:33:74:f8:23:e0:ec:6b:19:8a:16: + c6:e3:cd:a4:cd:0b:db:b3:a4:59:60:38:88:3b:ad: + 1d:b9:c6:8c:a7:53:1b:fc:bc:d9:a4:ab:bc:dd:3c: + 61:d7:93:15:98:ee:81:bd:8f:e2:64:47:20:40:06: + 4e:d7:ac:97:e8:b9:c0:59:12:a1:49:25:23:e4:ed: + 70:34:2c:a5:b4:63:7c:f9:a3:3d:83:d1:cd:6d:24: + ac:07 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + 98:D1:F8:6E:10:EB:CF:9B:EC:60:9F:18:90:1B:A0:EB:7D:09:FD:2B + X509v3 Authority Key Identifier: + keyid:9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E + + Authority Information Access: + OCSP - URI:http://ocsp.pki.goog/gsr2 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.pki.goog/gsr2/gsr2.crl + + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.2 + CPS: https://pki.goog/repository/ + + Signature Algorithm: sha256WithRSAEncryption + 1a:80:3e:36:79:fb:f3:2e:a9:46:37:7d:5e:54:16:35:ae:c7: + 4e:08:99:fe:bd:d1:34:69:26:52:66:07:3d:0a:ba:49:cb:62: + f4:f1:1a:8e:fc:11:4f:68:96:4c:74:2b:d3:67:de:b2:a3:aa: + 05:8d:84:4d:4c:20:65:0f:a5:96:da:0d:16:f8:6c:3b:db:6f: + 04:23:88:6b:3a:6c:c1:60:bd:68:9f:71:8e:ee:2d:58:34:07: + f0:d5:54:e9:86:59:fd:7b:5e:0d:21:94:f5:8c:c9:a8:f8:d8: + f2:ad:cc:0f:1a:f3:9a:a7:a9:04:27:f9:a3:c9:b0:ff:02:78: + 6b:61:ba:c7:35:2b:e8:56:fa:4f:c3:1c:0c:ed:b6:3c:b4:4b: + ea:ed:cc:e1:3c:ec:dc:0d:8c:d6:3e:9b:ca:42:58:8b:cc:16: + 21:17:40:bc:a2:d6:66:ef:da:c4:15:5b:cd:89:aa:9b:09:26: + e7:32:d2:0d:6e:67:20:02:5b:10:b0:90:09:9c:0c:1f:9e:ad: + d8:3b:ea:a1:fc:6c:e8:10:5c:08:52:19:51:2a:71:bb:ac:7a: + b5:dd:15:ed:2b:c9:08:2a:2c:8a:b4:a6:21:ab:63:ff:d7:52: + 49:50:d0:89:b7:ad:f2:af:fb:50:ae:2f:e1:95:0d:f3:46:ad: + 9d:9c:f5:ca -----BEGIN CERTIFICATE----- MIIESjCCAzKgAwIBAgINAeO0mqGNiqmBJWlQuDANBgkqhkiG9w0BAQsFADBMMSAw HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFs @@ -45,3 +97,90 @@ mqepBCf5o8mw/wJ4a2G6xzUr6Fb6T8McDO22PLRL6u3M4Tzs3A2M1j6bykJYi8wW IRdAvKLWZu/axBVbzYmqmwkm5zLSDW5nIAJbELCQCZwMH56t2Dvqofxs6BBcCFIZ USpxu6x6td0V7SvJCCosirSmIatj/9dSSVDQibet8q/7UK4v4ZUN80atnZz1yg== -----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:00:00:00:00:01:0f:86:26:e6:0d + Signature Algorithm: sha1WithRSAEncryption + Issuer: OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign + Validity + Not Before: Dec 15 08:00:00 2006 GMT + Not After : Dec 15 08:00:00 2021 GMT + Subject: OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:a6:cf:24:0e:be:2e:6f:28:99:45:42:c4:ab:3e: + 21:54:9b:0b:d3:7f:84:70:fa:12:b3:cb:bf:87:5f: + c6:7f:86:d3:b2:30:5c:d6:fd:ad:f1:7b:dc:e5:f8: + 60:96:09:92:10:f5:d0:53:de:fb:7b:7e:73:88:ac: + 52:88:7b:4a:a6:ca:49:a6:5e:a8:a7:8c:5a:11:bc: + 7a:82:eb:be:8c:e9:b3:ac:96:25:07:97:4a:99:2a: + 07:2f:b4:1e:77:bf:8a:0f:b5:02:7c:1b:96:b8:c5: + b9:3a:2c:bc:d6:12:b9:eb:59:7d:e2:d0:06:86:5f: + 5e:49:6a:b5:39:5e:88:34:ec:bc:78:0c:08:98:84: + 6c:a8:cd:4b:b4:a0:7d:0c:79:4d:f0:b8:2d:cb:21: + ca:d5:6c:5b:7d:e1:a0:29:84:a1:f9:d3:94:49:cb: + 24:62:91:20:bc:dd:0b:d5:d9:cc:f9:ea:27:0a:2b: + 73:91:c6:9d:1b:ac:c8:cb:e8:e0:a0:f4:2f:90:8b: + 4d:fb:b0:36:1b:f6:19:7a:85:e0:6d:f2:61:13:88: + 5c:9f:e0:93:0a:51:97:8a:5a:ce:af:ab:d5:f7:aa: + 09:aa:60:bd:dc:d9:5f:df:72:a9:60:13:5e:00:01: + c9:4a:fa:3f:a4:ea:07:03:21:02:8e:82:ca:03:c2: + 9b:8f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.globalsign.net/root-r2.crl + + X509v3 Authority Key Identifier: + keyid:9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E + + Signature Algorithm: sha1WithRSAEncryption + 99:81:53:87:1c:68:97:86:91:ec:e0:4a:b8:44:0b:ab:81:ac: + 27:4f:d6:c1:b8:1c:43:78:b3:0c:9a:fc:ea:2c:3c:6e:61:1b: + 4d:4b:29:f5:9f:05:1d:26:c1:b8:e9:83:00:62:45:b6:a9:08: + 93:b9:a9:33:4b:18:9a:c2:f8:87:88:4e:db:dd:71:34:1a:c1: + 54:da:46:3f:e0:d3:2a:ab:6d:54:22:f5:3a:62:cd:20:6f:ba: + 29:89:d7:dd:91:ee:d3:5c:a2:3e:a1:5b:41:f5:df:e5:64:43: + 2d:e9:d5:39:ab:d2:a2:df:b7:8b:d0:c0:80:19:1c:45:c0:2d: + 8c:e8:f8:2d:a4:74:56:49:c5:05:b5:4f:15:de:6e:44:78:39: + 87:a8:7e:bb:f3:79:18:91:bb:f4:6f:9d:c1:f0:8c:35:8c:5d: + 01:fb:c3:6d:b9:ef:44:6d:79:46:31:7e:0a:fe:a9:82:c1:ff: + ef:ab:6e:20:c4:50:c9:5f:9d:4d:9b:17:8c:0c:e5:01:c9:a0: + 41:6a:73:53:fa:a5:50:b4:6e:25:0f:fb:4c:18:f4:fd:52:d9: + 8e:69:b1:e8:11:0f:de:88:d8:fb:1d:49:f7:aa:de:95:cf:20: + 78:c2:60:12:db:25:40:8c:6a:fc:7e:42:38:40:64:12:f7:9e: + 81:e1:93:2e +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 +MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL +v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 +eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq +tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd +C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa +zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB +mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH +V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n +bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG +3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs +J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO +291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS +ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd +AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- diff --git a/certs/Go Daddy Secure Certificate Authority - G2.pem b/certs/Go Daddy Secure Certificate Authority - G2.pem index 72e5054..4faba90 100644 --- a/certs/Go Daddy Secure Certificate Authority - G2.pem +++ b/certs/Go Daddy Secure Certificate Authority - G2.pem @@ -1,26 +1,74 @@ ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT -EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp -ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz -NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH -EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE -AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD -E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH -/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy -DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh -GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR -tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA -AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX -WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu -9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr -gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo -2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO -LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI -4uJEvlz36hz1 ------END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7 (0x7) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", CN = Go Daddy Root Certificate Authority - G2 + Validity + Not Before: May 3 07:00:00 2011 GMT + Not After : May 3 07:00:00 2031 GMT + Subject: C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", OU = http://certs.godaddy.com/repository/, CN = Go Daddy Secure Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:b9:e0:cb:10:d4:af:76:bd:d4:93:62:eb:30:64: + b8:81:08:6c:c3:04:d9:62:17:8e:2f:ff:3e:65:cf: + 8f:ce:62:e6:3c:52:1c:da:16:45:4b:55:ab:78:6b: + 63:83:62:90:ce:0f:69:6c:99:c8:1a:14:8b:4c:cc: + 45:33:ea:88:dc:9e:a3:af:2b:fe:80:61:9d:79:57: + c4:cf:2e:f4:3f:30:3c:5d:47:fc:9a:16:bc:c3:37: + 96:41:51:8e:11:4b:54:f8:28:be:d0:8c:be:f0:30: + 38:1e:f3:b0:26:f8:66:47:63:6d:de:71:26:47:8f: + 38:47:53:d1:46:1d:b4:e3:dc:00:ea:45:ac:bd:bc: + 71:d9:aa:6f:00:db:db:cd:30:3a:79:4f:5f:4c:47: + f8:1d:ef:5b:c2:c4:9d:60:3b:b1:b2:43:91:d8:a4: + 33:4e:ea:b3:d6:27:4f:ad:25:8a:a5:c6:f4:d5:d0: + a6:ae:74:05:64:57:88:b5:44:55:d4:2d:2a:3a:3e: + f8:b8:bd:e9:32:0a:02:94:64:c4:16:3a:50:f1:4a: + ae:e7:79:33:af:0c:20:07:7f:e8:df:04:39:c2:69: + 02:6c:63:52:fa:77:c1:1b:c8:74:87:c8:b9:93:18: + 50:54:35:4b:69:4e:bc:3b:d3:49:2e:1f:dc:c1:d2: + 52:fb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 40:C2:BD:27:8E:CC:34:83:30:A2:33:D7:FB:6C:B3:F0:B4:2C:80:CE + X509v3 Authority Key Identifier: + keyid:3A:9A:85:07:10:67:28:B6:EF:F6:BD:05:41:6E:20:C1:94:DA:0F:DE + + Authority Information Access: + OCSP - URI:http://ocsp.godaddy.com/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.godaddy.com/gdroot-g2.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://certs.godaddy.com/repository/ + + Signature Algorithm: sha256WithRSAEncryption + 08:7e:6c:93:10:c8:38:b8:96:a9:90:4b:ff:a1:5f:4f:04:ef: + 6c:3e:9c:88:06:c9:50:8f:a6:73:f7:57:31:1b:be:bc:e4:2f: + db:f8:ba:d3:5b:e0:b4:e7:e6:79:62:0e:0c:a2:d7:6a:63:73: + 31:b5:f5:a8:48:a4:3b:08:2d:a2:5d:90:d7:b4:7c:25:4f:11: + 56:30:c4:b6:44:9d:7b:2c:9d:e5:5e:e6:ef:0c:61:aa:bf:e4: + 2a:1b:ee:84:9e:b8:83:7d:c1:43:ce:44:a7:13:70:0d:91:1f: + f4:c8:13:ad:83:60:d9:d8:72:a8:73:24:1e:b5:ac:22:0e:ca: + 17:89:62:58:44:1b:ab:89:25:01:00:0f:cd:c4:1b:62:db:51: + b4:d3:0f:51:2a:9b:f4:bc:73:fc:76:ce:36:a4:cd:d9:d8:2c: + ea:ae:9b:f5:2a:b2:90:d1:4d:75:18:8a:3f:8a:41:90:23:7d: + 5b:4b:fe:a4:03:58:9b:46:b2:c3:60:60:83:f8:7d:50:41:ce: + c2:a1:90:c3:bb:ef:02:2f:d2:15:54:ee:44:15:d9:0a:ae:a7: + 8a:33:ed:b1:2d:76:36:26:dc:04:eb:9f:f7:61:1f:15:dc:87: + 6f:ee:46:96:28:ad:a1:26:7d:0a:09:a7:2e:04:a3:8d:bc:f8: + bc:04:30:01 -----BEGIN CERTIFICATE----- MIIE0DCCA7igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT @@ -49,3 +97,82 @@ DsoXiWJYRBuriSUBAA/NxBti21G00w9RKpv0vHP8ds42pM3Z2Czqrpv1KrKQ0U11 GIo/ikGQI31bS/6kA1ibRrLDYGCD+H1QQc7CoZDDu+8CL9IVVO5EFdkKrqeKM+2x LXY2JtwE65/3YR8V3Idv7kaWKK2hJn0KCacuBKONvPi8BDAB -----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", CN = Go Daddy Root Certificate Authority - G2 + Validity + Not Before: Sep 1 00:00:00 2009 GMT + Not After : Dec 31 23:59:59 2037 GMT + Subject: C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", CN = Go Daddy Root Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:bf:71:62:08:f1:fa:59:34:f7:1b:c9:18:a3:f7: + 80:49:58:e9:22:83:13:a6:c5:20:43:01:3b:84:f1: + e6:85:49:9f:27:ea:f6:84:1b:4e:a0:b4:db:70:98: + c7:32:01:b1:05:3e:07:4e:ee:f4:fa:4f:2f:59:30: + 22:e7:ab:19:56:6b:e2:80:07:fc:f3:16:75:80:39: + 51:7b:e5:f9:35:b6:74:4e:a9:8d:82:13:e4:b6:3f: + a9:03:83:fa:a2:be:8a:15:6a:7f:de:0b:c3:b6:19: + 14:05:ca:ea:c3:a8:04:94:3b:46:7c:32:0d:f3:00: + 66:22:c8:8d:69:6d:36:8c:11:18:b7:d3:b2:1c:60: + b4:38:fa:02:8c:ce:d3:dd:46:07:de:0a:3e:eb:5d: + 7c:c8:7c:fb:b0:2b:53:a4:92:62:69:51:25:05:61: + 1a:44:81:8c:2c:a9:43:96:23:df:ac:3a:81:9a:0e: + 29:c5:1c:a9:e9:5d:1e:b6:9e:9e:30:0a:39:ce:f1: + 88:80:fb:4b:5d:cc:32:ec:85:62:43:25:34:02:56: + 27:01:91:b4:3b:70:2a:3f:6e:b1:e8:9c:88:01:7d: + 9f:d4:f9:db:53:6d:60:9d:bf:2c:e7:58:ab:b8:5f: + 46:fc:ce:c4:1b:03:3c:09:eb:49:31:5c:69:46:b3: + e0:47 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 3A:9A:85:07:10:67:28:B6:EF:F6:BD:05:41:6E:20:C1:94:DA:0F:DE + Signature Algorithm: sha256WithRSAEncryption + 99:db:5d:79:d5:f9:97:59:67:03:61:f1:7e:3b:06:31:75:2d: + a1:20:8e:4f:65:87:b4:f7:a6:9c:bc:d8:e9:2f:d0:db:5a:ee: + cf:74:8c:73:b4:38:42:da:05:7b:f8:02:75:b8:fd:a5:b1:d7: + ae:f6:d7:de:13:cb:53:10:7e:8a:46:d1:97:fa:b7:2e:2b:11: + ab:90:b0:27:80:f9:e8:9f:5a:e9:37:9f:ab:e4:df:6c:b3:85: + 17:9d:3d:d9:24:4f:79:91:35:d6:5f:04:eb:80:83:ab:9a:02: + 2d:b5:10:f4:d8:90:c7:04:73:40:ed:72:25:a0:a9:9f:ec:9e: + ab:68:12:99:57:c6:8f:12:3a:09:a4:bd:44:fd:06:15:37:c1: + 9b:e4:32:a3:ed:38:e8:d8:64:f3:2c:7e:14:fc:02:ea:9f:cd: + ff:07:68:17:db:22:90:38:2d:7a:8d:d1:54:f1:69:e3:5f:33: + ca:7a:3d:7b:0a:e3:ca:7f:5f:39:e5:e2:75:ba:c5:76:18:33: + ce:2c:f0:2f:4c:ad:f7:b1:e7:ce:4f:a8:c4:9b:4a:54:06:c5: + 7f:7d:d5:08:0f:e2:1c:fe:7e:17:b8:ac:5e:f6:d4:16:b2:43: + 09:0c:4d:f6:a7:6b:b4:99:84:65:ca:7a:88:e2:e2:44:be:5c: + f7:ea:1c:f5 +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- diff --git a/certs/R3.pem b/certs/R3.pem index 933f1d9..ac322ec 100644 --- a/certs/R3.pem +++ b/certs/R3.pem @@ -1,3 +1,91 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 91:2b:08:4a:cf:0c:18:a7:53:f6:d6:2e:25:a7:5f:5a + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 + Validity + Not Before: Sep 4 00:00:00 2020 GMT + Not After : Sep 15 16:00:00 2025 GMT + Subject: C = US, O = Let's Encrypt, CN = R3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:bb:02:15:28:cc:f6:a0:94:d3:0f:12:ec:8d:55: + 92:c3:f8:82:f1:99:a6:7a:42:88:a7:5d:26:aa:b5: + 2b:b9:c5:4c:b1:af:8e:6b:f9:75:c8:a3:d7:0f:47: + 94:14:55:35:57:8c:9e:a8:a2:39:19:f5:82:3c:42: + a9:4e:6e:f5:3b:c3:2e:db:8d:c0:b0:5c:f3:59:38: + e7:ed:cf:69:f0:5a:0b:1b:be:c0:94:24:25:87:fa: + 37:71:b3:13:e7:1c:ac:e1:9b:ef:db:e4:3b:45:52: + 45:96:a9:c1:53:ce:34:c8:52:ee:b5:ae:ed:8f:de: + 60:70:e2:a5:54:ab:b6:6d:0e:97:a5:40:34:6b:2b: + d3:bc:66:eb:66:34:7c:fa:6b:8b:8f:57:29:99:f8: + 30:17:5d:ba:72:6f:fb:81:c5:ad:d2:86:58:3d:17: + c7:e7:09:bb:f1:2b:f7:86:dc:c1:da:71:5d:d4:46: + e3:cc:ad:25:c1:88:bc:60:67:75:66:b3:f1:18:f7: + a2:5c:e6:53:ff:3a:88:b6:47:a5:ff:13:18:ea:98: + 09:77:3f:9d:53:f9:cf:01:e5:f5:a6:70:17:14:af: + 63:a4:ff:99:b3:93:9d:dc:53:a7:06:fe:48:85:1d: + a1:69:ae:25:75:bb:13:cc:52:03:f5:ed:51:a1:8b: + db:15 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + 14:2E:B3:17:B7:58:56:CB:AE:50:09:40:E6:1F:AF:9D:8B:14:C2:C6 + X509v3 Authority Key Identifier: + keyid:79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E + + Authority Information Access: + CA Issuers - URI:http://x1.i.lencr.org/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://x1.c.lencr.org/ + + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.1 + Policy: 1.3.6.1.4.1.44947.1.1.1 + + Signature Algorithm: sha256WithRSAEncryption + 85:ca:4e:47:3e:a3:f7:85:44:85:bc:d5:67:78:b2:98:63:ad: + 75:4d:1e:96:3d:33:65:72:54:2d:81:a0:ea:c3:ed:f8:20:bf: + 5f:cc:b7:70:00:b7:6e:3b:f6:5e:94:de:e4:20:9f:a6:ef:8b: + b2:03:e7:a2:b5:16:3c:91:ce:b4:ed:39:02:e7:7c:25:8a:47: + e6:65:6e:3f:46:f4:d9:f0:ce:94:2b:ee:54:ce:12:bc:8c:27: + 4b:b8:c1:98:2f:a2:af:cd:71:91:4a:08:b7:c8:b8:23:7b:04: + 2d:08:f9:08:57:3e:83:d9:04:33:0a:47:21:78:09:82:27:c3: + 2a:c8:9b:b9:ce:5c:f2:64:c8:c0:be:79:c0:4f:8e:6d:44:0c: + 5e:92:bb:2e:f7:8b:10:e1:e8:1d:44:29:db:59:20:ed:63:b9: + 21:f8:12:26:94:93:57:a0:1d:65:04:c1:0a:22:ae:10:0d:43: + 97:a1:18:1f:7e:e0:e0:86:37:b5:5a:b1:bd:30:bf:87:6e:2b: + 2a:ff:21:4e:1b:05:c3:f5:18:97:f0:5e:ac:c3:a5:b8:6a:f0: + 2e:bc:3b:33:b9:ee:4b:de:cc:fc:e4:af:84:0b:86:3f:c0:55: + 43:36:f6:68:e1:36:17:6a:8e:99:d1:ff:a5:40:a7:34:b7:c0: + d0:63:39:35:39:75:6e:f2:ba:76:c8:93:02:e9:a9:4b:6c:17: + ce:0c:02:d9:bd:81:fb:9f:b7:68:d4:06:65:b3:82:3d:77:53: + f8:8e:79:03:ad:0a:31:07:75:2a:43:d8:55:97:72:c4:29:0e: + f7:c4:5d:4e:c8:ae:46:84:30:d7:f2:85:5f:18:a1:79:bb:e7: + 5e:70:8b:07:e1:86:93:c3:b9:8f:dc:61:71:25:2a:af:df:ed: + 25:50:52:68:8b:92:dc:e5:d6:b5:e3:da:7d:d0:87:6c:84:21: + 31:ae:82:f5:fb:b9:ab:c8:89:17:3d:e1:4c:e5:38:0e:f6:bd: + 2b:bd:96:81:14:eb:d5:db:3d:20:a7:7e:59:d3:e2:f8:58:f9: + 5b:b8:48:cd:fe:5c:4f:16:29:fe:1e:55:23:af:c8:11:b0:8d: + ea:7c:93:90:17:2f:fd:ac:a2:09:47:46:3f:f0:e9:b0:b7:ff: + 28:4d:68:32:d6:67:5e:1e:69:a3:93:b8:f5:9d:8b:2f:0b:d2: + 52:43:a6:6f:32:57:65:4d:32:81:df:38:53:85:5d:7e:5d:66: + 29:ea:b8:dd:e4:95:b5:cd:b5:56:12:42:cd:c4:4e:c6:25:38: + 44:50:6d:ec:ce:00:55:18:fe:e9:49:64:d4:4e:ca:97:9c:b4: + 5b:c0:73:a8:ab:b8:47:c2 -----BEGIN CERTIFICATE----- MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh @@ -28,6 +116,94 @@ HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX nLRbwHOoq7hHwg== -----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 82:10:cf:b0:d2:40:e3:59:44:63:e0:bb:63:82:8b:00 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 + Validity + Not Before: Jun 4 11:04:38 2015 GMT + Not After : Jun 4 11:04:38 2035 GMT + Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:ad:e8:24:73:f4:14:37:f3:9b:9e:2b:57:28:1c: + 87:be:dc:b7:df:38:90:8c:6e:3c:e6:57:a0:78:f7: + 75:c2:a2:fe:f5:6a:6e:f6:00:4f:28:db:de:68:86: + 6c:44:93:b6:b1:63:fd:14:12:6b:bf:1f:d2:ea:31: + 9b:21:7e:d1:33:3c:ba:48:f5:dd:79:df:b3:b8:ff: + 12:f1:21:9a:4b:c1:8a:86:71:69:4a:66:66:6c:8f: + 7e:3c:70:bf:ad:29:22:06:f3:e4:c0:e6:80:ae:e2: + 4b:8f:b7:99:7e:94:03:9f:d3:47:97:7c:99:48:23: + 53:e8:38:ae:4f:0a:6f:83:2e:d1:49:57:8c:80:74: + b6:da:2f:d0:38:8d:7b:03:70:21:1b:75:f2:30:3c: + fa:8f:ae:dd:da:63:ab:eb:16:4f:c2:8e:11:4b:7e: + cf:0b:e8:ff:b5:77:2e:f4:b2:7b:4a:e0:4c:12:25: + 0c:70:8d:03:29:a0:e1:53:24:ec:13:d9:ee:19:bf: + 10:b3:4a:8c:3f:89:a3:61:51:de:ac:87:07:94:f4: + 63:71:ec:2e:e2:6f:5b:98:81:e1:89:5c:34:79:6c: + 76:ef:3b:90:62:79:e6:db:a4:9a:2f:26:c5:d0:10: + e1:0e:de:d9:10:8e:16:fb:b7:f7:a8:f7:c7:e5:02: + 07:98:8f:36:08:95:e7:e2:37:96:0d:36:75:9e:fb: + 0e:72:b1:1d:9b:bc:03:f9:49:05:d8:81:dd:05:b4: + 2a:d6:41:e9:ac:01:76:95:0a:0f:d8:df:d5:bd:12: + 1f:35:2f:28:17:6c:d2:98:c1:a8:09:64:77:6e:47: + 37:ba:ce:ac:59:5e:68:9d:7f:72:d6:89:c5:06:41: + 29:3e:59:3e:dd:26:f5:24:c9:11:a7:5a:a3:4c:40: + 1f:46:a1:99:b5:a7:3a:51:6e:86:3b:9e:7d:72:a7: + 12:05:78:59:ed:3e:51:78:15:0b:03:8f:8d:d0:2f: + 05:b2:3e:7b:4a:1c:4b:73:05:12:fc:c6:ea:e0:50: + 13:7c:43:93:74:b3:ca:74:e7:8e:1f:01:08:d0:30: + d4:5b:71:36:b4:07:ba:c1:30:30:5c:48:b7:82:3b: + 98:a6:7d:60:8a:a2:a3:29:82:cc:ba:bd:83:04:1b: + a2:83:03:41:a1:d6:05:f1:1b:c2:b6:f0:a8:7c:86: + 3b:46:a8:48:2a:88:dc:76:9a:76:bf:1f:6a:a5:3d: + 19:8f:eb:38:f3:64:de:c8:2b:0d:0a:28:ff:f7:db: + e2:15:42:d4:22:d0:27:5d:e1:79:fe:18:e7:70:88: + ad:4e:e6:d9:8b:3a:c6:dd:27:51:6e:ff:bc:64:f5: + 33:43:4f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E + Signature Algorithm: sha256WithRSAEncryption + 55:1f:58:a9:bc:b2:a8:50:d0:0c:b1:d8:1a:69:20:27:29:08: + ac:61:75:5c:8a:6e:f8:82:e5:69:2f:d5:f6:56:4b:b9:b8:73: + 10:59:d3:21:97:7e:e7:4c:71:fb:b2:d2:60:ad:39:a8:0b:ea: + 17:21:56:85:f1:50:0e:59:eb:ce:e0:59:e9:ba:c9:15:ef:86: + 9d:8f:84:80:f6:e4:e9:91:90:dc:17:9b:62:1b:45:f0:66:95: + d2:7c:6f:c2:ea:3b:ef:1f:cf:cb:d6:ae:27:f1:a9:b0:c8:ae: + fd:7d:7e:9a:fa:22:04:eb:ff:d9:7f:ea:91:2b:22:b1:17:0e: + 8f:f2:8a:34:5b:58:d8:fc:01:c9:54:b9:b8:26:cc:8a:88:33: + 89:4c:2d:84:3c:82:df:ee:96:57:05:ba:2c:bb:f7:c4:b7:c7: + 4e:3b:82:be:31:c8:22:73:73:92:d1:c2:80:a4:39:39:10:33: + 23:82:4c:3c:9f:86:b2:55:98:1d:be:29:86:8c:22:9b:9e:e2: + 6b:3b:57:3a:82:70:4d:dc:09:c7:89:cb:0a:07:4d:6c:e8:5d: + 8e:c9:ef:ce:ab:c7:bb:b5:2b:4e:45:d6:4a:d0:26:cc:e5:72: + ca:08:6a:a5:95:e3:15:a1:f7:a4:ed:c9:2c:5f:a5:fb:ff:ac: + 28:02:2e:be:d7:7b:bb:e3:71:7b:90:16:d3:07:5e:46:53:7c: + 37:07:42:8c:d3:c4:96:9c:d5:99:b5:2a:e0:95:1a:80:48:ae: + 4c:39:07:ce:cc:47:a4:52:95:2b:ba:b8:fb:ad:d2:33:53:7d: + e5:1d:4d:6d:d5:a1:b1:c7:42:6f:e6:40:27:35:5c:a3:28:b7: + 07:8d:e7:8d:33:90:e7:23:9f:fb:50:9c:79:6c:46:d5:b4:15: + b3:96:6e:7e:9b:0c:96:3a:b8:52:2d:3f:d6:5b:e1:fb:08:c2: + 84:fe:24:a8:a3:89:da:ac:6a:e1:18:2a:b1:a8:43:61:5b:d3: + 1f:dc:3b:8d:76:f2:2d:e8:8d:75:df:17:33:6c:3d:53:fb:7b: + cb:41:5f:ff:dc:a2:d0:61:38:e1:96:b8:ac:5d:8b:37:d7:75: + d5:33:c0:99:11:ae:9d:41:c1:72:75:84:be:02:41:42:5f:67: + 24:48:94:d1:9b:27:be:07:3f:b9:b8:4f:81:74:51:e1:7a:b7: + ed:9d:23:e2:be:e0:d5:28:04:13:3c:31:03:9e:dd:7a:6c:8f: + c6:07:18:c6:7f:de:47:8e:3f:28:9e:04:06:cf:a5:54:34:77: + bd:ec:89:9b:e9:17:43:df:5b:db:5f:fe:8e:1e:57:a2:cd:40: + 9d:7e:62:22:da:de:18:27 -----BEGIN CERTIFICATE----- MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh @@ -59,6 +235,63 @@ oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= -----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 44:af:b0:80:d6:a3:27:ba:89:30:39:86:2e:f8:40:6b + Signature Algorithm: sha1WithRSAEncryption + Issuer: O = Digital Signature Trust Co., CN = DST Root CA X3 + Validity + Not Before: Sep 30 21:12:19 2000 GMT + Not After : Sep 30 14:01:15 2021 GMT + Subject: O = Digital Signature Trust Co., CN = DST Root CA X3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:df:af:e9:97:50:08:83:57:b4:cc:62:65:f6:90: + 82:ec:c7:d3:2c:6b:30:ca:5b:ec:d9:c3:7d:c7:40: + c1:18:14:8b:e0:e8:33:76:49:2a:e3:3f:21:49:93: + ac:4e:0e:af:3e:48:cb:65:ee:fc:d3:21:0f:65:d2: + 2a:d9:32:8f:8c:e5:f7:77:b0:12:7b:b5:95:c0:89: + a3:a9:ba:ed:73:2e:7a:0c:06:32:83:a2:7e:8a:14: + 30:cd:11:a0:e1:2a:38:b9:79:0a:31:fd:50:bd:80: + 65:df:b7:51:63:83:c8:e2:88:61:ea:4b:61:81:ec: + 52:6b:b9:a2:e2:4b:1a:28:9f:48:a3:9e:0c:da:09: + 8e:3e:17:2e:1e:dd:20:df:5b:c6:2a:8a:ab:2e:bd: + 70:ad:c5:0b:1a:25:90:74:72:c5:7b:6a:ab:34:d6: + 30:89:ff:e5:68:13:7b:54:0b:c8:d6:ae:ec:5a:9c: + 92:1e:3d:64:b3:8c:c6:df:bf:c9:41:70:ec:16:72: + d5:26:ec:38:55:39:43:d0:fc:fd:18:5c:40:f1:97: + eb:d5:9a:9b:8d:1d:ba:da:25:b9:c6:d8:df:c1:15: + 02:3a:ab:da:6e:f1:3e:2e:f5:5c:08:9c:3c:d6:83: + 69:e4:10:9b:19:2a:b6:29:57:e3:e5:3d:9b:9f:f0: + 02:5d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + C4:A7:B1:A4:7B:2C:71:FA:DB:E1:4B:90:75:FF:C4:15:60:85:89:10 + Signature Algorithm: sha1WithRSAEncryption + a3:1a:2c:9b:17:00:5c:a9:1e:ee:28:66:37:3a:bf:83:c7:3f: + 4b:c3:09:a0:95:20:5d:e3:d9:59:44:d2:3e:0d:3e:bd:8a:4b: + a0:74:1f:ce:10:82:9c:74:1a:1d:7e:98:1a:dd:cb:13:4b:b3: + 20:44:e4:91:e9:cc:fc:7d:a5:db:6a:e5:fe:e6:fd:e0:4e:dd: + b7:00:3a:b5:70:49:af:f2:e5:eb:02:f1:d1:02:8b:19:cb:94: + 3a:5e:48:c4:18:1e:58:19:5f:1e:02:5a:f0:0c:f1:b1:ad:a9: + dc:59:86:8b:6e:e9:91:f5:86:ca:fa:b9:66:33:aa:59:5b:ce: + e2:a7:16:73:47:cb:2b:cc:99:b0:37:48:cf:e3:56:4b:f5:cf: + 0f:0c:72:32:87:c6:f0:44:bb:53:72:6d:43:f5:26:48:9a:52: + 67:b7:58:ab:fe:67:76:71:78:db:0d:a2:56:14:13:39:24:31: + 85:a2:a8:02:5a:30:47:e1:dd:50:07:bc:02:09:90:00:eb:64: + 63:60:9b:16:bc:88:c9:12:e6:d2:7d:91:8b:f9:3d:32:8d:65: + b4:e9:7c:b1:57:76:ea:c5:b6:28:39:bf:15:65:1c:c8:f6:77: + 96:6a:0a:8d:77:0b:d8:91:0b:04:8e:07:db:29:b6:0a:ee:9d: + 82:35:35:10 -----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT diff --git a/certs/Starfield Secure Certificate Authority - G2.pem b/certs/Starfield Secure Certificate Authority - G2.pem index 9c17e74..7772e6b 100644 --- a/certs/Starfield Secure Certificate Authority - G2.pem +++ b/certs/Starfield Secure Certificate Authority - G2.pem @@ -1,26 +1,74 @@ ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs -ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw -MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 -b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj -aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp -Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg -nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 -HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N -Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN -dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 -HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G -CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU -sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 -4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg -8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K -pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 -mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 ------END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7 (0x7) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Root Certificate Authority - G2 + Validity + Not Before: May 3 07:00:00 2011 GMT + Not After : May 3 07:00:00 2031 GMT + Subject: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", OU = http://certs.starfieldtech.com/repository/, CN = Starfield Secure Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:e5:90:66:4b:ec:f9:46:71:a9:20:83:be:e9:6c: + bf:4a:c9:48:69:81:75:4e:6d:24:f6:cb:17:13:f8: + b0:71:59:84:7a:6b:2b:85:a4:34:b5:16:e5:cb:cc: + e9:41:70:2c:a4:2e:d6:fa:32:7d:e1:a8:de:94:10: + ac:31:c1:c0:d8:6a:ff:59:27:ab:76:d6:fc:0b:74: + 6b:b8:a7:ae:3f:c4:54:f4:b4:31:44:dd:93:56:8c: + a4:4c:5e:9b:89:cb:24:83:9b:e2:57:7d:b7:d8:12: + 1f:c9:85:6d:f4:d1:80:f1:50:9b:87:ae:d4:0b:10: + 05:fb:27:ba:28:6d:17:e9:0e:d6:4d:b9:39:55:06: + ff:0a:24:05:7e:2f:c6:1d:72:6c:d4:8b:29:8c:57: + 7d:da:d9:eb:66:1a:d3:4f:a7:df:7f:52:c4:30:c5: + a5:c9:0e:02:c5:53:bf:77:38:68:06:24:c3:66:c8: + 37:7e:30:1e:45:71:23:35:ff:90:d8:2a:9d:8d:e7: + b0:92:4d:3c:7f:2a:0a:93:dc:cd:16:46:65:f7:60: + 84:8b:76:4b:91:27:73:14:92:e0:ea:ee:8f:16:ea: + 8d:0e:3e:76:17:bf:7d:89:80:80:44:43:e7:2d:e0: + 43:09:75:da:36:e8:ad:db:89:3a:f5:5d:12:8e:23: + 04:83 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 25:45:81:68:50:26:38:3D:3B:2D:2C:BE:CD:6A:D9:B6:3D:B3:66:63 + X509v3 Authority Key Identifier: + keyid:7C:0C:32:1F:A7:D9:30:7F:C4:7D:68:A3:62:A8:A1:CE:AB:07:5B:27 + + Authority Information Access: + OCSP - URI:http://ocsp.starfieldtech.com/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.starfieldtech.com/sfroot-g2.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://certs.starfieldtech.com/repository/ + + Signature Algorithm: sha256WithRSAEncryption + 56:65:ca:fe:f3:3f:0a:a8:93:8b:18:c7:de:43:69:13:34:20: + be:4e:5f:78:a8:6b:9c:db:6a:4d:41:db:c1:13:ec:dc:31:00: + 22:5e:f7:00:9e:0c:e0:34:65:34:f9:b1:3a:4e:48:c8:12:81: + 88:5c:5b:3e:08:53:7a:f7:1a:64:df:b8:50:61:cc:53:51:40: + 29:4b:c2:f4:ae:3a:5f:e4:ca:ad:26:cc:4e:61:43:e5:fd:57: + a6:37:70:ce:43:2b:b0:94:c3:92:e9:e1:5f:aa:10:49:b7:69: + e4:e0:d0:1f:64:a4:2b:cd:1f:6f:a0:f8:84:24:18:ce:79:3d: + a9:91:bf:54:18:13:89:99:54:11:0d:55:c5:26:0b:79:4f:5a: + 1c:6e:f9:63:db:14:80:a4:07:ab:fa:b2:a5:b9:88:dd:91:fe: + 65:3b:a4:a3:79:be:89:4d:e1:d0:b0:f4:c8:17:0c:0a:96:14: + 7c:09:b7:6c:e1:c2:d8:55:d4:18:a0:aa:41:69:70:24:a3:b9: + ef:e9:5a:dc:3e:eb:94:4a:f0:b7:de:5f:0e:76:fa:fb:fb:69: + 03:45:40:50:ee:72:0c:a4:12:86:81:cd:13:d1:4e:c4:3c:ca: + 4e:0d:d2:26:f1:00:b7:b4:a6:a2:e1:6e:7a:81:fd:30:ac:7a: + 1f:c7:59:7b -----BEGIN CERTIFICATE----- MIIFADCCA+igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT @@ -50,3 +98,82 @@ eT2pkb9UGBOJmVQRDVXFJgt5T1ocbvlj2xSApAer+rKluYjdkf5lO6Sjeb6JTeHQ sPTIFwwKlhR8Cbds4cLYVdQYoKpBaXAko7nv6VrcPuuUSvC33l8Odvr7+2kDRUBQ 7nIMpBKGgc0T0U7EPMpODdIm8QC3tKai4W56gf0wrHofx1l7 -----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Root Certificate Authority - G2 + Validity + Not Before: Sep 1 00:00:00 2009 GMT + Not After : Dec 31 23:59:59 2037 GMT + Subject: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Root Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:bd:ed:c1:03:fc:f6:8f:fc:02:b1:6f:5b:9f:48: + d9:9d:79:e2:a2:b7:03:61:56:18:c3:47:b6:d7:ca: + 3d:35:2e:89:43:f7:a1:69:9b:de:8a:1a:fd:13:20: + 9c:b4:49:77:32:29:56:fd:b9:ec:8c:dd:22:fa:72: + dc:27:61:97:ee:f6:5a:84:ec:6e:19:b9:89:2c:dc: + 84:5b:d5:74:fb:6b:5f:c5:89:a5:10:52:89:46:55: + f4:b8:75:1c:e6:7f:e4:54:ae:4b:f8:55:72:57:02: + 19:f8:17:71:59:eb:1e:28:07:74:c5:9d:48:be:6c: + b4:f4:a4:b0:f3:64:37:79:92:c0:ec:46:5e:7f:e1: + 6d:53:4c:62:af:cd:1f:0b:63:bb:3a:9d:fb:fc:79: + 00:98:61:74:cf:26:82:40:63:f3:b2:72:6a:19:0d: + 99:ca:d4:0e:75:cc:37:fb:8b:89:c1:59:f1:62:7f: + 5f:b3:5f:65:30:f8:a7:b7:4d:76:5a:1e:76:5e:34: + c0:e8:96:56:99:8a:b3:f0:7f:a4:cd:bd:dc:32:31: + 7c:91:cf:e0:5f:11:f8:6b:aa:49:5c:d1:99:94:d1: + a2:e3:63:5b:09:76:b5:56:62:e1:4b:74:1d:96:d4: + 26:d4:08:04:59:d0:98:0e:0e:e6:de:fc:c3:ec:1f: + 90:f1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 7C:0C:32:1F:A7:D9:30:7F:C4:7D:68:A3:62:A8:A1:CE:AB:07:5B:27 + Signature Algorithm: sha256WithRSAEncryption + 11:59:fa:25:4f:03:6f:94:99:3b:9a:1f:82:85:39:d4:76:05: + 94:5e:e1:28:93:6d:62:5d:09:c2:a0:a8:d4:b0:75:38:f1:34: + 6a:9d:e4:9f:8a:86:26:51:e6:2c:d1:c6:2d:6e:95:20:4a:92: + 01:ec:b8:8a:67:7b:31:e2:67:2e:8c:95:03:26:2e:43:9d:4a: + 31:f6:0e:b5:0c:bb:b7:e2:37:7f:22:ba:00:a3:0e:7b:52:fb: + 6b:bb:3b:c4:d3:79:51:4e:cd:90:f4:67:07:19:c8:3c:46:7a: + 0d:01:7d:c5:58:e7:6d:e6:85:30:17:9a:24:c4:10:e0:04:f7: + e0:f2:7f:d4:aa:0a:ff:42:1d:37:ed:94:e5:64:59:12:20:77: + 38:d3:32:3e:38:81:75:96:73:fa:68:8f:b1:cb:ce:1f:c5:ec: + fa:9c:7e:cf:7e:b1:f1:07:2d:b6:fc:bf:ca:a4:bf:d0:97:05: + 4a:bc:ea:18:28:02:90:bd:54:78:09:21:71:d3:d1:7d:1d:d9: + 16:b0:a9:61:3d:d0:0a:00:22:fc:c7:7b:cb:09:64:45:0b:3b: + 40:81:f7:7d:7c:32:f5:98:ca:58:8e:7d:2a:ee:90:59:73:64: + f9:36:74:5e:25:a1:f5:66:05:2e:7f:39:15:a9:2a:fb:50:8b: + 8e:85:69:f4 +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- From ca6668950b045f1c3eb775a7203ea26ddba5e4d8 Mon Sep 17 00:00:00 2001 From: Daniel Ziegenberg Date: Wed, 30 Dec 2020 12:38:10 +0100 Subject: [PATCH 0571/2612] collect-wireless-mac: always select first lease from dhcp-server The script fails at setting the hostname when there are multiple leases for a mac address. In line 36 and 37 the hostname gets set from the data the lease. When there is more than one lease for a specific mac address this fails with the message "invalid internal item number". More than one lease for a mac address is possible, if you have more than one SSID on a capsman and a single device can login into more than one SSID. Fixes #10 Signed-off-by: Christian Hesse --- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 7abae6a..3ed67fc 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -31,7 +31,7 @@ $ScriptLock "collect-wireless-mac.capsman"; :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease [ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]; + :local Lease ([ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]->0); :if ([ :len $Lease ] > 0) do={ :set Address [ / ip dhcp-server lease get $Lease address ]; :set HostName [ / ip dhcp-server lease get $Lease host-name ]; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 080d036..fc36e59 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -31,7 +31,7 @@ $ScriptLock "collect-wireless-mac.local"; :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease [ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]; + :local Lease ([ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]->0); :if ([ :len $Lease ] > 0) do={ :set Address [ / ip dhcp-server lease get $Lease address ]; :set HostName [ / ip dhcp-server lease get $Lease host-name ]; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index a7e2b4a..9b06dc3 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -32,7 +32,7 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease [ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]; + :local Lease ([ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]->0); :if ([ :len $Lease ] > 0) do={ :set Address [ / ip dhcp-server lease get $Lease address ]; :set HostName [ / ip dhcp-server lease get $Lease host-name ]; From ea7cdcb4a505547f9cd696aa9d3d8ae8f4c4231b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 30 Dec 2020 12:45:31 +0100 Subject: [PATCH 0572/2612] update list of contributors --- CONTRIBUTIONS.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 6cf5ade..a78b0df 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -9,7 +9,8 @@ Thanks a lot for your contributions! These persons contributed code. See the git history for details! -* [Michael Gisbers](mailto:michael@gisbers.de) +* [Daniel Ziegenberg](mailto:daniel@ziegenberg.at) (@ziegenberg) +* [Michael Gisbers](mailto:michael@gisbers.de) (@mgisbers) * [netztrip](mailto:dave-tvg@netztrip.de) (@netztrip) ## Donations @@ -17,11 +18,11 @@ These persons contributed code. See the git history for details! Add yourself to the list, [donate with PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)! -* Reiner Vehrenkamp -* Linux-Schmie.de Michael Gisbers * Christoph Boss (@Kampfwurst) * Klaus Michael RÃŧbsam +* Linux-Schmie.de Michael Gisbers * Marek ÄŒÃĄbÃĄk +* Reiner Vehrenkamp --- [◀ Go back to main README](README.md) From 547fbc630a71b7b890de5e74b5c10a1ed47cf747 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 1 Jan 2021 21:33:52 +0100 Subject: [PATCH 0573/2612] update copyright for 2021 --- accesslist-duplicates.capsman | 2 +- accesslist-duplicates.local | 2 +- accesslist-duplicates.template | 2 +- bridge-port-to-default | 2 +- bridge-port-toggle | 2 +- capsman-download-packages | 2 +- capsman-rolling-upgrade | 2 +- certificate-renew-issued | 2 +- check-certificates | 2 +- check-health | 2 +- check-lte-firmware-upgrade | 2 +- check-routeros-update | 2 +- cloud-backup | 2 +- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- daily-psk.capsman | 2 +- daily-psk.local | 2 +- daily-psk.template | 2 +- dhcp-lease-comment.capsman | 2 +- dhcp-lease-comment.local | 2 +- dhcp-lease-comment.template | 2 +- dhcp-to-dns | 2 +- email-backup | 2 +- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 2 +- global-functions | 2 +- global-wait | 2 +- gps-track | 2 +- hotspot-to-wpa | 2 +- ip-addr-bridge | 2 +- ipv6-update | 2 +- learn-mac-based-vlan | 2 +- lease-script | 2 +- leds-day-mode | 2 +- leds-night-mode | 2 +- leds-toggle-mode | 2 +- log-forward | 2 +- manage-umts | 2 +- mode-button | 2 +- netwatch-notify | 2 +- netwatch-syslog | 2 +- ospf-to-leds | 2 +- packages-update | 2 +- ppp-on-up | 2 +- rotate-ntp | 2 +- sms-action | 2 +- sms-forward | 2 +- ssh-keys-import | 2 +- super-mario-theme | 2 +- unattended-lte-firmware-upgrade | 2 +- update-gre-address | 2 +- update-tunnelbroker | 2 +- upload-backup | 2 +- 55 files changed, 55 insertions(+), 55 deletions(-) diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman index 30cd809..4911760 100644 --- a/accesslist-duplicates.capsman +++ b/accesslist-duplicates.capsman @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.capsman -# Copyright (c) 2018-2020 Christian Hesse +# Copyright (c) 2018-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # print duplicate antries in wireless access list diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local index 4ac98f2..84fafb3 100644 --- a/accesslist-duplicates.local +++ b/accesslist-duplicates.local @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.local -# Copyright (c) 2018-2020 Christian Hesse +# Copyright (c) 2018-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # print duplicate antries in wireless access list diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template index c38dd47..7161992 100644 --- a/accesslist-duplicates.template +++ b/accesslist-duplicates.template @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates%TEMPL% -# Copyright (c) 2018-2020 Christian Hesse +# Copyright (c) 2018-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # print duplicate antries in wireless access list diff --git a/bridge-port-to-default b/bridge-port-to-default index e4d4947..286fb45 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: bridge-port-to-default -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # reset bridge ports to default bridge diff --git a/bridge-port-toggle b/bridge-port-toggle index 1aa6b75..78a64f7 100644 --- a/bridge-port-toggle +++ b/bridge-port-toggle @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: bridge-port-toggle -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # toggle bridge ports between default and alt bridge diff --git a/capsman-download-packages b/capsman-download-packages index 8a5b465..339c70d 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-download-packages -# Copyright (c) 2018-2020 Christian Hesse +# Copyright (c) 2018-2021 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index 2868214..1f091b8 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-rolling-upgrade -# Copyright (c) 2018-2020 Christian Hesse +# Copyright (c) 2018-2021 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/certificate-renew-issued b/certificate-renew-issued index 50cabe7..0a9ca85 100644 --- a/certificate-renew-issued +++ b/certificate-renew-issued @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: certificate-renew-issued -# Copyright (c) 2019-2020 Christian Hesse +# Copyright (c) 2019-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # renew locally issued certificates diff --git a/check-certificates b/check-certificates index 4531c3d..fce8e7d 100644 --- a/check-certificates +++ b/check-certificates @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-certificates -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for certificate validity diff --git a/check-health b/check-health index bc7e064..7fa45cb 100644 --- a/check-health +++ b/check-health @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-health -# Copyright (c) 2019-2020 Christian Hesse +# Copyright (c) 2019-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for RouterOS health state diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 08b27ce..edbd5b1 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-lte-firmware-upgrade -# Copyright (c) 2018-2020 Christian Hesse +# Copyright (c) 2018-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for LTE firmware upgrade, send notification diff --git a/check-routeros-update b/check-routeros-update index a4dfe9d..297f726 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-routeros-update -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for RouterOS update, send notification and/or install diff --git a/cloud-backup b/cloud-backup index 46777b9..b4c9002 100644 --- a/cloud-backup +++ b/cloud-backup @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: cloud-backup -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # upload backup to MikroTik cloud diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 3ed67fc..d14cb10 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.capsman -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # collect wireless mac adresses in access list diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index fc36e59..f9795f5 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.local -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # collect wireless mac adresses in access list diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 9b06dc3..c10c827 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac%TEMPL% -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # collect wireless mac adresses in access list diff --git a/daily-psk.capsman b/daily-psk.capsman index 2f7e8f2..d7c4ad7 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk.capsman -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/daily-psk.local b/daily-psk.local index d51d5f6..1add2e9 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk.local -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/daily-psk.template b/daily-psk.template index acc8edd..7f8cd75 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk%TEMPL% -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index 6cd026a..b663a0a 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.capsman -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update dhcp-server lease comment with infos from access-list diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index f55931c..1d9eb08 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.local -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update dhcp-server lease comment with infos from access-list diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index b594324..4007765 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment%TEMPL% -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update dhcp-server lease comment with infos from access-list diff --git a/dhcp-to-dns b/dhcp-to-dns index 4ea4f59..acf93e5 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-to-dns -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check DHCP leases and add/remove/update DNS entries diff --git a/email-backup b/email-backup index 8f4fdc1..4c7d1a4 100644 --- a/email-backup +++ b/email-backup @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: email-backup -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # create and email backup and config file diff --git a/global-config b/global-config index 379701a..d33b7b7 100644 --- a/global-config +++ b/global-config @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-config -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global configuration diff --git a/global-config-overlay b/global-config-overlay index a7cd500..b45b0cb 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-config-overlay -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global configuration, custom overlay diff --git a/global-config.changes b/global-config.changes index 2d53160..e79047a 100644 --- a/global-config.changes +++ b/global-config.changes @@ -1,5 +1,5 @@ # RouterOS global-config changes -# Copyright (c) 2019-2020 Christian Hesse +# Copyright (c) 2019-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # Changes for global-config to be added to notification on script updates diff --git a/global-functions b/global-functions index 192e326..3cb8277 100644 --- a/global-functions +++ b/global-functions @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-functions -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/global-wait b/global-wait index fe19151..edb156b 100644 --- a/global-wait +++ b/global-wait @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-wait -# Copyright (c) 2020 Christian Hesse +# Copyright (c) 2020-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # wait for global-functions to finish diff --git a/gps-track b/gps-track index 53718e2..1f7d228 100644 --- a/gps-track +++ b/gps-track @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: gps-track -# Copyright (c) 2018-2020 Christian Hesse +# Copyright (c) 2018-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # track gps data by sending json data to http server diff --git a/hotspot-to-wpa b/hotspot-to-wpa index 7951ed0..54a9e8e 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa -# Copyright (c) 2019-2020 Christian Hesse +# Copyright (c) 2019-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # add private WPA passphrase after hotspot login diff --git a/ip-addr-bridge b/ip-addr-bridge index 9d2a281..762c74e 100644 --- a/ip-addr-bridge +++ b/ip-addr-bridge @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ip-addr-bridge -# Copyright (c) 2018-2020 Christian Hesse +# Copyright (c) 2018-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # enable or disable ip addresses based on bridge port state diff --git a/ipv6-update b/ipv6-update index 2224a11..ed266a6 100644 --- a/ipv6-update +++ b/ipv6-update @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ipv6-update -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update firewall and dns settings on IPv6 prefix change diff --git a/learn-mac-based-vlan b/learn-mac-based-vlan index d497714..e301a47 100644 --- a/learn-mac-based-vlan +++ b/learn-mac-based-vlan @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: learn-mac-based-vlan -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # learn MAC address for MAC-based-VLAN diff --git a/lease-script b/lease-script index 8230c6e..438df0f 100644 --- a/lease-script +++ b/lease-script @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: lease-script -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run scripts on DHCP lease diff --git a/leds-day-mode b/leds-day-mode index b2f37d3..4d77469 100644 --- a/leds-day-mode +++ b/leds-day-mode @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-day-mode -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # enable LEDs diff --git a/leds-night-mode b/leds-night-mode index a4e48fa..89ac834 100644 --- a/leds-night-mode +++ b/leds-night-mode @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-night-mode -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # disable LEDs diff --git a/leds-toggle-mode b/leds-toggle-mode index e817b1b..6ee81c8 100644 --- a/leds-toggle-mode +++ b/leds-toggle-mode @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-toggle-mode -# Copyright (c) 2018-2020 Christian Hesse +# Copyright (c) 2018-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # toggle LEDs mode diff --git a/log-forward b/log-forward index 831ffe1..feebedd 100644 --- a/log-forward +++ b/log-forward @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: log-forward -# Copyright (c) 2020 Christian Hesse +# Copyright (c) 2020-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # forward log messages via notification diff --git a/manage-umts b/manage-umts index 663c1dc..b8426bd 100644 --- a/manage-umts +++ b/manage-umts @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: manage-umts -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # manage UMTS interface based on ethernet and wireless status diff --git a/mode-button b/mode-button index 217c0cc..35c0899 100644 --- a/mode-button +++ b/mode-button @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mode-button -# Copyright (c) 2018-2020 Christian Hesse +# Copyright (c) 2018-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # act on multiple mode and reset button presses diff --git a/netwatch-notify b/netwatch-notify index 9a12c5a..9651841 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: netwatch-notify -# Copyright (c) 2020 Christian Hesse +# Copyright (c) 2020-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # monitor netwatch and send notifications diff --git a/netwatch-syslog b/netwatch-syslog index fee22cc..f274c18 100644 --- a/netwatch-syslog +++ b/netwatch-syslog @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: netwatch-syslog -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires: dont-require-permissions=yes diff --git a/ospf-to-leds b/ospf-to-leds index 61b90ce..b899b50 100644 --- a/ospf-to-leds +++ b/ospf-to-leds @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ospf-to-leds -# Copyright (c) 2020 Christian Hesse +# Copyright (c) 2020-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # visualize ospf instance state via leds diff --git a/packages-update b/packages-update index 7c88eac..022a110 100644 --- a/packages-update +++ b/packages-update @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: packages-update -# Copyright (c) 2019-2020 Christian Hesse +# Copyright (c) 2019-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # download packages and reboot for installation diff --git a/ppp-on-up b/ppp-on-up index 925cb6e..9de01b8 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ppp-on-up -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run scripts on ppp up diff --git a/rotate-ntp b/rotate-ntp index 159cdfe..a0cc524 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: rotate-ntp -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # rotate the ntp servers diff --git a/sms-action b/sms-action index 2008a8a..a070cc9 100644 --- a/sms-action +++ b/sms-action @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: sms-action -# Copyright (c) 2018-2020 Christian Hesse +# Copyright (c) 2018-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run action on received SMS diff --git a/sms-forward b/sms-forward index 28d60a1..96a001d 100644 --- a/sms-forward +++ b/sms-forward @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: sms-forward -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # forward SMS to e-mail diff --git a/ssh-keys-import b/ssh-keys-import index d4795d7..1f158fd 100644 --- a/ssh-keys-import +++ b/ssh-keys-import @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ssh-keys-import -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # import ssh keys from file diff --git a/super-mario-theme b/super-mario-theme index 6b2ea74..e13c934 100644 --- a/super-mario-theme +++ b/super-mario-theme @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: super-mario-theme -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # play Super Mario theme diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index d9bffad..cb8f87e 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: unattended-lte-firmware-upgrade -# Copyright (c) 2018-2020 Christian Hesse +# Copyright (c) 2018-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # schedule unattended lte firmware upgrade diff --git a/update-gre-address b/update-gre-address index c4d1dda..7dd4896 100644 --- a/update-gre-address +++ b/update-gre-address @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: update-gre-address -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update gre interface remote address with dynamic address from diff --git a/update-tunnelbroker b/update-tunnelbroker index a503df0..d014178 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: update-tunnelbroker -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/upload-backup b/upload-backup index 5d4dd8e..acb8399 100644 --- a/upload-backup +++ b/upload-backup @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: upload-backup -# Copyright (c) 2013-2020 Christian Hesse +# Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # create and upload backup and config file From 4368f500c3e5438bf6ccba2433def3b93670a765 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 3 Jan 2021 19:56:47 +0100 Subject: [PATCH 0574/2612] ipv6-update: get old prefix from first matching address list entry --- ipv6-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv6-update b/ipv6-update index ed266a6..34ed88c 100644 --- a/ipv6-update +++ b/ipv6-update @@ -22,7 +22,7 @@ / ipv6 firewall address-list add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool); :set AddrList [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ]; } -:local OldPrefix [ / ipv6 firewall address-list get $AddrList address ]; +:local OldPrefix [ / ipv6 firewall address-list get ($AddrList->0) address ]; :if ($OldPrefix != $PdPrefix) do={ :log info ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix); From 241d5fd2d7a3f5d7d79ef81ac5e1d736689ccdef Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 3 Jan 2021 20:22:56 +0100 Subject: [PATCH 0575/2612] ipv6-update: simplify the code... ... and make it match the code used in other scripts. --- ipv6-update | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ipv6-update b/ipv6-update index 34ed88c..d5b15c4 100644 --- a/ipv6-update +++ b/ipv6-update @@ -16,12 +16,11 @@ } :local Pool [ / ipv6 pool get [ find where prefix=$PdPrefix ] name ]; -:local AddrList [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ]; -:if ([ :len $AddrList ] = 0) do={ - :log info ("Missing ipv6 address list entry for ipv6-pool-" . $Pool . ", adding."); +:if ([ :len [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={ / ipv6 firewall address-list add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool); - :set AddrList [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ]; + :log warning ("Added ipv6 address list entry for ipv6-pool-" . $Pool . "."); } +:local AddrList [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ]; :local OldPrefix [ / ipv6 firewall address-list get ($AddrList->0) address ]; :if ($OldPrefix != $PdPrefix) do={ From c18f753338b806595bc861f5740365d165fcd7c3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 3 Jan 2021 20:33:32 +0100 Subject: [PATCH 0576/2612] collect-wireless-mac: always use first entry to place before --- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index d14cb10..fda401e 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -22,7 +22,7 @@ $ScriptLock "collect-wireless-mac.capsman"; / caps-man access-list add comment="--- collected above ---" disabled=yes; $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; } -:local PlaceBefore [ / caps-man access-list find where comment="--- collected above ---" disabled ]; +:local PlaceBefore ([ / caps-man access-list find where comment="--- collected above ---" disabled ]->0); :foreach RegTbl in=[ / caps-man registration-table find ] do={ :local Mac [ / caps-man registration-table get $RegTbl mac-address ]; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index f9795f5..f9c135c 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -22,7 +22,7 @@ $ScriptLock "collect-wireless-mac.local"; / interface wireless access-list add comment="--- collected above ---" disabled=yes; $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; } -:local PlaceBefore [ / interface wireless access-list find where comment="--- collected above ---" disabled ]; +:local PlaceBefore ([ / interface wireless access-list find where comment="--- collected above ---" disabled ]->0); :foreach RegTbl in=[ / interface wireless registration-table find ] do={ :local Mac [ / interface wireless registration-table get $RegTbl mac-address ]; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index c10c827..1d031fe 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -23,7 +23,7 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; / %PATH% access-list add comment="--- collected above ---" disabled=yes; $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; } -:local PlaceBefore [ / %PATH% access-list find where comment="--- collected above ---" disabled ]; +:local PlaceBefore ([ / %PATH% access-list find where comment="--- collected above ---" disabled ]->0); :foreach RegTbl in=[ / %PATH% registration-table find ] do={ :local Mac [ / %PATH% registration-table get $RegTbl mac-address ]; From 3eccf923cc6e29f2f5b27b882e8cec574e2976e6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 3 Jan 2021 20:34:04 +0100 Subject: [PATCH 0577/2612] dhcp-to-dns: always use first entry to place before --- dhcp-to-dns | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index acf93e5..375e083 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -26,7 +26,7 @@ / ip dns static add comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled=yes; $LogPrintExit warning "Added disabled static dns record with comment '--- dhcp-to-dns above ---'." false; } -:local PlaceBefore [ / ip dns static find where comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled ]; +:local PlaceBefore ([ / ip dns static find where comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled ]->0); :foreach DnsRecord in=[ / ip dns static find where comment ~ $CommentPrefix ] do={ :local DnsRecordVal [ / ip dns static get $DnsRecord ]; From 90672798e8d00a8bf73ee69215706107ec63f6c8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 3 Jan 2021 20:34:19 +0100 Subject: [PATCH 0578/2612] hotspot-to-wpa: always use first entry to place before --- hotspot-to-wpa | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot-to-wpa b/hotspot-to-wpa index 54a9e8e..ca11775 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -17,7 +17,7 @@ / caps-man access-list add comment="--- hotspot-to-wpa above ---" disabled=yes; $LogPrintExit warning "Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'." false; } -:local PlaceBefore [ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ]; +:local PlaceBefore ([ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ]->0); $LogPrintExit info ("Adding/updating accesslist entry for mac address " . $MacAddress . \ " (user " . $UserName . ").") false; From 156024ac2f210ef57c3b7905751829012afbc4ff Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 3 Jan 2021 21:20:04 +0100 Subject: [PATCH 0579/2612] global-functions: $ScriptInstallUpdate: log error on reloading global configuration --- global-functions | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 3cb8277..d9d180a 100644 --- a/global-functions +++ b/global-functions @@ -624,7 +624,11 @@ :if ($ScriptVal->"name" = "global-config" && \ [ :len [ / system script find where name="global-config-overlay" ] ] > 0) do={ $LogPrintExit info ("Reloading global configuration and overlay.") false; - / system script { run global-config; run global-config-overlay; } + :do { + / system script { run global-config; run global-config-overlay; } + } on-error={ + $LogPrintExit error ("Reloading global configuration and overlay failed! Syntax error?") false; + } } :if ($ScriptVal->"name" = "global-functions") do={ $LogPrintExit info ("Reloading global functions.") false; From ab267d54b35d11fcadbb2b0e3fae7c2e7a61b2a6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 3 Jan 2021 21:21:17 +0100 Subject: [PATCH 0580/2612] global-functions: $ScriptInstallUpdate: log error on reloading global functions --- global-functions | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index d9d180a..6f4ffbb 100644 --- a/global-functions +++ b/global-functions @@ -632,7 +632,11 @@ } :if ($ScriptVal->"name" = "global-functions") do={ $LogPrintExit info ("Reloading global functions.") false; - / system script run global-functions; + :do { + / system script run global-functions; + } on-error={ + $LogPrintExit error ("Reloading global functions failed!") false; + } } } else={ $LogPrintExit debug ("Script " . $ScriptVal->"name" . " did not change.") false; From faf08b057592faf6f1dd47a2ff63de31f5d6f9f1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Jan 2021 10:23:00 +0100 Subject: [PATCH 0581/2612] global-functions: introduce and use $RequiredRouterOS --- global-functions | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/global-functions b/global-functions index 6f4ffbb..7fa41ea 100644 --- a/global-functions +++ b/global-functions @@ -35,6 +35,7 @@ :global MkDir; :global ParseKeyValueStore; :global RandomDelay; +:global RequiredRouterOS; :global ScriptFromTerminal; :global ScriptInstallUpdate; :global ScriptLock; @@ -517,6 +518,23 @@ :delay ([ $GetRandomNumber $1 ] . "s"); } +# check for required RouterOS version +:set RequiredRouterOS do={ + :local Caller [ :tostr $1 ]; + :local Required [ :tostr $2 ]; + + :global IfThenElse; + :global LogPrintExit; + :global VersionToNum; + + :if ([ $VersionToNum $Required ] > [ $VersionToNum [ / system package update get installed-version ] ]) do={ + $LogPrintExit warning ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = "\$") "function" "script" ] . \ + " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!") false; + :return false; + } + :return true; +} + # check if script is run from terminal :set ScriptFromTerminal do={ :local Script [ :tostr $1 ]; @@ -1056,5 +1074,8 @@ } } +# check for required RouterOS version +$RequiredRouterOS "global-functions" "6.43"; + # signal we are ready :set GlobalFunctionsReady true; From 8e628ce11e95ccc867c9f4d3349cf0f63148109b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 10 Jan 2021 23:53:24 +0100 Subject: [PATCH 0582/2612] check-certificates: show info on private key --- check-certificates | 2 ++ 1 file changed, 2 insertions(+) diff --git a/check-certificates b/check-certificates index fce8e7d..89ca9eb 100644 --- a/check-certificates +++ b/check-certificates @@ -89,6 +89,7 @@ $WaitFullyConnected; ("A certificate on " . $Identity . " has been renewed.\n\n" . \ "Name: " . ($CertVal->"name") . "\n" . \ "CommonName: " . ($CertNewVal->"common-name") . "\n" . \ + "Private key: " . [ $IfThenElse (($CertNewVal->"private-key") = true) "available" "missing" ] . "\n" . \ "Fingerprint: " . ($CertNewVal->"fingerprint") . "\n" . \ "Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ @@ -111,6 +112,7 @@ $WaitFullyConnected; ("A certificate on " . $Identity . " " . $State . ".\n\n" . \ "Name: " . ($CertVal->"name") . "\n" . \ "CommonName: " . ($CertVal->"common-name") . "\n" . \ + "Private key: " . [ $IfThenElse (($CertNewVal->"private-key") = true) "available" "missing" ] . "\n" . \ "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ From d926c84cdb1cc28ee29c6ec0a6f339587ce9b280 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 11 Jan 2021 00:05:58 +0100 Subject: [PATCH 0583/2612] check-certificates: do not renew if loosing private key --- check-certificates | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/check-certificates b/check-certificates index 89ca9eb..76df7f9 100644 --- a/check-certificates +++ b/check-certificates @@ -66,6 +66,11 @@ $WaitFullyConnected; :if ($Cert != $CertNew) do={ $LogPrintExit debug ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; + :if (($CertVal->"private-key") = true && ($CertVal->"private-key") != ($CertNewVal->"private-key")) do={ + / certificate remove $CertNew; + $LogPrintExit warning ("Old certificate '" . ($CertVal->"name") . "' has a private key, new certificate does not. Aborting renew.") true; + } + / ip service set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; :do { From 6cea5a9f9b7f331ef0dcc7eb494887eef2441a62 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 11 Jan 2021 00:16:00 +0100 Subject: [PATCH 0584/2612] check-certificates: complete certificate renewal time With a modified certificate renewal time may have failed if the new certificate was not found. --- check-certificates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index 76df7f9..e54b915 100644 --- a/check-certificates +++ b/check-certificates @@ -56,7 +56,7 @@ $WaitFullyConnected; } } - :local CertNew [ / certificate find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>3w ]; + :local CertNew [ / certificate find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ]; :local CertNewVal [ / certificate get $CertNew ]; :if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") ] = false) do={ From dc148065dc62178efe6729ae018f83284b1770b5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 20 Jan 2021 14:03:31 +0100 Subject: [PATCH 0585/2612] global-functions: $MkDir: clean path --- global-functions | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global-functions b/global-functions index 7fa41ea..de4b64e 100644 --- a/global-functions +++ b/global-functions @@ -480,8 +480,11 @@ :set MkDir do={ :local Dir [ :tostr $1 ]; + :global CleanFilePath; :global WaitForFile; + :set Dir [ $CleanFilePath $Dir ]; + :if ([ :len [ / file find where name=$Dir type="directory" ] ] = 0) do={ :local WwwVal [ / ip service get www ]; / ip service set www address=127.0.0.1/32 disabled=no port=80; From fa7f37e87f2d46648c49e941a630917d72e02804 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 20 Jan 2021 14:07:20 +0100 Subject: [PATCH 0586/2612] global-functions: $WaitForFile: declare input first --- global-functions | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index de4b64e..c67fe7f 100644 --- a/global-functions +++ b/global-functions @@ -1033,9 +1033,11 @@ # wait for file to be available :set WaitForFile do={ + :local FileName [ :tostr $1 ]; + :global CleanFilePath; - :local FileName [ $CleanFilePath [ :tostr $1 ] ]; + :set FileName [ $CleanFilePath $FileName ]; :local I 0; :while ([ :len [ / file find where name=$FileName ] ] = 0) do={ From 11d43e9fe5d91269e0f7a4b0340a2e3d4dc9799f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 20 Jan 2021 14:08:01 +0100 Subject: [PATCH 0587/2612] global-functions: $SymbolForNotification: remove empty line --- global-functions | 1 - 1 file changed, 1 deletion(-) diff --git a/global-functions b/global-functions index c67fe7f..a9fe6de 100644 --- a/global-functions +++ b/global-functions @@ -917,7 +917,6 @@ # return symbol for notification :set SymbolForNotification do={ :global NotificationsWithSymbols; - :global SymbolByUnicodeName; :if ($NotificationsWithSymbols != true) do={ From c980699dd709a61d0409f0beb31a1dbfa58d995e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 20 Jan 2021 14:23:57 +0100 Subject: [PATCH 0588/2612] global-functions: add error handling --- global-functions | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/global-functions b/global-functions index a9fe6de..a46f35d 100644 --- a/global-functions +++ b/global-functions @@ -485,15 +485,23 @@ :set Dir [ $CleanFilePath $Dir ]; - :if ([ :len [ / file find where name=$Dir type="directory" ] ] = 0) do={ - :local WwwVal [ / ip service get www ]; - / ip service set www address=127.0.0.1/32 disabled=no port=80; + :if ([ :len [ / file find where name=$Dir type="directory" ] ] = 1) do={ + :return true; + } + + :local Return true; + :local WwwVal [ / ip service get www ]; + / ip service set www address=127.0.0.1/32 disabled=no port=80; + :do { / tool fetch http://127.0.0.1/ dst-path=($Dir . "/tmp"); $WaitForFile ($Dir . "/tmp"); / file remove ($Dir . "/tmp"); - / ip service set www address=($WwwVal->"address") \ - disabled=($WwwVal->"disabled") port=($WwwVal->"port"); + } on-error={ + :set Return false; } + / ip service set www address=($WwwVal->"address") \ + disabled=($WwwVal->"disabled") port=($WwwVal->"port"); + :return $Return; } # parse key value store From e135ca1238f85afd8d9a10d2feb8fcfa3931bbfd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 20 Jan 2021 14:38:11 +0100 Subject: [PATCH 0589/2612] certificate-renew-issued: handle error when creating directory --- certificate-renew-issued | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/certificate-renew-issued b/certificate-renew-issued index 0a9ca85..2eeaba0 100644 --- a/certificate-renew-issued +++ b/certificate-renew-issued @@ -19,12 +19,15 @@ 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={ - $MkDir "cert-issued"; - / certificate export-certificate ($CertVal->"name") type=pkcs12 \ - file-name=("cert-issued/" . $CertVal->"common-name") \ - export-passphrase=($CertIssuedExportPass->($CertVal->"common-name")); - $LogPrintExit info ("Issued a new certificate for \"" . $CertVal->"common-name" . \ - "\", exported to \"cert-issued/" . $CertVal->"common-name" . ".p12\".") false; + :if ([ $MkDir "cert-issued" ] = true) do={ + / certificate export-certificate ($CertVal->"name") type=pkcs12 \ + file-name=("cert-issued/" . $CertVal->"common-name") \ + export-passphrase=($CertIssuedExportPass->($CertVal->"common-name")); + $LogPrintExit info ("Issued a new certificate for \"" . $CertVal->"common-name" . \ + "\", exported to \"cert-issued/" . $CertVal->"common-name" . ".p12\".") false; + } else={ + $LogPrintExit warning ("Failed creating directory, not exporting certificate.") false; + } } else={ $LogPrintExit info ("Issued a new certificate for \"" . $CertVal->"common-name" . "\".") false; } From 99aaf642b24e7e6b2291e57788c84dd1429461a7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 20 Jan 2021 14:43:27 +0100 Subject: [PATCH 0590/2612] capsman-download-packages: handle error when creating directory --- capsman-download-packages | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/capsman-download-packages b/capsman-download-packages index 339c70d..b6bff3a 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -22,7 +22,10 @@ $WaitFullyConnected; :local Updated false; :if ([ :len [ / file find where name=$PackagePath type="directory" ] ] = 0) do={ - $MkDir $PackagePath; + :if ([ $MkDir $PackagePath ] = false) do={ + $LogPrintExit warning ("Creating directory at package path (" . \ + $PackagePath . ") failed!") true; + } $LogPrintExit info ("Created directory at package path (" . $PackagePath . \ "). Please place your packages!") false; } From 086a395e8233b81f702884492c7edb11e5fd0c32 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 21 Jan 2021 11:15:49 +0100 Subject: [PATCH 0591/2612] global-functions: $ScriptInstallUpdate: give hint on changes --- global-functions | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/global-functions b/global-functions index a46f35d..c1311cf 100644 --- a/global-functions +++ b/global-functions @@ -597,6 +597,8 @@ } } + :local ScriptInstallUpdateBefore $ScriptInstallUpdate; + :foreach Script in=[ / system script find where source~"^#!rsc( by RouterOS)\?\n" ] do={ :local ScriptVal [ / system script get $Script ]; :local ScriptFile [ / file find where name=("script-updates/" . $ScriptVal->"name") ]; @@ -735,6 +737,10 @@ $NotificationMessage $Link; :set SentConfigChangesNotification $ExpectedConfigVersion; } + + :if ($ScriptInstallUpdateBefore != $ScriptInstallUpdate) do={ + $LogPrintExit info ("This function '\$ScriptInstallUpdate' changed, you may want to re-run.") false; + } } # lock script against multiple invocation From bbf918e32915d3b7b929ad3ecfff7d51968a9ad4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 20 Jan 2021 17:06:34 +0100 Subject: [PATCH 0592/2612] global-functions: $LogPrintExit: colorful output --- global-functions | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index c1311cf..d66541d 100644 --- a/global-functions +++ b/global-functions @@ -412,6 +412,11 @@ :global PrintDebug; + :local PrintSeverity do={ + :local Color { debug=96; info=97; warning=93; error=91 }; + :return ("\1B[" . $Color->$1 . "m" . $1 . "\1B[0m"); + } + :if ($Severity ~ "^(debug|error|info)\$") do={ :if ($Severity = "debug") do={ :log debug $Message; } :if ($Severity = "error") do={ :log error $Message; } @@ -423,9 +428,9 @@ :if ($Severity != "debug" || $PrintDebug = true) do={ :if ($Exit = "true") do={ - :error ($Severity . ": " . $Message); + :error ([ $PrintSeverity $Severity ] . ": " . $Message); } else={ - :put ($Severity . ": " . $Message); + :put ([ $PrintSeverity $Severity ] . ": " . $Message); } } } From b780b40baf904a0448d1a8e60cc6e3626183120c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 22 Jan 2021 09:20:49 +0100 Subject: [PATCH 0593/2612] global-functions: $LogPrintExit: make colorful output configurable --- global-config | 2 ++ global-functions | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/global-config b/global-config index d33b7b7..4e1bca5 100644 --- a/global-config +++ b/global-config @@ -35,6 +35,8 @@ # Toggle this to disable symbols in notifications. :global NotificationsWithSymbols true; +# Toggle this to disable color output in terminal/cli. +:global TerminalColorOutput true; # This defines what backups to generate and what password to use. :global BackupSendBinary false; diff --git a/global-functions b/global-functions index d66541d..3518e36 100644 --- a/global-functions +++ b/global-functions @@ -413,6 +413,12 @@ :global PrintDebug; :local PrintSeverity do={ + :global TerminalColorOutput; + + :if ($TerminalColorOutput != true) do={ + :return $1; + } + :local Color { debug=96; info=97; warning=93; error=91 }; :return ("\1B[" . $Color->$1 . "m" . $1 . "\1B[0m"); } From eaea89112ab0b700c4b6b459eb31d8931159ce38 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 22 Jan 2021 10:08:15 +0100 Subject: [PATCH 0594/2612] global-functions: $LogPrintExit: notify about colorful output --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 4e1bca5..b8bdd44 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 41; +:global GlobalConfigVersion 42; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index b45b0cb..8925b4c 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 41; +:global GlobalConfigVersion 42; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index e79047a..4ad3fee 100644 --- a/global-config.changes +++ b/global-config.changes @@ -45,6 +45,7 @@ 39="Added support for interface specific address list entries in 'ipv6-update'."; 40="Made the certificate renewal time configurable."; 41="Implemented migration mechanism for script updates."; + 42="Made severity in terminal output colorful, with opt-out."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 3518e36..7d3e4c5 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 41; +:global ExpectedConfigVersion 42; # global variables not to be changed by user :global GlobalFunctionsReady false; From 55a8a984f71b25c527b12b706d99956e27e6a090 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 3 Feb 2021 14:28:16 +0100 Subject: [PATCH 0595/2612] global-functions: $GetMacVendor: this requires Let's Encrypt "R3" now --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 7d3e4c5..19195b3 100644 --- a/global-functions +++ b/global-functions @@ -327,7 +327,7 @@ :global LogPrintExit; :do { - :if ([ $CertificateAvailable "Let's Encrypt Authority X3" ] = false) do={ + :if ([ $CertificateAvailable "R3" ] = false) do={ $LogPrintExit warning ("Downloading required certificate failed.") true; } :local Vendor ([ / tool fetch check-certificate=yes-without-crl \ From dad525173cf58f0a3a95feacc1d661dc766d0e87 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 3 Feb 2021 14:32:38 +0100 Subject: [PATCH 0596/2612] global-functions: $DownloadPackage: this requires Let's Encrypt "R3" now --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 19195b3..29ff999 100644 --- a/global-functions +++ b/global-functions @@ -257,7 +257,7 @@ :return true; } - :if ([ $CertificateAvailable "Let's Encrypt Authority X3" ] = false) do={ + :if ([ $CertificateAvailable "R3" ] = false) do={ $LogPrintExit error ("Downloading required certificate failed.") true; } From 0c2143298d1d4908429e9d5d04aa6b055e88dc13 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Apr 2020 16:39:30 +0200 Subject: [PATCH 0597/2612] global-functions: $CertificateAvailable: check chain by akid and skid We can merge this when RouterOS 6.47 moves to long-term... --- global-functions | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/global-functions b/global-functions index 29ff999..851e632 100644 --- a/global-functions +++ b/global-functions @@ -60,6 +60,7 @@ :global CertificateDownload; :global LogPrintExit; :global ParseKeyValueStore; + :global RequiredRouterOS; :if ([ / system resource get free-hdd-space ] < 8388608 && \ [ / certificate settings get crl-download ] = true && \ @@ -75,19 +76,21 @@ } } - :local CertVal; - :local Issuer $CommonName; + :if ([ $RequiredRouterOS ("\$CertificateAvailable") "6.47" ] = false) do={ + :return true; + } + + :local CertVal [ / certificate get [ find where common-name=$CommonName ] ]; :do { - :if ([ :len [ / certificate find where common-name=$Issuer ] ] = 0) do={ + :if ([ :len [ / certificate find where skid=($CertVal->"akid") ] ] = 0) do={ $LogPrintExit info ("Certificate chain for \"" . $CommonName . \ - "\" is incomplete, missing \"" . $Issuer . "\".") false; + "\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\".") false; :if ([ $CertificateDownload $CommonName ] = false) do={ :return false; } } - :set CertVal [ / certificate get [ find where common-name=$Issuer ] ]; - :set Issuer ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN"); - } while=($Issuer != $CertVal->"common-name"); + :set CertVal [ / certificate get [ find where skid=($CertVal->"akid") ] ]; + } while=(($CertVal->"akid") != "" && ($CertVal->"akid") != ($CertVal->"skid")); :return true; } @@ -1104,7 +1107,7 @@ } # check for required RouterOS version -$RequiredRouterOS "global-functions" "6.43"; +$RequiredRouterOS "global-functions" "6.47"; # signal we are ready :set GlobalFunctionsReady true; From e7c2a7745a7aa6b252091c144a7bd66055b6434e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Feb 2021 16:01:36 +0100 Subject: [PATCH 0598/2612] daily-psk: drop support for attaching QR-Code The notification contains the link. Should be sufficient, no? --- daily-psk.capsman | 16 ++-------------- daily-psk.local | 16 ++-------------- daily-psk.template | 16 ++-------------- 3 files changed, 6 insertions(+), 42 deletions(-) diff --git a/daily-psk.capsman b/daily-psk.capsman index d7c4ad7..10b3403 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -75,26 +75,14 @@ $WaitFullyConnected; :if ($Skip = 0) do={ :set Seen ($Seen, $Ssid); - - :local Url ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ + :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - :local Attach "qrcode-daily.png"; - - :do { - / tool fetch check-certificate=yes-without-crl \ - $Url dst-path=$Attach; - $WaitForFile $Attach; - } on-error={ - :set Attach ""; - } - $SendNotification ([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid) \ ("This is the daily PSK on " . $Identity . ":\n\n" . \ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ "Date: " . $Date . "\n\n" . \ - "A client device specific rule must not exist!") \ - $Url $Attach; + "A client device specific rule must not exist!") $Link; } } } diff --git a/daily-psk.local b/daily-psk.local index 1add2e9..ec03c1a 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -75,26 +75,14 @@ $WaitFullyConnected; :if ($Skip = 0) do={ :set Seen ($Seen, $Ssid); - - :local Url ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ + :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - :local Attach "qrcode-daily.png"; - - :do { - / tool fetch check-certificate=yes-without-crl \ - $Url dst-path=$Attach; - $WaitForFile $Attach; - } on-error={ - :set Attach ""; - } - $SendNotification ([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid) \ ("This is the daily PSK on " . $Identity . ":\n\n" . \ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ "Date: " . $Date . "\n\n" . \ - "A client device specific rule must not exist!") \ - $Url $Attach; + "A client device specific rule must not exist!") $Link; } } } diff --git a/daily-psk.template b/daily-psk.template index 7f8cd75..590b1ea 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -81,26 +81,14 @@ $WaitFullyConnected; :if ($Skip = 0) do={ :set Seen ($Seen, $Ssid); - - :local Url ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ + :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - :local Attach "qrcode-daily.png"; - - :do { - / tool fetch check-certificate=yes-without-crl \ - $Url dst-path=$Attach; - $WaitForFile $Attach; - } on-error={ - :set Attach ""; - } - $SendNotification ([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid) \ ("This is the daily PSK on " . $Identity . ":\n\n" . \ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ "Date: " . $Date . "\n\n" . \ - "A client device specific rule must not exist!") \ - $Url $Attach; + "A client device specific rule must not exist!") $Link; } } } From 17d7678e2dbd641cf6f2a6950709cfc2ad9ea129 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Feb 2021 16:04:18 +0100 Subject: [PATCH 0599/2612] global-functions: drop support for attachment in notification e-mail --- check-certificates | 2 +- check-lte-firmware-upgrade | 2 +- check-routeros-update | 10 +++++----- cloud-backup | 2 +- global-functions | 9 +++------ upload-backup | 2 +- 6 files changed, 12 insertions(+), 15 deletions(-) diff --git a/check-certificates b/check-certificates index e54b915..39b7e2c 100644 --- a/check-certificates +++ b/check-certificates @@ -98,7 +98,7 @@ $WaitFullyConnected; "Fingerprint: " . ($CertNewVal->"fingerprint") . "\n" . \ "Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ - "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]) "" "" "true"; + "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]) "" "true"; $LogPrintExit info ("The certificate " . ($CertVal->"name") . " has been renewed.") false; } on-error={ $LogPrintExit debug ("Could not renew certificate " . ($CertVal->"name") . ".") false; diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index edbd5b1..a678fb6 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -30,7 +30,7 @@ "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ "Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \ "Installed: " . ($Firmware->"installed") . "\n" . \ - "Available: " . ($Firmware->"latest")) "" "" "true"; + "Available: " . ($Firmware->"latest")) "" "true"; :set SentLteFirmwareUpgradeNotification ($Firmware->"latest"); } } diff --git a/check-routeros-update b/check-routeros-update index 297f726..412d84a 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -55,7 +55,7 @@ $LogPrintExit info ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ ("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ - ", updating on " . $Identity . "...") $Link "" "true"; + ", updating on " . $Identity . "...") $Link "true"; $DoUpdate; } @@ -64,7 +64,7 @@ $LogPrintExit info ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ ("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \ - ", updating on " . $Identity . "...") $Link "" "true"; + ", updating on " . $Identity . "...") $Link "true"; $DoUpdate; } @@ -81,7 +81,7 @@ $LogPrintExit info ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ ("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ - ", updating on " . $Identity . "...") $Link "" "true"; + ", updating on " . $Identity . "...") $Link "true"; $DoUpdate; } } @@ -103,7 +103,7 @@ $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ ("A new RouterOS version " . ($Update->"latest-version") . \ " is available for " . $Identity . ".\n\n" . \ - [ $DeviceInfo ]) $Link "" "true"; + [ $DeviceInfo ]) $Link "true"; :set SentRouterosUpdateNotification ($Update->"latest-version"); } @@ -116,7 +116,7 @@ $SendNotification ([ $SymbolForNotification "warning-sign" ] . "RouterOS version") \ ("A different RouterOS version " . ($Update->"latest-version") . \ " is available for " . $Identity . ", but it is a downgrade.\n\n" . \ - [ $DeviceInfo ]) $Link "" "true"; + [ $DeviceInfo ]) $Link "true"; $LogPrintExit info ("A different RouterOS version " . ($Update->"latest-version") . \ " is available for downgrade.") false; :set SentRouterosUpdateNotification ($Update->"latest-version"); diff --git a/cloud-backup b/cloud-backup index b4c9002..b8c4191 100644 --- a/cloud-backup +++ b/cloud-backup @@ -32,7 +32,7 @@ [ $DeviceInfo ] . "\n\n" . \ "Name: " . $Cloud->"name" . "\n" . \ "Size: " . $Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)\n" . \ - "Download key: " . $Cloud->"secret-download-key") "" "" "true"; + "Download key: " . $Cloud->"secret-download-key") "" "true"; } on-error={ $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Cloud backup failed") \ ("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]); diff --git a/global-functions b/global-functions index 851e632..6434307 100644 --- a/global-functions +++ b/global-functions @@ -773,7 +773,6 @@ :local Subject [ :tostr $1 ]; :local Message [ :tostr $2 ]; :local Link [ :tostr $3 ]; - :local Attach [ :tostr $4 ]; :global Identity; :global EmailGeneralTo; @@ -792,8 +791,7 @@ subject=("[" . $Identity . "] " . $Subject) \ body=($Message . \ [ $IfThenElse ([ :len $Link ] > 0) ("\n\n" . $Link) "" ] . \ - [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]) \ - file=$Attach; + [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); } on-error={ $LogPrintExit warning ("Failed sending notification mail!") false; } @@ -805,13 +803,12 @@ :local Subject [ :tostr $1 ]; :local Message [ :tostr $2 ]; :local Link [ :tostr $3 ]; - :local Attach [ :tostr $4 ]; - :local Silent [ :tostr $5 ]; + :local Silent [ :tostr $4 ]; :global SendEMail; :global SendTelegram; - $SendEMail $Subject $Message $Link $Attach; + $SendEMail $Subject $Message $Link; $SendTelegram $Subject $Message $Link $Silent; } diff --git a/upload-backup b/upload-backup index acb8399..1249f36 100644 --- a/upload-backup +++ b/upload-backup @@ -72,7 +72,7 @@ $SendNotification [ $IfThenElse ($Failed > 0) \ ("Backup and config export upload for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ - "Config file: " . $ConfigFile) "" "" "true"; + "Config file: " . $ConfigFile) "" "true"; :if ($Failed = 1) do={ :error "An error occured!"; From 28db4732998da95a33a6f7698038b20a0be13473 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Feb 2021 15:20:01 +0100 Subject: [PATCH 0600/2612] global-functions: send (and re-send) e-mails from queue --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 66 ++++++++++++++++++++++++++++++++++++------- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/global-config b/global-config index b8bdd44..a3e515c 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 42; +:global GlobalConfigVersion 43; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 8925b4c..e8d7913 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 42; +:global GlobalConfigVersion 43; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 4ad3fee..a27b43a 100644 --- a/global-config.changes +++ b/global-config.changes @@ -46,6 +46,7 @@ 40="Made the certificate renewal time configurable."; 41="Implemented migration mechanism for script updates."; 42="Made severity in terminal output colorful, with opt-out."; + 43="Added queue for e-mail notifications to resend later on error."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 6434307..889dcea 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 42; +:global ExpectedConfigVersion 43; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -24,6 +24,7 @@ :global DeviceInfo; :global DNSIsResolving; :global DownloadPackage; +:global FlushEmailQueue; :global FlushTelegramQueue; :global GetMacVendor; :global GetRandom20CharHex; @@ -286,6 +287,47 @@ :return false; } +# flush e-mail queue +:set FlushEmailQueue do={ + :global EmailQueue; + + :global LogPrintExit; + + :local AllDone true; + :local QueueLen [ :len $EmailQueue ]; + + :if ([ :len [ / system scheduler find where name="FlushEmailQueue" ] ] > 0 && $QueueLen = 0) do={ + $LogPrintExit warning ("Flushing E-Mail messages from scheduler, but queue is empty.") false; + } + + / system scheduler set interval=1m [ find where name="FlushEmailQueue" interval=1s ]; + + :foreach Id,Message in=$EmailQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + / tool e-mail send to=($Message->"to") cc=($Message->"cc") \ + subject=($Message->"subject") body=($Message->"body"); + :local Wait true; + :do { + :delay 1s; + :local Status [ / tool e-mail get last-status ]; + :if ($Status = "succeeded") do={ + :set ($EmailQueue->$Id); + :set Wait false; + } + :if ($Status = "failed") do={ + :set AllDone false; + :set Wait false; + } + } while ($Wait = true); + } + } + + :if ($AllDone = true && $QueueLen = [ :len $EmailQueue ]) do={ + / system scheduler remove [ find where name="FlushEmailQueue" ]; + :set EmailQueue; + } +} + # flush telegram queue :set FlushTelegramQueue do={ :global TelegramQueue; @@ -777,6 +819,7 @@ :global Identity; :global EmailGeneralTo; :global EmailGeneralCc; + :global EmailQueue; :global LogPrintExit; :global IfThenElse; @@ -785,15 +828,18 @@ :return false; } - :do { - :local Signature [ / system note get note ]; - / tool e-mail send to=$EmailGeneralTo cc=$EmailGeneralCc \ - subject=("[" . $Identity . "] " . $Subject) \ - body=($Message . \ - [ $IfThenElse ([ :len $Link ] > 0) ("\n\n" . $Link) "" ] . \ - [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); - } on-error={ - $LogPrintExit warning ("Failed sending notification mail!") false; + :if ([ :typeof $EmailQueue ] = "nothing") do={ + :set EmailQueue [ :toarray "" ]; + } + :local Signature [ / system note get note ]; + :set ($EmailQueue->[ :len $EmailQueue ]) { + to=$EmailGeneralTo; cc=$EmailGeneralCc; subject=("[" . $Identity . "] " . $Subject); + body=($Message . \ + [ $IfThenElse ([ :len $Link ] > 0) ("\n\n" . $Link) "" ] . \ + [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]) }; + :if ([ :len [ / system scheduler find where name="FlushEmailQueue" ] ] = 0) do={ + / system scheduler add name=FlushEmailQueue interval=1s start-time=startup \ + on-event=":global FlushEmailQueue; \$FlushEmailQueue;"; } } From efca1ec049822e56a63fb6c772863694c3267756 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Feb 2021 16:13:41 +0100 Subject: [PATCH 0601/2612] global-functions: drop $MailServerIsUp Now that we have an e-mail queue we do not care if the server is up or not. --- global-functions | 47 ----------------------------------------------- log-forward | 5 ----- sms-forward | 5 ----- 3 files changed, 57 deletions(-) diff --git a/global-functions b/global-functions index 889dcea..8f4795d 100644 --- a/global-functions +++ b/global-functions @@ -32,7 +32,6 @@ :global IfThenElse; :global IPCalc; :global LogPrintExit; -:global MailServerIsUp; :global MkDir; :global ParseKeyValueStore; :global RandomDelay; @@ -486,52 +485,6 @@ } } -# check if mail server is up -:set MailServerIsUp do={ - :local MailServer [ / tool e-mail get address ]; - - :global EmailGeneralTo; - - :global LogPrintExit; - - :if ([ :len $EmailGeneralTo ] = 0) do={ - :return true; - } else={ - :if ($MailServer = "0.0.0.0") do={ - $LogPrintExit info ("No mail server is configured! Returning gracefully...") false; - :return true; - } - } - - :if ([ :len [ / tool netwatch find where comment=$MailServer ] ] = 0) do={ - $LogPrintExit info ("Adding netwatch entry for mail server.") false; - :local MailHost $MailServer; - :if ([ :typeof [ :toip $MailHost ] ] != "ip" ) do={ - :do { - :set MailHost [ :resolve $MailServer ]; - } on-error={ - $LogPrintExit warning ("Resolving mail server failed.") false; - :return false; - } - } - / tool netwatch add comment=$MailServer host=$MailHost; - } - - :local NetWatch [ / tool netwatch find where comment=$MailServer ]; - :local NetWatchVal [ / tool netwatch get $NetWatch ]; - :if ($NetWatchVal->"status" = "up") do={ - :return true; - } - - / tool netwatch set interval=($NetWatchVal->"interval") $NetWatch; - :delay ($NetWatchVal->"timeout"); - :if ([ / tool netwatch get $NetWatch status ] = "up") do={ - :return true; - } - - :return false; -} - # create directory :set MkDir do={ :local Dir [ :tostr $1 ]; diff --git a/log-forward b/log-forward index feebedd..ae9a352 100644 --- a/log-forward +++ b/log-forward @@ -14,7 +14,6 @@ :global IfThenElse; :global LogPrintExit; -:global MailServerIsUp; :global ScriptLock; :global SendNotification; :global SymbolForNotification; @@ -33,10 +32,6 @@ $ScriptLock "log-forward"; $WaitFullyConnected; -:if ([ $MailServerIsUp ] = false) do={ - $LogPrintExit warning ("Mail server is not up.") true; -} - :local Count 0; :local Messages ""; :local MessageVal; diff --git a/sms-forward b/sms-forward index 96a001d..3cfb3f0 100644 --- a/sms-forward +++ b/sms-forward @@ -10,7 +10,6 @@ :global IfThenElse; :global LogPrintExit; -:global MailServerIsUp; :global ScriptLock; :global SendNotification; :global SymbolForNotification; @@ -24,10 +23,6 @@ $ScriptLock "sms-forward"; $WaitFullyConnected; -:if ([ $MailServerIsUp ] = false) do={ - $LogPrintExit warning "Mail server is not up." true; -} - :local Settings [ / tool sms get ]; # forward SMS in a loop From fc601a57ee22e9f83b9c433d4695f8b42c8c4891 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Feb 2021 20:08:32 +0100 Subject: [PATCH 0602/2612] global-functions: $DeviceInfo: shorten text --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 8f4795d..942848a 100644 --- a/global-functions +++ b/global-functions @@ -215,7 +215,7 @@ [ $IfThenElse ([ :typeof ($Update->"latest-version") ] != "nothing" && \ $Update->"installed-version" != $Update->"latest-version") \ ("\n Available: " . $Update->"latest-version") ] . \ - "\nRouterOS-Scripts Configuration Version:" . \ + "\nRouterOS-Scripts:" . \ "\n Current: " . $GlobalConfigVersion . \ [ $IfThenElse ($GlobalConfigVersion != $ExpectedConfigVersion) \ ("\n Expected: " . $ExpectedConfigVersion) ]); From 1c40a90c795e63db66f4d0faf0450972b7d60c02 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Feb 2021 09:12:07 +0100 Subject: [PATCH 0603/2612] cloud-backup: wait to be fully connected --- cloud-backup | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cloud-backup b/cloud-backup index b8c4191..f92ee50 100644 --- a/cloud-backup +++ b/cloud-backup @@ -13,6 +13,9 @@ :global LogPrintExit; :global SendNotification; :global SymbolForNotification; +:global WaitFullyConnected; + +$WaitFullyConnected; :do { # we are not interested in output, but print is From 8c221842a61ebd207ef91fea65f16b9373c0227e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Feb 2021 09:12:31 +0100 Subject: [PATCH 0604/2612] email-backup: wait to be fully connected --- email-backup | 3 +++ 1 file changed, 3 insertions(+) diff --git a/email-backup b/email-backup index 4c7d1a4..d439d89 100644 --- a/email-backup +++ b/email-backup @@ -18,6 +18,9 @@ :global DeviceInfo; :global LogPrintExit; :global WaitForFile; +:global WaitFullyConnected; + +$WaitFullyConnected; :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ From e6f705f9e6c700f4ccf5818880f097e45b31d174 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Feb 2021 09:12:44 +0100 Subject: [PATCH 0605/2612] upload-backup: wait to be fully connected --- upload-backup | 3 +++ 1 file changed, 3 insertions(+) diff --git a/upload-backup b/upload-backup index 1249f36..155603f 100644 --- a/upload-backup +++ b/upload-backup @@ -22,6 +22,9 @@ :global SendNotification; :global SymbolForNotification; :global WaitForFile; +:global WaitFullyConnected; + +$WaitFullyConnected; :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ From 776f072415a853a8ba55d76de3df48e99062dc42 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Feb 2021 11:30:04 +0100 Subject: [PATCH 0606/2612] README: fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 448cb10..c10a660 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ Then we import the certificates. decryption-failures: 0 keys-with-no-certificate: 0 -For basic verification we rename the certifiactes and print their count. Make +For basic verification we rename the certificates and print their count. Make sure the certificate count is **three**. [admin@MikroTik] > / certificate set name="R3" [ find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" ] From 3f12730ed43cce4a5eda5c5522ea619e63b17515 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Feb 2021 12:45:16 +0100 Subject: [PATCH 0607/2612] email-backup: no example address, complain if missing --- email-backup | 4 ++++ global-config | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/email-backup b/email-backup index d439d89..a60b701 100644 --- a/email-backup +++ b/email-backup @@ -27,6 +27,10 @@ $WaitFullyConnected; $LogPrintExit error ("Configured to send neither backup nor config export.") true; } +:if ([ :len $EmailBackupTo ] = 0) do={ + $LogPrintExit error ("Configuration is missing recipient for e-mail backup.") true; +} + # filename based on identity :local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; :local BackupFile "none"; diff --git a/global-config b/global-config index a3e515c..4b20fbe 100644 --- a/global-config +++ b/global-config @@ -43,8 +43,8 @@ :global BackupSendExport true; :global BackupPassword "v3ry-s3cr3t"; # These addresses are used to send backup and config export files to. -:global EmailBackupTo "mail@example.com"; -:global EmailBackupCc "another@example.com"; +:global EmailBackupTo ""; +:global EmailBackupCc ""; # These credentials are used to upload backup and config export files. # SFTP authentication is tricky, you may have to limit authentication # methods for your SSH server. From 148a7f93a6d61c7f7df931d9265dd9271da2cc91 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Feb 2021 21:09:16 +0100 Subject: [PATCH 0608/2612] global-functions: $ScriptInstallUpdate: Properly escape question mark --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 942848a..b3a4f3c 100644 --- a/global-functions +++ b/global-functions @@ -667,7 +667,7 @@ :do { / system script { run global-config; run global-config-overlay; } } on-error={ - $LogPrintExit error ("Reloading global configuration and overlay failed! Syntax error?") false; + $LogPrintExit error ("Reloading global configuration and overlay failed! Syntax error\?") false; } } :if ($ScriptVal->"name" = "global-functions") do={ From 2db73a189c6eb2cc16ec2f2a4c4b33133ae8130d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Feb 2021 21:27:54 +0100 Subject: [PATCH 0609/2612] global-functions: $ScriptInstallUpdate: fix change notification In RouterOS functions are of type 'array' with 'code' (numerical index 1) inside. Cast to string to make comparison work. Also define the function to make it available. --- global-functions | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index b3a4f3c..bf09ad2 100644 --- a/global-functions +++ b/global-functions @@ -592,6 +592,7 @@ :global CertificateAvailable; :global LogPrintExit; :global ParseKeyValueStore; + :global ScriptInstallUpdate; :global SendNotification; :global SymbolForNotification; @@ -606,7 +607,7 @@ } } - :local ScriptInstallUpdateBefore $ScriptInstallUpdate; + :local ScriptInstallUpdateBefore [ :tostr $ScriptInstallUpdate ]; :foreach Script in=[ / system script find where source~"^#!rsc( by RouterOS)\?\n" ] do={ :local ScriptVal [ / system script get $Script ]; @@ -747,7 +748,7 @@ :set SentConfigChangesNotification $ExpectedConfigVersion; } - :if ($ScriptInstallUpdateBefore != $ScriptInstallUpdate) do={ + :if ($ScriptInstallUpdateBefore != [ :tostr $ScriptInstallUpdate ]) do={ $LogPrintExit info ("This function '\$ScriptInstallUpdate' changed, you may want to re-run.") false; } } From d5afc79eed2a54ab005f1b0ccf656c43a57e0a9b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Feb 2021 14:52:47 +0100 Subject: [PATCH 0610/2612] global: drop script 'global-wait' All scripts wait for the global functions on their own now. --- README.md | 1 - accesslist-duplicates.capsman | 3 +++ accesslist-duplicates.local | 3 +++ accesslist-duplicates.template | 3 +++ bridge-port-to-default | 3 +++ bridge-port-toggle | 3 +++ capsman-download-packages | 3 +++ capsman-rolling-upgrade | 3 +++ certificate-renew-issued | 3 +++ check-certificates | 3 +++ check-health | 3 +++ check-lte-firmware-upgrade | 3 +++ check-routeros-update | 3 +++ cloud-backup | 3 +++ collect-wireless-mac.capsman | 3 +++ collect-wireless-mac.local | 3 +++ collect-wireless-mac.template | 3 +++ daily-psk.capsman | 3 +++ daily-psk.local | 3 +++ daily-psk.template | 3 +++ dhcp-lease-comment.capsman | 3 +++ dhcp-lease-comment.local | 3 +++ dhcp-lease-comment.template | 3 +++ dhcp-to-dns | 3 +++ doc/bridge-port.md | 11 ++------- doc/capsman-download-packages.md | 7 ++---- doc/check-certificates.md | 2 +- doc/daily-psk.md | 13 ++++------- doc/global-wait.md | 40 -------------------------------- email-backup | 3 +++ global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 9 +------ global-wait | 10 ++++---- gps-track | 3 +++ hotspot-to-wpa | 3 +++ ipv6-update | 3 +++ lease-script | 3 +++ log-forward | 3 +++ mode-button | 3 +++ netwatch-notify | 3 +++ ospf-to-leds | 3 +++ packages-update | 3 +++ ppp-on-up | 3 +++ rotate-ntp | 3 +++ sms-action | 3 +++ sms-forward | 3 +++ update-gre-address | 3 +++ update-tunnelbroker | 3 +++ upload-backup | 3 +++ 51 files changed, 137 insertions(+), 81 deletions(-) delete mode 100644 doc/global-wait.md diff --git a/README.md b/README.md index c10a660..616f4e9 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,6 @@ Available Scripts * [Comment DHCP leases with info from access list](doc/dhcp-lease-comment.md) * [Create DNS records for DHCP leases](doc/dhcp-to-dns.md) * [Send backup via e-mail](doc/email-backup.md) -* [Wait for configuration und functions](doc/global-wait.md) * [Send GPS position to server](doc/gps-track.md) * [Use WPA2 network with hotspot credentials](doc/hotspot-to-wpa.md) * [Update configuration on IPv6 prefix change](doc/ipv6-update.md) diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman index 4911760..54271c3 100644 --- a/accesslist-duplicates.capsman +++ b/accesslist-duplicates.capsman @@ -8,6 +8,9 @@ # # !! Do not edit this file, it is generated from template! +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :local Seen [ :toarray "" ]; :local Shown [ :toarray "" ]; diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local index 84fafb3..3f783a4 100644 --- a/accesslist-duplicates.local +++ b/accesslist-duplicates.local @@ -8,6 +8,9 @@ # # !! Do not edit this file, it is generated from template! +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :local Seen [ :toarray "" ]; :local Shown [ :toarray "" ]; diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template index 7161992..c14b630 100644 --- a/accesslist-duplicates.template +++ b/accesslist-duplicates.template @@ -9,6 +9,9 @@ # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :local Seen [ :toarray "" ]; :local Shown [ :toarray "" ]; diff --git a/bridge-port-to-default b/bridge-port-to-default index 286fb45..60e3112 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -6,6 +6,9 @@ # reset bridge ports to default bridge # https://git.eworm.de/cgit/routeros-scripts/about/doc/bridge-port.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global BridgePortTo; :global IfThenElse; diff --git a/bridge-port-toggle b/bridge-port-toggle index 78a64f7..9ad38cb 100644 --- a/bridge-port-toggle +++ b/bridge-port-toggle @@ -6,6 +6,9 @@ # toggle bridge ports between default and alt bridge # https://git.eworm.de/cgit/routeros-scripts/about/doc/bridge-port.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global BridgePortTo; :if ($BridgePortTo != "default") do={ diff --git a/capsman-download-packages b/capsman-download-packages index b6bff3a..13537fa 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -7,6 +7,9 @@ # download and cleanup packages for CAP installation from CAPsMAN # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global CleanFilePath; :global DownloadPackage; :global LogPrintExit; diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index 1f091b8..a765fb5 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -7,6 +7,9 @@ # upgrade CAPs one after another # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global LogPrintExit; :global ScriptLock; diff --git a/certificate-renew-issued b/certificate-renew-issued index 2eeaba0..2345f30 100644 --- a/certificate-renew-issued +++ b/certificate-renew-issued @@ -6,6 +6,9 @@ # renew locally issued certificates # https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global CertIssuedExportPass; :global LogPrintExit; diff --git a/check-certificates b/check-certificates index 39b7e2c..94ccc99 100644 --- a/check-certificates +++ b/check-certificates @@ -6,6 +6,9 @@ # check for certificate validity # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global CertRenewPass; :global CertRenewTime; :global CertRenewUrl; diff --git a/check-health b/check-health index 7fa45cb..8cb2cf3 100644 --- a/check-health +++ b/check-health @@ -6,6 +6,9 @@ # check for RouterOS health state # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global CheckHealthLast; :global CheckHealthTemperature; :global CheckHealthTemperatureDeviation; diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index a678fb6..ed3cb98 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -6,6 +6,9 @@ # check for LTE firmware upgrade, send notification # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global Identity; :global SentLteFirmwareUpgradeNotification; diff --git a/check-routeros-update b/check-routeros-update index 412d84a..09127d3 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -6,6 +6,9 @@ # check for RouterOS update, send notification and/or install # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global Identity; :global SafeUpdateNeighbor; :global SafeUpdatePatch; diff --git a/cloud-backup b/cloud-backup index f92ee50..e4e527b 100644 --- a/cloud-backup +++ b/cloud-backup @@ -6,6 +6,9 @@ # upload backup to MikroTik cloud # https://git.eworm.de/cgit/routeros-scripts/about/doc/cloud-backup.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global BackupPassword; :global Identity; diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index fda401e..bf8e691 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -8,6 +8,9 @@ # # !! Do not edit this file, it is generated from template! +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global Identity; :global GetMacVendor; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index f9c135c..15c0c9a 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -8,6 +8,9 @@ # # !! Do not edit this file, it is generated from template! +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global Identity; :global GetMacVendor; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 1d031fe..2198136 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -9,6 +9,9 @@ # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global Identity; :global GetMacVendor; diff --git a/daily-psk.capsman b/daily-psk.capsman index 10b3403..b66b750 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -9,6 +9,9 @@ # # !! Do not edit this file, it is generated from template! +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global DailyPskMatchComment; :global Identity; diff --git a/daily-psk.local b/daily-psk.local index ec03c1a..e7f908f 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -9,6 +9,9 @@ # # !! Do not edit this file, it is generated from template! +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global DailyPskMatchComment; :global Identity; diff --git a/daily-psk.template b/daily-psk.template index 590b1ea..8cf08e0 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -10,6 +10,9 @@ # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global DailyPskMatchComment; :global Identity; diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index b663a0a..3c0b9e9 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -8,6 +8,9 @@ # # !! Do not edit this file, it is generated from template! +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global LogPrintExit; :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index 1d9eb08..dc2f708 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -8,6 +8,9 @@ # # !! Do not edit this file, it is generated from template! +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global LogPrintExit; :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index 4007765..e3ca6d0 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -9,6 +9,9 @@ # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global LogPrintExit; :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ diff --git a/dhcp-to-dns b/dhcp-to-dns index 375e083..30ca63c 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -6,6 +6,9 @@ # check DHCP leases and add/remove/update DNS entries # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global Domain; :global HostNameInZone; :global Identity; diff --git a/doc/bridge-port.md b/doc/bridge-port.md index 167fa87..8cbe15b 100644 --- a/doc/bridge-port.md +++ b/doc/bridge-port.md @@ -33,11 +33,9 @@ There is also global configuration: * `BridgePortTo`: specify the configuration to be applied by default -Install [global-wait](global-wait.md) and add a scheduler to start with -default setup on system startup: +Add a scheduler to start with default setup on system startup: - $ScriptInstallUpdate global-wait; - / system scheduler add name=bridge-port-to-default on-event="/ system script { run global-wait; run bridge-port-to-default; }" start-time=startup; + / system scheduler add name=bridge-port-to-default on-event="/ system script run bridge-port-to-default;" start-time=startup; Usage and invocation -------------------- @@ -75,11 +73,6 @@ More configuration can be loaded by setting `BridgePortTo`: * Interfaces `en1` and `en2` are unchanged. * Interface `en3` is put in bridge `br-intern`. -See also --------- - -* [Wait for configuration und functions](global-wait.md) - --- [◀ Go back to main README](../README.md) [▲ Go back to top](#top) diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index 5acf914..8516ff4 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -19,11 +19,9 @@ Just install the script on CAPsMAN device: $ScriptInstallUpdate capsman-download-packages; -Optionally install [global-wait](global-wait.md) and add a scheduler to run -after startup: +Optionally add a scheduler to run after startup: - $ScriptInstallUpdate global-wait; - / system scheduler add name=capsman-download-packages on-event="/ system script { run global-wait; run capsman-download-packages; }" start-time=startup; + / system scheduler add name=capsman-download-packages on-event="/ system script run capsman-download-packages;" start-time=startup; Only packages available in older version are downloaded. For initial setup place the required packages to CAPsMAN package path (see @@ -55,7 +53,6 @@ See also -------- * [Run rolling CAP upgrades from CAPsMAN](capsman-rolling-upgrade.md) -* [Wait for configuration und functions](global-wait.md) --- [◀ Go back to main README](../README.md) diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 6e4a851..318805d 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -44,7 +44,7 @@ Just run the script: Alternatively running on startup may be desired: - / system scheduler add name=check-certificates-startup on-event="/ system script { run global-wait; run check-certificates; }" start-time=startup; + / system scheduler add name=check-certificates-startup on-event="/ system script run check-certificates;" start-time=startup; See also -------- diff --git a/doc/daily-psk.md b/doc/daily-psk.md index c6055d6..d472269 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -12,23 +12,23 @@ passphrase to a pseudo-random string daily. Requirements and installation ----------------------------- -Just install this script and [global-wait](global-wait.md). +Just install this script. Depending on whether you use CAPsMAN (`/ caps-man`) or local wireless interface (`/ interface wireless`) you need to install a different script. For CAPsMAN: - $ScriptInstallUpdate daily-psk.capsman,global-wait; + $ScriptInstallUpdate daily-psk.capsman; For local interface: - $ScriptInstallUpdate daily-psk.local,global-wait; + $ScriptInstallUpdate daily-psk.local; And add schedulers to run the script: / system scheduler add interval=1d name=daily-psk-nightly on-event="/ system script run daily-psk.local;" start-date=may/23/2018 start-time=03:00:00; - / system scheduler add name=daily-psk-startup on-event="/ system script { run global-wait; run daily-psk.local; }" start-time=startup; + / system scheduler add name=daily-psk-startup on-event="/ system script run daily-psk.local;" start-time=startup; These will update the passphrase on boot and nightly at 3:00. @@ -46,11 +46,6 @@ Then add an access list entry: Also notification settings are required for e-mail and telegram. -See also --------- - -* [Wait for configuration und functions](global-wait.md) - --- [◀ Go back to main README](../README.md) [▲ Go back to top](#top) diff --git a/doc/global-wait.md b/doc/global-wait.md deleted file mode 100644 index bdceddf..0000000 --- a/doc/global-wait.md +++ /dev/null @@ -1,40 +0,0 @@ -Wait for configuration und functions -==================================== - -[◀ Go back to main README](../README.md) - -Description ------------ - -The global scripts `global-config`, `global-config-overlay` and -`global-functions` are run by scheduler at system startup. Running another -script at system startup may result in race condition where configuration -and/or function are not yet available. This script is supposed to wait -for everything being prepared. - -Do **not** add this script `global-wait` to the `global-scripts` scheduler! -It would inhibit the initialization of configuration and functions. - -Requirements and installation ------------------------------ - -Just install the script: - - $ScriptInstallUpdate global-wait; - -... and add it to your scheduler, for example in combination with -[bridge-port](bridge-port.md): - - / system scheduler add name=bridge-port-to-default on-event="/ system script { run global-wait; run bridge-port-to-default; }" start-time=startup; - -See also --------- - -* [Manage ports in bridge](bridge-port.md) -* [Download packages for CAP upgrade from CAPsMAN](capsman-download-packages.md) -* [Renew certificates and notify on expiration](check-certificates.md) -* [Use wireless network with daily psk](daily-psk.md) - ---- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) diff --git a/email-backup b/email-backup index a60b701..7cd8222 100644 --- a/email-backup +++ b/email-backup @@ -6,6 +6,9 @@ # create and email backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/email-backup.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global BackupPassword; :global BackupSendBinary; :global BackupSendExport; diff --git a/global-config b/global-config index 4b20fbe..bf8ff8a 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 43; +:global GlobalConfigVersion 44; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index e8d7913..3e374b1 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 43; +:global GlobalConfigVersion 44; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index a27b43a..dcafb7c 100644 --- a/global-config.changes +++ b/global-config.changes @@ -47,6 +47,7 @@ 41="Implemented migration mechanism for script updates."; 42="Made severity in terminal output colorful, with opt-out."; 43="Added queue for e-mail notifications to resend later on error."; + 44="Dropped script 'global-wait', all scripts wait on their own now."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index bf09ad2..072164d 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 43; +:global ExpectedConfigVersion 44; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -624,13 +624,6 @@ $LogPrintExit warning ("Policies differ for script " . $ScriptVal->"name" . \ " and its scheduler " . $SchedulerVal->"name" . "!") false; } - :if ($SchedulerVal->"name" != "global-scripts" && \ - $SchedulerVal->"start-time" = "startup" && \ - $SchedulerVal->"interval" = 0s && \ - !(($SchedulerVal->"on-event") ~ "\\brun global-wait\\b")) do={ - $LogPrintExit warning ("Scheduler " . $SchedulerVal->"name" . " starts on startup, " . \ - "without waiting for global-functions. Run 'global-wait' to avoid race conditions!") false; - } } :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ diff --git a/global-wait b/global-wait index edb156b..18f2fb8 100644 --- a/global-wait +++ b/global-wait @@ -1,13 +1,11 @@ #!rsc by RouterOS # RouterOS script: global-wait -# Copyright (c) 2020-2021 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# wait for global-functions to finish -# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md :global GlobalFunctionsReady; - :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global LogPrintExit; + +$LogPrintExit warning ("This script 'global-wait' is now useless, please remove it from configuration.") true; diff --git a/gps-track b/gps-track index 1f7d228..5fbe240 100644 --- a/gps-track +++ b/gps-track @@ -6,6 +6,9 @@ # track gps data by sending json data to http server # https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global GpsTrackUrl; :global Identity; diff --git a/hotspot-to-wpa b/hotspot-to-wpa index ca11775..09283cf 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -6,6 +6,9 @@ # add private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global LogPrintExit; :local MacAddress $"mac-address"; diff --git a/ipv6-update b/ipv6-update index d5b15c4..4f0812c 100644 --- a/ipv6-update +++ b/ipv6-update @@ -6,6 +6,9 @@ # update firewall and dns settings on IPv6 prefix change # https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :local PdPrefix $"pd-prefix"; :global LogPrintExit; diff --git a/lease-script b/lease-script index 438df0f..a39a874 100644 --- a/lease-script +++ b/lease-script @@ -6,6 +6,9 @@ # run scripts on DHCP lease # https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global LogPrintExit; :if ([ :typeof $leaseActIP ] = "nothing" || \ diff --git a/log-forward b/log-forward index ae9a352..c4458b2 100644 --- a/log-forward +++ b/log-forward @@ -6,6 +6,9 @@ # forward log messages via notification # https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global Identity; :global LogForwardFilter; :global LogForwardFilterMessage; diff --git a/mode-button b/mode-button index 35c0899..cd94919 100644 --- a/mode-button +++ b/mode-button @@ -6,6 +6,9 @@ # act on multiple mode and reset button presses # https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global ModeButton; :global LogPrintExit; diff --git a/netwatch-notify b/netwatch-notify index 9651841..d050b75 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -6,6 +6,9 @@ # monitor netwatch and send notifications # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global NetwatchNotify; :global IfThenElse; diff --git a/ospf-to-leds b/ospf-to-leds index b899b50..32027db 100644 --- a/ospf-to-leds +++ b/ospf-to-leds @@ -6,6 +6,9 @@ # visualize ospf instance state via leds # https://git.eworm.de/cgit/routeros-scripts/about/doc/ospf-to-leds.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global LogPrintExit; :global ParseKeyValueStore; diff --git a/packages-update b/packages-update index 022a110..4a2f418 100644 --- a/packages-update +++ b/packages-update @@ -6,6 +6,9 @@ # download packages and reboot for installation # https://git.eworm.de/cgit/routeros-scripts/about/doc/packages-update.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global DownloadPackage; :global LogPrintExit; :global ScriptFromTerminal; diff --git a/ppp-on-up b/ppp-on-up index 9de01b8..cf95e48 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -6,6 +6,9 @@ # run scripts on ppp up # https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global LogPrintExit; :local Interface $interface; diff --git a/rotate-ntp b/rotate-ntp index a0cc524..6578078 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -6,6 +6,9 @@ # rotate the ntp servers # https://git.eworm.de/cgit/routeros-scripts/about/doc/rotate-ntp.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global NtpPool; :global LogPrintExit; diff --git a/sms-action b/sms-action index a070cc9..4c39740 100644 --- a/sms-action +++ b/sms-action @@ -6,6 +6,9 @@ # run action on received SMS # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-action.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global SmsAction; :global LogPrintExit; diff --git a/sms-forward b/sms-forward index 3cfb3f0..abfea99 100644 --- a/sms-forward +++ b/sms-forward @@ -6,6 +6,9 @@ # forward SMS to e-mail # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global Identity; :global IfThenElse; diff --git a/update-gre-address b/update-gre-address index 7dd4896..50d1373 100644 --- a/update-gre-address +++ b/update-gre-address @@ -7,6 +7,9 @@ # ipsec remote peer # https://git.eworm.de/cgit/routeros-scripts/about/doc/update-gre-address.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global LogPrintExit; / interface gre set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; diff --git a/update-tunnelbroker b/update-tunnelbroker index d014178..6cdb195 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -7,6 +7,9 @@ # update local address of tunnelbroker interface # https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global CertificateAvailable; :global LogPrintExit; :global ParseKeyValueStore; diff --git a/upload-backup b/upload-backup index 155603f..e16a4e5 100644 --- a/upload-backup +++ b/upload-backup @@ -6,6 +6,9 @@ # create and upload backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/upload-backup.md +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + :global BackupPassword; :global BackupSendBinary; :global BackupSendExport; From 60ca07dc8a583e4585ab7b84773f6da17193b909 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Feb 2021 21:49:23 +0100 Subject: [PATCH 0611/2612] global-functions: $TimeIsSync: do not flood log... ... when returning gracefully. --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 072164d..8777c18 100644 --- a/global-functions +++ b/global-functions @@ -971,7 +971,7 @@ :return false; } - $LogPrintExit info ("No time source configured! Returning gracefully...") false; + $LogPrintExit debug ("No time source configured! Returning gracefully...") false; :return true; } From 182bd2fa0b21a499c8d82f479a261997fc4631f9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Feb 2021 23:11:10 +0100 Subject: [PATCH 0612/2612] check-routeros-update: give more context --- check-routeros-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-routeros-update b/check-routeros-update index 09127d3..02c547a 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -34,7 +34,7 @@ :if ([ :len [ / system package find where name="wireless" disabled=no ] ] > 0) do={ :if ([ / interface wireless cap get enabled ] = true && \ [ / caps-man manager get enabled ] = false) do={ - $LogPrintExit error "System is managed by CAPsMAN, not checking." true; + $LogPrintExit error "System is managed by CAPsMAN, not checking for RouterOS version." true; } } From 06b235b3b7a3fdc1a22e1622ceaf545376e8b01f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Feb 2021 23:14:46 +0100 Subject: [PATCH 0613/2612] check-routeros-update: wait to be fully connected --- check-routeros-update | 3 +++ 1 file changed, 3 insertions(+) diff --git a/check-routeros-update b/check-routeros-update index 02c547a..c641e04 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -21,6 +21,7 @@ :global SendNotification; :global SymbolForNotification; :global VersionToNum; +:global WaitFullyConnected; :local DoUpdate do={ :if ([ :len [ / system script find where name="packages-update" ] ] > 0) do={ @@ -31,6 +32,8 @@ :error "Waiting for system to reboot."; } +$WaitFullyConnected; + :if ([ :len [ / system package find where name="wireless" disabled=no ] ] > 0) do={ :if ([ / interface wireless cap get enabled ] = true && \ [ / caps-man manager get enabled ] = false) do={ From 4b945da9078be5f6f236cb4cbb5490fad22f9497 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Feb 2021 23:23:55 +0100 Subject: [PATCH 0614/2612] global-functions: $FlushTelegramQueue: disable web page preview ... just as without queue. --- global-functions | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 8777c18..d1fcf05 100644 --- a/global-functions +++ b/global-functions @@ -348,7 +348,8 @@ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ http-data=("chat_id=" . ($Message->"chatid") . \ "&disable_notification=" . ($Message->"silent") . \ - "&parse_mode=" . ($Message->"parsemode") . "&text=" . ($Message->"text")); + "&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \ + "&text=" . ($Message->"text")); :set ($TelegramQueue->$Id); } on-error={ $LogPrintExit debug ("Sending queued Telegram message failed.") false; From a2450dc9f0906ee7d99e0108253d06ba09a75ca2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Feb 2021 23:43:15 +0100 Subject: [PATCH 0615/2612] gps-track: fix syntax --- gps-track | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gps-track b/gps-track index 5fbe240..31e12e9 100644 --- a/gps-track +++ b/gps-track @@ -14,12 +14,11 @@ :global LogPrintExit; -:local CoordinateFormat [ /system gps get coordinate-format ]; +:local CoordinateFormat [ / system gps get coordinate-format ]; :local Gps [ / system gps monitor once as-value ]; -if ($Gps->"valid" = true) do={ - :tool fetch check-certificate=yes-without-crl \ - $GpsTrackUrl output=none \ +:if ($Gps->"valid" = true) do={ + / tool fetch check-certificate=yes-without-crl $GpsTrackUrl output=none \ http-method=post http-header-field="Content-Type: application/json" \ http-data=("{" . \ "\"lat\":\"" . ($Gps->"latitude") . "\"," . \ From 940d31b55592ee76c75c6e9da59369127b04940f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 21 Feb 2021 21:36:34 +0100 Subject: [PATCH 0616/2612] capsman-download-packages: complain on undefined path --- capsman-download-packages | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/capsman-download-packages b/capsman-download-packages index 13537fa..839540e 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -24,6 +24,10 @@ $WaitFullyConnected; :local InstalledVersion [ / system package update get installed-version ]; :local Updated false; +:if ([ :len $PackagePath ] = 0) do={ + $LogPrintExit warning ("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={ $LogPrintExit warning ("Creating directory at package path (" . \ From 9975709ab7c29540af2c298aeabafdee09d2a62c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 21 Feb 2021 21:40:28 +0100 Subject: [PATCH 0617/2612] capsman-download-packages: give more context in output --- capsman-download-packages | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/capsman-download-packages b/capsman-download-packages index 839540e..a9ef529 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -30,10 +30,10 @@ $WaitFullyConnected; :if ([ :len [ / file find where name=$PackagePath type="directory" ] ] = 0) do={ :if ([ $MkDir $PackagePath ] = false) do={ - $LogPrintExit warning ("Creating directory at package path (" . \ + $LogPrintExit warning ("Creating directory at CAPsMAN package path (" . \ $PackagePath . ") failed!") true; } - $LogPrintExit info ("Created directory at package path (" . $PackagePath . \ + $LogPrintExit info ("Created directory at CAPsMAN package path (" . $PackagePath . \ "). Please place your packages!") false; } From 292176e910e080e824779cc735081ff415c6c28a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 21 Feb 2021 21:59:36 +0100 Subject: [PATCH 0618/2612] README: swap stars and forks --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 616f4e9..d216fa0 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ RouterOS Scripts ================ -[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/stargazers) +[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/watchers) [RouterOS](https://mikrotik.com/software) is the operating system developed From 73eb92fb723e6f42c3d80a0a7d0e4d21bcfc8238 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 22 Feb 2021 10:34:09 +0100 Subject: [PATCH 0619/2612] We have a Telegram group! --- README.md | 7 +++++++ global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d216fa0..14b32db 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,13 @@ Available Scripts [comment]: # (* learn-mac-based-vlan) [comment]: # (* manage-umts) +Contact +------- + +We have a Telegram Group [RouterOS-Scripts](https://t.me/routeros_scripts)! +Get help, give feedback or just chat - but do not expect free professional +support! + Contribute ---------- diff --git a/global-config b/global-config index bf8ff8a..d574f60 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 44; +:global GlobalConfigVersion 45; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 3e374b1..6a8050a 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 44; +:global GlobalConfigVersion 45; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index dcafb7c..283d2c0 100644 --- a/global-config.changes +++ b/global-config.changes @@ -48,6 +48,7 @@ 42="Made severity in terminal output colorful, with opt-out."; 43="Added queue for e-mail notifications to resend later on error."; 44="Dropped script 'global-wait', all scripts wait on their own now."; + 45="We have a Telegram Group! Come along and say hello: https://t.me/routeros_scripts"; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index d1fcf05..502aa46 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 44; +:global ExpectedConfigVersion 45; # global variables not to be changed by user :global GlobalFunctionsReady false; From e99821c39a46ca36377c0ed134c532ec86d34bc2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Feb 2021 10:14:09 +0100 Subject: [PATCH 0620/2612] switch default branch from master to main --- global-config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-config b/global-config index d574f60..d9c8061 100644 --- a/global-config +++ b/global-config @@ -130,8 +130,8 @@ # Enable this to fetch scripts from given url. :global ScriptUpdatesFetch true; :global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/"; -#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/master/"; -#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/master/"; +#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/main/"; +#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/main/"; :global ScriptUpdatesUrlSuffix ""; # This project is developed in private spare time and usage is free of charge From 0d91445cca3cac1f9e13f5d51f433a5c74a70a25 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Feb 2021 14:48:28 +0100 Subject: [PATCH 0621/2612] global-functions: $ScriptInstallUpdate: handle migration before message --- global-functions | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 502aa46..32ef6ba 100644 --- a/global-functions +++ b/global-functions @@ -710,14 +710,14 @@ :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); [ :parse $ChangeLogCode ]; :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ - :set NotificationMessage ($NotificationMessage . \ - "\n * " . $GlobalConfigChanges->[ :tostr $I ]); - $LogPrintExit info ("Change: " . $GlobalConfigChanges->[ :tostr $I ]) false; :local Migration ($GlobalConfigMigration->[ :tostr $I ]); :if ([ :typeof $Migration ] = "str") do={ $LogPrintExit info ("Applying migration: " . $Migration) false; [ :parse $Migration ]; } + :set NotificationMessage ($NotificationMessage . \ + "\n * " . $GlobalConfigChanges->[ :tostr $I ]); + $LogPrintExit info ("Change: " . $GlobalConfigChanges->[ :tostr $I ]) false; } :set GlobalConfigChanges; :set GlobalConfigMigration; From b0e52aa2d1baa78fc9d025c0671fea8babba0ec2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Feb 2021 21:48:36 +0100 Subject: [PATCH 0622/2612] global-functions: $GetMacVendor: requires certificate "Cloudflare Inc ECC CA-3" now --- certs/Cloudflare Inc ECC CA-3.pem | 166 ++++++++++++++++++++++++++++++ global-functions | 2 +- 2 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 certs/Cloudflare Inc ECC CA-3.pem diff --git a/certs/Cloudflare Inc ECC CA-3.pem b/certs/Cloudflare Inc ECC CA-3.pem new file mode 100644 index 0000000..e2de16a --- /dev/null +++ b/certs/Cloudflare Inc ECC CA-3.pem @@ -0,0 +1,166 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0a:37:87:64:5e:5f:b4:8c:22:4e:fd:1b:ed:14:0c:3c + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root + Validity + Not Before: Jan 27 12:48:08 2020 GMT + Not After : Dec 31 23:59:59 2024 GMT + Subject: C = US, O = "Cloudflare, Inc.", CN = Cloudflare Inc ECC CA-3 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:b9:ad:4d:66:99:14:0b:46:ec:1f:81:d1:2a:50: + 1e:9d:03:15:2f:34:12:7d:2d:96:b8:88:38:9b:85: + 5f:8f:bf:bb:4d:ef:61:46:c4:c9:73:d4:24:4f:e0: + ee:1c:ce:6c:b3:51:71:2f:6a:ee:4c:05:09:77:d3: + 72:62:a4:9b:d7 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Subject Key Identifier: + A5:CE:37:EA:EB:B0:75:0E:94:67:88:B4:45:FA:D9:24:10:87:96:1F + X509v3 Authority Key Identifier: + keyid:E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl3.digicert.com/Omniroot2025.crl + + X509v3 Certificate Policies: + Policy: 2.16.840.1.114412.1.1 + CPS: https://www.digicert.com/CPS + Policy: 2.16.840.1.114412.1.2 + Policy: 2.23.140.1.2.1 + Policy: 2.23.140.1.2.2 + Policy: 2.23.140.1.2.3 + + Signature Algorithm: sha256WithRSAEncryption + 05:24:1d:dd:1b:b0:2a:eb:98:d6:85:e3:39:4d:5e:6b:57:9d: + 82:57:fc:eb:e8:31:a2:57:90:65:05:be:16:44:38:5a:77:02: + b9:cf:10:42:c6:e1:92:a4:e3:45:27:f8:00:47:2c:68:a8:56: + 99:53:54:8f:ad:9e:40:c1:d0:0f:b6:d7:0d:0b:38:48:6c:50: + 2c:49:90:06:5b:64:1d:8b:cc:48:30:2e:de:08:e2:9b:49:22: + c0:92:0c:11:5e:96:92:94:d5:fc:20:dc:56:6c:e5:92:93:bf: + 7a:1c:c0:37:e3:85:49:15:fa:2b:e1:74:39:18:0f:b7:da:f3: + a2:57:58:60:4f:cc:8e:94:00:fc:46:7b:34:31:3e:4d:47:82: + 81:3a:cb:f4:89:5d:0e:ef:4d:0d:6e:9c:1b:82:24:dd:32:25: + 5d:11:78:51:10:3d:a0:35:23:04:2f:65:6f:9c:c1:d1:43:d7: + d0:1e:f3:31:67:59:27:dd:6b:d2:75:09:93:11:24:24:14:cf: + 29:be:e6:23:c3:b8:8f:72:3f:e9:07:c8:24:44:53:7a:b3:b9: + 61:65:a1:4c:0e:c6:48:00:c9:75:63:05:87:70:45:52:83:d3: + 95:9d:45:ea:f0:e8:31:1d:7e:09:1f:0a:fe:3e:dd:aa:3c:5e: + 74:d2:ac:b1 +-----BEGIN CERTIFICATE----- +MIIDzTCCArWgAwIBAgIQCjeHZF5ftIwiTv0b7RQMPDANBgkqhkiG9w0BAQsFADBa +MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl +clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTIw +MDEyNzEyNDgwOFoXDTI0MTIzMTIzNTk1OVowSjELMAkGA1UEBhMCVVMxGTAXBgNV +BAoTEENsb3VkZmxhcmUsIEluYy4xIDAeBgNVBAMTF0Nsb3VkZmxhcmUgSW5jIEVD +QyBDQS0zMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEua1NZpkUC0bsH4HRKlAe +nQMVLzQSfS2WuIg4m4Vfj7+7Te9hRsTJc9QkT+DuHM5ss1FxL2ruTAUJd9NyYqSb +16OCAWgwggFkMB0GA1UdDgQWBBSlzjfq67B1DpRniLRF+tkkEIeWHzAfBgNVHSME +GDAWgBTlnVkwgkdYzKz6CFQ2hns6tQRN8DAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0l +BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYI +KwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j +b20wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL09t +bmlyb290MjAyNS5jcmwwbQYDVR0gBGYwZDA3BglghkgBhv1sAQEwKjAoBggrBgEF +BQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzALBglghkgBhv1sAQIw +CAYGZ4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggEB +AAUkHd0bsCrrmNaF4zlNXmtXnYJX/OvoMaJXkGUFvhZEOFp3ArnPEELG4ZKk40Un ++ABHLGioVplTVI+tnkDB0A+21w0LOEhsUCxJkAZbZB2LzEgwLt4I4ptJIsCSDBFe +lpKU1fwg3FZs5ZKTv3ocwDfjhUkV+ivhdDkYD7fa86JXWGBPzI6UAPxGezQxPk1H +goE6y/SJXQ7vTQ1unBuCJN0yJV0ReFEQPaA1IwQvZW+cwdFD19Ae8zFnWSfda9J1 +CZMRJCQUzym+5iPDuI9yP+kHyCREU3qzuWFloUwOxkgAyXVjBYdwRVKD05WdRerw +6DEdfgkfCv4+3ao8XnTSrLE= +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 33554617 (0x20000b9) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root + Validity + Not Before: May 12 18:46:00 2000 GMT + Not After : May 12 23:59:00 2025 GMT + Subject: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:a3:04:bb:22:ab:98:3d:57:e8:26:72:9a:b5:79: + d4:29:e2:e1:e8:95:80:b1:b0:e3:5b:8e:2b:29:9a: + 64:df:a1:5d:ed:b0:09:05:6d:db:28:2e:ce:62:a2: + 62:fe:b4:88:da:12:eb:38:eb:21:9d:c0:41:2b:01: + 52:7b:88:77:d3:1c:8f:c7:ba:b9:88:b5:6a:09:e7: + 73:e8:11:40:a7:d1:cc:ca:62:8d:2d:e5:8f:0b:a6: + 50:d2:a8:50:c3:28:ea:f5:ab:25:87:8a:9a:96:1c: + a9:67:b8:3f:0c:d5:f7:f9:52:13:2f:c2:1b:d5:70: + 70:f0:8f:c0:12:ca:06:cb:9a:e1:d9:ca:33:7a:77: + d6:f8:ec:b9:f1:68:44:42:48:13:d2:c0:c2:a4:ae: + 5e:60:fe:b6:a6:05:fc:b4:dd:07:59:02:d4:59:18: + 98:63:f5:a5:63:e0:90:0c:7d:5d:b2:06:7a:f3:85: + ea:eb:d4:03:ae:5e:84:3e:5f:ff:15:ed:69:bc:f9: + 39:36:72:75:cf:77:52:4d:f3:c9:90:2c:b9:3d:e5: + c9:23:53:3f:1f:24:98:21:5c:07:99:29:bd:c6:3a: + ec:e7:6e:86:3a:6b:97:74:63:33:bd:68:18:31:f0: + 78:8d:76:bf:fc:9e:8e:5d:2a:86:a7:4d:90:dc:27: + 1a:39 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:3 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + 85:0c:5d:8e:e4:6f:51:68:42:05:a0:dd:bb:4f:27:25:84:03: + bd:f7:64:fd:2d:d7:30:e3:a4:10:17:eb:da:29:29:b6:79:3f: + 76:f6:19:13:23:b8:10:0a:f9:58:a4:d4:61:70:bd:04:61:6a: + 12:8a:17:d5:0a:bd:c5:bc:30:7c:d6:e9:0c:25:8d:86:40:4f: + ec:cc:a3:7e:38:c6:37:11:4f:ed:dd:68:31:8e:4c:d2:b3:01: + 74:ee:be:75:5e:07:48:1a:7f:70:ff:16:5c:84:c0:79:85:b8: + 05:fd:7f:be:65:11:a3:0f:c0:02:b4:f8:52:37:39:04:d5:a9: + 31:7a:18:bf:a0:2a:f4:12:99:f7:a3:45:82:e3:3c:5e:f5:9d: + 9e:b5:c8:9e:7c:2e:c8:a4:9e:4e:08:14:4b:6d:fd:70:6d:6b: + 1a:63:bd:64:e6:1f:b7:ce:f0:f2:9f:2e:bb:1b:b7:f2:50:88: + 73:92:c2:e2:e3:16:8d:9a:32:02:ab:8e:18:dd:e9:10:11:ee: + 7e:35:ab:90:af:3e:30:94:7a:d0:33:3d:a7:65:0f:f5:fc:8e: + 9e:62:cf:47:44:2c:01:5d:bb:1d:b5:32:d2:47:d2:38:2e:d0: + fe:81:dc:32:6a:1e:b5:ee:3c:d5:fc:e7:81:1d:19:c3:24:42: + ea:63:39:a9 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- diff --git a/global-functions b/global-functions index 32ef6ba..b6748f6 100644 --- a/global-functions +++ b/global-functions @@ -372,7 +372,7 @@ :global LogPrintExit; :do { - :if ([ $CertificateAvailable "R3" ] = false) do={ + :if ([ $CertificateAvailable "Cloudflare Inc ECC CA-3" ] = false) do={ $LogPrintExit warning ("Downloading required certificate failed.") true; } :local Vendor ([ / tool fetch check-certificate=yes-without-crl \ From f46db918453dcb8878b9a0de6e122fb0ea2224d9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 22 Feb 2021 15:14:10 +0100 Subject: [PATCH 0623/2612] global: give script or function name in log messages --- accesslist-duplicates.capsman | 1 + accesslist-duplicates.local | 1 + accesslist-duplicates.template | 1 + bridge-port-to-default | 11 +-- bridge-port-toggle | 1 + capsman-download-packages | 9 ++- capsman-rolling-upgrade | 5 +- certificate-renew-issued | 9 ++- check-certificates | 25 ++++--- check-health | 7 +- check-lte-firmware-upgrade | 7 +- check-routeros-update | 21 +++--- cloud-backup | 5 +- collect-wireless-mac.capsman | 9 ++- collect-wireless-mac.local | 9 ++- collect-wireless-mac.template | 9 ++- daily-psk.capsman | 7 +- daily-psk.local | 7 +- daily-psk.template | 7 +- dhcp-lease-comment.capsman | 5 +- dhcp-lease-comment.local | 5 +- dhcp-lease-comment.template | 5 +- dhcp-to-dns | 15 ++-- early-errors | 4 +- email-backup | 7 +- global-functions | 130 ++++++++++++++++++--------------- global-wait | 4 +- gps-track | 7 +- hotspot-to-wpa | 7 +- ipv6-update | 5 +- lease-script | 5 +- log-forward | 5 +- mode-button | 13 ++-- mode-button-event | 4 +- mode-button-scheduler | 4 +- netwatch-notify | 11 +-- ospf-to-leds | 5 +- packages-update | 27 +++---- ppp-on-up | 5 +- rotate-ntp | 9 ++- script-updates | 4 +- sms-action | 5 +- sms-forward | 7 +- update-gre-address | 5 +- update-tunnelbroker | 11 +-- upload-backup | 9 ++- 46 files changed, 262 insertions(+), 212 deletions(-) diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman index 54271c3..5fcf6ae 100644 --- a/accesslist-duplicates.capsman +++ b/accesslist-duplicates.capsman @@ -8,6 +8,7 @@ # # !! Do not edit this file, it is generated from template! +:local 0 "accesslist-duplicates.capsman"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local index 3f783a4..4d058d4 100644 --- a/accesslist-duplicates.local +++ b/accesslist-duplicates.local @@ -8,6 +8,7 @@ # # !! Do not edit this file, it is generated from template! +:local 0 "accesslist-duplicates.local"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template index c14b630..8878bcc 100644 --- a/accesslist-duplicates.template +++ b/accesslist-duplicates.template @@ -9,6 +9,7 @@ # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! +:local 0 "accesslist-duplicates%TEMPL%"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/bridge-port-to-default b/bridge-port-to-default index 60e3112..b8503df 100644 --- a/bridge-port-to-default +++ b/bridge-port-to-default @@ -6,13 +6,14 @@ # reset bridge ports to default bridge # https://git.eworm.de/cgit/routeros-scripts/about/doc/bridge-port.md +:local 0 "bridge-port-to-default"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global BridgePortTo; :global IfThenElse; -:global LogPrintExit; +:global LogPrintExit2; :global ParseKeyValueStore; :foreach BridgePort in=[ / interface bridge port find where !(comment=[]) ] do={ @@ -23,19 +24,19 @@ :if ($BridgeDefault = "dhcp-client") do={ :if ([ :len $DHCPClient ] != 1) do={ - $LogPrintExit warning ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ + $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; } :local DHCPClientDisabled [ / ip dhcp-client get $DHCPClient disabled ]; :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ - $LogPrintExit info ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; + $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; / interface bridge port disable $BridgePort; / ip dhcp-client enable $DHCPClient; } } else={ :if ($BridgePortVal->"disabled" = true || $BridgeDefault != $BridgePortVal->"bridge") do={ - $LogPrintExit info ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ + $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ " bridge " . $BridgeDefault . ", disabling dhcp client.") false; :if ([ :len $DHCPClient ] = 1) do={ / ip dhcp-client disable $DHCPClient; @@ -43,7 +44,7 @@ } / interface bridge port set disabled=no bridge=$BridgeDefault $BridgePort; } else={ - $LogPrintExit debug ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ + $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ " bridge " . $BridgeDefault . ".") false; } } diff --git a/bridge-port-toggle b/bridge-port-toggle index 9ad38cb..9eeab35 100644 --- a/bridge-port-toggle +++ b/bridge-port-toggle @@ -6,6 +6,7 @@ # toggle bridge ports between default and alt bridge # https://git.eworm.de/cgit/routeros-scripts/about/doc/bridge-port.md +:local 0 "bridge-port-toggle"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/capsman-download-packages b/capsman-download-packages index a9ef529..37e2658 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -7,12 +7,13 @@ # download and cleanup packages for CAP installation from CAPsMAN # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md +:local 0 "capsman-download-packages"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global CleanFilePath; :global DownloadPackage; -:global LogPrintExit; +:global LogPrintExit2; :global MkDir; :global ScriptLock; :global WaitFullyConnected; @@ -25,15 +26,15 @@ $WaitFullyConnected; :local Updated false; :if ([ :len $PackagePath ] = 0) do={ - $LogPrintExit warning ("The CAPsMAN package path is not defined, can not download packages.") true; + $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={ - $LogPrintExit warning ("Creating directory at CAPsMAN package path (" . \ + $LogPrintExit2 warning $0 ("Creating directory at CAPsMAN package path (" . \ $PackagePath . ") failed!") true; } - $LogPrintExit info ("Created directory at CAPsMAN package path (" . $PackagePath . \ + $LogPrintExit2 info $0 ("Created directory at CAPsMAN package path (" . $PackagePath . \ "). Please place your packages!") false; } diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index a765fb5..fe4410a 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -7,10 +7,11 @@ # upgrade CAPs one after another # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md +:local 0 "capsman-rolling-upgrade"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit; +:global LogPrintExit2; :global ScriptLock; $ScriptLock "capsman-rolling-upgrade"; @@ -23,7 +24,7 @@ $ScriptLock "capsman-rolling-upgrade"; :if ($Delay > 120) do={ :set Delay 120; } :foreach RemoteCap in=[ / caps-man remote-cap find where version!=$InstalledVersion ] do={ :local RemoteCapVal [ / caps-man remote-cap get $RemoteCap ]; - $LogPrintExit info ("Starting upgrade for " . $RemoteCapVal->"name" . \ + $LogPrintExit2 info $0 ("Starting upgrade for " . $RemoteCapVal->"name" . \ " (" . $RemoteCapVal->"identity" . ")...") false; / caps-man remote-cap upgrade [ find where name=$RemoteCapVal->"name" ]; :delay ($Delay . "s"); diff --git a/certificate-renew-issued b/certificate-renew-issued index 2345f30..c8ce4ae 100644 --- a/certificate-renew-issued +++ b/certificate-renew-issued @@ -6,12 +6,13 @@ # renew locally issued certificates # https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md +:local 0 "certificate-renew-issued"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global CertIssuedExportPass; -:global LogPrintExit; +:global LogPrintExit2; :global MkDir; :foreach Cert in=[ / certificate find where issued expires-after<3w ] do={ @@ -26,12 +27,12 @@ / certificate export-certificate ($CertVal->"name") type=pkcs12 \ file-name=("cert-issued/" . $CertVal->"common-name") \ export-passphrase=($CertIssuedExportPass->($CertVal->"common-name")); - $LogPrintExit info ("Issued a new certificate for \"" . $CertVal->"common-name" . \ + $LogPrintExit2 info $0 ("Issued a new certificate for \"" . $CertVal->"common-name" . \ "\", exported to \"cert-issued/" . $CertVal->"common-name" . ".p12\".") false; } else={ - $LogPrintExit warning ("Failed creating directory, not exporting certificate.") false; + $LogPrintExit2 warning $0 ("Failed creating directory, not exporting certificate.") false; } } else={ - $LogPrintExit info ("Issued a new certificate for \"" . $CertVal->"common-name" . "\".") false; + $LogPrintExit2 info $0 ("Issued a new certificate for \"" . $CertVal->"common-name" . "\".") false; } } diff --git a/check-certificates b/check-certificates index 94ccc99..5946a86 100644 --- a/check-certificates +++ b/check-certificates @@ -6,6 +6,7 @@ # check for certificate validity # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md +:local 0 "check-certificates"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } @@ -17,7 +18,7 @@ :global CertificateAvailable :global CertificateNameByCN; :global IfThenElse; -:global LogPrintExit; +:global LogPrintExit2; :global ParseKeyValueStore; :global SendNotification; :global SymbolForNotification; @@ -37,7 +38,7 @@ $WaitFullyConnected; :do { :if ([ :len $CertRenewUrl ] = 0) do={ - $LogPrintExit info ("No CertRenewUrl given.") true; + $LogPrintExit2 info $0 ("No CertRenewUrl given.") true; } :foreach Type in={ ".pem"; ".p12" } do={ @@ -55,7 +56,7 @@ $WaitFullyConnected; $CertificateNameByCN [ / certificate get $CertInChain common-name ]; } } on-error={ - $LogPrintExit debug ("Could not download certificate file " . $CertFileName) false; + $LogPrintExit2 debug $0 ("Could not download certificate file " . $CertFileName) false; } } @@ -63,15 +64,15 @@ $WaitFullyConnected; :local CertNewVal [ / certificate get $CertNew ]; :if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") ] = false) do={ - $LogPrintExit warning ("The certificate chain is not available!") false; + $LogPrintExit2 warning $0 ("The certificate chain is not available!") false; } :if ($Cert != $CertNew) do={ - $LogPrintExit debug ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; + $LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; :if (($CertVal->"private-key") = true && ($CertVal->"private-key") != ($CertNewVal->"private-key")) do={ / certificate remove $CertNew; - $LogPrintExit warning ("Old certificate '" . ($CertVal->"name") . "' has a private key, new certificate does not. Aborting renew.") true; + $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") ]; @@ -80,13 +81,13 @@ $WaitFullyConnected; / ip ipsec identity set certificate=($CertNewVal->"name") [ / ip ipsec identity find where certificate=($CertVal->"name") ]; / ip ipsec identity set remote-certificate=($CertNewVal->"name") [ / ip ipsec identity find where remote-certificate=($CertVal->"name") ]; } on-error={ - $LogPrintExit debug ("Setting IPSEC certificates failed. Package 'security' not installed?") false; + $LogPrintExit2 debug $0 ("Setting IPSEC certificates failed. Package 'security' not installed?") false; } :do { / ip hotspot profile set ssl-certificate=($CertNewVal->"name") [ / ip hotspot profile find where ssl-certificate=($CertVal->"name") ]; } on-error={ - $LogPrintExit debug ("Setting hotspot certificates failed. Package 'hotspot' not installed?") false; + $LogPrintExit2 debug $0 ("Setting hotspot certificates failed. Package 'hotspot' not installed?") false; } / certificate remove $Cert; @@ -102,9 +103,9 @@ $WaitFullyConnected; "Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]) "" "true"; - $LogPrintExit info ("The certificate " . ($CertVal->"name") . " has been renewed.") false; + $LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " has been renewed.") false; } on-error={ - $LogPrintExit debug ("Could not renew certificate " . ($CertVal->"name") . ".") false; + $LogPrintExit2 debug $0 ("Could not renew certificate " . ($CertVal->"name") . ".") false; } } @@ -112,7 +113,7 @@ $WaitFullyConnected; :local CertVal [ / certificate get $Cert ]; :if ([ :len [ / certificate scep-server find where ca-cert=($CertVal->"ca") ] ] > 0) do={ - $LogPrintExit debug ("Certificate \"" . ($CertVal->"name") . "\" is handled by SCEP, skipping.") false; + $LogPrintExit2 debug $0 ("Certificate \"" . ($CertVal->"name") . "\" is handled by SCEP, skipping.") false; } else={ :local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ]; @@ -125,7 +126,7 @@ $WaitFullyConnected; "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ "Expires in: " . [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ]); - $LogPrintExit info ("The certificate " . ($CertVal->"name") . " " . $State . \ + $LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " " . $State . \ ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; } } diff --git a/check-health b/check-health index 8cb2cf3..761a72f 100644 --- a/check-health +++ b/check-health @@ -6,6 +6,7 @@ # check for RouterOS health state # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md +:local 0 "check-health"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } @@ -16,7 +17,7 @@ :global CheckHealthVoltagePercent; :global Identity; -:global LogPrintExit; +:global LogPrintExit2; :global SendNotification; :global SymbolForNotification; @@ -28,7 +29,7 @@ :local CheckHealthCurrent [ / system health get ]; :if ([ :len $CheckHealthCurrent ] = 0) do={ - $LogPrintExit error ("Your device does not provide any health values.") true; + $LogPrintExit2 error $0 ("Your device does not provide any health values.") true; } :if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ @@ -70,7 +71,7 @@ :if ($Name ~ "temperature" && \ [ :typeof $Temperature ] = "num") do={ :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ - $LogPrintExit info ("No threshold given for " . $Name . ", assuming 50C.") false; + $LogPrintExit2 info $0 ("No threshold given for " . $Name . ", assuming 50C.") false; :set ($CheckHealthTemperature->$Name) 50; } :local Validate [ / system health get $Name ]; diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index ed3cb98..f55ec5f 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -6,6 +6,7 @@ # check for LTE firmware upgrade, send notification # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md +:local 0 "check-lte-firmware-upgrade"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } @@ -13,7 +14,7 @@ :global SentLteFirmwareUpgradeNotification; :global CharacterReplace; -:global LogPrintExit; +:global LogPrintExit2; :global SendNotification; :global SymbolForNotification; @@ -23,7 +24,7 @@ :local Firmware [ / interface lte firmware-upgrade $Interface once as-value ]; :if ($SentLteFirmwareUpgradeNotification = ($Firmware->"latest")) do={ - $LogPrintExit debug ("Already sent the LTE firmware upgrade notification for version " . \ + $LogPrintExit2 debug $0 ("Already sent the LTE firmware upgrade notification for version " . \ ($Firmware->"latest") . ".") false; } else={ :if (($Firmware->"installed") != ($Firmware->"latest")) do={ @@ -38,7 +39,7 @@ } } } on-error={ - $LogPrintExit debug ("Could not get latest LTE firmware version for interface " . \ + $LogPrintExit2 debug $0 ("Could not get latest LTE firmware version for interface " . \ $IntName . ".") false; } } diff --git a/check-routeros-update b/check-routeros-update index c641e04..fe87d9c 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -6,6 +6,7 @@ # check for RouterOS update, send notification and/or install # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md +:local 0 "check-routeros-update"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } @@ -16,7 +17,7 @@ :global SentRouterosUpdateNotification; :global DeviceInfo; -:global LogPrintExit; +:global LogPrintExit2; :global ScriptFromTerminal; :global SendNotification; :global SymbolForNotification; @@ -37,7 +38,7 @@ $WaitFullyConnected; :if ([ :len [ / system package find where name="wireless" disabled=no ] ] > 0) do={ :if ([ / interface wireless cap get enabled ] = true && \ [ / caps-man manager get enabled ] = false) do={ - $LogPrintExit error "System is managed by CAPsMAN, not checking for RouterOS version." true; + $LogPrintExit2 error $0 ("System is managed by CAPsMAN, not checking for RouterOS version.") true; } } @@ -49,7 +50,7 @@ $WaitFullyConnected; :local Update [ / system package update get ]; :if ([ :len ($Update->"latest-version") ] = 0) do={ - $LogPrintExit info "An empty string is not a valid version." true; + $LogPrintExit2 info $0 ("An empty string is not a valid version.") true; } :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; @@ -58,7 +59,7 @@ $WaitFullyConnected; :if ($NumInstalled < $NumLatest) do={ :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ - $LogPrintExit info ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; + $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ ("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ ", updating on " . $Identity . "...") $Link "true"; @@ -67,7 +68,7 @@ $WaitFullyConnected; :if ($SafeUpdateNeighbor = true && [ :len [ / ip neighbor find where \ version=($Update->"latest-version" . " (" . $Update->"channel" . ")") ] ] > 0) do={ - $LogPrintExit info ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; + $LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ ("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \ ", updating on " . $Identity . "...") $Link "true"; @@ -81,10 +82,10 @@ $WaitFullyConnected; ($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \ "&latest=" . $Update->"latest-version") output=user as-value ]; } on-error={ - $LogPrintExit warning ("Failed receiving safe version for " . $Update->"channel" . ".") false; + $LogPrintExit2 warning $0 ("Failed receiving safe version for " . $Update->"channel" . ".") false; } :if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={ - $LogPrintExit info ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; + $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ ("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ ", updating on " . $Identity . "...") $Link "true"; @@ -102,7 +103,7 @@ $WaitFullyConnected; } :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ - $LogPrintExit info ("Already sent the RouterOS update notification for version " . \ + $LogPrintExit2 info $0 ("Already sent the RouterOS update notification for version " . \ $Update->"latest-version" . ".") true; } @@ -115,7 +116,7 @@ $WaitFullyConnected; :if ($NumInstalled > $NumLatest) do={ :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ - $LogPrintExit info ("Already sent the RouterOS downgrade notification for version " . \ + $LogPrintExit2 info $0 ("Already sent the RouterOS downgrade notification for version " . \ $Update->"latest-version" . ".") true; } @@ -123,7 +124,7 @@ $WaitFullyConnected; ("A different RouterOS version " . ($Update->"latest-version") . \ " is available for " . $Identity . ", but it is a downgrade.\n\n" . \ [ $DeviceInfo ]) $Link "true"; - $LogPrintExit info ("A different RouterOS version " . ($Update->"latest-version") . \ + $LogPrintExit2 info $0 ("A different RouterOS version " . ($Update->"latest-version") . \ " is available for downgrade.") false; :set SentRouterosUpdateNotification ($Update->"latest-version"); } diff --git a/cloud-backup b/cloud-backup index e4e527b..598a500 100644 --- a/cloud-backup +++ b/cloud-backup @@ -6,6 +6,7 @@ # upload backup to MikroTik cloud # https://git.eworm.de/cgit/routeros-scripts/about/doc/cloud-backup.md +:local 0 "cloud-backup"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } @@ -13,7 +14,7 @@ :global Identity; :global DeviceInfo; -:global LogPrintExit; +:global LogPrintExit2; :global SendNotification; :global SymbolForNotification; :global WaitFullyConnected; @@ -42,5 +43,5 @@ $WaitFullyConnected; } on-error={ $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Cloud backup failed") \ ("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]); - $LogPrintExit error ("Failed uploading backup for " . $Identity . " to cloud!") true; + $LogPrintExit2 error $0 ("Failed uploading backup for " . $Identity . " to cloud!") true; } diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index bf8e691..248a14d 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -8,13 +8,14 @@ # # !! Do not edit this file, it is generated from template! +:local 0 "collect-wireless-mac.capsman"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global Identity; :global GetMacVendor; -:global LogPrintExit; +:global LogPrintExit2; :global ScriptLock; :global SendNotification; :global SymbolForNotification; @@ -23,7 +24,7 @@ $ScriptLock "collect-wireless-mac.capsman"; :if ([ :len [ / caps-man access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ / caps-man access-list add comment="--- collected above ---" disabled=yes; - $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; + $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); @@ -53,7 +54,7 @@ $ScriptLock "collect-wireless-mac.capsman"; :local Vendor [ $GetMacVendor $Mac ]; :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \ "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); - $LogPrintExit info $Message false; + $LogPrintExit2 info $0 $Message false; / caps-man access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; $SendNotification ([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid) \ ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ @@ -67,7 +68,7 @@ $ScriptLock "collect-wireless-mac.capsman"; "DNS name: " . $DnsName . "\n" . \ "Date: " . $DateTime); } else={ - $LogPrintExit debug ("MAC address " . $Mac . " already known: " . \ + $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ [ / caps-man access-list get $AccessList comment ]) false; } } diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 15c0c9a..20a5f83 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -8,13 +8,14 @@ # # !! Do not edit this file, it is generated from template! +:local 0 "collect-wireless-mac.local"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global Identity; :global GetMacVendor; -:global LogPrintExit; +:global LogPrintExit2; :global ScriptLock; :global SendNotification; :global SymbolForNotification; @@ -23,7 +24,7 @@ $ScriptLock "collect-wireless-mac.local"; :if ([ :len [ / interface wireless access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ / interface wireless access-list add comment="--- collected above ---" disabled=yes; - $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; + $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); @@ -53,7 +54,7 @@ $ScriptLock "collect-wireless-mac.local"; :local Vendor [ $GetMacVendor $Mac ]; :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \ "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); - $LogPrintExit info $Message false; + $LogPrintExit2 info $0 $Message false; / interface wireless access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; $SendNotification ([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid) \ ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ @@ -67,7 +68,7 @@ $ScriptLock "collect-wireless-mac.local"; "DNS name: " . $DnsName . "\n" . \ "Date: " . $DateTime); } else={ - $LogPrintExit debug ("MAC address " . $Mac . " already known: " . \ + $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ [ / interface wireless access-list get $AccessList comment ]) false; } } diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 2198136..fe84287 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -9,13 +9,14 @@ # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! +:local 0 "collect-wireless-mac%TEMPL%"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global Identity; :global GetMacVendor; -:global LogPrintExit; +:global LogPrintExit2; :global ScriptLock; :global SendNotification; :global SymbolForNotification; @@ -24,7 +25,7 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; :if ([ :len [ / %PATH% access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ / %PATH% access-list add comment="--- collected above ---" disabled=yes; - $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; + $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false; } :local PlaceBefore ([ / %PATH% access-list find where comment="--- collected above ---" disabled ]->0); @@ -55,7 +56,7 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; :local Vendor [ $GetMacVendor $Mac ]; :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \ "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); - $LogPrintExit info $Message false; + $LogPrintExit2 info $0 $Message false; / %PATH% access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; $SendNotification ([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid) \ ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ @@ -69,7 +70,7 @@ $ScriptLock "collect-wireless-mac%TEMPL%"; "DNS name: " . $DnsName . "\n" . \ "Date: " . $DateTime); } else={ - $LogPrintExit debug ("MAC address " . $Mac . " already known: " . \ + $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ [ / %PATH% access-list get $AccessList comment ]) false; } } diff --git a/daily-psk.capsman b/daily-psk.capsman index b66b750..7d2c2ae 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -9,13 +9,14 @@ # # !! Do not edit this file, it is generated from template! +:local 0 "daily-psk.capsman"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global DailyPskMatchComment; :global Identity; -:global LogPrintExit; +:global LogPrintExit2; :global SendNotification; :global SymbolForNotification; :global UrlEncode; @@ -65,13 +66,13 @@ $WaitFullyConnected; :local Skip 0; :if ($NewPsk != $OldPsk) do={ - $LogPrintExit info ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; / caps-man access-list set $AccList private-passphrase=$NewPsk; :if ([ :len [ / caps-man interface find where configuration=$Configuration ] ] > 0) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ - $LogPrintExit debug ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; + $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; :set Skip 1; } } diff --git a/daily-psk.local b/daily-psk.local index e7f908f..6186ddc 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -9,13 +9,14 @@ # # !! Do not edit this file, it is generated from template! +:local 0 "daily-psk.local"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global DailyPskMatchComment; :global Identity; -:global LogPrintExit; +:global LogPrintExit2; :global SendNotification; :global SymbolForNotification; :global UrlEncode; @@ -65,13 +66,13 @@ $WaitFullyConnected; :local Skip 0; :if ($NewPsk != $OldPsk) do={ - $LogPrintExit info ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; / interface wireless access-list set $AccList private-pre-shared-key=$NewPsk; :if ([ :len [ / interface wireless find where name=$IntName disabled=no ] ] = 1) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ - $LogPrintExit debug ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; + $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; :set Skip 1; } } diff --git a/daily-psk.template b/daily-psk.template index 8cf08e0..42abba5 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -10,13 +10,14 @@ # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! +:local 0 "daily-psk%TEMPL%"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global DailyPskMatchComment; :global Identity; -:global LogPrintExit; +:global LogPrintExit2; :global SendNotification; :global SymbolForNotification; :global UrlEncode; @@ -69,7 +70,7 @@ $WaitFullyConnected; :local Skip 0; :if ($NewPsk != $OldPsk) do={ - $LogPrintExit info ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; / interface wireless access-list set $AccList private-pre-shared-key=$NewPsk; / caps-man access-list set $AccList private-passphrase=$NewPsk; @@ -77,7 +78,7 @@ $WaitFullyConnected; :if ([ :len [ / caps-man interface find where configuration=$Configuration ] ] > 0) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ - $LogPrintExit debug ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; + $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; :set Skip 1; } } diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index 3c0b9e9..96b1741 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -8,10 +8,11 @@ # # !! Do not edit this file, it is generated from template! +:local 0 "dhcp-lease-comment.capsman"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit; +:global LogPrintExit2; :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ :local LeaseVal [ / ip dhcp-server lease get $Lease ]; @@ -21,7 +22,7 @@ :set NewComment [ / caps-man access-list get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; + $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; / ip dhcp-server lease set comment=$NewComment $Lease; } } diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index dc2f708..74de2c8 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -8,10 +8,11 @@ # # !! Do not edit this file, it is generated from template! +:local 0 "dhcp-lease-comment.local"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit; +:global LogPrintExit2; :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ :local LeaseVal [ / ip dhcp-server lease get $Lease ]; @@ -21,7 +22,7 @@ :set NewComment [ / interface wireless access-list get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; + $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; / ip dhcp-server lease set comment=$NewComment $Lease; } } diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index e3ca6d0..0e31007 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -9,10 +9,11 @@ # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! +:local 0 "dhcp-lease-comment%TEMPL%"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit; +:global LogPrintExit2; :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ :local LeaseVal [ / ip dhcp-server lease get $Lease ]; @@ -22,7 +23,7 @@ :set NewComment [ / %PATH% access-list get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; + $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; / ip dhcp-server lease set comment=$NewComment $Lease; } } diff --git a/dhcp-to-dns b/dhcp-to-dns index 30ca63c..dfb438f 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -6,6 +6,7 @@ # check DHCP leases and add/remove/update DNS entries # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md +:local 0 "dhcp-to-dns"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } @@ -17,7 +18,7 @@ :global CharacterReplace; :global IfThenElse; -:global LogPrintExit; +:global LogPrintExit2; :local Zone \ ([ $IfThenElse ($PrefixInZone = true) "dhcp." ] . \ @@ -27,7 +28,7 @@ :if ([ :len [ / ip dns static find where comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled ] ] = 0) do={ / ip dns static add comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled=yes; - $LogPrintExit warning "Added disabled static dns record with comment '--- dhcp-to-dns above ---'." false; + $LogPrintExit2 warning $0 ("Added disabled static dns record with comment '--- dhcp-to-dns above ---'.") false; } :local PlaceBefore ([ / ip dns static find where comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled ]->0); @@ -35,10 +36,10 @@ :local DnsRecordVal [ / ip dns static get $DnsRecord ]; :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; :if ([ :len [ / ip dhcp-server lease find where mac-address=$MacAddress address=($DnsRecordVal->"address") status=bound ] ] > 0) do={ - $LogPrintExit debug ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; + $LogPrintExit2 debug $0 ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; } else={ :local Found false; - $LogPrintExit info ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry.") false; + $LogPrintExit2 info $0 ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry.") false; / ip dns static remove $DnsRecord; } } @@ -65,13 +66,13 @@ } :if ($DnsIp = $LeaseVal->"address") do={ - $LogPrintExit debug ("DNS entry for " . $Fqdn . " does not need updating.") false; + $LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false; } else={ - $LogPrintExit info ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . ".") false; + $LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . ".") false; / ip dns static set name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; } } else={ - $LogPrintExit info ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false; + $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false; / ip dns static add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } diff --git a/early-errors b/early-errors index e6160e8..7c2e509 100644 --- a/early-errors +++ b/early-errors @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: early-errors -:global LogPrintExit; +:global LogPrintExit2; -$LogPrintExit warning ("This script has been replaced. Please migrate to 'log-forward'.") true; +$LogPrintExit2 warning "early-errors" ("This script has been replaced. Please migrate to 'log-forward'.") true; diff --git a/email-backup b/email-backup index 7cd8222..129075a 100644 --- a/email-backup +++ b/email-backup @@ -6,6 +6,7 @@ # create and email backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/email-backup.md +:local 0 "email-backup"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } @@ -19,7 +20,7 @@ :global CharacterReplace; :global DeviceInfo; -:global LogPrintExit; +:global LogPrintExit2; :global WaitForFile; :global WaitFullyConnected; @@ -27,11 +28,11 @@ $WaitFullyConnected; :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ - $LogPrintExit error ("Configured to send neither backup nor config export.") true; + $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; } :if ([ :len $EmailBackupTo ] = 0) do={ - $LogPrintExit error ("Configuration is missing recipient for e-mail backup.") true; + $LogPrintExit2 error $0 ("Configuration is missing recipient for e-mail backup.") true; } # filename based on identity diff --git a/global-functions b/global-functions index b6748f6..e958d74 100644 --- a/global-functions +++ b/global-functions @@ -32,6 +32,7 @@ :global IfThenElse; :global IPCalc; :global LogPrintExit; +:global LogPrintExit2; :global MkDir; :global ParseKeyValueStore; :global RandomDelay; @@ -58,19 +59,19 @@ :local CommonName [ :tostr $1 ]; :global CertificateDownload; - :global LogPrintExit; + :global LogPrintExit2; :global ParseKeyValueStore; :global RequiredRouterOS; :if ([ / system resource get free-hdd-space ] < 8388608 && \ [ / certificate settings get crl-download ] = true && \ [ / certificate settings get crl-store ] = "system") do={ - $LogPrintExit warning ("This system has low free flash space but " . \ + $LogPrintExit2 warning $0 ("This system has low free flash space but " . \ "is configured to download certificate CRLs to system!") false; } :if ([ :len [ / certificate find where common-name=$CommonName ] ] = 0) do={ - $LogPrintExit info ("Certificate with CommonName \"" . $CommonName . "\" not available.") false; + $LogPrintExit2 info $0 ("Certificate with CommonName \"" . $CommonName . "\" not available.") false; :if ([ $CertificateDownload $CommonName ] = false) do={ :return false; } @@ -83,7 +84,7 @@ :local CertVal [ / certificate get [ find where common-name=$CommonName ] ]; :do { :if ([ :len [ / certificate find where skid=($CertVal->"akid") ] ] = 0) do={ - $LogPrintExit info ("Certificate chain for \"" . $CommonName . \ + $LogPrintExit2 info $0 ("Certificate chain for \"" . $CommonName . \ "\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\".") false; :if ([ $CertificateDownload $CommonName ] = false) do={ :return false; @@ -102,11 +103,11 @@ :global ScriptUpdatesUrlSuffix; :global CertificateNameByCN; - :global LogPrintExit; + :global LogPrintExit2; :global UrlEncode; :global WaitForFile; - $LogPrintExit info ("Downloading and importing certificate with " . \ + $LogPrintExit2 info $0 ("Downloading and importing certificate with " . \ "CommonName \"" . $CommonName . "\".") false; :do { :local LocalFileName ($CommonName . ".pem"); @@ -123,7 +124,7 @@ $CertificateNameByCN [ / certificate get $Cert common-name ]; } } on-error={ - $LogPrintExit warning ("Failed importing certificate with " . \ + $LogPrintExit2 warning $0 ("Failed importing certificate with " . \ "CommonName \"" . $CommonName . "\"!") false; :return false; } @@ -242,7 +243,7 @@ :global CertificateAvailable; :global CleanFilePath; - :global LogPrintExit; + :global LogPrintExit2; :global WaitForFile; :if ([ :len $PkgName ] = 0) do={ :return false; } @@ -256,12 +257,12 @@ :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; :if ([ :len [ / file find where name=$PkgDest type="package" ] ] > 0) do={ - $LogPrintExit info ("Package file alreasy exists.") false; + $LogPrintExit2 info $0 ("Package file alreasy exists.") false; :return true; } :if ([ $CertificateAvailable "R3" ] = false) do={ - $LogPrintExit error ("Downloading required certificate failed.") true; + $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; } :local Retry 3; @@ -276,7 +277,7 @@ :return true; } } on-error={ - $LogPrintExit debug ("Downloading package failed.") false; + $LogPrintExit2 debug $0 ("Downloading package failed.") false; } / file remove [ find where name=$PkgDest ]; @@ -290,13 +291,13 @@ :set FlushEmailQueue do={ :global EmailQueue; - :global LogPrintExit; + :global LogPrintExit2; :local AllDone true; :local QueueLen [ :len $EmailQueue ]; :if ([ :len [ / system scheduler find where name="FlushEmailQueue" ] ] > 0 && $QueueLen = 0) do={ - $LogPrintExit warning ("Flushing E-Mail messages from scheduler, but queue is empty.") false; + $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; } / system scheduler set interval=1m [ find where name="FlushEmailQueue" interval=1s ]; @@ -332,13 +333,13 @@ :global TelegramQueue; :global TelegramTokenId; - :global LogPrintExit; + :global LogPrintExit2; :local AllDone true; :local QueueLen [ :len $TelegramQueue ]; :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] > 0 && $QueueLen = 0) do={ - $LogPrintExit warning ("Flushing Telegram messages from scheduler, but queue is empty.") false; + $LogPrintExit2 warning $0 ("Flushing Telegram messages from scheduler, but queue is empty.") false; } :foreach Id,Message in=$TelegramQueue do={ @@ -352,7 +353,7 @@ "&text=" . ($Message->"text")); :set ($TelegramQueue->$Id); } on-error={ - $LogPrintExit debug ("Sending queued Telegram message failed.") false; + $LogPrintExit2 debug $0 ("Sending queued Telegram message failed.") false; :set AllDone false; } } @@ -369,11 +370,11 @@ :local Mac [ :tostr $1 ]; :global CertificateAvailable; - :global LogPrintExit; + :global LogPrintExit2; :do { :if ([ $CertificateAvailable "Cloudflare Inc ECC CA-3" ] = false) do={ - $LogPrintExit warning ("Downloading required certificate failed.") true; + $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; } :local Vendor ([ / tool fetch check-certificate=yes-without-crl \ ("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data"); @@ -449,11 +450,19 @@ :return $Return; } -# log and print with same text, optionally exit +# deprecated compatibility wrapper :set LogPrintExit do={ + :global LogPrintExit2; + + $LogPrintExit2 $1 "unknown" $2 $3; +} + +# log and print with same text, optionally exit +:set LogPrintExit2 do={ :local Severity [ :tostr $1 ]; - :local Message [ :tostr $2 ]; - :local Exit [ :tostr $3 ]; + :local Name [ :tostr $2 ]; + :local Message [ :tostr $3 ]; + :local Exit [ :tostr $4 ]; :global PrintDebug; @@ -468,12 +477,13 @@ :return ("\1B[" . $Color->$1 . "m" . $1 . "\1B[0m"); } + :local Log ($Name . ": " . $Message); :if ($Severity ~ "^(debug|error|info)\$") do={ - :if ($Severity = "debug") do={ :log debug $Message; } - :if ($Severity = "error") do={ :log error $Message; } - :if ($Severity = "info" ) do={ :log info $Message; } + :if ($Severity = "debug") do={ :log debug $Log; } + :if ($Severity = "error") do={ :log error $Log; } + :if ($Severity = "info" ) do={ :log info $Log; } } else={ - :log warning $Message; + :log warning $Log; :set Severity "warning"; } @@ -545,11 +555,11 @@ :local Required [ :tostr $2 ]; :global IfThenElse; - :global LogPrintExit; + :global LogPrintExit2; :global VersionToNum; :if ([ $VersionToNum $Required ] > [ $VersionToNum [ / system package update get installed-version ] ]) do={ - $LogPrintExit warning ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = "\$") "function" "script" ] . \ + $LogPrintExit2 warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = "\$") "function" "script" ] . \ " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!") false; :return false; } @@ -560,7 +570,7 @@ :set ScriptFromTerminal do={ :local Script [ :tostr $1 ]; - :global LogPrintExit; + :global LogPrintExit2; :foreach Job in=[ / system script job find where script=$Script ] do={ :set Job [ / system script job get $Job ]; @@ -568,11 +578,11 @@ :set Job [ / system script job get [ find where .id=($Job->"parent") ] ]; } :if (($Job->"type") = "login") do={ - $LogPrintExit debug ("Script " . $Script . " started from terminal.") false; + $LogPrintExit2 debug $0 ("Script " . $Script . " started from terminal.") false; :return true; } } - $LogPrintExit debug ("Script " . $Script . " NOT started from terminal.") false; + $LogPrintExit2 debug $0 ("Script " . $Script . " NOT started from terminal.") false; :return false; } @@ -591,19 +601,19 @@ :global SentConfigChangesNotification; :global CertificateAvailable; - :global LogPrintExit; + :global LogPrintExit2; :global ParseKeyValueStore; :global ScriptInstallUpdate; :global SendNotification; :global SymbolForNotification; :if ([ $CertificateAvailable "R3" ] = false) do={ - $LogPrintExit warning ("Downloading certificate failed, trying without.") false; + $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; } :foreach Script in=$Scripts do={ :if ([ :len [ / system script find where name=$Script ] ] = 0) do={ - $LogPrintExit info ("Adding new script: " . $Script) false; + $LogPrintExit2 info $0 ("Adding new script: " . $Script) false; / system script add name=$Script source="#!rsc by RouterOS\n"; } } @@ -622,7 +632,7 @@ :foreach Scheduler in=[ / system scheduler find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ :local SchedulerVal [ / system scheduler get $Scheduler ]; :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ - $LogPrintExit warning ("Policies differ for script " . $ScriptVal->"name" . \ + $LogPrintExit2 warning $0 ("Policies differ for script " . $ScriptVal->"name" . \ " and its scheduler " . $SchedulerVal->"name" . "!") false; } } @@ -630,7 +640,7 @@ :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ :local Comment [ $ParseKeyValueStore ($ScriptVal->"comment") ]; :if (!($Comment->"ignore" = true)) do={ - $LogPrintExit debug ("Fetching script from url: " . $ScriptVal->"name") false; + $LogPrintExit2 debug $0 ("Fetching script from url: " . $ScriptVal->"name") false; :do { :local BaseUrl $ScriptUpdatesBaseUrl; :local UrlSuffix $ScriptUpdatesUrlSuffix; @@ -643,7 +653,7 @@ :set SourceNew ($Result->"data"); } } on-error={ - $LogPrintExit warning ("Failed fetching " . $ScriptVal->"name") false; + $LogPrintExit2 warning $0 ("Failed fetching " . $ScriptVal->"name") false; } } } @@ -653,34 +663,34 @@ :if ($SourceNew != $ScriptVal->"source") do={ :local DontRequirePermissions \ ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); - $LogPrintExit info ("Updating script: " . $ScriptVal->"name") false; + $LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; / system script set owner=($ScriptVal->"name") source=$SourceNew \ dont-require-permissions=$DontRequirePermissions $Script; :if ($ScriptVal->"name" = "global-config" && \ [ :len [ / system script find where name="global-config-overlay" ] ] > 0) do={ - $LogPrintExit info ("Reloading global configuration and overlay.") false; + $LogPrintExit2 info $0 ("Reloading global configuration and overlay.") false; :do { / system script { run global-config; run global-config-overlay; } } on-error={ - $LogPrintExit error ("Reloading global configuration and overlay failed! Syntax error\?") false; + $LogPrintExit2 error $0 ("Reloading global configuration and overlay failed! Syntax error\?") false; } } :if ($ScriptVal->"name" = "global-functions") do={ - $LogPrintExit info ("Reloading global functions.") false; + $LogPrintExit2 info $0 ("Reloading global functions.") false; :do { / system script run global-functions; } on-error={ - $LogPrintExit error ("Reloading global functions failed!") false; + $LogPrintExit2 error $0 ("Reloading global functions failed!") false; } } } else={ - $LogPrintExit debug ("Script " . $ScriptVal->"name" . " did not change.") false; + $LogPrintExit2 debug $0 ("Script " . $ScriptVal->"name" . " did not change.") false; } } else={ - $LogPrintExit warning ("Looks like new script " . $ScriptVal->"name" . " is not valid. Ignoring!") false; + $LogPrintExit2 warning $0 ("Looks like new script " . $ScriptVal->"name" . " is not valid. Ignoring!") false; } } else={ - $LogPrintExit debug ("No update for script " . $ScriptVal->"name" . ".") false; + $LogPrintExit2 debug $0 ("No update for script " . $ScriptVal->"name" . ".") false; } } @@ -697,9 +707,9 @@ " is out of date. Please update " . $ConfigScript . ", then increase " . \ "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \ ") to " . $ExpectedConfigVersion . " and re-run " . $ConfigScript . "."); - $LogPrintExit info ($NotificationMessage) false; + $LogPrintExit2 info $0 ($NotificationMessage) false; - $LogPrintExit debug ("Fetching changelog.") false; + $LogPrintExit2 debug $0 ("Fetching changelog.") false; :do { :local Result [ / tool fetch check-certificate=yes-without-crl \ ($ScriptUpdatesBaseUrl . "global-config.changes" . $ScriptUpdatesUrlSuffix) \ @@ -712,17 +722,17 @@ :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ :local Migration ($GlobalConfigMigration->[ :tostr $I ]); :if ([ :typeof $Migration ] = "str") do={ - $LogPrintExit info ("Applying migration: " . $Migration) false; + $LogPrintExit2 info $0 ("Applying migration: " . $Migration) false; [ :parse $Migration ]; } :set NotificationMessage ($NotificationMessage . \ "\n * " . $GlobalConfigChanges->[ :tostr $I ]); - $LogPrintExit info ("Change: " . $GlobalConfigChanges->[ :tostr $I ]) false; + $LogPrintExit2 info $0 ("Change: " . $GlobalConfigChanges->[ :tostr $I ]) false; } :set GlobalConfigChanges; :set GlobalConfigMigration; } on-error={ - $LogPrintExit warning ("Failed fetching changes!") false; + $LogPrintExit2 warning $0 ("Failed fetching changes!") false; :set NotificationMessage ($NotificationMessage . \ "\n\nChanges are not available."); } @@ -743,18 +753,18 @@ } :if ($ScriptInstallUpdateBefore != [ :tostr $ScriptInstallUpdate ]) do={ - $LogPrintExit info ("This function '\$ScriptInstallUpdate' changed, you may want to re-run.") false; + $LogPrintExit2 info $0 ("This function changed, you may want to re-run.") false; } } # lock script against multiple invocation :set ScriptLock do={ - :global LogPrintExit; + :global LogPrintExit2; :local Script [ :tostr $1 ]; :if ([ :len [ / system script job find where script=$Script ] ] > 1) do={ - $LogPrintExit info ("Script " . $Script . " started more than once... Aborting.") true; + $LogPrintExit2 info $0 ("Script " . $Script . " started more than once... Aborting.") true; } } @@ -769,7 +779,7 @@ :global EmailGeneralCc; :global EmailQueue; - :global LogPrintExit; + :global LogPrintExit2; :global IfThenElse; :if ([ :len $EmailGeneralTo ] = 0) do={ @@ -823,7 +833,7 @@ :global CertificateAvailable; :global CharacterReplace; :global IfThenElse; - :global LogPrintExit; + :global LogPrintExit2; :global SymbolForNotification; :global UrlEncode; @@ -886,14 +896,14 @@ :do { :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ - $LogPrintExit warning ("Downloading required certificate failed.") true; + $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; } / tool fetch check-certificate=yes-without-crl output=none http-method=post \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ http-data=("chat_id=" . $ChatId . "&disable_notification=" . $Silent . \ "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text); } on-error={ - $LogPrintExit info ("Failed sending telegram notification! Queuing...") false; + $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; :if ([ :typeof $TelegramQueue ] = "nothing") do={ :set TelegramQueue [ :toarray "" ]; @@ -950,7 +960,7 @@ # check if system time is sync :set TimeIsSync do={ - :global LogPrintExit; + :global LogPrintExit2; :if ([ / system ntp client get enabled ] = true) do={ :do { @@ -972,7 +982,7 @@ :return false; } - $LogPrintExit debug ("No time source configured! Returning gracefully...") false; + $LogPrintExit2 debug $0 ("No time source configured! Returning gracefully...") false; :return true; } @@ -1081,7 +1091,7 @@ # wait for time to become synced :set WaitTimeSync do={ - :global LogPrintExit; + :global LogPrintExit2; :global TimeIsSync; :while ([ $TimeIsSync ] = false) do={ @@ -1090,7 +1100,7 @@ :do { / system script run rotate-ntp; } on-error={ - $LogPrintExit debug ("Running rotate-ntp failed.") false; + $LogPrintExit2 debug $0 ("Running rotate-ntp failed.") false; } } :delay 1s; diff --git a/global-wait b/global-wait index 18f2fb8..3ce6d27 100644 --- a/global-wait +++ b/global-wait @@ -6,6 +6,6 @@ :delay 500ms; } -:global LogPrintExit; +:global LogPrintExit2; -$LogPrintExit warning ("This script 'global-wait' is now useless, please remove it from configuration.") true; +$LogPrintExit2 warning "global-wait" ("This script is now useless, please remove it from configuration.") true; diff --git a/gps-track b/gps-track index 31e12e9..bfab8de 100644 --- a/gps-track +++ b/gps-track @@ -6,13 +6,14 @@ # track gps data by sending json data to http server # https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md +:local 0 "gps-track"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global GpsTrackUrl; :global Identity; -:global LogPrintExit; +:global LogPrintExit2; :local CoordinateFormat [ / system gps get coordinate-format ]; :local Gps [ / system gps monitor once as-value ]; @@ -25,9 +26,9 @@ "\"lon\":\"" . ($Gps->"longitude") . "\"," . \ "\"identity\":\"" . $Identity . "\"" . \ "}"); - $LogPrintExit debug ("Sending GPS data in " . $CoordinateFormat . " format: " . \ + $LogPrintExit2 debug $0 ("Sending GPS data in " . $CoordinateFormat . " format: " . \ "lat: " . ($Gps->"latitude") . " " . \ "lon: " . ($Gps->"longitude")) false; } else={ - $LogPrintExit debug ("GPS data not valid.") false; + $LogPrintExit2 debug $0 ("GPS data not valid.") false; } diff --git a/hotspot-to-wpa b/hotspot-to-wpa index 09283cf..68f887f 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -6,10 +6,11 @@ # add private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +:local 0 "hotspot-to-wpa"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit; +:global LogPrintExit2; :local MacAddress $"mac-address"; :local UserName $username; @@ -18,11 +19,11 @@ :if ([ :len [ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ / caps-man access-list add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrintExit warning "Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'." false; + $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; } :local PlaceBefore ([ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ]->0); -$LogPrintExit info ("Adding/updating accesslist entry for mac address " . $MacAddress . \ +$LogPrintExit2 info $0 ("Adding/updating accesslist entry for mac address " . $MacAddress . \ " (user " . $UserName . ").") false; / caps-man access-list remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; diff --git a/ipv6-update b/ipv6-update index 4f0812c..3223807 100644 --- a/ipv6-update +++ b/ipv6-update @@ -6,16 +6,17 @@ # update firewall and dns settings on IPv6 prefix change # https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md +:local 0 "ipv6-update"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :local PdPrefix $"pd-prefix"; -:global LogPrintExit; +:global LogPrintExit2; :global ParseKeyValueStore; :if ([ :typeof $PdPrefix ] = "nothing") do={ - $LogPrintExit error "This script is supposed to run from ipv6 dhcp-client." true; + $LogPrintExit2 error $0 ("This script is supposed to run from ipv6 dhcp-client.") true; } :local Pool [ / ipv6 pool get [ find where prefix=$PdPrefix ] name ]; diff --git a/lease-script b/lease-script index a39a874..28f9e20 100644 --- a/lease-script +++ b/lease-script @@ -6,16 +6,17 @@ # run scripts on DHCP lease # https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md +:local 0 "lease-script"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit; +:global LogPrintExit2; :if ([ :typeof $leaseActIP ] = "nothing" || \ [ :typeof $leaseActMAC ] = "nothing" || \ [ :typeof $leaseServerName ] = "nothing" || \ [ :typeof $leaseBound ] = "nothing") do={ - $LogPrintExit error "This script is supposed to run from ip dhcp-server." true; + $LogPrintExit2 error $0 ("This script is supposed to run from ip dhcp-server.") true; } :local Scripts; diff --git a/log-forward b/log-forward index c4458b2..e90e720 100644 --- a/log-forward +++ b/log-forward @@ -6,6 +6,7 @@ # forward log messages via notification # https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md +:local 0 "log-forward"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } @@ -16,7 +17,7 @@ :global LogForwardRateLimit; :global IfThenElse; -:global LogPrintExit; +:global LogPrintExit2; :global ScriptLock; :global SendNotification; :global SymbolForNotification; @@ -30,7 +31,7 @@ $ScriptLock "log-forward"; :if ($LogForwardRateLimit > 30) do={ :set LogForwardRateLimit ($LogForwardRateLimit - 1); - $LogPrintExit info ("Rate limit in action, not forwarding logs, if any!") true; + $LogPrintExit2 info $0 ("Rate limit in action, not forwarding logs, if any!") true; } $WaitFullyConnected; diff --git a/mode-button b/mode-button index cd94919..8d96fcd 100644 --- a/mode-button +++ b/mode-button @@ -6,23 +6,24 @@ # act on multiple mode and reset button presses # https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md +:local 0 "mode-button"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global ModeButton; -:global LogPrintExit; +:global LogPrintExit2; :set ($ModeButton->"count") ($ModeButton->"count" + 1); :local Scheduler [ / system scheduler find where name="ModeButtonScheduler" ]; :if ([ :len $Scheduler ] = 0) do={ - $LogPrintExit info ("Creating scheduler ModeButtonScheduler, counting presses...") false; + $LogPrintExit2 info $0 ("Creating scheduler ModeButtonScheduler, counting presses...") false; :global ModeButtonScheduler do={ :global ModeButton; - :global LogPrintExit; + :global LogPrintExit2; :global ModeButtonScheduler; :local LEDInvert do={ @@ -45,7 +46,7 @@ / system scheduler remove ModeButtonScheduler; :if ([ :len $Code ] > 0) do={ - $LogPrintExit info ("Acting on " . $Count . " mode-button presses: " . $Code) false; + $LogPrintExit2 info $0 ("Acting on " . $Count . " mode-button presses: " . $Code) false; :for I from=1 to=$Count do={ $LEDInvert; @@ -59,12 +60,12 @@ [ :parse $Code ]; } else={ - $LogPrintExit info ("No action defined for " . $Count . " mode-button presses.") false; + $LogPrintExit2 info $0 ("No action defined for " . $Count . " mode-button presses.") false; } } / system scheduler add name="ModeButtonScheduler" \ on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s; } else={ - $LogPrintExit debug ("Updating scheduler ModeButtonScheduler...") false; + $LogPrintExit2 debug $0 ("Updating scheduler ModeButtonScheduler...") false; / system scheduler set $Scheduler start-time=[ /system clock get time ]; } diff --git a/mode-button-event b/mode-button-event index b31ddc3..09c0283 100644 --- a/mode-button-event +++ b/mode-button-event @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mode-button-event -:global LogPrintExit; +:global LogPrintExit2; -$LogPrintExit warning ("This script's functionality has been merged into 'mode-button'.") true; +$LogPrintExit2 warning "mode-button-event" ("This script's functionality has been merged into 'mode-button'.") true; diff --git a/mode-button-scheduler b/mode-button-scheduler index 8844e49..f7045b2 100644 --- a/mode-button-scheduler +++ b/mode-button-scheduler @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mode-button-scheduler -:global LogPrintExit; +:global LogPrintExit2; -$LogPrintExit warning ("This script's functionality has been merged into 'mode-button'.") true; +$LogPrintExit2 warning "mode-button-scheduler" ("This script's functionality has been merged into 'mode-button'.") true; diff --git a/netwatch-notify b/netwatch-notify index d050b75..6bd8953 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -6,13 +6,14 @@ # monitor netwatch and send notifications # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md +:local 0 "netwatch-notify"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global NetwatchNotify; :global IfThenElse; -:global LogPrintExit; +:global LogPrintExit2; :global ParseKeyValueStore; :global SendNotification; :global SymbolForNotification; @@ -32,7 +33,7 @@ } :if ($HostVal->"status" = "up") do={ - $LogPrintExit debug ("Host " . $HostName . " (" . $HostVal->"host" . ") is up.") false; + $LogPrintExit2 debug $0 ("Host " . $HostName . " (" . $HostVal->"host" . ") is up.") false; :local Count ($Metric->"count"); :set ($Metric->"count") 0; :if ($Metric->"notified" = true) do={ @@ -40,7 +41,7 @@ ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ - $LogPrintExit info ("Running hook on host " . $HostName . " up: " . ($HostInfo->"up-hook")) false; + $LogPrintExit2 info $0 ("Running hook on host " . $HostName . " up: " . ($HostInfo->"up-hook")) false; [ :parse ($HostInfo->"up-hook") ]; } } @@ -65,7 +66,7 @@ :set Parent ($NetwatchNotify->$Parent->"parent"); } } - $LogPrintExit info ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ + $LogPrintExit2 info $0 ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ $Metric->"count" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ ($Metric->"notified" = true) ("already notified.") ($Count - $Metric->"count" . " to go.") ] \ ("parent host " . $Parent . " is down.") ]) false; @@ -74,7 +75,7 @@ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :set ($Metric->"notified") true; :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ - $LogPrintExit info ("Running hook on host " . $HostName . " down: " . ($HostInfo->"down-hook")) false; + $LogPrintExit2 info $0 ("Running hook on host " . $HostName . " down: " . ($HostInfo->"down-hook")) false; [ :parse ($HostInfo->"down-hook") ]; } } diff --git a/ospf-to-leds b/ospf-to-leds index 32027db..727f33b 100644 --- a/ospf-to-leds +++ b/ospf-to-leds @@ -6,10 +6,11 @@ # visualize ospf instance state via leds # https://git.eworm.de/cgit/routeros-scripts/about/doc/ospf-to-leds.md +:local 0 "ospf-to-leds"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit; +:global LogPrintExit2; :global ParseKeyValueStore; :foreach Instance in=[ / routing ospf instance find where comment~"^ospf-to-leds," ] do={ @@ -17,7 +18,7 @@ :local LED ([ $ParseKeyValueStore ($InstanceVal->"comment") ]->"leds"); :local LEDType [ / system leds get [ find where leds=$LED ] type ]; - $LogPrintExit debug ("OSPF instance " . $InstanceVal->"name" . " is " . $InstanceVal->"state" . ".") false; + $LogPrintExit2 debug $0 ("OSPF instance " . $InstanceVal->"name" . " is " . $InstanceVal->"state" . ".") false; :if ($InstanceVal->"state" = "running" && $LEDType = "off") do={ / system leds set type=on [ find where leds=$LED ]; } diff --git a/packages-update b/packages-update index 4a2f418..d23be09 100644 --- a/packages-update +++ b/packages-update @@ -6,11 +6,12 @@ # download packages and reboot for installation # https://git.eworm.de/cgit/routeros-scripts/about/doc/packages-update.md +:local 0 "packages-update"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global DownloadPackage; -:global LogPrintExit; +:global LogPrintExit2; :global ScriptFromTerminal; :global ScriptLock; :global VersionToNum; @@ -20,11 +21,11 @@ $ScriptLock "packages-update"; :local Update [ / system package update get ]; :if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ - $LogPrintExit warning "Latest version is not known." true; + $LogPrintExit2 warning $0 ("Latest version is not known.") true; } :if ($Update->"installed-version" = $Update->"latest-version") do={ - $LogPrintExit info ("Version " . $Update->"latest-version" . " is already installed.") true; + $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is already installed.") true; } :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; @@ -40,39 +41,39 @@ $ScriptLock "packages-update"; :put "Canceled..."; } } else={ - $LogPrintExit warning ("Not installing downgrade automatically.") true; + $LogPrintExit2 warning $0 ("Not installing downgrade automatically.") true; } } :foreach Package in=[ / system package find where !bundle ] do={ :local PkgName [ / system package get $Package name ]; if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ - $LogPrintExit error ("Download for package " . $PkgName . " failed.") true; + $LogPrintExit2 error $0 ("Download for package " . $PkgName . " failed.") true; } } :foreach Script in=[ / system script find where name~"^(cloud|email|upload)-backup\$" ] do={ :local ScriptName [ / system script get $Script name ]; :do { - $LogPrintExit info ("Running backup script " . $ScriptName . " before update.") false; + $LogPrintExit2 info $0 ("Running backup script " . $ScriptName . " before update.") false; / system script run $Script; } on-error={ - $LogPrintExit warning ("Running backup script " . $ScriptName . " before update failed!") false; + $LogPrintExit2 warning $0 ("Running backup script " . $ScriptName . " before update failed!") false; :if ([ $ScriptFromTerminal "packages-update" ] = true) do={ :put "Do you want to continue anyway? [y/N]"; :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ - $LogPrintExit info ("User requested to continue anyway.") false; + $LogPrintExit2 info $0 ("User requested to continue anyway.") false; } else={ - $LogPrintExit info ("Canceled update...") true; + $LogPrintExit2 info $0 ("Canceled update...") true; } } else={ - $LogPrintExit info ("Canceled non-interactive update.") true; + $LogPrintExit2 info $0 ("Canceled non-interactive update.") true; } } } :if ($DoDowngrade = true) do={ - $LogPrintExit info ("Rebooting for downgrade.") false; + $LogPrintExit2 info $0 ("Rebooting for downgrade.") false; :delay 1s; / system package downgrade; } @@ -83,10 +84,10 @@ $ScriptLock "packages-update"; / system scheduler add name="reboot-for-update" start-time=03:00:00 interval=1d \ on-event=(":global RandomDelay; \$RandomDelay 3600; " . \ "/ system scheduler remove reboot-for-update; / system reboot;"); - $LogPrintExit info ("Scheduled reboot for update between 03:00 and 04:00.") true; + $LogPrintExit2 info $0 ("Scheduled reboot for update between 03:00 and 04:00.") true; } } -$LogPrintExit info ("Rebooting for update.") false; +$LogPrintExit2 info $0 ("Rebooting for update.") false; :delay 1s; / system reboot; diff --git a/ppp-on-up b/ppp-on-up index cf95e48..fe1492d 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -6,15 +6,16 @@ # run scripts on ppp up # https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md +:local 0 "ppp-on-up"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit; +:global LogPrintExit2; :local Interface $interface; :if ([ :typeof $Interface ] = "nothing") do={ - $LogPrintExit error "This script is supposed to run from ppp on-up script hook." true; + $LogPrintExit2 error $0 ("This script is supposed to run from ppp on-up script hook.") true; } :local IntName [ / interface get $Interface name ]; diff --git a/rotate-ntp b/rotate-ntp index 6578078..24eb107 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -6,26 +6,27 @@ # rotate the ntp servers # https://git.eworm.de/cgit/routeros-scripts/about/doc/rotate-ntp.md +:local 0 "rotate-ntp"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global NtpPool; -:global LogPrintExit; +:global LogPrintExit2; :local Ntp1; :local Ntp2; :if ([ / system ntp client get enabled ] != true) do={ - $LogPrintExit warning "NTP client is not enabled!" true; + $LogPrintExit2 warning $0 ("NTP client is not enabled!") true; } :do { :set Ntp1 [ :resolve ("0." . $NtpPool) ]; :set Ntp2 [ :resolve ("1." . $NtpPool) ]; } on-error={ - $LogPrintExit warning "Resolving NTP server failed." true; + $LogPrintExit2 warning $0 ("Resolving NTP server failed.") true; } -$LogPrintExit info ("Updating NTP servers to " . $Ntp1 . " and " . $Ntp2) false; +$LogPrintExit2 info $0 ("Updating NTP servers to " . $Ntp1 . " and " . $Ntp2) false; / system ntp client set primary-ntp=$Ntp1 secondary-ntp=$Ntp2; diff --git a/script-updates b/script-updates index be79f58..e35f15c 100644 --- a/script-updates +++ b/script-updates @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: script-updates -:global LogPrintExit; +:global LogPrintExit2; -$LogPrintExit warning ("This script has been replaced by function '\$ScriptInstallUpdate'.") true; +$LogPrintExit2 warning "script-updates" ("This script has been replaced by function '\$ScriptInstallUpdate'.") true; diff --git a/sms-action b/sms-action index 4c39740..2d2600d 100644 --- a/sms-action +++ b/sms-action @@ -6,17 +6,18 @@ # run action on received SMS # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-action.md +:local 0 "sms-action"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global SmsAction; -:global LogPrintExit; +:global LogPrintExit2; :local Action $action; :if ([ :typeof $Action ] = "nothing") do={ - $LogPrintExit error "This script is supposed to run from SMS hook with action=..." true; + $LogPrintExit2 error $0 ("This script is supposed to run from SMS hook with action=...") true; } :local Code ($SmsAction->$Action); diff --git a/sms-forward b/sms-forward index abfea99..58ed520 100644 --- a/sms-forward +++ b/sms-forward @@ -6,13 +6,14 @@ # forward SMS to e-mail # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md +:local 0 "sms-forward"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global Identity; :global IfThenElse; -:global LogPrintExit; +:global LogPrintExit2; :global ScriptLock; :global SendNotification; :global SymbolForNotification; @@ -21,7 +22,7 @@ $ScriptLock "sms-forward"; :if ([ / tool sms get receive-enabled ] = false) do={ - $LogPrintExit warning "Receiving of SMS is not enabled." true; + $LogPrintExit2 warning $0 ("Receiving of SMS is not enabled.") true; } $WaitFullyConnected; @@ -39,7 +40,7 @@ $WaitFullyConnected; :if ($Phone = $Settings->"allowed-number" && \ ($SmsVal->"message")~("^:cmd " . $Settings->"secret" . " script ")) do={ - $LogPrintExit debug ("Removing SMS, which started a script.") false; + $LogPrintExit2 debug $0 ("Removing SMS, which started a script.") false; / tool sms inbox remove $Sms; } else={ :set Messages ($Messages . "\n\nOn " . $SmsVal->"timestamp" . \ diff --git a/update-gre-address b/update-gre-address index 50d1373..af57d2d 100644 --- a/update-gre-address +++ b/update-gre-address @@ -7,10 +7,11 @@ # ipsec remote peer # https://git.eworm.de/cgit/routeros-scripts/about/doc/update-gre-address.md +:local 0 "update-gre-address"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit; +:global LogPrintExit2; / interface gre set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; @@ -22,7 +23,7 @@ :if ([ :typeof ($PeerVal->"dynamic-address") ] = "str" && \ ($PeerVal->"dynamic-address" != $GreIntVal->"remote-address" || \ $GreIntVal->"disabled" = true)) do={ - $LogPrintExit info ("Updating remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address") false; + $LogPrintExit2 info $0 ("Updating remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address") false; / interface gre set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$PeerVal->"dynamic-address" name!=$GreIntVal->"name" ]; / interface gre set $GreInt remote-address=($PeerVal->"dynamic-address") disabled=no; } diff --git a/update-tunnelbroker b/update-tunnelbroker index 6cdb195..2168390 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -7,15 +7,16 @@ # update local address of tunnelbroker interface # https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md +:local 0 "update-tunnelbroker"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global CertificateAvailable; -:global LogPrintExit; +:global LogPrintExit2; :global ParseKeyValueStore; :if ([ / ip cloud get ddns-enabled ] != true) do={ - $LogPrintExit error "IP cloud DDNS is not enabled." true; + $LogPrintExit2 error $0 ("IP cloud DDNS is not enabled.") true; } # Get the current ip address from cloud @@ -32,14 +33,14 @@ :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; :if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ - $LogPrintExit error ("Downloading required certificate failed.") true; + $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; } - $LogPrintExit info ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress) false; + $LogPrintExit2 info $0 ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress) false; / tool fetch check-certificate=yes-without-crl \ ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ user=($Comment->"user") password=($Comment->"pass") output=none; / interface 6to4 set $Interface local-address=$PublicAddress; } else={ - $LogPrintExit debug ("All tunnelbroker configuration is up to date for interface " . $InterfaceVal->"name" . ".") false; + $LogPrintExit2 debug $0 ("All tunnelbroker configuration is up to date for interface " . $InterfaceVal->"name" . ".") false; } } diff --git a/upload-backup b/upload-backup index e16a4e5..1e3e8e8 100644 --- a/upload-backup +++ b/upload-backup @@ -6,6 +6,7 @@ # create and upload backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/upload-backup.md +:local 0 "upload-backup"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } @@ -21,7 +22,7 @@ :global CharacterReplace; :global DeviceInfo; :global IfThenElse; -:global LogPrintExit; +:global LogPrintExit2; :global SendNotification; :global SymbolForNotification; :global WaitForFile; @@ -31,7 +32,7 @@ $WaitFullyConnected; :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ - $LogPrintExit error ("Configured to send neither backup nor config export.") true; + $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; } # filename based on identity @@ -50,7 +51,7 @@ $WaitFullyConnected; user=$BackupUploadUser password=$BackupUploadPass src-path=($FileName . ".backup"); :set BackupFile ($FileName . ".backup"); } on-error={ - $LogPrintExit error ("Uploading backup file failed!") false; + $LogPrintExit2 error $0 ("Uploading backup file failed!") false; :set BackupFile "failed"; :set Failed 1; } @@ -66,7 +67,7 @@ $WaitFullyConnected; user=$BackupUploadUser password=$BackupUploadPass src-path=($FileName . ".rsc"); :set ConfigFile ($FileName . ".rsc"); } on-error={ - $LogPrintExit error ("Uploading configuration export failed!") false; + $LogPrintExit2 error $0 ("Uploading configuration export failed!") false; :set ConfigFile "failed"; :set Failed 1; } From 041ca062b1d07843e7ef9ae8e99a753e344189e5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 22 Feb 2021 19:52:20 +0100 Subject: [PATCH 0624/2612] global: use $0 for $ScriptLock --- capsman-download-packages | 2 +- capsman-rolling-upgrade | 2 +- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- log-forward | 2 +- packages-update | 2 +- sms-forward | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/capsman-download-packages b/capsman-download-packages index 37e2658..5b03bba 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -18,7 +18,7 @@ :global ScriptLock; :global WaitFullyConnected; -$ScriptLock "capsman-download-packages"; +$ScriptLock $0; $WaitFullyConnected; :local PackagePath [ $CleanFilePath [ / caps-man manager get package-path ] ]; diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index fe4410a..9e7aec0 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -14,7 +14,7 @@ :global LogPrintExit2; :global ScriptLock; -$ScriptLock "capsman-rolling-upgrade"; +$ScriptLock $0; :local InstalledVersion [ / system package update get installed-version ]; diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 248a14d..ca43dc5 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -20,7 +20,7 @@ :global SendNotification; :global SymbolForNotification; -$ScriptLock "collect-wireless-mac.capsman"; +$ScriptLock $0; :if ([ :len [ / caps-man access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ / caps-man access-list add comment="--- collected above ---" disabled=yes; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 20a5f83..7489c4c 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -20,7 +20,7 @@ :global SendNotification; :global SymbolForNotification; -$ScriptLock "collect-wireless-mac.local"; +$ScriptLock $0; :if ([ :len [ / interface wireless access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ / interface wireless access-list add comment="--- collected above ---" disabled=yes; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index fe84287..b6c4efa 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -21,7 +21,7 @@ :global SendNotification; :global SymbolForNotification; -$ScriptLock "collect-wireless-mac%TEMPL%"; +$ScriptLock $0; :if ([ :len [ / %PATH% access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ / %PATH% access-list add comment="--- collected above ---" disabled=yes; diff --git a/log-forward b/log-forward index e90e720..def04e6 100644 --- a/log-forward +++ b/log-forward @@ -23,7 +23,7 @@ :global SymbolForNotification; :global WaitFullyConnected; -$ScriptLock "log-forward"; +$ScriptLock $0; :if ([ :typeof $LogForwardRateLimit ] = "nothing") do={ :set LogForwardRateLimit 0; diff --git a/packages-update b/packages-update index d23be09..fb5c7fa 100644 --- a/packages-update +++ b/packages-update @@ -16,7 +16,7 @@ :global ScriptLock; :global VersionToNum; -$ScriptLock "packages-update"; +$ScriptLock $0; :local Update [ / system package update get ]; diff --git a/sms-forward b/sms-forward index 58ed520..1d47000 100644 --- a/sms-forward +++ b/sms-forward @@ -19,7 +19,7 @@ :global SymbolForNotification; :global WaitFullyConnected; -$ScriptLock "sms-forward"; +$ScriptLock $0; :if ([ / tool sms get receive-enabled ] = false) do={ $LogPrintExit2 warning $0 ("Receiving of SMS is not enabled.") true; From 766a92a74b728653ae73df7566f1ed34981c1063 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 22 Feb 2021 20:01:43 +0100 Subject: [PATCH 0625/2612] global: use $0 for $ScriptFromTerminal --- check-routeros-update | 2 +- packages-update | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index fe87d9c..9dcef1d 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -93,7 +93,7 @@ $WaitFullyConnected; } } - :if ([ $ScriptFromTerminal "check-routeros-update" ] = true) do={ + :if ([ $ScriptFromTerminal $0 ] = true) do={ :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ $DoUpdate; diff --git a/packages-update b/packages-update index fb5c7fa..99f1f30 100644 --- a/packages-update +++ b/packages-update @@ -33,7 +33,7 @@ $ScriptLock $0; :local DoDowngrade false; :if ($NumInstalled > $NumLatest) do={ - :if ([ $ScriptFromTerminal "packages-update" ] = true) do={ + :if ([ $ScriptFromTerminal $0 ] = true) do={ :put "Latest version is older than installed one. Want to downgrade? [y/N]"; :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ :set DoDowngrade true; @@ -59,7 +59,7 @@ $ScriptLock $0; / system script run $Script; } on-error={ $LogPrintExit2 warning $0 ("Running backup script " . $ScriptName . " before update failed!") false; - :if ([ $ScriptFromTerminal "packages-update" ] = true) do={ + :if ([ $ScriptFromTerminal $0 ] = true) do={ :put "Do you want to continue anyway? [y/N]"; :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ $LogPrintExit2 info $0 ("User requested to continue anyway.") false; @@ -78,7 +78,7 @@ $ScriptLock $0; / system package downgrade; } -:if ([ $ScriptFromTerminal "packages-update" ] = true) do={ +:if ([ $ScriptFromTerminal $0 ] = true) do={ :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; :if (([ :terminal inkey timeout=60 ] % 32) = 19) do={ / system scheduler add name="reboot-for-update" start-time=03:00:00 interval=1d \ From 6770a15a7d1df1ef5f2cc0a6f82e0d4f82b214d6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Feb 2021 09:55:14 +0100 Subject: [PATCH 0626/2612] cloud-backup: add configurable random delay --- cloud-backup | 7 +++++++ doc/cloud-backup.md | 3 ++- global-config | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/cloud-backup b/cloud-backup index 598a500..aa29faa 100644 --- a/cloud-backup +++ b/cloud-backup @@ -11,16 +11,23 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global BackupPassword; +:global BackupRandomDelay; :global Identity; :global DeviceInfo; :global LogPrintExit2; +:global RandomDelay; +:global ScriptFromTerminal; :global SendNotification; :global SymbolForNotification; :global WaitFullyConnected; $WaitFullyConnected; +:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ + $RandomDelay $BackupRandomDelay; +} + :do { # we are not interested in output, but print is # required to fetch information from cloud diff --git a/doc/cloud-backup.md b/doc/cloud-backup.md index bda1267..1417242 100644 --- a/doc/cloud-backup.md +++ b/doc/cloud-backup.md @@ -18,9 +18,10 @@ Just install the script: Configuration ------------- -The configuration goes to `global-config-overlay`, this is the only parameter: +The configuration goes to `global-config-overlay`, these are the parameters: * `BackupPassword`: password to encrypt the backup with +* `BackupRandomDelay`: delay up to amount of seconds when run from scheduler Also notification settings are required for e-mail and telegram. diff --git a/global-config b/global-config index d9c8061..d25c456 100644 --- a/global-config +++ b/global-config @@ -42,6 +42,7 @@ :global BackupSendBinary false; :global BackupSendExport true; :global BackupPassword "v3ry-s3cr3t"; +:global BackupRandomDelay 0; # These addresses are used to send backup and config export files to. :global EmailBackupTo ""; :global EmailBackupCc ""; From 8b44964a36e5a5eebe70ab94eae6086bfbdbfb36 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Feb 2021 09:56:12 +0100 Subject: [PATCH 0627/2612] email-backup: add configurable random delay --- doc/email-backup.md | 3 ++- email-backup | 11 +++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/doc/email-backup.md b/doc/email-backup.md index 7f89a06..4b769ec 100644 --- a/doc/email-backup.md +++ b/doc/email-backup.md @@ -20,11 +20,12 @@ Just install the script: Configuration ------------- -The configuration goes to `global-config-overlay`, These are the parameters: +The configuration goes to `global-config-overlay`, these are the parameters: * `BackupSendBinary`: whether to send binary backup * `BackupSendExport`: whether to send configuration export * `BackupPassword`: password to encrypt the backup with +* `BackupRandomDelay`: delay up to amount of seconds when run from scheduler * `EmailBackupTo`: e-mail address to send to * `EmailBackupCc`: e-mail address(es) to send in copy diff --git a/email-backup b/email-backup index 129075a..b9e91c2 100644 --- a/email-backup +++ b/email-backup @@ -11,6 +11,7 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global BackupPassword; +:global BackupRandomDelay; :global BackupSendBinary; :global BackupSendExport; :global Domain; @@ -21,11 +22,11 @@ :global CharacterReplace; :global DeviceInfo; :global LogPrintExit2; +:global RandomDelay; +:global ScriptFromTerminal; :global WaitForFile; :global WaitFullyConnected; -$WaitFullyConnected; - :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; @@ -35,6 +36,12 @@ $WaitFullyConnected; $LogPrintExit2 error $0 ("Configuration is missing recipient for e-mail backup.") true; } +$WaitFullyConnected; + +:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ + $RandomDelay $BackupRandomDelay; +} + # filename based on identity :local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; :local BackupFile "none"; From bc8b19fc31a2c2c437c6fea703b601b802470e02 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Feb 2021 09:56:28 +0100 Subject: [PATCH 0628/2612] upload-backup: add configurable random delay --- doc/upload-backup.md | 1 + upload-backup | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/upload-backup.md b/doc/upload-backup.md index bbfbcc4..e6ba9e2 100644 --- a/doc/upload-backup.md +++ b/doc/upload-backup.md @@ -24,6 +24,7 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupSendBinary`: whether to send binary backup * `BackupSendExport`: whether to send configuration export * `BackupPassword`: password to encrypt the backup with +* `BackupRandomDelay`: delay up to amount of seconds when run from scheduler * `BackupUploadUrl`: url to upload to * `BackupUploadUser`: username for server authentication * `BackupUploadPass`: password for server authentication diff --git a/upload-backup b/upload-backup index 1e3e8e8..15adc1f 100644 --- a/upload-backup +++ b/upload-backup @@ -11,6 +11,7 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global BackupPassword; +:global BackupRandomDelay; :global BackupSendBinary; :global BackupSendExport; :global BackupUploadPass; @@ -23,18 +24,24 @@ :global DeviceInfo; :global IfThenElse; :global LogPrintExit2; +:global RandomDelay; +:global ScriptFromTerminal; :global SendNotification; :global SymbolForNotification; :global WaitForFile; :global WaitFullyConnected; -$WaitFullyConnected; - :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; } +$WaitFullyConnected; + +:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ + $RandomDelay $BackupRandomDelay; +} + # filename based on identity :local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; :local BackupFile "none"; From 8a366f035d4ac940166cbb7923654d5b2bf8a6da Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Feb 2021 10:02:12 +0100 Subject: [PATCH 0629/2612] backup: notify about random delay --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index d25c456..1838725 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 45; +:global GlobalConfigVersion 46; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 6a8050a..6fd48e6 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 45; +:global GlobalConfigVersion 46; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 283d2c0..e1951df 100644 --- a/global-config.changes +++ b/global-config.changes @@ -49,6 +49,7 @@ 43="Added queue for e-mail notifications to resend later on error."; 44="Dropped script 'global-wait', all scripts wait on their own now."; 45="We have a Telegram Group! Come along and say hello: https://t.me/routeros_scripts"; + 46="Added configurable random delay in backup scripts to stretch execution and prevent resource congestion."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index e958d74..cc01ed3 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 45; +:global ExpectedConfigVersion 46; # global variables not to be changed by user :global GlobalFunctionsReady false; From eaeda375e27c9909cb49913ef26d9984d541c637 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Feb 2021 13:51:51 +0100 Subject: [PATCH 0630/2612] certs: remove obsolote certificate "Let's Encrypt Authority X3" Let's Encrypt started issuing certificates from "R3" intermediate on December 2nd. All certificates should be renewed by now... --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 2 ++ global-functions | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 1838725..607cb79 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 46; +:global GlobalConfigVersion 47; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 6fd48e6..10376c7 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -9,7 +9,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable change notifications. -:global GlobalConfigVersion 46; +:global GlobalConfigVersion 47; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index e1951df..2bc18c0 100644 --- a/global-config.changes +++ b/global-config.changes @@ -50,9 +50,11 @@ 44="Dropped script 'global-wait', all scripts wait on their own now."; 45="We have a Telegram Group! Come along and say hello: https://t.me/routeros_scripts"; 46="Added configurable random delay in backup scripts to stretch execution and prevent resource congestion."; + 47="Removed obsolete intermediate certificate 'Let's Encrypt Authority X3' from store."; }; # Migration steps to be applied on script updates :global GlobalConfigMigration { 41=":global SendNotification; \$SendNotification (\"Migration mechanism\") (\"Congratulations!\nSuccessfully tested the new migration mechanism.\");"; + 47="/ certificate remove [ find where fingerprint=\"731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568\" or fingerprint=\"25847d668eb4f04fdd40b12b6b0740c567da7d024308eb6c2c96fe41d9de218d\" ];"; }; diff --git a/global-functions b/global-functions index cc01ed3..79e0ea6 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 46; +:global ExpectedConfigVersion 47; # global variables not to be changed by user :global GlobalFunctionsReady false; From 274af988865accdae914e3645ea23bae8d8c425d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Feb 2021 22:05:43 +0100 Subject: [PATCH 0631/2612] global-functions: $GetMacVendor: improve error handling The API returns 404 on unknown mac vendor... We can just catch error, but not decide whether it is connection error or unknown vendor. Try without mac address - on error we have a connection issue. --- global-functions | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/global-functions b/global-functions index 79e0ea6..7425273 100644 --- a/global-functions +++ b/global-functions @@ -380,6 +380,13 @@ ("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data"); :return $Vendor; } on-error={ + :do { + / tool fetch check-certificate=yes-without-crl ("https://api.macvendors.com/") \ + output=none as-value; + $LogPrintExit2 debug $0 ("The mac vendor is not known in database.") false; + } on-error={ + $LogPrintExit2 warning $0 ("Failed getting mac vendor.") false; + } :return "unknown vendor"; } } From 295203cc1c99d7e21059e6e1fb00ea53cf4f1fb9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Feb 2021 22:14:33 +0100 Subject: [PATCH 0632/2612] check-certificates: silence fetch --- check-certificates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index 5946a86..68be7ee 100644 --- a/check-certificates +++ b/check-certificates @@ -45,7 +45,7 @@ $WaitFullyConnected; :local CertFileName ([ $UrlEncode ($CertVal->"common-name") ] . $Type); :do { / tool fetch check-certificate=yes-without-crl \ - ($CertRenewUrl . $CertFileName) dst-path=$CertFileName; + ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; $WaitForFile $CertFileName; :foreach PassPhrase in=$CertRenewPass do={ / certificate import file-name=$CertFileName passphrase=$PassPhrase; From 9d35b49f1686818a00e6ed0ef42f4718200fb15a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Feb 2021 22:36:52 +0100 Subject: [PATCH 0633/2612] global-functions: silence fetch --- global-functions | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/global-functions b/global-functions index 7425273..fbc3f4a 100644 --- a/global-functions +++ b/global-functions @@ -115,7 +115,7 @@ / tool fetch check-certificate=yes-without-crl \ ($ScriptUpdatesBaseUrl . "certs/" . \ $UrlFileName . $ScriptUpdatesUrlSuffix) \ - dst-path=$LocalFileName; + dst-path=$LocalFileName as-value; $WaitForFile $LocalFileName; / certificate import file-name=$LocalFileName passphrase=""; / file remove $LocalFileName; @@ -350,7 +350,7 @@ http-data=("chat_id=" . ($Message->"chatid") . \ "&disable_notification=" . ($Message->"silent") . \ "&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \ - "&text=" . ($Message->"text")); + "&text=" . ($Message->"text")) as-value; :set ($TelegramQueue->$Id); } on-error={ $LogPrintExit2 debug $0 ("Sending queued Telegram message failed.") false; @@ -520,7 +520,7 @@ :local WwwVal [ / ip service get www ]; / ip service set www address=127.0.0.1/32 disabled=no port=80; :do { - / tool fetch http://127.0.0.1/ dst-path=($Dir . "/tmp"); + / tool fetch http://127.0.0.1/ dst-path=($Dir . "/tmp") as-value; $WaitForFile ($Dir . "/tmp"); / file remove ($Dir . "/tmp"); } on-error={ @@ -908,7 +908,7 @@ / tool fetch check-certificate=yes-without-crl output=none http-method=post \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ http-data=("chat_id=" . $ChatId . "&disable_notification=" . $Silent . \ - "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text); + "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; } on-error={ $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; From 78a53e6fe27e6037f25470f70ea661863026f7c9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Feb 2021 22:32:51 +0100 Subject: [PATCH 0634/2612] gps-track: silence fetch --- gps-track | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gps-track b/gps-track index bfab8de..3fc3807 100644 --- a/gps-track +++ b/gps-track @@ -25,7 +25,7 @@ "\"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; From 8abb3c1e33dca7382bf18e0609115933bbf617df Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Feb 2021 22:18:01 +0100 Subject: [PATCH 0635/2612] update-tunnelbroker: silence fetch --- update-tunnelbroker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/update-tunnelbroker b/update-tunnelbroker index 2168390..e6f50e4 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -38,7 +38,7 @@ $LogPrintExit2 info $0 ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress) false; / tool fetch check-certificate=yes-without-crl \ ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ - user=($Comment->"user") password=($Comment->"pass") output=none; + user=($Comment->"user") password=($Comment->"pass") output=none as-value; / interface 6to4 set $Interface local-address=$PublicAddress; } else={ $LogPrintExit2 debug $0 ("All tunnelbroker configuration is up to date for interface " . $InterfaceVal->"name" . ".") false; From 1015a1bbde2f0bca4dd09907d97a2d256f7be940 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Feb 2021 22:49:29 +0100 Subject: [PATCH 0636/2612] global-functions: $CertificateAvailable: use $0 for $RequiredRouterOS --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index fbc3f4a..8bb18fd 100644 --- a/global-functions +++ b/global-functions @@ -77,7 +77,7 @@ } } - :if ([ $RequiredRouterOS ("\$CertificateAvailable") "6.47" ] = false) do={ + :if ([ $RequiredRouterOS $0 "6.47" ] = false) do={ :return true; } From 68ab6af56b62ec8cc9cc1b278b0a3d8a3c2546a0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Feb 2021 11:13:35 +0100 Subject: [PATCH 0637/2612] let's keep next branch and document it --- global-config | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/global-config b/global-config index 607cb79..9c8dbea 100644 --- a/global-config +++ b/global-config @@ -131,9 +131,14 @@ # Enable this to fetch scripts from given url. :global ScriptUpdatesFetch true; :global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/"; +# alternative urls - main: stable code - next: currently in development #:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/main/"; +#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/next/"; #:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/main/"; +#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/next/"; :global ScriptUpdatesUrlSuffix ""; +# use next branch with default url (git.eworm.de) +#:global ScriptUpdatesUrlSuffix "\?h=next"; # This project is developed in private spare time and usage is free of charge # for you. If you like the scripts and think this is of value for you or your From 948a2664c4d6edc85393b13437360439fbafb3f2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Feb 2021 12:27:20 +0100 Subject: [PATCH 0638/2612] global-functions: $ScriptInstallUpdate: list news with 'black circle' ... if symbols are enabled. --- global-functions | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 8bb18fd..5f524c7 100644 --- a/global-functions +++ b/global-functions @@ -602,12 +602,14 @@ :global GlobalConfigVersion; :global Identity; :global IDonate; + :global NotificationsWithSymbols; :global ScriptUpdatesBaseUrl; :global ScriptUpdatesFetch; :global ScriptUpdatesUrlSuffix; :global SentConfigChangesNotification; :global CertificateAvailable; + :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; :global ScriptInstallUpdate; @@ -733,7 +735,8 @@ [ :parse $Migration ]; } :set NotificationMessage ($NotificationMessage . \ - "\n * " . $GlobalConfigChanges->[ :tostr $I ]); + "\n " . [ $IfThenElse ($NotificationsWithSymbols = true) ("\E2\97\8F") "*" ] . " " . \ + $GlobalConfigChanges->[ :tostr $I ]); $LogPrintExit2 info $0 ("Change: " . $GlobalConfigChanges->[ :tostr $I ]) false; } :set GlobalConfigChanges; From 60ec2009452ddd54c384bc9e81f19a8896409a9e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Feb 2021 12:36:49 +0100 Subject: [PATCH 0639/2612] global-functions: $ScriptInstallUpdate: expect global-config-overlay to be present --- global-functions | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/global-functions b/global-functions index 5f524c7..403d077 100644 --- a/global-functions +++ b/global-functions @@ -675,8 +675,7 @@ $LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; / system script set owner=($ScriptVal->"name") source=$SourceNew \ dont-require-permissions=$DontRequirePermissions $Script; - :if ($ScriptVal->"name" = "global-config" && \ - [ :len [ / system script find where name="global-config-overlay" ] ] > 0) do={ + :if ($ScriptVal->"name" = "global-config") do={ $LogPrintExit2 info $0 ("Reloading global configuration and overlay.") false; :do { / system script { run global-config; run global-config-overlay; } @@ -708,14 +707,10 @@ :global GlobalConfigChanges; :global GlobalConfigMigration; :local ChangeLogCode; - :local ConfigScript "global-config"; - :if ([ :len [ / system script find where name="global-config-overlay" ] ] > 0) do={ - :set ConfigScript "global-config-overlay"; - } :local NotificationMessage ("Current configuration on " . $Identity . \ - " is out of date. Please update " . $ConfigScript . ", then increase " . \ + " is out of date. Please update global-config-overlay, then increase " . \ "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \ - ") to " . $ExpectedConfigVersion . " and re-run " . $ConfigScript . "."); + ") to " . $ExpectedConfigVersion . " and re-run global-config-overlay."); $LogPrintExit2 info $0 ($NotificationMessage) false; $LogPrintExit2 debug $0 ("Fetching changelog.") false; From fe3d582c1f68a995db9a25ec0e41545b2c8fd3d4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Feb 2021 12:51:57 +0100 Subject: [PATCH 0640/2612] global-functions: $FlushEmailQueue: fix syntax --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 403d077..4b495d9 100644 --- a/global-functions +++ b/global-functions @@ -318,7 +318,7 @@ :set AllDone false; :set Wait false; } - } while ($Wait = true); + } while=($Wait = true); } } From d0cdad791c937c48fe3598338599f678f1cd1e0d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Feb 2021 16:31:19 +0100 Subject: [PATCH 0641/2612] global-functions: $ScriptInstallUpdate: swap conditions --- global-functions | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/global-functions b/global-functions index 4b495d9..7dddb50 100644 --- a/global-functions +++ b/global-functions @@ -668,8 +668,8 @@ } :if ([ :len $SourceNew ] > 0) do={ - :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ - :if ($SourceNew != $ScriptVal->"source") do={ + :if ($SourceNew != $ScriptVal->"source") do={ + :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ :local DontRequirePermissions \ ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); $LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; @@ -692,10 +692,11 @@ } } } else={ - $LogPrintExit2 debug $0 ("Script " . $ScriptVal->"name" . " did not change.") false; + $LogPrintExit2 warning $0 ("Looks like new script " . $ScriptVal->"name" . \ + " is not valid (missing shebang). Ignoring!") false; } } else={ - $LogPrintExit2 warning $0 ("Looks like new script " . $ScriptVal->"name" . " is not valid. Ignoring!") false; + $LogPrintExit2 debug $0 ("Script " . $ScriptVal->"name" . " did not change.") false; } } else={ $LogPrintExit2 debug $0 ("No update for script " . $ScriptVal->"name" . ".") false; From bd6b67ad7a643eebdacb0b00e5b92da28c45cdd8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Feb 2021 16:36:44 +0100 Subject: [PATCH 0642/2612] global-functions: $ScriptInstallUpdate: add syntax validation --- global-functions | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/global-functions b/global-functions index 7dddb50..8396f60 100644 --- a/global-functions +++ b/global-functions @@ -670,26 +670,38 @@ :if ([ :len $SourceNew ] > 0) do={ :if ($SourceNew != $ScriptVal->"source") do={ :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ - :local DontRequirePermissions \ - ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); - $LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; - / system script set owner=($ScriptVal->"name") source=$SourceNew \ - dont-require-permissions=$DontRequirePermissions $Script; - :if ($ScriptVal->"name" = "global-config") do={ - $LogPrintExit2 info $0 ("Reloading global configuration and overlay.") false; - :do { - / system script { run global-config; run global-config-overlay; } - } on-error={ - $LogPrintExit2 error $0 ("Reloading global configuration and overlay failed! Syntax error\?") false; - } + :local SyntaxOK true; + :do { + [ :parse (":local ValidateFunction do={ " . $SourceNew . " }") ] + } on-error={ + :set SyntaxOK false; } - :if ($ScriptVal->"name" = "global-functions") do={ - $LogPrintExit2 info $0 ("Reloading global functions.") false; - :do { - / system script run global-functions; - } on-error={ - $LogPrintExit2 error $0 ("Reloading global functions failed!") false; + :if ($SyntaxOK = true) do={ + :local DontRequirePermissions \ + ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); + $LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; + / system script set owner=($ScriptVal->"name") source=$SourceNew \ + dont-require-permissions=$DontRequirePermissions $Script; + :if ($ScriptVal->"name" = "global-config") do={ + $LogPrintExit2 info $0 ("Reloading global configuration and overlay.") false; + :do { + / system script { run global-config; run global-config-overlay; } + } on-error={ + $LogPrintExit2 error $0 ("Reloading global configuration and overlay failed!" . \ + " Syntax error or missing overlay\?") false; + } } + :if ($ScriptVal->"name" = "global-functions") do={ + $LogPrintExit2 info $0 ("Reloading global functions.") false; + :do { + / system script run global-functions; + } on-error={ + $LogPrintExit2 error $0 ("Reloading global functions failed!") false; + } + } + } else={ + $LogPrintExit2 warning $0 ("Syntax validation for script " . $ScriptVal->"name" . \ + " failed! Ignoring!") false; } } else={ $LogPrintExit2 warning $0 ("Looks like new script " . $ScriptVal->"name" . \ From c9854fa800ad53b50ce7419ba58facd3fb4c0b28 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Feb 2021 11:14:46 +0100 Subject: [PATCH 0643/2612] doc/unattended-lte-firmware-upgrade: broadband connection is required! --- doc/unattended-lte-firmware-upgrade.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/unattended-lte-firmware-upgrade.md b/doc/unattended-lte-firmware-upgrade.md index 68c74a1..65801a6 100644 --- a/doc/unattended-lte-firmware-upgrade.md +++ b/doc/unattended-lte-firmware-upgrade.md @@ -19,6 +19,10 @@ starting the upgrade process over the broadband connection is supported. Requirements and installation ----------------------------- +The firmware is downloaded over the air, so a working broadband connection +on the lte interface to be updated is required! Having internet access from +different gateway is not sufficient! + Just install the script: $ScriptInstallUpdate unattended-lte-firmware-upgrade; From fcbfb568daa63dc3f9c2ca78b0ef7e1f66d74367 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Feb 2021 11:51:19 +0100 Subject: [PATCH 0644/2612] unattended-lte-firmware-upgrade: act on running interfaces only The firmware is downloaded over the air, so broadband connection is required. --- unattended-lte-firmware-upgrade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index cb8f87e..574874c 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -6,7 +6,7 @@ # schedule unattended lte firmware upgrade # https://git.eworm.de/cgit/routeros-scripts/about/doc/unattended-lte-firmware-upgrade.md -:foreach Interface in=[ / interface lte find ] do={ +:foreach Interface in=[ / interface lte find where running ] do={ :local Firmware; :local IntName [ / interface lte get $Interface name ]; :do { From 9c9c9f4d347a253ebbe1df75d3a98aeee235fa89 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Feb 2021 11:58:28 +0100 Subject: [PATCH 0645/2612] unattended-lte-firmware-upgrade: be more verbose --- unattended-lte-firmware-upgrade | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index 574874c..93638c3 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -29,5 +29,7 @@ } / system scheduler add name=($IntName . "-firmware-upgrade") start-time=startup interval=2s \ on-event=(":global LTEFirmwareUpgrade; \$LTEFirmwareUpgrade \"" . $IntName . "\";"); + } else={ + :log info ("The LTE firmware is up to date on interface " . $IntName . "."); } } From 464dd55bbdc008f0e8c8ac1b8405e9dc880506c4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Feb 2021 12:21:38 +0100 Subject: [PATCH 0646/2612] unattended-lte-firmware-upgrade: skip interface on missing firmware information --- unattended-lte-firmware-upgrade | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index 93638c3..0bac0a2 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -15,21 +15,25 @@ :log debug ("Could not get latest LTE firmware version for interface " . $IntName . "."); } - :if (($Firmware->"installed") != ($Firmware->"latest")) do={ - :log info ("Scheduling LTE firmware upgrade for interface " . $IntName . "."); - :global LTEFirmwareUpgrade do={ - :global LTEFirmwareUpgrade; - :set LTEFirmwareUpgrade; - / system scheduler remove ($1 . "-firmware-upgrade"); - / interface lte firmware-upgrade $1 upgrade=yes; - :log info ("LTE firmware upgrade finished, waiting for installation before reset."); - :delay 150s; - / interface lte at-chat $1 input="AT+RESET"; - :log info ("Reset device, waiting to finish and reconnect."); + :if ([ :typeof $Firmware ] = "array") do={ + :if (($Firmware->"installed") != ($Firmware->"latest")) do={ + :log info ("Scheduling LTE firmware upgrade for interface " . $IntName . "."); + :global LTEFirmwareUpgrade do={ + :global LTEFirmwareUpgrade; + :set LTEFirmwareUpgrade; + / system scheduler remove ($1 . "-firmware-upgrade"); + / interface lte firmware-upgrade $1 upgrade=yes; + :log info ("LTE firmware upgrade finished, waiting for installation before reset."); + :delay 150s; + / interface lte at-chat $1 input="AT+RESET"; + :log info ("Reset device, waiting to finish and reconnect."); + } + / system scheduler add name=($IntName . "-firmware-upgrade") start-time=startup interval=2s \ + on-event=(":global LTEFirmwareUpgrade; \$LTEFirmwareUpgrade \"" . $IntName . "\";"); + } else={ + :log info ("The LTE firmware is up to date on interface " . $IntName . "."); } - / system scheduler add name=($IntName . "-firmware-upgrade") start-time=startup interval=2s \ - on-event=(":global LTEFirmwareUpgrade; \$LTEFirmwareUpgrade \"" . $IntName . "\";"); } else={ - :log info ("The LTE firmware is up to date on interface " . $IntName . "."); + :log info ("No LTE firmware information available for interface " . $IntName . "."); } } From c48ad50f24458b28f4fc2f7d2845c519b541673a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Feb 2021 14:44:54 +0100 Subject: [PATCH 0647/2612] global-functions: introduce and use $ValidateSyntax --- global-functions | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/global-functions b/global-functions index 8396f60..aba1cff 100644 --- a/global-functions +++ b/global-functions @@ -47,6 +47,7 @@ :global SymbolForNotification; :global TimeIsSync; :global UrlEncode; +:global ValidateSyntax; :global VersionToNum; :global WaitDefaultRouteReachable; :global WaitDNSResolving; @@ -615,6 +616,7 @@ :global ScriptInstallUpdate; :global SendNotification; :global SymbolForNotification; + :global ValidateSyntax; :if ([ $CertificateAvailable "R3" ] = false) do={ $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; @@ -670,13 +672,7 @@ :if ([ :len $SourceNew ] > 0) do={ :if ($SourceNew != $ScriptVal->"source") do={ :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ - :local SyntaxOK true; - :do { - [ :parse (":local ValidateFunction do={ " . $SourceNew . " }") ] - } on-error={ - :set SyntaxOK false; - } - :if ($SyntaxOK = true) do={ + :if ([ $ValidateSyntax $SourceNew ] = true) do={ :local DontRequirePermissions \ ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); $LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; @@ -1030,6 +1026,18 @@ :return $Return; } +# basic syntax validation +:set ValidateSyntax do={ + :local Code [ :tostr $1 ]; + + :do { + [ :parse (":local Validate do={ " . $Code . " }") ]; + } on-error={ + :return false; + } + :return true; +} + # convert version string to numeric value :set VersionToNum do={ :local Input [ :tostr $1 ]; From 8e005452672bda1f1cd7fd2e7957ce6bdff934ee Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Feb 2021 14:52:50 +0100 Subject: [PATCH 0648/2612] global-functions: $ScriptInstallUpdate: validate syntax of changelog and migration code --- global-functions | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/global-functions b/global-functions index aba1cff..7de3d72 100644 --- a/global-functions +++ b/global-functions @@ -730,27 +730,40 @@ :if ($Result->"status" = "finished") do={ :set ChangeLogCode ($Result->"data"); } - :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); - [ :parse $ChangeLogCode ]; - :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ - :local Migration ($GlobalConfigMigration->[ :tostr $I ]); - :if ([ :typeof $Migration ] = "str") do={ - $LogPrintExit2 info $0 ("Applying migration: " . $Migration) false; - [ :parse $Migration ]; - } - :set NotificationMessage ($NotificationMessage . \ - "\n " . [ $IfThenElse ($NotificationsWithSymbols = true) ("\E2\97\8F") "*" ] . " " . \ - $GlobalConfigChanges->[ :tostr $I ]); - $LogPrintExit2 info $0 ("Change: " . $GlobalConfigChanges->[ :tostr $I ]) false; - } - :set GlobalConfigChanges; - :set GlobalConfigMigration; } on-error={ $LogPrintExit2 warning $0 ("Failed fetching changes!") false; :set NotificationMessage ($NotificationMessage . \ "\n\nChanges are not available."); } + :if ([ :len $ChangeLogCode ] > 0) do={ + :if ([ $ValidateSyntax $ChangeLogCode ] = true) do={ + :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); + [ :parse $ChangeLogCode ]; + :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ + :local Migration ($GlobalConfigMigration->[ :tostr $I ]); + :if ([ :typeof $Migration ] = "str") do={ + :if ([ $ValidateSyntax $Migration ] = true) do={ + $LogPrintExit2 info $0 ("Applying migration: " . $Migration) false; + [ :parse $Migration ]; + } else={ + $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed syntax validation!") false; + } + } + :set NotificationMessage ($NotificationMessage . \ + "\n " . [ $IfThenElse ($NotificationsWithSymbols = true) ("\E2\97\8F") "*" ] . " " . \ + $GlobalConfigChanges->[ :tostr $I ]); + $LogPrintExit2 info $0 ("Change: " . $GlobalConfigChanges->[ :tostr $I ]) false; + } + :set GlobalConfigChanges; + :set GlobalConfigMigration; + } else={ + $LogPrintExit2 warning $0 ("The changelog failed syntax validation!") false; + :set NotificationMessage ($NotificationMessage . \ + "\n\nChanges are not available."); + } + } + :local Link; :if ($IDonate != true) do={ :set NotificationMessage ($NotificationMessage . \ From e76b52e3b08d1e66c47a067040071ffb95b1b528 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Feb 2021 15:51:29 +0100 Subject: [PATCH 0649/2612] sms-action: use $ValidateSyntax --- sms-action | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sms-action b/sms-action index 2d2600d..e48c632 100644 --- a/sms-action +++ b/sms-action @@ -13,6 +13,7 @@ :global SmsAction; :global LogPrintExit2; +:global ValidateSyntax; :local Action $action; @@ -21,8 +22,10 @@ } :local Code ($SmsAction->$Action); -:local Parsed [ :parse $Code ]; - -:log info ("Acting on SMS action '" . $Action . "': " . $Code); -:delay 1s; -$Parsed; +:if ([ $ValidateSyntax $Code ] = true) do={ + :log info ("Acting on SMS action '" . $Action . "': " . $Code); + :delay 1s; + [ :parse $Code ]; +} else={ + $LogPrintExit2 warning $0 ("The code for action '" . $Action . "' failed syntax validation!") false; +} From cf87be70f9836bfcf93ef33f4f2cb3eb5f431697 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Feb 2021 16:01:39 +0100 Subject: [PATCH 0650/2612] mode-button: use $ValidateSyntax --- mode-button | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/mode-button b/mode-button index 8d96fcd..e2da374 100644 --- a/mode-button +++ b/mode-button @@ -25,6 +25,7 @@ :global LogPrintExit2; :global ModeButtonScheduler; + :global ValidateSyntax; :local LEDInvert do={ :global ModeButtonLED; @@ -46,19 +47,23 @@ / system scheduler remove ModeButtonScheduler; :if ([ :len $Code ] > 0) do={ - $LogPrintExit2 info $0 ("Acting on " . $Count . " mode-button presses: " . $Code) false; + :if ([ $ValidateSyntax $Code ] = true) do={ + $LogPrintExit2 info $0 ("Acting on " . $Count . " mode-button presses: " . $Code) false; - :for I from=1 to=$Count do={ - $LEDInvert; - :if ([ / system routerboard settings get silent-boot ] = false) do={ - :beep length=200ms; + :for I from=1 to=$Count do={ + $LEDInvert; + :if ([ / system routerboard settings get silent-boot ] = false) do={ + :beep length=200ms; + } + :delay 200ms; + $LEDInvert; + :delay 200ms; } - :delay 200ms; - $LEDInvert; - :delay 200ms; - } - [ :parse $Code ]; + [ :parse $Code ]; + } else={ + $LogPrintExit2 warning $0 ("The code for " . $Count . " mode-button presses failed syntax validation!") false; + } } else={ $LogPrintExit2 info $0 ("No action defined for " . $Count . " mode-button presses.") false; } From 99d3e5d578bb73be020c718a5816f221b58a5f14 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Feb 2021 16:05:34 +0100 Subject: [PATCH 0651/2612] netwatch-notify: use $ValidateSyntax --- netwatch-notify | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 6bd8953..ef67804 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -17,6 +17,7 @@ :global ParseKeyValueStore; :global SendNotification; :global SymbolForNotification; +:global ValidateSyntax; :if ([ :typeof $NetwatchNotify ] = "nothing") do={ :set NetwatchNotify [ :toarray "" ]; @@ -41,8 +42,12 @@ ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ - $LogPrintExit2 info $0 ("Running hook on host " . $HostName . " up: " . ($HostInfo->"up-hook")) false; - [ :parse ($HostInfo->"up-hook") ]; + :if ([ $ValidateSyntax ($HostInfo->"up-hook") ] = true) do={ + $LogPrintExit2 info $0 ("Running hook on host " . $HostName . " up: " . ($HostInfo->"up-hook")) false; + [ :parse ($HostInfo->"up-hook") ]; + } else={ + $LogPrintExit2 warning $0 ("The up-hook for host " . $HostName . " failed syntax validation.") false; + } } } :set ($Metric->"notified") false; @@ -75,8 +80,12 @@ ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :set ($Metric->"notified") true; :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ - $LogPrintExit2 info $0 ("Running hook on host " . $HostName . " down: " . ($HostInfo->"down-hook")) false; - [ :parse ($HostInfo->"down-hook") ]; + :if ([ $ValidateSyntax ($HostInfo->"down-hook") ] = true) do={ + $LogPrintExit2 info $0 ("Running hook on host " . $HostName . " down: " . ($HostInfo->"down-hook")) false; + [ :parse ($HostInfo->"down-hook") ]; + } else={ + $LogPrintExit2 warning $0 ("The down-hook for host " . $HostName . " failed syntax validation.") false; + } } } } From a019ff861eae84d3c026861807bbde3d995d41ee Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Feb 2021 20:59:27 +0100 Subject: [PATCH 0652/2612] global-functions: $ValidateSyntax: add line breaks This makes sure the closing curly bracket is not hidden in comment. --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 7de3d72..92d8fea 100644 --- a/global-functions +++ b/global-functions @@ -1044,7 +1044,7 @@ :local Code [ :tostr $1 ]; :do { - [ :parse (":local Validate do={ " . $Code . " }") ]; + [ :parse (":local Validate do={\n" . $Code . "\n}") ]; } on-error={ :return false; } From 7829a6c33adfc0391a88d05e070d3c30397b4444 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 3 Mar 2021 10:17:45 +0100 Subject: [PATCH 0653/2612] global-functions: $UrlEncode: simplify code --- global-functions | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/global-functions b/global-functions index 92d8fea..382722a 100644 --- a/global-functions +++ b/global-functions @@ -1016,24 +1016,25 @@ # url encoding :set UrlEncode do={ :local Input [ :tostr $1 ]; + + :if ([ :len $Input ] = 0) do={ + :return ""; + } + :local Return ""; + :local Chars "\n\r !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~"; + :local Subs { "%0A"; "%0D"; "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27"; + "%28"; "%29"; "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; "%3F"; + "%40"; "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; "%7E" }; - :if ([ :len $Input ] > 0) do={ - :local Chars "\n\r !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~"; - :local Subs { "%0A"; "%0D"; "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27"; - "%28"; "%29"; "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; - "%3F"; "%40"; "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; - "%7E" }; + :for I from=0 to=([ :len $Input ] - 1) do={ + :local Char [ :pick $Input $I ]; + :local Replace [ :find $Chars $Char ]; - :for I from=0 to=([ :len $Input ] - 1) do={ - :local Char [ :pick $Input $I ]; - :local Replace [ :find $Chars $Char ]; - - :if ([ :len $Replace ] > 0) do={ - :set Char ($Subs->$Replace); - } - :set Return ($Return . $Char); + :if ([ :typeof $Replace ] = "num") do={ + :set Char ($Subs->$Replace); } + :set Return ($Return . $Char); } :return $Return; From e65802007fc95613d9b2e0dbe68dd55c70f97fd1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 3 Mar 2021 10:42:14 +0100 Subject: [PATCH 0654/2612] global-functions: introduce and use $QuotedPrintable Some mail clients do not like unencoded utf-8 in subject... Let's encode in quoted-printable to fix. --- global-functions | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 382722a..177cd4f 100644 --- a/global-functions +++ b/global-functions @@ -35,6 +35,7 @@ :global LogPrintExit2; :global MkDir; :global ParseKeyValueStore; +:global QuotedPrintable; :global RandomDelay; :global RequiredRouterOS; :global ScriptFromTerminal; @@ -550,6 +551,42 @@ :return $Result; } +# convert string to quoted-printable +:global QuotedPrintable do={ + :local Input [ :tostr $1 ]; + + :if ([ :len $Input ] = 0) do={ + :return $Input; + } + + :local Return ""; + :local Chars ("\80\81\82\83\84\85\86\87\88\89\8A\8B\8C\8D\8E\8F\90\91\92\93\94\95\96\97" . \ + "\98\99\9A\9B\9C\9D\9E\9F\A0\A1\A2\A3\A4\A5\A6\A7\A8\A9\AA\AB\AC\AD\AE\AF\B0\B1\B2\B3" . \ + "\B4\B5\B6\B7\B8\B9\BA\BB\BC\BD\BE\BF\C0\C1\C2\C3\C4\C5\C6\C7\C8\C9\CA\CB\CC\CD\CE\CF" . \ + "\D0\D1\D2\D3\D4\D5\D6\D7\D8\D9\DA\DB\DC\DD\DE\DF\E0\E1\E2\E3\E4\E5\E6\E7\E8\E9\EA\EB" . \ + "\EC\ED\EE\EF\F0\F1\F2\F3\F4\F5\F6\F7\F8\F9\FA\FB\FC\FD\FE\FF"); + :local Hex { "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"; "9"; "A"; "B"; "C"; "D"; "E"; "F" }; + + :for I from=0 to=([ :len $Input ] - 1) do={ + :local Char [ :pick $Input $I ]; + :local Replace [ :find $Chars $Char ]; + + :if ($Char = "=") do={ + :set Char "=3D"; + } + :if ([ :typeof $Replace ] = "num") do={ + :set Char ("=" . ($Hex->($Replace / 16 + 8)) . ($Hex->($Replace % 16))); + } + :set Return ($Return . $Char); + } + + :if ($Input = $Return) do={ + :return $Input; + } + + :return ("=\?utf-8\?Q\?" . $Return . "\?="); +} + # delay a random amount of seconds :set RandomDelay do={ :global GetRandomNumber; @@ -806,8 +843,9 @@ :global EmailGeneralCc; :global EmailQueue; - :global LogPrintExit2; :global IfThenElse; + :global LogPrintExit2; + :global QuotedPrintable; :if ([ :len $EmailGeneralTo ] = 0) do={ :return false; @@ -818,7 +856,8 @@ } :local Signature [ / system note get note ]; :set ($EmailQueue->[ :len $EmailQueue ]) { - to=$EmailGeneralTo; cc=$EmailGeneralCc; subject=("[" . $Identity . "] " . $Subject); + to=$EmailGeneralTo; cc=$EmailGeneralCc; + subject=[ $QuotedPrintable ("[" . $Identity . "] " . $Subject) ]; body=($Message . \ [ $IfThenElse ([ :len $Link ] > 0) ("\n\n" . $Link) "" ] . \ [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]) }; From 842c44b10a1d73f9020665b3f8c1eb7855a3a41e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 3 Mar 2021 11:15:10 +0100 Subject: [PATCH 0655/2612] global-functions: $DNSIsResolving: have a final return --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 177cd4f..9e4d118 100644 --- a/global-functions +++ b/global-functions @@ -230,10 +230,10 @@ :do { :resolve "low-ttl.eworm.de"; - :return true; } on-error={ :return false; } + :return true; } # download package from upgrade server From 9ab20bb92700339977e3920890500f67d81152dd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 4 Mar 2021 00:31:58 +0100 Subject: [PATCH 0656/2612] global-config-overlay: remove magic This allows to drop the ignore flag. --- INITIAL-COMMANDS.md | 1 - README.md | 4 ---- global-config-overlay | 5 ++--- global-config.changes | 2 +- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 9a5d6c8..fa32654 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -17,7 +17,6 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } - / system script set comment="ignore" global-config-overlay; / system script { run global-config; run global-config-overlay; run global-functions; } / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }"; :global CertificateNameByCN; diff --git a/README.md b/README.md index 14b32db..090aab9 100644 --- a/README.md +++ b/README.md @@ -92,10 +92,6 @@ Now let's download the main scripts and add them in configuration on the fly. [admin@MikroTik] > :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } -Mark `global-config-overlay` not to be overwritten by future updates. - - [admin@MikroTik] > / system script set comment="ignore" global-config-overlay - The configuration needs to be tweaked for your needs. Edit `global-config-overlay`, copy configuration from [`global-config`](global-config) (the one without `-overlay`). diff --git a/global-config-overlay b/global-config-overlay index 10376c7..850e6d8 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -1,5 +1,4 @@ -#!rsc by RouterOS -# RouterOS script: global-config-overlay +# Overlay for global configuration by RouterOS Scripts # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # @@ -8,7 +7,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -# Comment or remove to disable change notifications. +# Comment or remove to disable news and change notifications. :global GlobalConfigVersion 47; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 2bc18c0..2dc68f7 100644 --- a/global-config.changes +++ b/global-config.changes @@ -1,4 +1,4 @@ -# RouterOS global-config changes +# News, changes and migration by RouterOS Scripts # Copyright (c) 2019-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md From d1741c99fe7dc803a9597e05b8b97a14843cb412 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 4 Mar 2021 12:06:47 +0100 Subject: [PATCH 0657/2612] global-functions: $ScriptInstallUpdate: run migration unconditionally We want the migration to run even if the notification is disabled. --- global-functions | 95 +++++++++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 42 deletions(-) diff --git a/global-functions b/global-functions index 9e4d118..2f68148 100644 --- a/global-functions +++ b/global-functions @@ -666,6 +666,7 @@ } } + :local ExpectedConfigVersionBefore $ExpectedConfigVersion; :local ScriptInstallUpdateBefore [ :tostr $ScriptInstallUpdate ]; :foreach Script in=[ / system script find where source~"^#!rsc( by RouterOS)\?\n" ] do={ @@ -748,18 +749,12 @@ } } - :if ($SentConfigChangesNotification!=$ExpectedConfigVersion && \ - $GlobalConfigVersion < $ExpectedConfigVersion) do={ + :if ($ExpectedConfigVersionBefore != $ExpectedConfigVersion) do={ :global GlobalConfigChanges; :global GlobalConfigMigration; :local ChangeLogCode; - :local NotificationMessage ("Current configuration on " . $Identity . \ - " is out of date. Please update global-config-overlay, then increase " . \ - "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \ - ") to " . $ExpectedConfigVersion . " and re-run global-config-overlay."); - $LogPrintExit2 info $0 ($NotificationMessage) false; - $LogPrintExit2 debug $0 ("Fetching changelog.") false; + $LogPrintExit2 debug $0 ("Fetching news, changes and migration.") false; :do { :local Result [ / tool fetch check-certificate=yes-without-crl \ ($ScriptUpdatesBaseUrl . "global-config.changes" . $ScriptUpdatesUrlSuffix) \ @@ -768,52 +763,68 @@ :set ChangeLogCode ($Result->"data"); } } on-error={ - $LogPrintExit2 warning $0 ("Failed fetching changes!") false; - :set NotificationMessage ($NotificationMessage . \ - "\n\nChanges are not available."); + $LogPrintExit2 warning $0 ("Failed fetching news, changes and migration!") false; } :if ([ :len $ChangeLogCode ] > 0) do={ :if ([ $ValidateSyntax $ChangeLogCode ] = true) do={ - :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); [ :parse $ChangeLogCode ]; - :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ - :local Migration ($GlobalConfigMigration->[ :tostr $I ]); - :if ([ :typeof $Migration ] = "str") do={ - :if ([ $ValidateSyntax $Migration ] = true) do={ - $LogPrintExit2 info $0 ("Applying migration: " . $Migration) false; - [ :parse $Migration ]; - } else={ - $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed syntax validation!") false; - } - } - :set NotificationMessage ($NotificationMessage . \ - "\n " . [ $IfThenElse ($NotificationsWithSymbols = true) ("\E2\97\8F") "*" ] . " " . \ - $GlobalConfigChanges->[ :tostr $I ]); - $LogPrintExit2 info $0 ("Change: " . $GlobalConfigChanges->[ :tostr $I ]) false; - } - :set GlobalConfigChanges; - :set GlobalConfigMigration; } else={ $LogPrintExit2 warning $0 ("The changelog failed syntax validation!") false; - :set NotificationMessage ($NotificationMessage . \ - "\n\nChanges are not available."); } } - :local Link; - :if ($IDonate != true) do={ - :set NotificationMessage ($NotificationMessage . \ - "\n\n==== donation hint ====\n" . \ - "This project is developed in private spare time and usage is " . \ - "free of charge for you. If you like the scripts and think this is " . \ - "of value for you or your business please consider a donation."); - :set Link "https://git.eworm.de/cgit/routeros-scripts/about/#donate"; + :if ([ :len $GlobalConfigMigration ] > 0) do={ + :for I from=($ExpectedConfigVersionBefore + 1) to=$ExpectedConfigVersion do={ + :local Migration ($GlobalConfigMigration->[ :tostr $I ]); + :if ([ :typeof $Migration ] = "str") do={ + :if ([ $ValidateSyntax $Migration ] = true) do={ + $LogPrintExit2 info $0 ("Applying migration for change " . $I . ": " . $Migration) false; + [ :parse $Migration ]; + } else={ + $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed syntax validation!") false; + } + } + } } - $SendNotification ([ $SymbolForNotification "pushpin" ] . "News and configuration changes") \ - $NotificationMessage $Link; - :set SentConfigChangesNotification $ExpectedConfigVersion; + :if ($SentConfigChangesNotification != $ExpectedConfigVersion && \ + $GlobalConfigVersion < $ExpectedConfigVersion) do={ + :local NotificationMessage ("Current configuration on " . $Identity . \ + " is out of date. Please update global-config-overlay, then increase " . \ + "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \ + ") to " . $ExpectedConfigVersion . " and re-run global-config-overlay."); + $LogPrintExit2 info $0 ($NotificationMessage) false; + + :if ([ :len $GlobalConfigChanges ] > 0) do={ + :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); + :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ + :local Change ($GlobalConfigChanges->[ :tostr $I ]); + :set NotificationMessage ($NotificationMessage . "\n " . \ + [ $IfThenElse ($NotificationsWithSymbols = true) ("\E2\97\8F") "*" ] . " " . $Change); + $LogPrintExit2 info $0 ("Change " . $I . ": " . $Change) false; + } + } else={ + :set NotificationMessage ($NotificationMessage . "\n\nNews and changes are not available."); + } + + :local Link; + :if ($IDonate != true) do={ + :set NotificationMessage ($NotificationMessage . \ + "\n\n==== donation hint ====\n" . \ + "This project is developed in private spare time and usage is " . \ + "free of charge for you. If you like the scripts and think this is " . \ + "of value for you or your business please consider a donation."); + :set Link "https://git.eworm.de/cgit/routeros-scripts/about/#donate"; + } + + $SendNotification ([ $SymbolForNotification "pushpin" ] . "News and configuration changes") \ + $NotificationMessage $Link; + :set SentConfigChangesNotification $ExpectedConfigVersion; + } + + :set GlobalConfigChanges; + :set GlobalConfigMigration; } :if ($ScriptInstallUpdateBefore != [ :tostr $ScriptInstallUpdate ]) do={ From f762d395ebd7ffe914ea3e95571e18cd7e1bcb85 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 4 Mar 2021 18:42:57 +0100 Subject: [PATCH 0658/2612] log-forward: skip multi-repeated messages --- log-forward | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/log-forward b/log-forward index def04e6..ecb55cc 100644 --- a/log-forward +++ b/log-forward @@ -37,18 +37,28 @@ $ScriptLock $0; $WaitFullyConnected; :local Count 0; +:local Duplicates false; :local Messages ""; :local MessageVal; +:local MessageDups [ :toarray "" ]; :foreach Message in=[ / log find where !(topics~$LogForwardFilter) !(message~$LogForwardFilterMessage) ] do={ :set MessageVal [ / log get $Message ]; :if ($LogForwardLast = ($MessageVal->".id")) do={ - :set Messages ""; :set Count 0; + :set Duplicates false; + :set Messages ""; + :set MessageDups [ :toarray "" ]; } else={ - :set Messages ($Messages . "\n" . $MessageVal->"time" . " " . \ - [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message"); + :local DupCount ($MessageDups->($MessageVal->"message")); + :if ($DupCount < 3) do={ + :set Messages ($Messages . "\n" . $MessageVal->"time" . " " . \ + [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message"); + } else={ + :set Duplicates true; + } + :set ($MessageDups->($MessageVal->"message")) ($DupCount + 1); :set Count ($Count + 1); } } @@ -57,7 +67,8 @@ $WaitFullyConnected; $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Log Forwarding") \ ("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) \ "this message" ("these " . $Count . " messages") ] . " after " . \ - [ / system resource get uptime ] . " uptime.\n" . $Messages); + [ / system resource get uptime ] . " uptime." . [ $IfThenElse ($Duplicates = true) \ + (" Multi-repeated messages have been skipped.") ] . "\n" . $Messages); :set LogForwardRateLimit ($LogForwardRateLimit + 10); :set LogForwardLast ($MessageVal->".id"); From b1647c760c202c79fc0d1f1be38914b6886fb91f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 4 Mar 2021 18:47:55 +0100 Subject: [PATCH 0659/2612] log-forward: list messages with 'black circle' --- log-forward | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/log-forward b/log-forward index ecb55cc..4332c2a 100644 --- a/log-forward +++ b/log-forward @@ -15,6 +15,7 @@ :global LogForwardFilterMessage; :global LogForwardLast; :global LogForwardRateLimit; +:global NotificationsWithSymbols; :global IfThenElse; :global LogPrintExit2; @@ -53,8 +54,8 @@ $WaitFullyConnected; } else={ :local DupCount ($MessageDups->($MessageVal->"message")); :if ($DupCount < 3) do={ - :set Messages ($Messages . "\n" . $MessageVal->"time" . " " . \ - [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message"); + :set Messages ($Messages . "\n" . [ $IfThenElse ($NotificationsWithSymbols = true) (" \E2\97\8F ") ] . \ + $MessageVal->"time" . " " . [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message"); } else={ :set Duplicates true; } From 44727842749c418165730b714ac87b2bc48265fa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 Mar 2021 23:16:39 +0100 Subject: [PATCH 0660/2612] global-functions: $CertificateAvailable: use pre-test loop This is required to test for root CA (without intermediate) directly. --- global-functions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 2f68148..042d89b 100644 --- a/global-functions +++ b/global-functions @@ -84,7 +84,7 @@ } :local CertVal [ / certificate get [ find where common-name=$CommonName ] ]; - :do { + :while (($CertVal->"akid") != "" && ($CertVal->"akid") != ($CertVal->"skid")) do={ :if ([ :len [ / certificate find where skid=($CertVal->"akid") ] ] = 0) do={ $LogPrintExit2 info $0 ("Certificate chain for \"" . $CommonName . \ "\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\".") false; @@ -93,7 +93,7 @@ } } :set CertVal [ / certificate get [ find where skid=($CertVal->"akid") ] ]; - } while=(($CertVal->"akid") != "" && ($CertVal->"akid") != ($CertVal->"skid")); + } :return true; } From d00f18dc8c94bbeff2e3fd981ae4b9e29e570152 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Mar 2021 21:21:40 +0100 Subject: [PATCH 0661/2612] log-forward: update filter to match mail with quoted-printable encoding --- global-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config b/global-config index 9c8dbea..f713b5c 100644 --- a/global-config +++ b/global-config @@ -56,7 +56,7 @@ # This defines a filter on log topics not to be forwarded. :global LogForwardFilter "(debug|info)"; # ... and the same for log message text. -:global LogForwardFilterMessage "(^\$|^Error sending e-mail <.* Log Forwarding>:)"; +:global LogForwardFilterMessage "(^\$|^Error sending e-mail .* Log Forwarding)"; #:global LogForwardFilterMessage "(^\$|message text|...)"; # Specify an address to enable auto update to version assumed safe. From baa096fe03440725f8b72912daa3df7c30a6dbc0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 15 Mar 2021 00:48:38 +0100 Subject: [PATCH 0662/2612] log-forward: filter e-mail error on log forwarding in script... ... and update the filter in global configuration. --- global-config | 8 +++++--- log-forward | 8 +++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/global-config b/global-config index f713b5c..107ef19 100644 --- a/global-config +++ b/global-config @@ -55,9 +55,11 @@ # This defines a filter on log topics not to be forwarded. :global LogForwardFilter "(debug|info)"; -# ... and the same for log message text. -:global LogForwardFilterMessage "(^\$|^Error sending e-mail .* Log Forwarding)"; -#:global LogForwardFilterMessage "(^\$|message text|...)"; +# ... and the same for log message text. Regular expressions are supported. +# Do *NOT* set an empty string - that will filter everything! +:global LogForwardFilterMessage []; +#:global LogForwardFilterMessage "message text"; +#:global LogForwardFilterMessage "(message text|another text|...)"; # Specify an address to enable auto update to version assumed safe. # The configured channel (bugfix, current, release-candidate) is appended. diff --git a/log-forward b/log-forward index 4332c2a..2866e2f 100644 --- a/log-forward +++ b/log-forward @@ -17,8 +17,10 @@ :global LogForwardRateLimit; :global NotificationsWithSymbols; +:global CharacterReplace; :global IfThenElse; :global LogPrintExit2; +:global QuotedPrintable; :global ScriptLock; :global SendNotification; :global SymbolForNotification; @@ -43,7 +45,11 @@ $WaitFullyConnected; :local MessageVal; :local MessageDups [ :toarray "" ]; -:foreach Message in=[ / log find where !(topics~$LogForwardFilter) !(message~$LogForwardFilterMessage) ] do={ +:local LogForwardFilterLogForwarding [ $CharacterReplace ("^Error sending e-mail <" . \ + [ $QuotedPrintable ("\\[" . $Identity . "\\] " . [ $SymbolForNotification "warning-sign" ] . \ + "Log Forwarding") ] . ">:") ("\?") ("\\\?") ]; +:foreach Message in=[ / log find where !(topics~$LogForwardFilter) !(message="") \ + !(message~$LogForwardFilterLogForwarding) !(message~$LogForwardFilterMessage) ] do={ :set MessageVal [ / log get $Message ]; :if ($LogForwardLast = ($MessageVal->".id")) do={ From 7c4ab95394094d35499429504c6d393df27f08a9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 17 Mar 2021 08:51:23 +0100 Subject: [PATCH 0663/2612] global-functions: introduce $EscapeForRegEx --- global-functions | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/global-functions b/global-functions index 042d89b..7b61f72 100644 --- a/global-functions +++ b/global-functions @@ -24,6 +24,7 @@ :global DeviceInfo; :global DNSIsResolving; :global DownloadPackage; +:global EscapeForRegEx; :global FlushEmailQueue; :global FlushTelegramQueue; :global GetMacVendor; @@ -289,6 +290,28 @@ :return false; } +# escape for regular expression +:set EscapeForRegEx do={ + :local Input [ :tostr $1 ]; + + :if ([ :len $Input ] = 0) do={ + :return ""; + } + + :local Return ""; + :local Chars "^.[]\$()|*+\?{}\\"; + + :for I from=0 to=([ :len $Input ] - 1) do={ + :local Char [ :pick $Input $I ]; + :if ([ :find $Chars $Char ]) do={ + :set Char ("\\" . $Char); + } + :set Return ($Return . $Char); + } + + :return $Return; +} + # flush e-mail queue :set FlushEmailQueue do={ :global EmailQueue; From 5610926d0af994aad826dc031ebbd587144cb965 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 17 Mar 2021 08:55:33 +0100 Subject: [PATCH 0664/2612] log-forward: use $EscapeForRegEx --- log-forward | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/log-forward b/log-forward index 2866e2f..8842c7c 100644 --- a/log-forward +++ b/log-forward @@ -17,7 +17,7 @@ :global LogForwardRateLimit; :global NotificationsWithSymbols; -:global CharacterReplace; +:global EscapeForRegEx; :global IfThenElse; :global LogPrintExit2; :global QuotedPrintable; @@ -45,9 +45,9 @@ $WaitFullyConnected; :local MessageVal; :local MessageDups [ :toarray "" ]; -:local LogForwardFilterLogForwarding [ $CharacterReplace ("^Error sending e-mail <" . \ - [ $QuotedPrintable ("\\[" . $Identity . "\\] " . [ $SymbolForNotification "warning-sign" ] . \ - "Log Forwarding") ] . ">:") ("\?") ("\\\?") ]; +:local LogForwardFilterLogForwarding ("^" . [ $EscapeForRegEx ("Error sending e-mail <" . \ + [ $QuotedPrintable ("[" . $Identity . "] " . [ $SymbolForNotification "warning-sign" ] . \ + "Log Forwarding") ] . ">:") ]); :foreach Message in=[ / log find where !(topics~$LogForwardFilter) !(message="") \ !(message~$LogForwardFilterLogForwarding) !(message~$LogForwardFilterMessage) ] do={ :set MessageVal [ / log get $Message ]; From f77213c6d0214d0fe7010c55cf46664459b41c3c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 21 Mar 2021 22:22:52 +0100 Subject: [PATCH 0665/2612] check-certificates: be more verbose when attempting to renew --- check-certificates | 1 + 1 file changed, 1 insertion(+) diff --git a/check-certificates b/check-certificates index 68be7ee..d51cdaa 100644 --- a/check-certificates +++ b/check-certificates @@ -40,6 +40,7 @@ $WaitFullyConnected; :if ([ :len $CertRenewUrl ] = 0) do={ $LogPrintExit2 info $0 ("No CertRenewUrl given.") true; } + $LogPrintExit2 info $0 ("Attempting to renew certificate " . ($CertVal->"name") . ".") false; :foreach Type in={ ".pem"; ".p12" } do={ :local CertFileName ([ $UrlEncode ($CertVal->"common-name") ] . $Type); From b55cdfb5667db7206ab917b649a881e6f7bc7fec Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 21 Mar 2021 22:27:31 +0100 Subject: [PATCH 0666/2612] check-certificates: silence certificate import --- check-certificates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index d51cdaa..f99b20a 100644 --- a/check-certificates +++ b/check-certificates @@ -49,7 +49,7 @@ $WaitFullyConnected; ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; $WaitForFile $CertFileName; :foreach PassPhrase in=$CertRenewPass do={ - / certificate import file-name=$CertFileName passphrase=$PassPhrase; + / certificate import file-name=$CertFileName passphrase=$PassPhrase as-value; } / file remove [ find where name=$CertFileName ]; From 025f14ae13c241a6f0a4c4ccd0516d0edf985013 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 21 Mar 2021 22:28:09 +0100 Subject: [PATCH 0667/2612] global-functions: CertificateDownload: silence certificate import --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 7b61f72..387e4c0 100644 --- a/global-functions +++ b/global-functions @@ -120,7 +120,7 @@ $UrlFileName . $ScriptUpdatesUrlSuffix) \ dst-path=$LocalFileName as-value; $WaitForFile $LocalFileName; - / certificate import file-name=$LocalFileName passphrase=""; + / certificate import file-name=$LocalFileName passphrase="" as-value; / file remove $LocalFileName; :foreach Cert in=[ / certificate find where name~("^" . $LocalFileName . "_[0-9]+\$") ] do={ From 7fee37f57e92065acb6032ecc11396e020ce4bc8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 12 Apr 2021 23:40:17 +0200 Subject: [PATCH 0668/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index a78b0df..92cf2e7 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -21,6 +21,7 @@ Add yourself to the list, * Christoph Boss (@Kampfwurst) * Klaus Michael RÃŧbsam * Linux-Schmie.de Michael Gisbers +* Manuel Kuhn * Marek ÄŒÃĄbÃĄk * Reiner Vehrenkamp From 625d1dda120cda02977b9f306c108755336ab4ec Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 26 Apr 2021 16:33:41 +0200 Subject: [PATCH 0669/2612] check-routeros-update: silence check-for-updates, but be more verbose --- check-routeros-update | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/check-routeros-update b/check-routeros-update index 9dcef1d..27e346a 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -46,13 +46,18 @@ $WaitFullyConnected; :error "A reboot for update is already scheduled."; } -/ system package update check-for-updates without-paging; +$LogPrintExit2 debug $0 ("Checking for updates...") false; +/ system package update check-for-updates without-paging as-value; :local Update [ / system package update get ]; :if ([ :len ($Update->"latest-version") ] = 0) do={ $LogPrintExit2 info $0 ("An empty string is not a valid version.") true; } +:if (($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"); From 96613e9bdd3fea3722ac807b01565d274bc82da0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 26 Apr 2021 16:40:02 +0200 Subject: [PATCH 0670/2612] global-functions: $LogPrintExit: add deprecation warning --- global-functions | 1 + 1 file changed, 1 insertion(+) diff --git a/global-functions b/global-functions index 387e4c0..855221e 100644 --- a/global-functions +++ b/global-functions @@ -486,6 +486,7 @@ :set LogPrintExit do={ :global LogPrintExit2; + $LogPrintExit2 warning $0 ("This function is deprecated. Please use \$LogPrintExit2 instead.") false; $LogPrintExit2 $1 "unknown" $2 $3; } From a90511cff95bae67682f8b2c242ad3b74e4740b3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 08:57:05 +0200 Subject: [PATCH 0671/2612] check-routeros-update: be verbose when run from terminal only --- check-routeros-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-routeros-update b/check-routeros-update index 27e346a..5109e30 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -54,7 +54,7 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; $LogPrintExit2 info $0 ("An empty string is not a valid version.") true; } -:if (($Update->"installed-version") = ($Update->"latest-version")) do={ +:if ([ $ScriptFromTerminal $0 ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={ $LogPrintExit2 info $0 ("System is already up to date.") true; } From 99f828e7c0944538e3e06841dcfca0ff6fe29ceb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Apr 2021 12:05:04 +0200 Subject: [PATCH 0672/2612] add logo This should be displayed by Gitlab now... Also it is the logo we use for the Telegram group. --- logo.png | Bin 0 -> 3727 bytes logo.svg | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 logo.png create mode 100644 logo.svg diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..cfe91be6063926b3ecc641d0d9909dda3134f06c GIT binary patch literal 3727 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 + + + + + + + + + image/svg+xml + + + + + + + + + + #!rsc + + + + + + + + From d4c9d1c577d14991a63f285e57fcf2cfaa2d5cd4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Apr 2021 13:57:04 +0200 Subject: [PATCH 0673/2612] README: add logo --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 090aab9..b030d08 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ RouterOS Scripts [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/watchers) +![RouterOS Scripts Logo](logo.png) + [RouterOS](https://mikrotik.com/software) is the operating system developed by [MikroTik](https://mikrotik.com/aboutus) for networking tasks. This repository holds a number of [scripts](https://wiki.mikrotik.com/wiki/Manual:Scripting) From c7a2eecd3c875e8225da13a83cfd37c390ee7082 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 17:46:03 +0200 Subject: [PATCH 0674/2612] global-functions: introduce $SendEMail2, $SendNotification2 & $SendTelegram2 These accept just one array as argument. Adding new features is possible without breaking the API. These calls are the same for now: $SendNotification "Subject..." "Message..."; $SendNotification2 ({ subject="Subject..."; message="Message..." }); But the latter will bring more features in future. --- global-functions | 71 +++++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/global-functions b/global-functions index 855221e..b8a7dad 100644 --- a/global-functions +++ b/global-functions @@ -43,8 +43,11 @@ :global ScriptInstallUpdate; :global ScriptLock; :global SendEMail; +:global SendEMail2; :global SendNotification; +:global SendNotification2; :global SendTelegram; +:global SendTelegram2; :global SymbolByUnicodeName; :global SymbolForNotification; :global TimeIsSync; @@ -867,11 +870,16 @@ } } -# send notification via e-mail +# send notification via e-mail - expects at lease two string arguments :set SendEMail do={ - :local Subject [ :tostr $1 ]; - :local Message [ :tostr $2 ]; - :local Link [ :tostr $3 ]; + :global SendEMail2; + + $SendEMail2 ({ subject=$1; message=$2; link=$3 }); +} + +# send notification via e-mail - expects one array argument +:set SendEMail2 do={ + :local Notification $1; :global Identity; :global EmailGeneralTo; @@ -892,9 +900,9 @@ :local Signature [ / system note get note ]; :set ($EmailQueue->[ :len $EmailQueue ]) { to=$EmailGeneralTo; cc=$EmailGeneralCc; - subject=[ $QuotedPrintable ("[" . $Identity . "] " . $Subject) ]; - body=($Message . \ - [ $IfThenElse ([ :len $Link ] > 0) ("\n\n" . $Link) "" ] . \ + subject=[ $QuotedPrintable ("[" . $Identity . "] " . ($Notification->"subject")) ]; + body=(($Notification->"message") . \ + [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]) }; :if ([ :len [ / system scheduler find where name="FlushEmailQueue" ] ] = 0) do={ / system scheduler add name=FlushEmailQueue interval=1s start-time=startup \ @@ -902,27 +910,34 @@ } } -# send notification via e-mail and telegram -# Note that attachment is ignored for telegram, silent is ignored for e-mail! +# send notification via e-mail and telegram - expects at lease two string arguments :set SendNotification do={ - :local Subject [ :tostr $1 ]; - :local Message [ :tostr $2 ]; - :local Link [ :tostr $3 ]; - :local Silent [ :tostr $4 ]; + :global SendNotification2; - :global SendEMail; - :global SendTelegram; - - $SendEMail $Subject $Message $Link; - $SendTelegram $Subject $Message $Link $Silent; + $SendNotification2 ({ subject=$1; message=$2; link=$3; silent=$4 }); } -# send notification via telegram +# send notification via e-mail and telegram - expects one array argument +:set SendNotification2 do={ + :local Notification $1; + + :global SendEMail2; + :global SendTelegram2; + + $SendEMail2 $Notification; + $SendTelegram2 $Notification; +} + +# send notification via telegram - expects at lease two string arguments :set SendTelegram do={ - :local Subject [ :tostr $1 ]; - :local Message [ :tostr $2 ]; - :local Link [ :tostr $3 ]; - :local Silent [ :tostr $4 ]; + :global SendTelegram2; + + $SendTelegram2 ({ subject=$1; message=$2; link=$3; silent=$4 }); +} + +# send notification via telegram - expects one array argument +:set SendTelegram2 do={ + :local Notification $1; :global Identity; :global TelegramChatId; @@ -975,8 +990,8 @@ } :local Truncated false; - :local LenLink [ :len $Link ]; - :local Text ("[" . $Identity . "] " . $Subject . "\n\n" . $Message); + :local LenLink [ :len ($Notification->"link") ]; + :local Text ("[" . $Identity . "] " . ($Notification->"subject") . "\n\n" . ($Notification->"message")); :local LenText [ :len $Text ]; :if ($LenText > (3968 - $LenLink)) do={ :set Text [ $EscapeMD ([ :pick $Text 0 (3840 - $LenLink) ] . "...") "body" ]; @@ -985,7 +1000,7 @@ :set Text [ $EscapeMD $Text "body" ]; } :if ($LenLink > 0) do={ - :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD $Link "hint" ]); + :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD ($Notification->"link") "hint" ]); } :if ($Truncated = true) do={ :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ @@ -1001,7 +1016,7 @@ } / tool fetch check-certificate=yes-without-crl output=none http-method=post \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ - http-data=("chat_id=" . $ChatId . "&disable_notification=" . $Silent . \ + http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; } on-error={ $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; @@ -1013,7 +1028,7 @@ [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ " " . [ / system clock get time ] . " and may be obsolete.") "hint" ]) ]); :set ($TelegramQueue->[ :len $TelegramQueue ]) { - chatid=$ChatId; parsemode=$ParseMode; text=$Text; silent=$Silent }; + chatid=$ChatId; parsemode=$ParseMode; text=$Text; silent=($Notification->"silent") }; :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ / system scheduler add name=FlushTelegramQueue interval=1m start-time=startup \ on-event=":global FlushTelegramQueue; \$FlushTelegramQueue;"; From 76f32e3927d2e40f2b6cc28f93186bf84d222799 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 20:37:33 +0200 Subject: [PATCH 0675/2612] global-functions: $ScriptInstallUpdate: use $SendNotification2 --- global-functions | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index b8a7dad..aa0ea07 100644 --- a/global-functions +++ b/global-functions @@ -678,7 +678,7 @@ :global LogPrintExit2; :global ParseKeyValueStore; :global ScriptInstallUpdate; - :global SendNotification; + :global SendNotification2; :global SymbolForNotification; :global ValidateSyntax; @@ -845,8 +845,8 @@ :set Link "https://git.eworm.de/cgit/routeros-scripts/about/#donate"; } - $SendNotification ([ $SymbolForNotification "pushpin" ] . "News and configuration changes") \ - $NotificationMessage $Link; + $SendNotification2 ({ subject=([ $SymbolForNotification "pushpin" ] . \ + "News and configuration changes"); message=$NotificationMessage; link=$Link }); :set SentConfigChangesNotification $ExpectedConfigVersion; } From 71976f2eb92c68d8754385b318162d55b9171817 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 20:58:19 +0200 Subject: [PATCH 0676/2612] check-certificates: use $SendNotification2 --- check-certificates | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/check-certificates b/check-certificates index f99b20a..ff93046 100644 --- a/check-certificates +++ b/check-certificates @@ -20,7 +20,7 @@ :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; :global UrlEncode; :global WaitForFile; @@ -95,15 +95,15 @@ $WaitFullyConnected; / certificate set $CertNew name=($CertVal->"name"); } - $SendNotification ([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed") \ - ("A certificate on " . $Identity . " has been renewed.\n\n" . \ + $SendNotification2 ({ subject=([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed"); \ + message=("A certificate on " . $Identity . " has been renewed.\n\n" . \ "Name: " . ($CertVal->"name") . "\n" . \ "CommonName: " . ($CertNewVal->"common-name") . "\n" . \ "Private key: " . [ $IfThenElse (($CertNewVal->"private-key") = true) "available" "missing" ] . "\n" . \ "Fingerprint: " . ($CertNewVal->"fingerprint") . "\n" . \ "Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ - "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]) "" "true"; + "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]); silent=true }); $LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " has been renewed.") false; } on-error={ $LogPrintExit2 debug $0 ("Could not renew certificate " . ($CertVal->"name") . ".") false; @@ -118,15 +118,15 @@ $WaitFullyConnected; } else={ :local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ]; - $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Certificate warning!") \ - ("A certificate on " . $Identity . " " . $State . ".\n\n" . \ + $SendNotification2 ({ subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning!"); \ + message=("A certificate on " . $Identity . " " . $State . ".\n\n" . \ "Name: " . ($CertVal->"name") . "\n" . \ "CommonName: " . ($CertVal->"common-name") . "\n" . \ "Private key: " . [ $IfThenElse (($CertNewVal->"private-key") = true) "available" "missing" ] . "\n" . \ "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ - "Expires in: " . [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ]); + "Expires in: " . [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ]) }); $LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " " . $State . \ ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; } From bf315c15f64d677ee879a6225d5985f6b8e25610 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 20:42:42 +0200 Subject: [PATCH 0677/2612] check-health: use $SendNotification2 --- check-health | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/check-health b/check-health index 761a72f..dba24d8 100644 --- a/check-health +++ b/check-health @@ -18,7 +18,7 @@ :global Identity; :global LogPrintExit2; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; :local FormatVoltage do={ @@ -42,10 +42,10 @@ [ :typeof $Voltage ] = "num") do={ :if ($CheckHealthLast->$Name * (100 + $CheckHealthVoltagePercent) < $Voltage * 100 || \ $CheckHealthLast->$Name * 100 > $Voltage * (100 + $CheckHealthVoltagePercent)) do={ - $SendNotification ([ $SymbolForNotification "high-voltage-sign" ] . "Health warning: " . $Name) \ - ("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ + $SendNotification2 ({ subject=([ $SymbolForNotification "high-voltage-sign" ] . "Health warning: " . $Name); \ + message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ "old value: " . [ $FormatVoltage ($CheckHealthLast->$Name) ] . "\n" . \ - "new value: " . [ $FormatVoltage $Voltage ]); + "new value: " . [ $FormatVoltage $Voltage ]) }); } } } @@ -56,13 +56,13 @@ [ :typeof $PSU ] = "str") do={ :if ($CheckHealthLast->$Name = "ok" && \ $PSU != "ok") do={ - $SendNotification ([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name) \ - ("The power supply unit '" . $Name . "' on " . $Identity . " failed!"); + $SendNotification2 ({ subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ + message=("The power supply unit '" . $Name . "' on " . $Identity . " failed!") }); } :if ($CheckHealthLast->$Name != "ok" && \ $PSU = "ok") do={ - $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name) \ - ("The power supply unit '" . $Name . "' on " . $Identity . " recovered!"); + $SendNotification2 ({ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ + message=("The power supply unit '" . $Name . "' on " . $Identity . " recovered!") }); } } } @@ -81,16 +81,16 @@ } :if ($Temperature > $CheckHealthTemperature->$Name && \ $CheckHealthTemperatureNotified->$Name != true) do={ - $SendNotification ([ $SymbolForNotification "fire" ] . "Health warning: " . $Name) \ - ("The " . $Name . " on " . $Identity . " is above threshold: " . \ - $Temperature . "\C2\B0" . "C"); + $SendNotification2 ({ subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ + message=("The " . $Name . " on " . $Identity . " is above threshold: " . \ + $Temperature . "\C2\B0" . "C") }); :set ($CheckHealthTemperatureNotified->$Name) true; } :if ($Temperature <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ $CheckHealthTemperatureNotified->$Name = true) do={ - $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name) \ - ("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ - $Temperature . "\C2\B0" . "C"); + $SendNotification2 ({ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ + message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ + $Temperature . "\C2\B0" . "C") }); :set ($CheckHealthTemperatureNotified->$Name) false; } } From 4fe11fadee928b40ea7d9a6f10fdfea9a49095ea Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 20:56:20 +0200 Subject: [PATCH 0678/2612] check-lte-firmware-upgrade: use $SendNotification2 --- check-lte-firmware-upgrade | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index f55ec5f..6b46502 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -15,7 +15,7 @@ :global CharacterReplace; :global LogPrintExit2; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; :foreach Interface in=[ / interface lte find ] do={ @@ -29,12 +29,12 @@ } else={ :if (($Firmware->"installed") != ($Firmware->"latest")) do={ :local Info [ / interface lte info $Interface once as-value ]; - $SendNotification ([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade") \ - ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ - "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ - "Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \ - "Installed: " . ($Firmware->"installed") . "\n" . \ - "Available: " . ($Firmware->"latest")) "" "true"; + $SendNotification2 ({ subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \ + message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \ + "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ + "Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \ + "Installed: " . ($Firmware->"installed") . "\n" . \ + "Available: " . ($Firmware->"latest")); silent=true }); :set SentLteFirmwareUpgradeNotification ($Firmware->"latest"); } } From 19ca17190d6b8b9eaa979e5547e58ef661f7dbb9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 20:51:04 +0200 Subject: [PATCH 0679/2612] check-routeros-update: use $SendNotification2 --- check-routeros-update | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index 5109e30..683f9be 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -19,7 +19,7 @@ :global DeviceInfo; :global LogPrintExit2; :global ScriptFromTerminal; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; :global VersionToNum; :global WaitFullyConnected; @@ -65,18 +65,18 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; :if ($NumInstalled < $NumLatest) do={ :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; - $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ - ("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ - ", updating on " . $Identity . "...") $Link "true"; + $SendNotification2 ({ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ + ", updating on " . $Identity . "..."); link=$Link; silent=true }); $DoUpdate; } :if ($SafeUpdateNeighbor = true && [ :len [ / ip neighbor find where \ version=($Update->"latest-version" . " (" . $Update->"channel" . ")") ] ] > 0) do={ $LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; - $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ - ("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \ - ", updating on " . $Identity . "...") $Link "true"; + $SendNotification2 ({ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + message=("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \ + ", updating on " . $Identity . "..."); link=$Link; silent=true }); $DoUpdate; } @@ -91,9 +91,9 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; } :if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={ $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; - $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ - ("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ - ", updating on " . $Identity . "...") $Link "true"; + $SendNotification2 ({ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + message=("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ + ", updating on " . $Identity . "..."); link=$Link; silent=true }); $DoUpdate; } } @@ -112,10 +112,10 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; $Update->"latest-version" . ".") true; } - $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ - ("A new RouterOS version " . ($Update->"latest-version") . \ + $SendNotification2 ({ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + message=("A new RouterOS version " . ($Update->"latest-version") . \ " is available for " . $Identity . ".\n\n" . \ - [ $DeviceInfo ]) $Link "true"; + [ $DeviceInfo ]); link=$Link; silent=true }); :set SentRouterosUpdateNotification ($Update->"latest-version"); } @@ -125,10 +125,10 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; $Update->"latest-version" . ".") true; } - $SendNotification ([ $SymbolForNotification "warning-sign" ] . "RouterOS version") \ - ("A different RouterOS version " . ($Update->"latest-version") . \ + $SendNotification2 ({ subject=([ $SymbolForNotification "warning-sign" ] . "RouterOS version"); \ + message=("A different RouterOS version " . ($Update->"latest-version") . \ " is available for " . $Identity . ", but it is a downgrade.\n\n" . \ - [ $DeviceInfo ]) $Link "true"; + [ $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"); From d6edf6c2d38255b7618d15124e3da790a8f5f414 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 20:53:54 +0200 Subject: [PATCH 0680/2612] cloud-backup: use $SendNotification2 --- cloud-backup | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cloud-backup b/cloud-backup index aa29faa..23fa164 100644 --- a/cloud-backup +++ b/cloud-backup @@ -18,7 +18,7 @@ :global LogPrintExit2; :global RandomDelay; :global ScriptFromTerminal; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; :global WaitFullyConnected; @@ -41,14 +41,14 @@ $WaitFullyConnected; } :local Cloud [ / system backup cloud get ([ find ]->0) ]; - $SendNotification ([ $SymbolForNotification "floppy-disk" ] . "Cloud backup") \ - ("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ + $SendNotification2 ({ subject=([ $SymbolForNotification "floppy-disk" ] . "Cloud backup"); \ + message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Name: " . $Cloud->"name" . "\n" . \ "Size: " . $Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)\n" . \ - "Download key: " . $Cloud->"secret-download-key") "" "true"; + "Download key: " . $Cloud->"secret-download-key"); silent=true }); } on-error={ - $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Cloud backup failed") \ - ("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]); + $SendNotification2 ({ subject=([ $SymbolForNotification "warning-sign" ] . "Cloud backup failed"); \ + message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); $LogPrintExit2 error $0 ("Failed uploading backup for " . $Identity . " to cloud!") true; } From 1ca3e8b59fbd4374ba9d94d83944411ef0d81ae2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 20:33:05 +0200 Subject: [PATCH 0681/2612] collect-wireless-mac: use $SendNotification2 --- collect-wireless-mac.capsman | 8 ++++---- collect-wireless-mac.local | 8 ++++---- collect-wireless-mac.template | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index ca43dc5..92ac9d1 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -17,7 +17,7 @@ :global GetMacVendor; :global LogPrintExit2; :global ScriptLock; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; $ScriptLock $0; @@ -56,8 +56,8 @@ $ScriptLock $0; "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); $LogPrintExit2 info $0 $Message false; / caps-man access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; - $SendNotification ([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid) \ - ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ + $SendNotification2 ({ subject=([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid); \ + message=("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ "Controller: " . $Identity . "\n" . \ "Interface: " . $Interface . "\n" . \ "SSID: " . $Ssid . "\n" . \ @@ -66,7 +66,7 @@ $ScriptLock $0; "Hostname: " . $HostName . "\n" . \ "Address: " . $Address . "\n" . \ "DNS name: " . $DnsName . "\n" . \ - "Date: " . $DateTime); + "Date: " . $DateTime) }); } else={ $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ [ / caps-man access-list get $AccessList comment ]) false; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 7489c4c..828b2eb 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -17,7 +17,7 @@ :global GetMacVendor; :global LogPrintExit2; :global ScriptLock; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; $ScriptLock $0; @@ -56,8 +56,8 @@ $ScriptLock $0; "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); $LogPrintExit2 info $0 $Message false; / interface wireless access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; - $SendNotification ([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid) \ - ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ + $SendNotification2 ({ subject=([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid); \ + message=("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ "Controller: " . $Identity . "\n" . \ "Interface: " . $Interface . "\n" . \ "SSID: " . $Ssid . "\n" . \ @@ -66,7 +66,7 @@ $ScriptLock $0; "Hostname: " . $HostName . "\n" . \ "Address: " . $Address . "\n" . \ "DNS name: " . $DnsName . "\n" . \ - "Date: " . $DateTime); + "Date: " . $DateTime) }); } else={ $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ [ / interface wireless access-list get $AccessList comment ]) false; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index b6c4efa..8e4ab5d 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -18,7 +18,7 @@ :global GetMacVendor; :global LogPrintExit2; :global ScriptLock; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; $ScriptLock $0; @@ -58,8 +58,8 @@ $ScriptLock $0; "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); $LogPrintExit2 info $0 $Message false; / %PATH% access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; - $SendNotification ([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid) \ - ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ + $SendNotification2 ({ subject=([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid); \ + message=("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ "Controller: " . $Identity . "\n" . \ "Interface: " . $Interface . "\n" . \ "SSID: " . $Ssid . "\n" . \ @@ -68,7 +68,7 @@ $ScriptLock $0; "Hostname: " . $HostName . "\n" . \ "Address: " . $Address . "\n" . \ "DNS name: " . $DnsName . "\n" . \ - "Date: " . $DateTime); + "Date: " . $DateTime) }); } else={ $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ [ / %PATH% access-list get $AccessList comment ]) false; From 354aedd98e308ca860796c2f8fdd53ea9eedbb17 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 20:54:50 +0200 Subject: [PATCH 0682/2612] daily-psk: use $SendNotification2 --- daily-psk.capsman | 8 ++++---- daily-psk.local | 8 ++++---- daily-psk.template | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/daily-psk.capsman b/daily-psk.capsman index 7d2c2ae..eec3115 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -17,7 +17,7 @@ :global Identity; :global LogPrintExit2; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; :global UrlEncode; :global WaitForFile; @@ -81,12 +81,12 @@ $WaitFullyConnected; :set Seen ($Seen, $Ssid); :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - $SendNotification ([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid) \ - ("This is the daily PSK on " . $Identity . ":\n\n" . \ + $SendNotification2 ({ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ + message=("This is the daily PSK on " . $Identity . ":\n\n" . \ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ "Date: " . $Date . "\n\n" . \ - "A client device specific rule must not exist!") $Link; + "A client device specific rule must not exist!"); link=$Link }); } } } diff --git a/daily-psk.local b/daily-psk.local index 6186ddc..473238e 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -17,7 +17,7 @@ :global Identity; :global LogPrintExit2; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; :global UrlEncode; :global WaitForFile; @@ -81,12 +81,12 @@ $WaitFullyConnected; :set Seen ($Seen, $Ssid); :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - $SendNotification ([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid) \ - ("This is the daily PSK on " . $Identity . ":\n\n" . \ + $SendNotification2 ({ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ + message=("This is the daily PSK on " . $Identity . ":\n\n" . \ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ "Date: " . $Date . "\n\n" . \ - "A client device specific rule must not exist!") $Link; + "A client device specific rule must not exist!"); link=$Link }); } } } diff --git a/daily-psk.template b/daily-psk.template index 42abba5..cfb7ae7 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -18,7 +18,7 @@ :global Identity; :global LogPrintExit2; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; :global UrlEncode; :global WaitForFile; @@ -87,12 +87,12 @@ $WaitFullyConnected; :set Seen ($Seen, $Ssid); :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - $SendNotification ([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid) \ - ("This is the daily PSK on " . $Identity . ":\n\n" . \ + $SendNotification2 ({ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ + message=("This is the daily PSK on " . $Identity . ":\n\n" . \ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ "Date: " . $Date . "\n\n" . \ - "A client device specific rule must not exist!") $Link; + "A client device specific rule must not exist!"); link=$Link }); } } } From 81f84353cd75fb8e91e2e02d70b5ed5f17df12dd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 20:45:51 +0200 Subject: [PATCH 0683/2612] log-forward: use $SendNotification2 --- log-forward | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/log-forward b/log-forward index 8842c7c..74aaeb4 100644 --- a/log-forward +++ b/log-forward @@ -22,7 +22,7 @@ :global LogPrintExit2; :global QuotedPrintable; :global ScriptLock; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; :global WaitFullyConnected; @@ -71,11 +71,11 @@ $WaitFullyConnected; } :if ($Count > 0) do={ - $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Log Forwarding") \ - ("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) \ - "this message" ("these " . $Count . " messages") ] . " after " . \ - [ / system resource get uptime ] . " uptime." . [ $IfThenElse ($Duplicates = true) \ - (" Multi-repeated messages have been skipped.") ] . "\n" . $Messages); + $SendNotification2 ({ subject=([ $SymbolForNotification "warning-sign" ] . "Log Forwarding"); \ + message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) \ + "this message" ("these " . $Count . " messages") ] . " after " . \ + [ / system resource get uptime ] . " uptime." . [ $IfThenElse ($Duplicates = true) \ + (" Multi-repeated messages have been skipped.") ] . "\n" . $Messages) }); :set LogForwardRateLimit ($LogForwardRateLimit + 10); :set LogForwardLast ($MessageVal->".id"); From 557016387ce270d0c7035be85c7b432841535eda Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 20:52:26 +0200 Subject: [PATCH 0684/2612] netwatch-notify: use $SendNotification2 --- netwatch-notify | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index ef67804..09dbfb8 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -15,7 +15,7 @@ :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; :global ValidateSyntax; @@ -38,9 +38,9 @@ :local Count ($Metric->"count"); :set ($Metric->"count") 0; :if ($Metric->"notified" = true) do={ - $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $HostName . " up") \ - ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ - "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); + $SendNotification2 ({ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $HostName . " up"); \ + message=("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ + "It was down for " . $Count . " checks since " . ($Metric->"since") . ".") }); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ :if ([ $ValidateSyntax ($HostInfo->"up-hook") ] = true) do={ $LogPrintExit2 info $0 ("Running hook on host " . $HostName . " up: " . ($HostInfo->"up-hook")) false; @@ -76,8 +76,8 @@ ($Metric->"notified" = true) ("already notified.") ($Count - $Metric->"count" . " to go.") ] \ ("parent host " . $Parent . " is down.") ]) false; :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ - $SendNotification ([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down") \ - ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); + $SendNotification2 ({ subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down"); \ + message=("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . ".") }); :set ($Metric->"notified") true; :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ :if ([ $ValidateSyntax ($HostInfo->"down-hook") ] = true) do={ From 123fe011151f66f0d6c9a27875d5139a9129ac10 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 20:46:58 +0200 Subject: [PATCH 0685/2612] sms-forward: use $SendNotification2 --- sms-forward | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sms-forward b/sms-forward index 1d47000..55103fc 100644 --- a/sms-forward +++ b/sms-forward @@ -15,7 +15,7 @@ :global IfThenElse; :global LogPrintExit2; :global ScriptLock; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; :global WaitFullyConnected; @@ -51,9 +51,9 @@ $WaitFullyConnected; :if ([ :len $Messages ] > 0) do={ :local Count [ :len $Delete ]; - $SendNotification ([ $SymbolForNotification "incoming-envelope" ] . "SMS Forwarding from " . $Phone) \ - ("Received " . [ $IfThenElse ($Count = 1) "this message" ("these " . $Count . " messages") ] . \ - " by " . $Identity . " from " . $Phone . ":" . $Messages); + $SendNotification2 ({ subject=([ $SymbolForNotification "incoming-envelope" ] . "SMS Forwarding from " . $Phone); \ + message=("Received " . [ $IfThenElse ($Count = 1) "this message" ("these " . $Count . " messages") ] . \ + " by " . $Identity . " from " . $Phone . ":" . $Messages) }); :foreach Sms in=$Delete do={ / tool sms inbox remove $Sms; } From 66a92c3da9a43cf4b2df33d652053f72b70898a1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 20:44:34 +0200 Subject: [PATCH 0686/2612] upload-backup: use $SendNotification2 --- upload-backup | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/upload-backup b/upload-backup index 15adc1f..eb9e2e0 100644 --- a/upload-backup +++ b/upload-backup @@ -26,7 +26,7 @@ :global LogPrintExit2; :global RandomDelay; :global ScriptFromTerminal; -:global SendNotification; +:global SendNotification2; :global SymbolForNotification; :global WaitForFile; :global WaitFullyConnected; @@ -80,13 +80,13 @@ $WaitFullyConnected; } } -$SendNotification [ $IfThenElse ($Failed > 0) \ +$SendNotification2 ({ subject=[ $IfThenElse ($Failed > 0) \ ([ $SymbolForNotification "warning-sign" ] . "Backup & Config upload with failure") \ - ([ $SymbolForNotification "floppy-disk" ] . "Backup & Config upload") ] \ - ("Backup and config export upload for " . $Identity . ".\n\n" . \ + ([ $SymbolForNotification "floppy-disk" ] . "Backup & Config upload") ]; \ + message=("Backup and config export upload for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ - "Config file: " . $ConfigFile) "" "true"; + "Config file: " . $ConfigFile); silent=true }); :if ($Failed = 1) do={ :error "An error occured!"; From e97b3945363c8f322b7ff7f4bf65f13d887d373b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:17:45 +0200 Subject: [PATCH 0687/2612] global-functions: introduce $EitherOr --- global-functions | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/global-functions b/global-functions index aa0ea07..48b58a6 100644 --- a/global-functions +++ b/global-functions @@ -24,6 +24,7 @@ :global DeviceInfo; :global DNSIsResolving; :global DownloadPackage; +:global EitherOr; :global EscapeForRegEx; :global FlushEmailQueue; :global FlushTelegramQueue; @@ -293,6 +294,16 @@ :return false; } +# return either first (if "true") or second +:set EitherOr do={ + :global IfThenElse; + + :if ([ :typeof $1 ] = "num") do={ + :return [ $IfThenElse ($1 != 0) $1 $2 ]; + } + :return [ $IfThenElse ([ :len [ :tostr $1 ] ] > 0) $1 $2 ]; +} + # escape for regular expression :set EscapeForRegEx do={ :local Input [ :tostr $1 ]; From 42dcdae11eb5d3dcb25c07e2bb790b2c7851a785 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:20:02 +0200 Subject: [PATCH 0688/2612] global-functions: $SendEMail2: support overriding to and cc --- global-functions | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 48b58a6..e32a66e 100644 --- a/global-functions +++ b/global-functions @@ -894,14 +894,20 @@ :global Identity; :global EmailGeneralTo; + :global EmailGeneralToOverride; :global EmailGeneralCc; + :global EmailGeneralCcOverride; :global EmailQueue; + :global EitherOr; :global IfThenElse; :global LogPrintExit2; :global QuotedPrintable; - :if ([ :len $EmailGeneralTo ] = 0) do={ + :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; + :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; + + :if ([ :len $To ] = 0) do={ :return false; } @@ -910,7 +916,7 @@ } :local Signature [ / system note get note ]; :set ($EmailQueue->[ :len $EmailQueue ]) { - to=$EmailGeneralTo; cc=$EmailGeneralCc; + to=$To; cc=$Cc; subject=[ $QuotedPrintable ("[" . $Identity . "] " . ($Notification->"subject")) ]; body=(($Notification->"message") . \ [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ From bd05ca1133635a595a976d150fd10e36d46705aa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:28:52 +0200 Subject: [PATCH 0689/2612] global-functions: $SendTelegram2: store token id in queue --- global-functions | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/global-functions b/global-functions index e32a66e..fa0a34f 100644 --- a/global-functions +++ b/global-functions @@ -370,7 +370,6 @@ # flush telegram queue :set FlushTelegramQueue do={ :global TelegramQueue; - :global TelegramTokenId; :global LogPrintExit2; @@ -385,7 +384,7 @@ :if ([ :typeof $Message ] = "array" ) do={ :do { / tool fetch check-certificate=yes-without-crl output=none http-method=post \ - ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ + ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ http-data=("chat_id=" . ($Message->"chatid") . \ "&disable_notification=" . ($Message->"silent") . \ "&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \ @@ -1044,8 +1043,8 @@ :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ " " . [ / system clock get time ] . " and may be obsolete.") "hint" ]) ]); - :set ($TelegramQueue->[ :len $TelegramQueue ]) { - chatid=$ChatId; parsemode=$ParseMode; text=$Text; silent=($Notification->"silent") }; + :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TelegramTokenId; + parsemode=$ParseMode; text=$Text; silent=($Notification->"silent") }; :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ / system scheduler add name=FlushTelegramQueue interval=1m start-time=startup \ on-event=":global FlushTelegramQueue; \$FlushTelegramQueue;"; From 2d0ce176299c12de6898e17964ccfc4505b65b7c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:31:11 +0200 Subject: [PATCH 0690/2612] global-functions: $SendTelegram2: support overriding token id and chat id --- global-functions | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/global-functions b/global-functions index fa0a34f..3535f38 100644 --- a/global-functions +++ b/global-functions @@ -961,9 +961,11 @@ :global TelegramFixedWidthFont; :global TelegramQueue; :global TelegramTokenId; + :global TelegramTokenIdOverride; :global CertificateAvailable; :global CharacterReplace; + :global EitherOr; :global IfThenElse; :global LogPrintExit2; :global SymbolForNotification; @@ -996,12 +998,10 @@ :return $Return; } - :local ChatId $TelegramChatId; - :if ([ :len $TelegramChatIdOverride ] > 0) do={ - :set ChatId $TelegramChatIdOverride; - } + :local ChatId [ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ]; + :local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ]; - :if ([ :len $TelegramTokenId ] = 0 || [ :len $ChatId ] = 0) do={ + :if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={ :return false; } @@ -1031,7 +1031,7 @@ $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; } / tool fetch check-certificate=yes-without-crl output=none http-method=post \ - ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ + ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; } on-error={ @@ -1043,7 +1043,7 @@ :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ " " . [ / system clock get time ] . " and may be obsolete.") "hint" ]) ]); - :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TelegramTokenId; + :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; parsemode=$ParseMode; text=$Text; silent=($Notification->"silent") }; :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ / system scheduler add name=FlushTelegramQueue interval=1m start-time=startup \ From c64082388195fc81d0d43e8d360d64663c1d70a9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:38:37 +0200 Subject: [PATCH 0691/2612] global-functions: $ScriptInstallUpdate: pass origin to $SendNotification2 --- global-functions | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 3535f38..ddddcb8 100644 --- a/global-functions +++ b/global-functions @@ -855,8 +855,9 @@ :set Link "https://git.eworm.de/cgit/routeros-scripts/about/#donate"; } - $SendNotification2 ({ subject=([ $SymbolForNotification "pushpin" ] . \ - "News and configuration changes"); message=$NotificationMessage; link=$Link }); + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "pushpin" ] . "News and configuration changes"); \ + message=$NotificationMessage; link=$Link }); :set SentConfigChangesNotification $ExpectedConfigVersion; } From ebd3dbedcbe5c71dde258a5e05a531ad8c70983f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:58:35 +0200 Subject: [PATCH 0692/2612] check-certificates: pass origin to $SendNotification2 --- check-certificates | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/check-certificates b/check-certificates index ff93046..a052930 100644 --- a/check-certificates +++ b/check-certificates @@ -95,7 +95,8 @@ $WaitFullyConnected; / certificate set $CertNew name=($CertVal->"name"); } - $SendNotification2 ({ subject=([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed"); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed"); \ message=("A certificate on " . $Identity . " has been renewed.\n\n" . \ "Name: " . ($CertVal->"name") . "\n" . \ "CommonName: " . ($CertNewVal->"common-name") . "\n" . \ @@ -118,7 +119,8 @@ $WaitFullyConnected; } else={ :local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ]; - $SendNotification2 ({ subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning!"); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning!"); \ message=("A certificate on " . $Identity . " " . $State . ".\n\n" . \ "Name: " . ($CertVal->"name") . "\n" . \ "CommonName: " . ($CertVal->"common-name") . "\n" . \ From baed8b5cfd7245efef3432182a53c63651aa744a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:43:22 +0200 Subject: [PATCH 0693/2612] check-health: pass origin to $SendNotification2 --- check-health | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/check-health b/check-health index dba24d8..ec89545 100644 --- a/check-health +++ b/check-health @@ -42,7 +42,8 @@ [ :typeof $Voltage ] = "num") do={ :if ($CheckHealthLast->$Name * (100 + $CheckHealthVoltagePercent) < $Voltage * 100 || \ $CheckHealthLast->$Name * 100 > $Voltage * (100 + $CheckHealthVoltagePercent)) do={ - $SendNotification2 ({ subject=([ $SymbolForNotification "high-voltage-sign" ] . "Health warning: " . $Name); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "high-voltage-sign" ] . "Health warning: " . $Name); \ message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ "old value: " . [ $FormatVoltage ($CheckHealthLast->$Name) ] . "\n" . \ "new value: " . [ $FormatVoltage $Voltage ]) }); @@ -56,12 +57,14 @@ [ :typeof $PSU ] = "str") do={ :if ($CheckHealthLast->$Name = "ok" && \ $PSU != "ok") do={ - $SendNotification2 ({ subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ message=("The power supply unit '" . $Name . "' on " . $Identity . " failed!") }); } :if ($CheckHealthLast->$Name != "ok" && \ $PSU = "ok") do={ - $SendNotification2 ({ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ message=("The power supply unit '" . $Name . "' on " . $Identity . " recovered!") }); } } @@ -81,14 +84,16 @@ } :if ($Temperature > $CheckHealthTemperature->$Name && \ $CheckHealthTemperatureNotified->$Name != true) do={ - $SendNotification2 ({ subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ message=("The " . $Name . " on " . $Identity . " is above threshold: " . \ $Temperature . "\C2\B0" . "C") }); :set ($CheckHealthTemperatureNotified->$Name) true; } :if ($Temperature <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ $CheckHealthTemperatureNotified->$Name = true) do={ - $SendNotification2 ({ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ $Temperature . "\C2\B0" . "C") }); :set ($CheckHealthTemperatureNotified->$Name) false; From fbe4c457c6c233e3dbe8e58c2d8d8eead9d9c091 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:57:25 +0200 Subject: [PATCH 0694/2612] check-lte-firmware-upgrade: pass origin to $SendNotification2 --- check-lte-firmware-upgrade | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 6b46502..c05c436 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -29,7 +29,8 @@ } else={ :if (($Firmware->"installed") != ($Firmware->"latest")) do={ :local Info [ / interface lte info $Interface once as-value ]; - $SendNotification2 ({ subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \ message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \ "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ "Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \ From 8e1c524b8583aa476af232d2e2e2a19f5f34540c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:53:28 +0200 Subject: [PATCH 0695/2612] check-routeros-update: pass origin to $SendNotification2 --- check-routeros-update | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index 683f9be..0309730 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -65,7 +65,8 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; :if ($NumInstalled < $NumLatest) do={ :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; - $SendNotification2 ({ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ ", updating on " . $Identity . "..."); link=$Link; silent=true }); $DoUpdate; @@ -74,7 +75,8 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; :if ($SafeUpdateNeighbor = true && [ :len [ / ip neighbor find where \ version=($Update->"latest-version" . " (" . $Update->"channel" . ")") ] ] > 0) do={ $LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; - $SendNotification2 ({ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ message=("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \ ", updating on " . $Identity . "..."); link=$Link; silent=true }); $DoUpdate; @@ -91,7 +93,8 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; } :if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={ $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; - $SendNotification2 ({ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ message=("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ ", updating on " . $Identity . "..."); link=$Link; silent=true }); $DoUpdate; @@ -112,7 +115,8 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; $Update->"latest-version" . ".") true; } - $SendNotification2 ({ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ message=("A new RouterOS version " . ($Update->"latest-version") . \ " is available for " . $Identity . ".\n\n" . \ [ $DeviceInfo ]); link=$Link; silent=true }); @@ -125,7 +129,8 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; $Update->"latest-version" . ".") true; } - $SendNotification2 ({ subject=([ $SymbolForNotification "warning-sign" ] . "RouterOS version"); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "warning-sign" ] . "RouterOS version"); \ message=("A different RouterOS version " . ($Update->"latest-version") . \ " is available for " . $Identity . ", but it is a downgrade.\n\n" . \ [ $DeviceInfo ]); link=$Link; silent=true }); From a9b932d67e294db78555a1473b53e2a23e5632ca Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:55:31 +0200 Subject: [PATCH 0696/2612] cloud-backup: pass origin to $SendNotification2 --- cloud-backup | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cloud-backup b/cloud-backup index 23fa164..546f614 100644 --- a/cloud-backup +++ b/cloud-backup @@ -41,14 +41,16 @@ $WaitFullyConnected; } :local Cloud [ / system backup cloud get ([ find ]->0) ]; - $SendNotification2 ({ subject=([ $SymbolForNotification "floppy-disk" ] . "Cloud backup"); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "floppy-disk" ] . "Cloud backup"); \ message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Name: " . $Cloud->"name" . "\n" . \ "Size: " . $Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)\n" . \ "Download key: " . $Cloud->"secret-download-key"); silent=true }); } on-error={ - $SendNotification2 ({ subject=([ $SymbolForNotification "warning-sign" ] . "Cloud backup failed"); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "warning-sign" ] . "Cloud backup failed"); \ message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); $LogPrintExit2 error $0 ("Failed uploading backup for " . $Identity . " to cloud!") true; } From 714a679402ffaa009c74ae5c0d30c2f995e83f57 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:39:30 +0200 Subject: [PATCH 0697/2612] collect-wireless-mac: pass origin to $SendNotification2 --- collect-wireless-mac.capsman | 3 ++- collect-wireless-mac.local | 3 ++- collect-wireless-mac.template | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 92ac9d1..4cf8649 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -56,7 +56,8 @@ $ScriptLock $0; "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); $LogPrintExit2 info $0 $Message false; / caps-man access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; - $SendNotification2 ({ subject=([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid); \ message=("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ "Controller: " . $Identity . "\n" . \ "Interface: " . $Interface . "\n" . \ diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 828b2eb..a7c26e6 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -56,7 +56,8 @@ $ScriptLock $0; "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); $LogPrintExit2 info $0 $Message false; / interface wireless access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; - $SendNotification2 ({ subject=([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid); \ message=("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ "Controller: " . $Identity . "\n" . \ "Interface: " . $Interface . "\n" . \ diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 8e4ab5d..41cf299 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -58,7 +58,8 @@ $ScriptLock $0; "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); $LogPrintExit2 info $0 $Message false; / %PATH% access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; - $SendNotification2 ({ subject=([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid); \ message=("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ "Controller: " . $Identity . "\n" . \ "Interface: " . $Interface . "\n" . \ From fe9754c6939fb58dd0d9d2cd281e8dcf9cd9a128 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:56:30 +0200 Subject: [PATCH 0698/2612] daily-psk: pass origin to $SendNotification2 --- daily-psk.capsman | 3 ++- daily-psk.local | 3 ++- daily-psk.template | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/daily-psk.capsman b/daily-psk.capsman index eec3115..ca95fb8 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -81,7 +81,8 @@ $WaitFullyConnected; :set Seen ($Seen, $Ssid); :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - $SendNotification2 ({ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ message=("This is the daily PSK on " . $Identity . ":\n\n" . \ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ diff --git a/daily-psk.local b/daily-psk.local index 473238e..bddf2c9 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -81,7 +81,8 @@ $WaitFullyConnected; :set Seen ($Seen, $Ssid); :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - $SendNotification2 ({ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ message=("This is the daily PSK on " . $Identity . ":\n\n" . \ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ diff --git a/daily-psk.template b/daily-psk.template index cfb7ae7..967b51a 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -87,7 +87,8 @@ $WaitFullyConnected; :set Seen ($Seen, $Ssid); :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - $SendNotification2 ({ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ message=("This is the daily PSK on " . $Identity . ":\n\n" . \ "SSID: " . $Ssid . "\n" . \ "PSK: " . $NewPsk . "\n" . \ From 87cbc1edadddaae330d58b23cc101d8ab5abddc6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:50:44 +0200 Subject: [PATCH 0699/2612] log-forward: pass origin to $SendNotification2 --- log-forward | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-forward b/log-forward index 74aaeb4..8f72893 100644 --- a/log-forward +++ b/log-forward @@ -71,7 +71,8 @@ $WaitFullyConnected; } :if ($Count > 0) do={ - $SendNotification2 ({ subject=([ $SymbolForNotification "warning-sign" ] . "Log Forwarding"); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "warning-sign" ] . "Log Forwarding"); \ message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) \ "this message" ("these " . $Count . " messages") ] . " after " . \ [ / system resource get uptime ] . " uptime." . [ $IfThenElse ($Duplicates = true) \ From e6223a3661af4ee3888f2656d103a865eb6ab27a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:54:30 +0200 Subject: [PATCH 0700/2612] netwatch-notify: pass origin to $SendNotification2 --- netwatch-notify | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 09dbfb8..5600857 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -38,7 +38,8 @@ :local Count ($Metric->"count"); :set ($Metric->"count") 0; :if ($Metric->"notified" = true) do={ - $SendNotification2 ({ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $HostName . " up"); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $HostName . " up"); \ message=("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ "It was down for " . $Count . " checks since " . ($Metric->"since") . ".") }); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ @@ -76,7 +77,8 @@ ($Metric->"notified" = true) ("already notified.") ($Count - $Metric->"count" . " to go.") ] \ ("parent host " . $Parent . " is down.") ]) false; :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ - $SendNotification2 ({ subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down"); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down"); \ message=("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . ".") }); :set ($Metric->"notified") true; :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ From 0d249d6da4fa1e1a02b7bdaee8be6c4be72b942b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:51:32 +0200 Subject: [PATCH 0701/2612] sms-forward: pass origin to $SendNotification2 --- sms-forward | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sms-forward b/sms-forward index 55103fc..2eecc07 100644 --- a/sms-forward +++ b/sms-forward @@ -51,7 +51,8 @@ $WaitFullyConnected; :if ([ :len $Messages ] > 0) do={ :local Count [ :len $Delete ]; - $SendNotification2 ({ subject=([ $SymbolForNotification "incoming-envelope" ] . "SMS Forwarding from " . $Phone); \ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "incoming-envelope" ] . "SMS Forwarding from " . $Phone); \ message=("Received " . [ $IfThenElse ($Count = 1) "this message" ("these " . $Count . " messages") ] . \ " by " . $Identity . " from " . $Phone . ":" . $Messages) }); :foreach Sms in=$Delete do={ From 9fc75f5932d6a1db129b2d74cfa1fd2aed851328 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Apr 2021 21:49:39 +0200 Subject: [PATCH 0702/2612] upload-backup: pass origin to $SendNotification2 --- upload-backup | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/upload-backup b/upload-backup index eb9e2e0..921b196 100644 --- a/upload-backup +++ b/upload-backup @@ -80,7 +80,8 @@ $WaitFullyConnected; } } -$SendNotification2 ({ subject=[ $IfThenElse ($Failed > 0) \ +$SendNotification2 ({ origin=$0; \ + subject=[ $IfThenElse ($Failed > 0) \ ([ $SymbolForNotification "warning-sign" ] . "Backup & Config upload with failure") \ ([ $SymbolForNotification "floppy-disk" ] . "Backup & Config upload") ]; \ message=("Backup and config export upload for " . $Identity . ".\n\n" . \ From b497edd092b5b01e7601460308c45d6970fabb54 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Apr 2021 15:11:08 +0200 Subject: [PATCH 0703/2612] global-config: comment on overriding e-mail and Telegram settings --- global-config | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/global-config b/global-config index 107ef19..58c9617 100644 --- a/global-config +++ b/global-config @@ -33,6 +33,13 @@ # This is whether or not to send Telegram messages with fixed-width font. :global TelegramFixedWidthFont true; +# It is possible to override e-mail and Telegram setting for every script. +# This is done in arrays EmailGeneralToOverride, EmailGeneralCcOverride, +# TelegramTokenIdOverride and TelegramChatIdOverride like this: +#:global EmailGeneralToOverride { +# "check-certificates"="override@example.com"; +#} + # Toggle this to disable symbols in notifications. :global NotificationsWithSymbols true; # Toggle this to disable color output in terminal/cli. From 56b75237754eb065aecb932b3082ba0ca29c3f7c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Apr 2021 15:33:37 +0200 Subject: [PATCH 0704/2612] global-functions: notify about settings override --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 58c9617..9e69c18 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 47; +:global GlobalConfigVersion 48; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 850e6d8..316fde5 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 47; +:global GlobalConfigVersion 48; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 2dc68f7..d3d1059 100644 --- a/global-config.changes +++ b/global-config.changes @@ -51,6 +51,7 @@ 45="We have a Telegram Group! Come along and say hello: https://t.me/routeros_scripts"; 46="Added configurable random delay in backup scripts to stretch execution and prevent resource congestion."; 47="Removed obsolete intermediate certificate 'Let's Encrypt Authority X3' from store."; + 48="Added support for overriding e-mail and Telegram settings for every script."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index ddddcb8..ff16076 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 47; +:global ExpectedConfigVersion 48; # global variables not to be changed by user :global GlobalFunctionsReady false; From 5d973a095a63751c8707685c603d672b8101c44d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Apr 2021 09:12:17 +0200 Subject: [PATCH 0705/2612] global-functions: $FlushEmailQueue: try to avoid running simultaneously We can not check the status for a *specific* mail, so running simultaneously is a problem. Let's increase the interval to the number of queue items - and hope it helps. Decrease when done. --- global-functions | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index ff16076..d048748 100644 --- a/global-functions +++ b/global-functions @@ -339,7 +339,7 @@ $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; } - / system scheduler set interval=1m [ find where name="FlushEmailQueue" interval=1s ]; + / system scheduler set interval=($QueueLen . "m") [ find where name="FlushEmailQueue" ]; :foreach Id,Message in=$EmailQueue do={ :if ([ :typeof $Message ] = "array" ) do={ @@ -364,6 +364,8 @@ :if ($AllDone = true && $QueueLen = [ :len $EmailQueue ]) do={ / system scheduler remove [ find where name="FlushEmailQueue" ]; :set EmailQueue; + } else={ + / system scheduler set interval=1m [ find where name="FlushEmailQueue" ]; } } From 0f445fd52893be776cd46ea4b345b4085947ce1d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Apr 2021 14:40:29 +0200 Subject: [PATCH 0706/2612] global-functions: $DownloadPackage: fix typo --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index d048748..2ce60f6 100644 --- a/global-functions +++ b/global-functions @@ -264,7 +264,7 @@ :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; :if ([ :len [ / file find where name=$PkgDest type="package" ] ] > 0) do={ - $LogPrintExit2 info $0 ("Package file alreasy exists.") false; + $LogPrintExit2 info $0 ("Package file already exists.") false; :return true; } From 7ed54a4fe749a6bfd4e58c2063abb4a13bdebe31 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Apr 2021 14:54:49 +0200 Subject: [PATCH 0707/2612] global-functions: $DownloadPackage: be more verbose --- global-functions | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 2ce60f6..65c9721 100644 --- a/global-functions +++ b/global-functions @@ -264,7 +264,7 @@ :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; :if ([ :len [ / file find where name=$PkgDest type="package" ] ] > 0) do={ - $LogPrintExit2 info $0 ("Package file already exists.") false; + $LogPrintExit2 info $0 ("Package file " . $PkgName . " already exists.") false; :return true; } @@ -272,6 +272,7 @@ $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; } + $LogPrintExit2 info $0 ("Downloading package file " . $PkgName . "...") false; :local Retry 3; :while ($Retry > 0) do={ :do { @@ -284,13 +285,14 @@ :return true; } } on-error={ - $LogPrintExit2 debug $0 ("Downloading package failed.") false; + $LogPrintExit2 debug $0 ("Downloading package file failed.") false; } / file remove [ find where name=$PkgDest ]; :set Retry ($Retry - 1); } + $LogPrintExit2 warning $0 ("Downloading package file " . $PkgName . " failed.") false; :return false; } From 6f7ecaeec49d594aa987fe15f6bc5da3a8ec5d13 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Apr 2021 14:52:38 +0200 Subject: [PATCH 0708/2612] packages-update: add missing colon --- packages-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages-update b/packages-update index 99f1f30..3142a85 100644 --- a/packages-update +++ b/packages-update @@ -47,7 +47,7 @@ $ScriptLock $0; :foreach Package in=[ / system package find where !bundle ] do={ :local PkgName [ / system package get $Package name ]; - if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ + :if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ $LogPrintExit2 error $0 ("Download for package " . $PkgName . " failed.") true; } } From afc231596cdec85f148d675ff552a3e4bf444dcd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Apr 2021 14:55:13 +0200 Subject: [PATCH 0709/2612] packages-update: update wording --- packages-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages-update b/packages-update index 3142a85..bb138d7 100644 --- a/packages-update +++ b/packages-update @@ -48,7 +48,7 @@ $ScriptLock $0; :foreach Package in=[ / system package find where !bundle ] do={ :local PkgName [ / system package get $Package name ]; :if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ - $LogPrintExit2 error $0 ("Download for package " . $PkgName . " failed.") true; + $LogPrintExit2 error $0 ("Download for package " . $PkgName . " failed, update aborted.") true; } } From ff4e5339d0103f73bf36f4b63f7ce8970d25e29f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Apr 2021 15:10:08 +0200 Subject: [PATCH 0710/2612] capsman-rolling-upgrade: properly handle vanished cap --- capsman-rolling-upgrade | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index 9e7aec0..4c3b1c7 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -24,9 +24,13 @@ $ScriptLock $0; :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 ]; - $LogPrintExit2 info $0 ("Starting upgrade for " . $RemoteCapVal->"name" . \ + :if ([ :len $RemoteCapVal ] > 1) do={ + $LogPrintExit2 info $0 ("Starting upgrade for " . $RemoteCapVal->"name" . \ " (" . $RemoteCapVal->"identity" . ")...") false; - / caps-man remote-cap upgrade [ find where name=$RemoteCapVal->"name" ]; + / caps-man remote-cap upgrade $RemoteCap; + } else={ + $LogPrintExit2 warning $0 ("Remote CAP vanished, skipping upgrade.") false; + } :delay ($Delay . "s"); } } From 51007f922456597466f01d643d9c9d554bd4cae7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Apr 2021 16:07:33 +0200 Subject: [PATCH 0711/2612] upload-backup: work inside directory --- upload-backup | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/upload-backup b/upload-backup index 921b196..08b4adf 100644 --- a/upload-backup +++ b/upload-backup @@ -24,6 +24,7 @@ :global DeviceInfo; :global IfThenElse; :global LogPrintExit2; +:global MkDir; :global RandomDelay; :global ScriptFromTerminal; :global SendNotification2; @@ -42,20 +43,25 @@ $WaitFullyConnected; $RandomDelay $BackupRandomDelay; } +:if ([ $MkDir $0 ] = false) do={ + $LogPrintExit2 error $0 ("Failed creating directory!") true; +} + # filename based on identity :local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; +:local FilePath ($0 . "/" . $FileName); :local BackupFile "none"; :local ConfigFile "none"; :local Failed 0; # binary backup :if ($BackupSendBinary = true) do={ - / system backup save encryption=aes-sha256 name=$FileName password=$BackupPassword; - $WaitForFile ($FileName . ".backup"); + / 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=($FileName . ".backup"); + user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".backup"); :set BackupFile ($FileName . ".backup"); } on-error={ $LogPrintExit2 error $0 ("Uploading backup file failed!") false; @@ -66,12 +72,12 @@ $WaitFullyConnected; # create configuration export :if ($BackupSendExport = true) do={ - / export terse file=$FileName; - $WaitForFile ($FileName . ".rsc"); + / export terse file=$FilePath; + $WaitForFile ($FilePath . ".rsc"); :do { / tool fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \ - user=$BackupUploadUser password=$BackupUploadPass src-path=($FileName . ".rsc"); + user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".rsc"); :set ConfigFile ($FileName . ".rsc"); } on-error={ $LogPrintExit2 error $0 ("Uploading configuration export failed!") false; From c2b45a90934e4860652dce0022a0a4081588391d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Apr 2021 16:13:17 +0200 Subject: [PATCH 0712/2612] email-backup: work inside directory --- email-backup | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/email-backup b/email-backup index b9e91c2..e9a75cd 100644 --- a/email-backup +++ b/email-backup @@ -22,6 +22,7 @@ :global CharacterReplace; :global DeviceInfo; :global LogPrintExit2; +:global MkDir; :global RandomDelay; :global ScriptFromTerminal; :global WaitForFile; @@ -42,26 +43,31 @@ $WaitFullyConnected; $RandomDelay $BackupRandomDelay; } +:if ([ $MkDir $0 ] = false) do={ + $LogPrintExit2 error $0 ("Failed creating directory!") true; +} + # filename based on identity :local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; +:local FilePath ($0 . "/" . $FileName); :local BackupFile "none"; :local ConfigFile "none"; :local Attach [ :toarray "" ]; # binary backup :if ($BackupSendBinary = true) do={ - / system backup save encryption=aes-sha256 name=$FileName password=$BackupPassword; - $WaitForFile ($FileName . ".backup"); + / system backup save encryption=aes-sha256 name=$FilePath password=$BackupPassword; + $WaitForFile ($FilePath . ".backup"); :set BackupFile ($FileName . ".backup"); - :set Attach ($Attach, $BackupFile); + :set Attach ($Attach, ($FilePath . ".backup")); } # create configuration export :if ($BackupSendExport = true) do={ - / export terse file=$FileName; - $WaitForFile ($FileName . ".rsc"); + / export terse file=$FilePath; + $WaitForFile ($FilePath . ".rsc"); :set ConfigFile ($FileName . ".rsc"); - :set Attach ($Attach, $ConfigFile); + :set Attach ($Attach, ($FilePath . ".rsc")); } # send email with status and files From 529cefffafca2dedd93f48303db73805d965431f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Apr 2021 16:22:04 +0200 Subject: [PATCH 0713/2612] global-functions: $SendEMail2: support file attachments --- global-functions | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 65c9721..a1a070c 100644 --- a/global-functions +++ b/global-functions @@ -332,6 +332,7 @@ :set FlushEmailQueue do={ :global EmailQueue; + :global EitherOr; :global LogPrintExit2; :local AllDone true; @@ -345,8 +346,8 @@ :foreach Id,Message in=$EmailQueue do={ :if ([ :typeof $Message ] = "array" ) do={ - / tool e-mail send to=($Message->"to") cc=($Message->"cc") \ - subject=($Message->"subject") body=($Message->"body"); + / tool e-mail send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \ + body=($Message->"body") file=[ $EitherOr ($Message->"attach") "" ]; :local Wait true; :do { :delay 1s; @@ -924,7 +925,8 @@ subject=[ $QuotedPrintable ("[" . $Identity . "] " . ($Notification->"subject")) ]; body=(($Notification->"message") . \ [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ - [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]) }; + [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \ + attach=($Notification->"attach") }; :if ([ :len [ / system scheduler find where name="FlushEmailQueue" ] ] = 0) do={ / system scheduler add name=FlushEmailQueue interval=1s start-time=startup \ on-event=":global FlushEmailQueue; \$FlushEmailQueue;"; From d2560db5c96b5e2679178fd4f6595af89cab0801 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Apr 2021 16:26:31 +0200 Subject: [PATCH 0714/2612] email-backup: use $SendEMail2 This drops $EmailBackupTo & $EmailBackupCc from settings! Use settings overwrite if required: :global EmailGeneralToOverride { "email-backup"="backup@example.com"; } --- doc/email-backup.md | 4 +--- email-backup | 23 +++++++++-------------- global-config | 6 ++---- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 6 files changed, 15 insertions(+), 23 deletions(-) diff --git a/doc/email-backup.md b/doc/email-backup.md index 4b769ec..7076691 100644 --- a/doc/email-backup.md +++ b/doc/email-backup.md @@ -26,10 +26,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupSendExport`: whether to send configuration export * `BackupPassword`: password to encrypt the backup with * `BackupRandomDelay`: delay up to amount of seconds when run from scheduler -* `EmailBackupTo`: e-mail address to send to -* `EmailBackupCc`: e-mail address(es) to send in copy -Also valid e-mail settings in `/ tool e-mail` are required to send mails. +Also valid e-mail settings are required to send mails. Usage and invocation -------------------- diff --git a/email-backup b/email-backup index e9a75cd..0ba4d45 100644 --- a/email-backup +++ b/email-backup @@ -15,8 +15,6 @@ :global BackupSendBinary; :global BackupSendExport; :global Domain; -:global EmailBackupCc; -:global EmailBackupTo; :global Identity; :global CharacterReplace; @@ -25,6 +23,7 @@ :global MkDir; :global RandomDelay; :global ScriptFromTerminal; +:global SendEMail2; :global WaitForFile; :global WaitFullyConnected; @@ -33,10 +32,6 @@ $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; } -:if ([ :len $EmailBackupTo ] = 0) do={ - $LogPrintExit2 error $0 ("Configuration is missing recipient for e-mail backup.") true; -} - $WaitFullyConnected; :if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ @@ -71,11 +66,11 @@ $WaitFullyConnected; } # send email with status and files -/ tool e-mail send to=$EmailBackupTo cc=$EmailBackupCc \ - subject=("[" . $Identity . "] Backup & Config") \ - body=("See attached files for backup and config export for " . \ - $Identity . ".\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - "Backup file: " . $BackupFile . "\n" . \ - "Config file: " . $ConfigFile) \ - file=$Attach; +$SendEMail2 ({ origin=$0; \ + subject=("Backup & Config"); \ + message=("See attached files for backup and config export for " . \ + $Identity . ".\n\n" . \ + [ $DeviceInfo ] . "\n\n" . \ + "Backup file: " . $BackupFile . "\n" . \ + "Config file: " . $ConfigFile); \ + attach=$Attach }); diff --git a/global-config b/global-config index 9e69c18..25d0496 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 48; +:global GlobalConfigVersion 49; # This is used for DNS and backup file. :global Domain "example.com"; @@ -38,6 +38,7 @@ # TelegramTokenIdOverride and TelegramChatIdOverride like this: #:global EmailGeneralToOverride { # "check-certificates"="override@example.com"; +# "email-backup"="backup@example.com"; #} # Toggle this to disable symbols in notifications. @@ -50,9 +51,6 @@ :global BackupSendExport true; :global BackupPassword "v3ry-s3cr3t"; :global BackupRandomDelay 0; -# These addresses are used to send backup and config export files to. -:global EmailBackupTo ""; -:global EmailBackupCc ""; # These credentials are used to upload backup and config export files. # SFTP authentication is tricky, you may have to limit authentication # methods for your SSH server. diff --git a/global-config-overlay b/global-config-overlay index 316fde5..7057765 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 48; +:global GlobalConfigVersion 49; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index d3d1059..61850dd 100644 --- a/global-config.changes +++ b/global-config.changes @@ -52,6 +52,7 @@ 46="Added configurable random delay in backup scripts to stretch execution and prevent resource congestion."; 47="Removed obsolete intermediate certificate 'Let's Encrypt Authority X3' from store."; 48="Added support for overriding e-mail and Telegram settings for every script."; + 49="Dropped '\$EmailBackupTo' & '\$EmailBackupCc' from configuration, use settings override if required."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index a1a070c..699b0fe 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 48; +:global ExpectedConfigVersion 49; # global variables not to be changed by user :global GlobalFunctionsReady false; From 34ab2837a806f6668aca4590b4e19b1ccfe96752 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Apr 2021 22:10:38 +0200 Subject: [PATCH 0715/2612] email-backup: add symbol in e-mail That's easy now that we use $SendEMail2... --- email-backup | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/email-backup b/email-backup index 0ba4d45..75fc6df 100644 --- a/email-backup +++ b/email-backup @@ -24,6 +24,7 @@ :global RandomDelay; :global ScriptFromTerminal; :global SendEMail2; +:global SymbolForNotification; :global WaitForFile; :global WaitFullyConnected; @@ -67,7 +68,7 @@ $WaitFullyConnected; # send email with status and files $SendEMail2 ({ origin=$0; \ - subject=("Backup & Config"); \ + subject=([ $SymbolForNotification "floppy-disk" ] . "Backup & Config"); \ message=("See attached files for backup and config export for " . \ $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ From aa4ad27b0a5b540e9052f6b4ff8cba29a72b04d3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Apr 2021 22:25:30 +0200 Subject: [PATCH 0716/2612] cloud-backup: add second symbol --- cloud-backup | 2 +- global-functions | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cloud-backup b/cloud-backup index 546f614..5003f8f 100644 --- a/cloud-backup +++ b/cloud-backup @@ -42,7 +42,7 @@ $WaitFullyConnected; :local Cloud [ / system backup cloud get ([ find ]->0) ]; $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "floppy-disk" ] . "Cloud backup"); \ + subject=([ $SymbolForNotification "floppy-disk,cloud" ] . "Cloud backup"); \ message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Name: " . $Cloud->"name" . "\n" . \ diff --git a/global-functions b/global-functions index 699b0fe..1866489 100644 --- a/global-functions +++ b/global-functions @@ -1064,6 +1064,7 @@ :local Symbols { "alarm-clock"="\E2\8F\B0"; "calendar"="\F0\9F\93\85"; + "cloud"="\E2\98\81"; "cross-mark"="\E2\9D\8C"; "fire"="\F0\9F\94\A5"; "floppy-disk"="\F0\9F\92\BE"; From 9e8170749132d3e2e5a98160d94b79be1ef4f90e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Apr 2021 22:26:42 +0200 Subject: [PATCH 0717/2612] email-backup: add second symbol --- email-backup | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/email-backup b/email-backup index 75fc6df..d09ae2a 100644 --- a/email-backup +++ b/email-backup @@ -68,7 +68,8 @@ $WaitFullyConnected; # send email with status and files $SendEMail2 ({ origin=$0; \ - subject=([ $SymbolForNotification "floppy-disk" ] . "Backup & Config"); \ + subject=([ $SymbolForNotification "floppy-disk,incoming-envelope" ] . \ + "Backup & Config"); \ message=("See attached files for backup and config export for " . \ $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ From 666cd3f18423769a01297368d74464d2f01e57e4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Apr 2021 22:27:29 +0200 Subject: [PATCH 0718/2612] upload-backup: add second symbol --- global-functions | 1 + upload-backup | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 1866489..0c90ad8 100644 --- a/global-functions +++ b/global-functions @@ -1076,6 +1076,7 @@ "pushpin"="\F0\9F\93\8C"; "scissors"="\E2\9C\82"; "sparkles"="\E2\9C\A8"; + "up-arrow"="\E2\AC\86"; "warning-sign"="\E2\9A\A0"; "white-heavy-check-mark"="\E2\9C\85" } diff --git a/upload-backup b/upload-backup index 08b4adf..8136599 100644 --- a/upload-backup +++ b/upload-backup @@ -89,7 +89,7 @@ $WaitFullyConnected; $SendNotification2 ({ origin=$0; \ subject=[ $IfThenElse ($Failed > 0) \ ([ $SymbolForNotification "warning-sign" ] . "Backup & Config upload with failure") \ - ([ $SymbolForNotification "floppy-disk" ] . "Backup & Config upload") ]; \ + ([ $SymbolForNotification "floppy-disk,up-arrow" ] . "Backup & Config upload") ]; \ message=("Backup and config export upload for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ From e0e53b8add204e8dab3e0eb42a4da94a8f9e405b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 3 May 2021 10:35:30 +0200 Subject: [PATCH 0719/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 92cf2e7..1d2d04a 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -23,6 +23,7 @@ Add yourself to the list, * Linux-Schmie.de Michael Gisbers * Manuel Kuhn * Marek ÄŒÃĄbÃĄk +* Peter Holtkamp * Reiner Vehrenkamp --- From 64ff7fcf65ade97535afaa84531697f997239b30 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 3 May 2021 15:07:50 +0200 Subject: [PATCH 0720/2612] doc: inform about dependency on base installation That should make the documentation clearer if external sites link to the documentation of a specific script. --- doc/accesslist-duplicates.md | 3 +++ doc/bridge-port.md | 3 +++ doc/capsman-download-packages.md | 3 +++ doc/capsman-rolling-upgrade.md | 3 +++ doc/certificate-renew-issued.md | 3 +++ doc/check-certificates.md | 3 +++ doc/check-health.md | 3 +++ doc/check-lte-firmware-upgrade.md | 3 +++ doc/check-routeros-update.md | 3 +++ doc/cloud-backup.md | 3 +++ doc/collect-wireless-mac.md | 3 +++ doc/daily-psk.md | 3 +++ doc/dhcp-lease-comment.md | 3 +++ doc/dhcp-to-dns.md | 3 +++ doc/email-backup.md | 3 +++ doc/gps-track.md | 3 +++ doc/hotspot-to-wpa.md | 3 +++ doc/ipv6-update.md | 3 +++ doc/lease-script.md | 3 +++ doc/log-forward.md | 3 +++ doc/mode-button.md | 3 +++ doc/netwatch-notify.md | 3 +++ doc/ospf-to-leds.md | 3 +++ doc/packages-update.md | 3 +++ doc/ppp-on-up.md | 3 +++ doc/rotate-ntp.md | 3 +++ doc/sms-action.md | 3 +++ doc/sms-forward.md | 3 +++ doc/update-gre-address.md | 3 +++ doc/update-tunnelbroker.md | 3 +++ doc/upload-backup.md | 3 +++ 31 files changed, 93 insertions(+) diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index 2189322..0f08284 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -3,6 +3,9 @@ Find and remove access list duplicates [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/bridge-port.md b/doc/bridge-port.md index 8cbe15b..d5435b4 100644 --- a/doc/bridge-port.md +++ b/doc/bridge-port.md @@ -3,6 +3,9 @@ Manage ports in bridge [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index 8516ff4..cdbd72b 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -3,6 +3,9 @@ Download packages for CAP upgrade from CAPsMAN [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index 04952e2..92eafa6 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -3,6 +3,9 @@ Run rolling CAP upgrades from CAPsMAN [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/certificate-renew-issued.md b/doc/certificate-renew-issued.md index e460ce1..63d6408 100644 --- a/doc/certificate-renew-issued.md +++ b/doc/certificate-renew-issued.md @@ -3,6 +3,9 @@ Renew locally issued certificates [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 318805d..5b1e3b2 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -3,6 +3,9 @@ Renew certificates and notify on expiration [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/check-health.md b/doc/check-health.md index 37f8e34..f1b9d91 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -3,6 +3,9 @@ Notify about health state [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index c71dee5..a145da8 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -3,6 +3,9 @@ Notify on LTE firmware upgrade [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index bd25ab1..416ba98 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -3,6 +3,9 @@ Notify on RouterOS update [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/cloud-backup.md b/doc/cloud-backup.md index 1417242..60e71c9 100644 --- a/doc/cloud-backup.md +++ b/doc/cloud-backup.md @@ -3,6 +3,9 @@ Upload backup to Mikrotik cloud [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 45489bf..4da06b9 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -3,6 +3,9 @@ Collect MAC addresses in wireless access list [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/daily-psk.md b/doc/daily-psk.md index d472269..ec55c85 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -3,6 +3,9 @@ Use wireless network with daily psk [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/dhcp-lease-comment.md b/doc/dhcp-lease-comment.md index caba7d6..0b8ceb2 100644 --- a/doc/dhcp-lease-comment.md +++ b/doc/dhcp-lease-comment.md @@ -3,6 +3,9 @@ Comment DHCP leases with info from access list [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 699b6a5..22bf3bc 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -3,6 +3,9 @@ Create DNS records for DHCP leases [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/email-backup.md b/doc/email-backup.md index 7076691..85d50bd 100644 --- a/doc/email-backup.md +++ b/doc/email-backup.md @@ -3,6 +3,9 @@ Send backup via e-mail [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/gps-track.md b/doc/gps-track.md index cda7901..e4e553c 100644 --- a/doc/gps-track.md +++ b/doc/gps-track.md @@ -3,6 +3,9 @@ Send GPS position to server [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index fbb9640..108cfd5 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -3,6 +3,9 @@ Use WPA2 network with hotspot credentials [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md index f736433..994ea23 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -3,6 +3,9 @@ Update configuration on IPv6 prefix change [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/lease-script.md b/doc/lease-script.md index 3c774f1..6391c40 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -3,6 +3,9 @@ Run other scripts on DHCP lease [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/log-forward.md b/doc/log-forward.md index afb695e..0993b52 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -3,6 +3,9 @@ Forward log messages via notification [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/mode-button.md b/doc/mode-button.md index 8d037e5..3cea720 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -3,6 +3,9 @@ Mode button with multiple presses [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 11371ff..627070a 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -3,6 +3,9 @@ Notify on host up and down [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/ospf-to-leds.md b/doc/ospf-to-leds.md index 72fab6b..908fb56 100644 --- a/doc/ospf-to-leds.md +++ b/doc/ospf-to-leds.md @@ -3,6 +3,9 @@ Visualize OSPF state via LEDs [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/packages-update.md b/doc/packages-update.md index 882ce80..cc4a29b 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -3,6 +3,9 @@ Manage system update [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/ppp-on-up.md b/doc/ppp-on-up.md index 432a640..7514f82 100644 --- a/doc/ppp-on-up.md +++ b/doc/ppp-on-up.md @@ -3,6 +3,9 @@ Run scripts on ppp connection [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/rotate-ntp.md b/doc/rotate-ntp.md index eb04f5c..c151db2 100644 --- a/doc/rotate-ntp.md +++ b/doc/rotate-ntp.md @@ -3,6 +3,9 @@ Rotate NTP servers [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/sms-action.md b/doc/sms-action.md index df9e14f..e36d384 100644 --- a/doc/sms-action.md +++ b/doc/sms-action.md @@ -3,6 +3,9 @@ Act on received SMS [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 27c3847..d603daa 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -3,6 +3,9 @@ Forward received SMS [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/update-gre-address.md b/doc/update-gre-address.md index 870759e..e45e17a 100644 --- a/doc/update-gre-address.md +++ b/doc/update-gre-address.md @@ -3,6 +3,9 @@ Update GRE configuration with dynamic addresses [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/update-tunnelbroker.md b/doc/update-tunnelbroker.md index 3641588..caff9ff 100644 --- a/doc/update-tunnelbroker.md +++ b/doc/update-tunnelbroker.md @@ -3,6 +3,9 @@ Update tunnelbroker configuration [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- diff --git a/doc/upload-backup.md b/doc/upload-backup.md index e6ba9e2..4b656e4 100644 --- a/doc/upload-backup.md +++ b/doc/upload-backup.md @@ -3,6 +3,9 @@ Upload backup to server [◀ Go back to main README](../README.md) +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + Description ----------- From 41f7d1e4668a8ff1d72594e811df0b6c44d865ba Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 May 2021 08:28:58 +0200 Subject: [PATCH 0721/2612] doc/netwatch-notify: tips & tricks: one of several hosts --- doc/netwatch-notify.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 627070a..a3d8ccd 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -54,6 +54,18 @@ threshould by one. Also notification settings are required for e-mail and telegram. +Tips & Tricks +------------- + +### One of several hosts + +Sometimes it is sufficient if one of a number of hosts is available. You can +make `netwatch-notify` check for that by adding several items with same +`hostname`. Note that `count` has to be multiplied to keep the actual time. + + / tool netwatch add comment="notify, hostname=service, count=10" host=10.0.0.10; + / tool netwatch add comment="notify, hostname=service, count=10" host=10.0.0.20; + --- [◀ Go back to main README](../README.md) [▲ Go back to top](#top) From 9d19313eee7e647a7f094aa01f40f179bfd23b0b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 May 2021 14:50:45 +0200 Subject: [PATCH 0722/2612] netwatch-notify: log on host up... ... if logged on host down before. --- netwatch-notify | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 5600857..9cb99bb 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -34,9 +34,11 @@ } :if ($HostVal->"status" = "up") do={ - $LogPrintExit2 debug $0 ("Host " . $HostName . " (" . $HostVal->"host" . ") is up.") false; :local Count ($Metric->"count"); - :set ($Metric->"count") 0; + :if ($Count > 0) do={ + $LogPrintExit2 info $0 ("Host " . $HostName . " (" . $HostVal->"host" . ") is up.") false; + :set ($Metric->"count") 0; + } :if ($Metric->"notified" = true) do={ $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $HostName . " up"); \ From cfb31e844c39089046de1fc7021d5dedef14c145 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 May 2021 12:55:05 +0200 Subject: [PATCH 0723/2612] netwatch-notify: support dynamic address update --- doc/netwatch-notify.md | 9 +++++++++ global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- netwatch-notify | 15 +++++++++++++++ 6 files changed, 28 insertions(+), 3 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index a3d8ccd..ff1eae9 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -52,6 +52,15 @@ suppress notification if the parent host is down: Note that every configured parent in a chain increases the check count threshould by one. +The host address can be updated dynamically. Give extra parameter `resolve` +with a resolvable name: + + / tool netwatch add comment="notify, hostname=example.com, resolve=example.com"; + +But be warned: Dynamic updates will probably cause issues if the name has +more than one record in dns - a high rate of configuration changes (and flash +writes) at least. + Also notification settings are required for e-mail and telegram. Tips & Tricks diff --git a/global-config b/global-config index 25d0496..77f41f6 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 49; +:global GlobalConfigVersion 50; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 7057765..ac5e396 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 49; +:global GlobalConfigVersion 50; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 61850dd..74af117 100644 --- a/global-config.changes +++ b/global-config.changes @@ -53,6 +53,7 @@ 47="Removed obsolete intermediate certificate 'Let's Encrypt Authority X3' from store."; 48="Added support for overriding e-mail and Telegram settings for every script."; 49="Dropped '\$EmailBackupTo' & '\$EmailBackupCc' from configuration, use settings override if required."; + 50="Added support for dynamic address update in 'netwatch-notify'."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 0c90ad8..2626c36 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 49; +:global ExpectedConfigVersion 50; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/netwatch-notify b/netwatch-notify index 9cb99bb..50441a9 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -33,6 +33,21 @@ :set $Metric ($NetwatchNotify->$HostName); } + :if ([ :typeof ($HostInfo->"resolve") ] = "str") do={ + :do { + :local Resolve [ :resolve ($HostInfo->"resolve") ]; + :if ($Resolve != $HostVal->"host") do={ + $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ + $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . \ + "' resolves to different address " . $Resolve . ", updating.") false; + / tool netwatch set host=$Resolve $Host; + } + } on-error={ + $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ + $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . "' failed.") false; + } + } + :if ($HostVal->"status" = "up") do={ :local Count ($Metric->"count"); :if ($Count > 0) do={ From 0b1bb0f2b2b388c3fb591e1872c18779bf034415 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 May 2021 15:10:33 +0200 Subject: [PATCH 0724/2612] netwatch-notify: attempt to update address with working resolver only --- netwatch-notify | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index 50441a9..3d0bd91 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -12,6 +12,7 @@ :global NetwatchNotify; +:global DNSIsResolving; :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; @@ -33,7 +34,7 @@ :set $Metric ($NetwatchNotify->$HostName); } - :if ([ :typeof ($HostInfo->"resolve") ] = "str") do={ + :if ([ :typeof ($HostInfo->"resolve") ] = "str" && [ $DNSIsResolving ] = true) do={ :do { :local Resolve [ :resolve ($HostInfo->"resolve") ]; :if ($Resolve != $HostVal->"host") do={ From 96621e01cb6e0331fc9e2e4b90610fb7c210aab7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 May 2021 15:17:05 +0200 Subject: [PATCH 0725/2612] netwatch-notify: log failed resolve just once --- netwatch-notify | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 3d0bd91..27afd70 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -42,10 +42,14 @@ $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . \ "' resolves to different address " . $Resolve . ", updating.") false; / tool netwatch set host=$Resolve $Host; + :set ($Metric->"resolve-failed") false; } } on-error={ - $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ - $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . "' failed.") false; + :if ($Metric->"resolve-failed" != true) do={ + $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ + $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . "' failed.") false; + :set ($Metric->"resolve-failed") true; + } } } @@ -113,5 +117,6 @@ "count"=($Metric->"count"); "notified"=($Metric->"notified"); "parent"=($Metric->"parent"); + "resolve-failed"=($Metric->"resolve-failed"); "since"=($Metric->"since") }; } From 8ac4f6570a2c537a49ad0f01b6fb736217ac1544 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 May 2021 09:07:20 +0200 Subject: [PATCH 0726/2612] logo: scale to 96x96 pixels --- logo.svg | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/logo.svg b/logo.svg index c6ded77..2e376f8 100644 --- a/logo.svg +++ b/logo.svg @@ -7,16 +7,16 @@ xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="48" - height="48" - viewBox="0 0 12.7 12.7" + width="96" + height="96" + viewBox="0 0 25.4 25.4" version="1.1" id="svg8" inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)" - sodipodi:docname="routeros-scripts.svg" - inkscape:export-filename="routeros-scripts.png" - inkscape:export-xdpi="512" - inkscape:export-ydpi="512"> + sodipodi:docname="logo.svg" + inkscape:export-filename="logo.png" + inkscape:export-xdpi="96" + inkscape:export-ydpi="96"> + id="g931" + transform="scale(2)" + style="stroke-width:0.5"> + id="g906" + style="stroke-width:0.5"> #!rsc + style="stroke-width:0.132291px">#!rsc + transform="translate(-0.20567219,1.5875)" + style="stroke-width:0.5"> From 2c77db52bf7288a36890e1ff491f85f1bf741f11 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 May 2021 09:11:55 +0200 Subject: [PATCH 0727/2612] logo: convert text to path --- logo.svg | 59 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/logo.svg b/logo.svg index 2e376f8..f0923fd 100644 --- a/logo.svg +++ b/logo.svg @@ -51,7 +51,7 @@ image/svg+xml - + @@ -60,41 +60,52 @@ inkscape:groupmode="layer" id="layer1"> + id="g884"> + d="m 23.177407,23.177407 c -2.963458,2.963458 -17.9913546,2.963458 -20.9548127,0 -2.96345803,-2.963458 -2.96345808,-17.9913546 0,-20.9548127 2.963458,-2.96345803 17.9913547,-2.96345808 20.9548127,0 2.963458,2.963458 2.963458,17.9913547 0,20.9548127 z" /> - #!rsc + id="g871"> + + + + + + + Date: Fri, 7 May 2021 09:18:03 +0200 Subject: [PATCH 0728/2612] logo: clean png export --- logo.png | Bin 3727 -> 3807 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/logo.png b/logo.png index cfe91be6063926b3ecc641d0d9909dda3134f06c..142e9186fb149f5508d2942e93aca9db90ee7276 100644 GIT binary patch literal 3807 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 Date: Fri, 7 May 2021 09:13:09 +0200 Subject: [PATCH 0729/2612] README: use svg logo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b030d08..5d7498d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ RouterOS Scripts [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/watchers) -![RouterOS Scripts Logo](logo.png) +![RouterOS Scripts Logo](logo.svg) [RouterOS](https://mikrotik.com/software) is the operating system developed by [MikroTik](https://mikrotik.com/aboutus) for networking tasks. This From 2ba389a2beeb8684f633684d606da6f653fa1205 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 17 May 2021 15:54:54 +0200 Subject: [PATCH 0730/2612] dhcp-to-dns: put string into variable --- dhcp-to-dns | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index dfb438f..83e312f 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -25,12 +25,13 @@ [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); :local Ttl 5m; :local CommentPrefix "managed by dhcp-to-dns for "; +:local CommentString "--- dhcp-to-dns above ---"; -:if ([ :len [ / ip dns static find where comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled ] ] = 0) do={ - / ip dns static add comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled static dns record with comment '--- dhcp-to-dns above ---'.") false; +:if ([ :len [ / ip dns static find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ + / ip dns static add comment=$CommentString name=- type=NXDOMAIN disabled=yes; + $LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false; } -:local PlaceBefore ([ / ip dns static find where comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled ]->0); +:local PlaceBefore ([ / ip dns static find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0); :foreach DnsRecord in=[ / ip dns static find where comment ~ $CommentPrefix ] do={ :local DnsRecordVal [ / ip dns static get $DnsRecord ]; From 604306f2200a2a4bc6f6865f4aea90befe2e0142 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 17 May 2021 15:46:32 +0200 Subject: [PATCH 0731/2612] dhcp-to-dns: use $0 in strings --- dhcp-to-dns | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index 83e312f..bfd6195 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -24,8 +24,8 @@ ([ $IfThenElse ($PrefixInZone = true) "dhcp." ] . \ [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); :local Ttl 5m; -:local CommentPrefix "managed by dhcp-to-dns for "; -:local CommentString "--- dhcp-to-dns above ---"; +:local CommentPrefix ("managed by " . $0 . " for "); +:local CommentString ("--- " . $0 . " above ---"); :if ([ :len [ / ip dns static find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ / ip dns static add comment=$CommentString name=- type=NXDOMAIN disabled=yes; From 862417b8d32f6eef1c05ba9137fe2a7f14436987 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 17 May 2021 16:32:07 +0200 Subject: [PATCH 0732/2612] add 'ipsec-to-dns' --- README.md | 1 + doc/dhcp-to-dns.md | 1 + doc/ipsec-to-dns.md | 46 +++++++++++++++++++++++++++++ global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- ipsec-to-dns | 68 +++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 doc/ipsec-to-dns.md create mode 100644 ipsec-to-dns diff --git a/README.md b/README.md index 5d7498d..e102202 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,7 @@ Available Scripts * [Send backup via e-mail](doc/email-backup.md) * [Send GPS position to server](doc/gps-track.md) * [Use WPA2 network with hotspot credentials](doc/hotspot-to-wpa.md) +* [Create DNS records for IPSec peers](doc/ipsec-to-dns.md) * [Update configuration on IPv6 prefix change](doc/ipv6-update.md) * [Manage IP addresses with bridge status](doc/ip-addr-bridge.md) * [Run other scripts on DHCP lease](doc/lease-script.md) diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 22bf3bc..60eb29d 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -44,6 +44,7 @@ See also * [Collect MAC addresses in wireless access list](collect-wireless-mac.md) * [Comment DHCP leases with info from access list](dhcp-lease-comment.md) +* [Create DNS records for IPSec peers](ipsec-to-dns.md) * [Run other scripts on DHCP lease](lease-script.md) --- diff --git a/doc/ipsec-to-dns.md b/doc/ipsec-to-dns.md new file mode 100644 index 0000000..9a0f486 --- /dev/null +++ b/doc/ipsec-to-dns.md @@ -0,0 +1,46 @@ +Create DNS records for IPSec peers +================================== + +[◀ Go back to main README](../README.md) + +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + +Description +----------- + +This script adds (and removes) dns records based on IPSec peers and their +dynamic addresses from mode-config. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate ipsec-to-dns; + +This script is run from scheduler: + + / system scheduler add interval=1m name=ipsec-to-dns on-event="/ system script run ipsec-to-dns;" start-time=startup; + +Configuration +------------- + +On first run a disabled static dns record acting as marker (with comment +"`--- ipsec-to-dns above ---`") is added. Move this entry to define where new +entries are to be added. + +The configuration goes to `global-config-overlay`, these are the parameters: + +* `Domain`: the domain used for dns records +* `HostNameInZone`: whether or not to add the ipsec/dns server's hostname +* `PrefixInZone`: whether or not to add prefix `ipsec` + +See also +-------- + +* [Create DNS records for DHCP leases](dns-to-dhcp.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/global-config b/global-config index 77f41f6..a02d840 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 50; +:global GlobalConfigVersion 51; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index ac5e396..6ff1a9e 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 50; +:global GlobalConfigVersion 51; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 74af117..4bada85 100644 --- a/global-config.changes +++ b/global-config.changes @@ -54,6 +54,7 @@ 48="Added support for overriding e-mail and Telegram settings for every script."; 49="Dropped '\$EmailBackupTo' & '\$EmailBackupCc' from configuration, use settings override if required."; 50="Added support for dynamic address update in 'netwatch-notify'."; + 51="Added 'ipsec-to-dns' to add DNS records for IPSec peers from mode-config."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 2626c36..92995c9 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 50; +:global ExpectedConfigVersion 51; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/ipsec-to-dns b/ipsec-to-dns new file mode 100644 index 0000000..bfdc807 --- /dev/null +++ b/ipsec-to-dns @@ -0,0 +1,68 @@ +#!rsc by RouterOS +# RouterOS script: ipsec-to-dns +# Copyright (c) 2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# and add/remove/update DNS entries from IPSec mode-config +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipsec-to-dns.md + +:local 0 "ipsec-to-dns"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Domain; +:global HostNameInZone; +:global Identity; +:global PrefixInZone; + +:global CharacterReplace; +:global LogPrintExit2; +:global IfThenElse; + +:local Zone \ + ([ $IfThenElse ($PrefixInZone = true) "ipsec." ] . \ + [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); +:local Ttl 5m; +:local CommentPrefix ("managed by " . $0 . " for "); +:local CommentString ("--- " . $0 . " above ---"); + +:if ([ :len [ / ip dns static find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ + / ip dns static add comment=$CommentString name=- type=NXDOMAIN disabled=yes; + $LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false; +} +:local PlaceBefore ([ / ip dns static find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0); + +:foreach DnsRecord in=[ / ip dns static find where comment ~ $CommentPrefix ] do={ + :local DnsRecordVal [ / ip dns static get $DnsRecord ]; + :local PeerId [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; + :if ([ :len [ / ip ipsec active-peers find where id=$PeerId dynamic-address=($DnsRecordVal->"address") ] ] > 0) do={ + $LogPrintExit2 debug $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; + } else={ + :local Found false; + $LogPrintExit2 info $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") has gone, deleting DNS entry.") false; + / ip dns static remove $DnsRecord; + } +} + +:foreach Peer in=[ / ip ipsec active-peers find where !(dynamic-address=[]) ] do={ + :local PeerVal [ / ip ipsec active-peers get $Peer ]; + :local Comment ($CommentPrefix . $PeerVal->"id"); +:put ($PeerVal->"id"); + :local HostName [ :pick ($PeerVal->"id") 0 [ :find ($PeerVal->"id" . ".") "." ] ]; +:put $HostName; + + :local Fqdn ($HostName . "." . $Zone); + :local DnsRecord [ / ip dns static find where name=$Fqdn ]; + :if ([ :len $DnsRecord ] > 0) do={ + :local DnsIp [ / ip dns static get $DnsRecord address ]; + :if ($DnsIp = $PeerVal->"dynamic-address") do={ + $LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false; + } else={ + $LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $PeerVal->"dynamic-address" . ".") false; + / ip dns static set name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment $DnsRecord; + } + } else={ + $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $PeerVal->"dynamic-address" . ".") false; + / ip dns static add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + } +} From f2433b8091a7966db6cf2a8bc6890e576b592d13 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 30 Apr 2019 15:11:54 +0200 Subject: [PATCH 0733/2612] drop certificate DST Root CA X3 Let's Encrypt planned the transition to ISRG's root certificate ("ISRG Root X1") on July 8, 2019, but postponed several times. Finally they found another solution: A certificate 'ISRG Root X1', but cross-signed with 'DST Root CA X3' and with a livetime that exceeds that of the root CA. This is said to work for most operating system where root certificate authorities are just 'trust anchors'. I doubt this is true for RouterOS, where certificates are just imported into the certificate store. So let's migrate to 'ISRG Root X1' now. --- INITIAL-COMMANDS.md | 3 +- README.md | 16 +++------- certs/R3.pem | 77 --------------------------------------------- 3 files changed, 5 insertions(+), 91 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index fa32654..9df69fa 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -10,7 +10,7 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem"; :delay 1s; / certificate import file-name=letsencrypt-R3.pem passphrase=""; - :if ([ :len [ / certificate find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] ] != 3) do={ + :if ([ :len [ / certificate find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ] ] != 2) do={ :error "Something is wrong with your certificates!"; } / file remove "letsencrypt-R3.pem"; @@ -22,7 +22,6 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai :global CertificateNameByCN; $CertificateNameByCN "R3"; $CertificateNameByCN "ISRG Root X1"; - $CertificateNameByCN "DST Root CA X3"; } Optional to update the scripts automatically: diff --git a/README.md b/README.md index e102202..c5c0ba5 100644 --- a/README.md +++ b/README.md @@ -66,30 +66,22 @@ files to your MikroTik device. Then we import the certificates. [admin@MikroTik] > / certificate import file-name=letsencrypt-R3.pem passphrase="" - certificates-imported: 3 + certificates-imported: 2 private-keys-imported: 0 files-imported: 1 decryption-failures: 0 keys-with-no-certificate: 0 For basic verification we rename the certificates and print their count. Make -sure the certificate count is **three**. +sure the certificate count is **two**. [admin@MikroTik] > / certificate set name="R3" [ find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" ] [admin@MikroTik] > / certificate set name="ISRG-Root-X1" [ find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ] - [admin@MikroTik] > / certificate set name="DST-Root-CA-X3" [ find where fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] - [admin@MikroTik] > / certificate print count-only where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" - 3 + [admin@MikroTik] > / certificate print count-only where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" + 2 Always make sure there are no certificates installed you do not know or want! -Actually we do not require the certificate named `DST Root CA X3`, but as it -is used by `Let's Encrypt` to cross-sign we install it anyway - this makes -sure things do not go wrong if the intermediate certificate is replaced. -The IdenTrust certificate *should* be available from their -[download page](https://www.identrust.com/support/downloads). The site is -crap and a good example how to *not* do it. - Now let's download the main scripts and add them in configuration on the fly. [admin@MikroTik] > :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } diff --git a/certs/R3.pem b/certs/R3.pem index ac322ec..837b709 100644 --- a/certs/R3.pem +++ b/certs/R3.pem @@ -235,80 +235,3 @@ oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= -----END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 44:af:b0:80:d6:a3:27:ba:89:30:39:86:2e:f8:40:6b - Signature Algorithm: sha1WithRSAEncryption - Issuer: O = Digital Signature Trust Co., CN = DST Root CA X3 - Validity - Not Before: Sep 30 21:12:19 2000 GMT - Not After : Sep 30 14:01:15 2021 GMT - Subject: O = Digital Signature Trust Co., CN = DST Root CA X3 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:df:af:e9:97:50:08:83:57:b4:cc:62:65:f6:90: - 82:ec:c7:d3:2c:6b:30:ca:5b:ec:d9:c3:7d:c7:40: - c1:18:14:8b:e0:e8:33:76:49:2a:e3:3f:21:49:93: - ac:4e:0e:af:3e:48:cb:65:ee:fc:d3:21:0f:65:d2: - 2a:d9:32:8f:8c:e5:f7:77:b0:12:7b:b5:95:c0:89: - a3:a9:ba:ed:73:2e:7a:0c:06:32:83:a2:7e:8a:14: - 30:cd:11:a0:e1:2a:38:b9:79:0a:31:fd:50:bd:80: - 65:df:b7:51:63:83:c8:e2:88:61:ea:4b:61:81:ec: - 52:6b:b9:a2:e2:4b:1a:28:9f:48:a3:9e:0c:da:09: - 8e:3e:17:2e:1e:dd:20:df:5b:c6:2a:8a:ab:2e:bd: - 70:ad:c5:0b:1a:25:90:74:72:c5:7b:6a:ab:34:d6: - 30:89:ff:e5:68:13:7b:54:0b:c8:d6:ae:ec:5a:9c: - 92:1e:3d:64:b3:8c:c6:df:bf:c9:41:70:ec:16:72: - d5:26:ec:38:55:39:43:d0:fc:fd:18:5c:40:f1:97: - eb:d5:9a:9b:8d:1d:ba:da:25:b9:c6:d8:df:c1:15: - 02:3a:ab:da:6e:f1:3e:2e:f5:5c:08:9c:3c:d6:83: - 69:e4:10:9b:19:2a:b6:29:57:e3:e5:3d:9b:9f:f0: - 02:5d - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - C4:A7:B1:A4:7B:2C:71:FA:DB:E1:4B:90:75:FF:C4:15:60:85:89:10 - Signature Algorithm: sha1WithRSAEncryption - a3:1a:2c:9b:17:00:5c:a9:1e:ee:28:66:37:3a:bf:83:c7:3f: - 4b:c3:09:a0:95:20:5d:e3:d9:59:44:d2:3e:0d:3e:bd:8a:4b: - a0:74:1f:ce:10:82:9c:74:1a:1d:7e:98:1a:dd:cb:13:4b:b3: - 20:44:e4:91:e9:cc:fc:7d:a5:db:6a:e5:fe:e6:fd:e0:4e:dd: - b7:00:3a:b5:70:49:af:f2:e5:eb:02:f1:d1:02:8b:19:cb:94: - 3a:5e:48:c4:18:1e:58:19:5f:1e:02:5a:f0:0c:f1:b1:ad:a9: - dc:59:86:8b:6e:e9:91:f5:86:ca:fa:b9:66:33:aa:59:5b:ce: - e2:a7:16:73:47:cb:2b:cc:99:b0:37:48:cf:e3:56:4b:f5:cf: - 0f:0c:72:32:87:c6:f0:44:bb:53:72:6d:43:f5:26:48:9a:52: - 67:b7:58:ab:fe:67:76:71:78:db:0d:a2:56:14:13:39:24:31: - 85:a2:a8:02:5a:30:47:e1:dd:50:07:bc:02:09:90:00:eb:64: - 63:60:9b:16:bc:88:c9:12:e6:d2:7d:91:8b:f9:3d:32:8d:65: - b4:e9:7c:b1:57:76:ea:c5:b6:28:39:bf:15:65:1c:c8:f6:77: - 96:6a:0a:8d:77:0b:d8:91:0b:04:8e:07:db:29:b6:0a:ee:9d: - 82:35:35:10 ------BEGIN CERTIFICATE----- -MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ -MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT -DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow -PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD -Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O -rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq -OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b -xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw -7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD -aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV -HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG -SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 -ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr -AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz -R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 -JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo -Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ ------END CERTIFICATE----- From 4427cabd0eac9f8a5b18f939198284621933fa36 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 21 Dec 2020 00:02:49 +0100 Subject: [PATCH 0734/2612] update Let's Encrypt trust chain Drop 'DST Root CA X3', use 'ISRG Root X1' instead. The migration code makes sure that... * the intermediate certificate 'R3' is signed by 'ISRG Root X1' * 'ISRG Root X1' is self-signed, not cross-signed by 'DST Root CA X3' * 'DST Root CA X3' is finally gone --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 2 ++ global-functions | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index a02d840..6730a45 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 51; +:global GlobalConfigVersion 52; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 6ff1a9e..f90abd6 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 51; +:global GlobalConfigVersion 52; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 4bada85..cfaf649 100644 --- a/global-config.changes +++ b/global-config.changes @@ -55,10 +55,12 @@ 49="Dropped '\$EmailBackupTo' & '\$EmailBackupCc' from configuration, use settings override if required."; 50="Added support for dynamic address update in 'netwatch-notify'."; 51="Added 'ipsec-to-dns' to add DNS records for IPSec peers from mode-config."; + 52="Updated Let's Encrypt trust chain to use root certificate 'ISRG Root X1'. Do not re-import the old chain!"; }; # Migration steps to be applied on script updates :global GlobalConfigMigration { 41=":global SendNotification; \$SendNotification (\"Migration mechanism\") (\"Congratulations!\nSuccessfully tested the new migration mechanism.\");"; 47="/ certificate remove [ find where fingerprint=\"731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568\" or fingerprint=\"25847d668eb4f04fdd40b12b6b0740c567da7d024308eb6c2c96fe41d9de218d\" ];"; + 52=":global CertificateDownload; :if ([ :len [ / certificate find where fingerprint=\"67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd\" or fingerprint=\"96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6\" ] ] < 2) do={ \$CertificateDownload \"R3\"; }; / certificate remove [ find where fingerprint=\"0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739\" ];"; }; diff --git a/global-functions b/global-functions index 92995c9..86a6494 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 51; +:global ExpectedConfigVersion 52; # global variables not to be changed by user :global GlobalFunctionsReady false; From 05a7ae409ba1cee217b68adacf1d8d27d43414d5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 18 May 2021 16:44:07 +0200 Subject: [PATCH 0735/2612] netwatch-notify: add info on hook in notification --- netwatch-notify | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 27afd70..c630678 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -60,18 +60,20 @@ :set ($Metric->"count") 0; } :if ($Metric->"notified" = true) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $HostName . " up"); \ - message=("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ - "It was down for " . $Count . " checks since " . ($Metric->"since") . ".") }); + :local Message ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ + "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ :if ([ $ValidateSyntax ($HostInfo->"up-hook") ] = true) do={ $LogPrintExit2 info $0 ("Running hook on host " . $HostName . " up: " . ($HostInfo->"up-hook")) false; + :set Message ($Message . "\n\nRunning hook:\n" . $HostInfo->"up-hook"); [ :parse ($HostInfo->"up-hook") ]; } else={ $LogPrintExit2 warning $0 ("The up-hook for host " . $HostName . " failed syntax validation.") false; } } + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $HostName . " up"); \ + message=$Message }); } :set ($Metric->"notified") false; :set ($Metric->"parent") ($HostInfo->"parent"); @@ -99,18 +101,20 @@ ($Metric->"notified" = true) ("already notified.") ($Count - $Metric->"count" . " to go.") ] \ ("parent host " . $Parent . " is down.") ]) false; :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down"); \ - message=("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . ".") }); - :set ($Metric->"notified") true; + :local Message ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ :if ([ $ValidateSyntax ($HostInfo->"down-hook") ] = true) do={ $LogPrintExit2 info $0 ("Running hook on host " . $HostName . " down: " . ($HostInfo->"down-hook")) false; + :set Message ($Message . "\n\nRunning hook:\n" . $HostInfo->"down-hook"); [ :parse ($HostInfo->"down-hook") ]; } else={ $LogPrintExit2 warning $0 ("The down-hook for host " . $HostName . " failed syntax validation.") false; } } + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down"); \ + message=$Message }); + :set ($Metric->"notified") true; } } :set ($NetwatchNotify->$HostName) { From 45dd33c90a8404ee9bd317067fa1f88462c5d907 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 19 May 2021 14:03:18 +0200 Subject: [PATCH 0736/2612] global-functions: $DownloadPackage: quote package name --- global-functions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 86a6494..56b9135 100644 --- a/global-functions +++ b/global-functions @@ -272,7 +272,7 @@ $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; } - $LogPrintExit2 info $0 ("Downloading package file " . $PkgName . "...") false; + $LogPrintExit2 info $0 ("Downloading package file '" . $PkgName . "'...") false; :local Retry 3; :while ($Retry > 0) do={ :do { @@ -292,7 +292,7 @@ :set Retry ($Retry - 1); } - $LogPrintExit2 warning $0 ("Downloading package file " . $PkgName . " failed.") false; + $LogPrintExit2 warning $0 ("Downloading package file '" . $PkgName . "' failed.") false; :return false; } From 330bc7fc8b39bebccf3d439acdc3318e4fe6623c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 21 May 2021 08:31:45 +0200 Subject: [PATCH 0737/2612] check-certificates: fix variable name --- check-certificates | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index a052930..9ddf0e7 100644 --- a/check-certificates +++ b/check-certificates @@ -124,7 +124,7 @@ $WaitFullyConnected; message=("A certificate on " . $Identity . " " . $State . ".\n\n" . \ "Name: " . ($CertVal->"name") . "\n" . \ "CommonName: " . ($CertVal->"common-name") . "\n" . \ - "Private key: " . [ $IfThenElse (($CertNewVal->"private-key") = true) "available" "missing" ] . "\n" . \ + "Private key: " . [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] . "\n" . \ "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ From e74b2e03a25cf7722de0013e7a2c7ed990602ff6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 May 2021 21:32:56 +0200 Subject: [PATCH 0738/2612] ipv6-update: apply a mask on prefix Fixes #11 --- ipv6-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv6-update b/ipv6-update index 3223807..45efccd 100644 --- a/ipv6-update +++ b/ipv6-update @@ -51,7 +51,7 @@ :local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ]; :local Prefix [ / ipv6 address get [ find where interface=($Comment->"interface") from-pool=$Pool global ] address ]; - :set Prefix [ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ]; + :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); :log info ("Updating DNS record for " . ($RecordVal->"name") . ($RecordVal->"regexp") . " to " . $Address); From 80ee7d3bdd0bdd7f640a4eb74544322d2c9d78f8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 May 2021 08:51:51 +0200 Subject: [PATCH 0739/2612] Makefile: remove extra whitespace --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f96e73e..01b9a72 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ CAPSMAN = $(TEMPLATE:.template=.capsman) LOCAL = $(TEMPLATE:.template=.local) MARKDOWN = $(wildcard *.md) -HTML = $(MARKDOWN:.md=.html) +HTML = $(MARKDOWN:.md=.html) all: $(CAPSMAN) $(LOCAL) $(HTML) From 7de5b58ad49ba30ccb03c116aee4cdcb828f1c22 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 6 Jun 2021 21:41:42 +0200 Subject: [PATCH 0740/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 1d2d04a..faac400 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -18,6 +18,7 @@ These persons contributed code. See the git history for details! Add yourself to the list, [donate with PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)! +* Andrew Cox * Christoph Boss (@Kampfwurst) * Klaus Michael RÃŧbsam * Linux-Schmie.de Michael Gisbers From a1c8716a9523ffff61d1151cf7384cdeb11f27a7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 8 Jun 2021 20:46:40 +0200 Subject: [PATCH 0741/2612] INITIAL-COMMANDS: make github copy function work The Github copy function skips all line breaks, so add some extra semicolons to fix syntax. --- INITIAL-COMMANDS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 9df69fa..c88b709 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -12,12 +12,12 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai / certificate import file-name=letsencrypt-R3.pem passphrase=""; :if ([ :len [ / certificate find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ] ] != 2) do={ :error "Something is wrong with your certificates!"; - } + }; / file remove "letsencrypt-R3.pem"; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); - } - / system script { run global-config; run global-config-overlay; run global-functions; } + }; + / system script { run global-config; run global-config-overlay; run global-functions; }; / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }"; :global CertificateNameByCN; $CertificateNameByCN "R3"; From 57b0f1b2dd237848f0cdcd19b43b9b0bb16cd15e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 27 May 2021 22:31:50 +0200 Subject: [PATCH 0742/2612] global-functions: support loading modules If script's name starts with "global-functions.d/" it is handled as module: * loaded at startup * triggers reload on update --- global-functions | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 56b9135..9f5be02 100644 --- a/global-functions +++ b/global-functions @@ -767,7 +767,7 @@ " Syntax error or missing overlay\?") false; } } - :if ($ScriptVal->"name" = "global-functions") do={ + :if ($ScriptVal->"name" ~ "^global-functions(\$|\\.d/.)") do={ $LogPrintExit2 info $0 ("Reloading global functions.") false; :do { / system script run global-functions; @@ -1261,6 +1261,11 @@ } } +# load modules +:foreach Script in=[ / system script find where name ~ "^global-functions\\.d/." ] do={ + / system script run $Script; +} + # check for required RouterOS version $RequiredRouterOS "global-functions" "6.47"; From 2315d6bc59e6d2294fadb5f0ab8d712f55793db2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 31 May 2021 10:04:45 +0200 Subject: [PATCH 0743/2612] global-functions: $ScriptInstallUpdate: reload functions just once --- global-functions | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/global-functions b/global-functions index 9f5be02..cf4ad7a 100644 --- a/global-functions +++ b/global-functions @@ -709,6 +709,7 @@ } :local ExpectedConfigVersionBefore $ExpectedConfigVersion; + :local ReloadGlobalFunctions false; :local ScriptInstallUpdateBefore [ :tostr $ScriptInstallUpdate ]; :foreach Script in=[ / system script find where source~"^#!rsc( by RouterOS)\?\n" ] do={ @@ -768,12 +769,7 @@ } } :if ($ScriptVal->"name" ~ "^global-functions(\$|\\.d/.)") do={ - $LogPrintExit2 info $0 ("Reloading global functions.") false; - :do { - / system script run global-functions; - } on-error={ - $LogPrintExit2 error $0 ("Reloading global functions failed!") false; - } + :set ReloadGlobalFunctions true; } } else={ $LogPrintExit2 warning $0 ("Syntax validation for script " . $ScriptVal->"name" . \ @@ -791,6 +787,15 @@ } } + :if ($ReloadGlobalFunctions = true) do={ + $LogPrintExit2 info $0 ("Reloading global functions.") false; + :do { + / system script run global-functions; + } on-error={ + $LogPrintExit2 error $0 ("Reloading global functions failed!") false; + } + } + :if ($ExpectedConfigVersionBefore != $ExpectedConfigVersion) do={ :global GlobalConfigChanges; :global GlobalConfigMigration; From f9a2afdedafc9639bf658335218bd00274364827 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 2 Jun 2021 23:51:11 +0200 Subject: [PATCH 0744/2612] global-functions: $ScriptInstallUpdate: reload configuration later --- global-functions | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/global-functions b/global-functions index cf4ad7a..ab95f3f 100644 --- a/global-functions +++ b/global-functions @@ -710,6 +710,7 @@ :local ExpectedConfigVersionBefore $ExpectedConfigVersion; :local ReloadGlobalFunctions false; + :local ReloadGlobalConfig false; :local ScriptInstallUpdateBefore [ :tostr $ScriptInstallUpdate ]; :foreach Script in=[ / system script find where source~"^#!rsc( by RouterOS)\?\n" ] do={ @@ -760,13 +761,7 @@ / system script set owner=($ScriptVal->"name") source=$SourceNew \ dont-require-permissions=$DontRequirePermissions $Script; :if ($ScriptVal->"name" = "global-config") do={ - $LogPrintExit2 info $0 ("Reloading global configuration and overlay.") false; - :do { - / system script { run global-config; run global-config-overlay; } - } on-error={ - $LogPrintExit2 error $0 ("Reloading global configuration and overlay failed!" . \ - " Syntax error or missing overlay\?") false; - } + :set ReloadGlobalConfig true; } :if ($ScriptVal->"name" ~ "^global-functions(\$|\\.d/.)") do={ :set ReloadGlobalFunctions true; @@ -796,6 +791,16 @@ } } + :if ($ReloadGlobalConfig = true) do={ + $LogPrintExit2 info $0 ("Reloading global configuration and overlay.") false; + :do { + / system script { run global-config; run global-config-overlay; } + } on-error={ + $LogPrintExit2 error $0 ("Reloading global configuration and overlay failed!" . \ + " Syntax error or missing overlay\?") false; + } + } + :if ($ExpectedConfigVersionBefore != $ExpectedConfigVersion) do={ :global GlobalConfigChanges; :global GlobalConfigMigration; From b866eca3eca714e60bb1b23887717e88dd9d66e8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 2 Jun 2021 23:54:35 +0200 Subject: [PATCH 0745/2612] global-functions: $ScriptInstallUpdate: drop the re-run message This makes sense just rarely... For important changes we have the migration mechanism. So just drop this. --- global-functions | 5 ----- 1 file changed, 5 deletions(-) diff --git a/global-functions b/global-functions index ab95f3f..c5996ee 100644 --- a/global-functions +++ b/global-functions @@ -711,7 +711,6 @@ :local ExpectedConfigVersionBefore $ExpectedConfigVersion; :local ReloadGlobalFunctions false; :local ReloadGlobalConfig false; - :local ScriptInstallUpdateBefore [ :tostr $ScriptInstallUpdate ]; :foreach Script in=[ / system script find where source~"^#!rsc( by RouterOS)\?\n" ] do={ :local ScriptVal [ / system script get $Script ]; @@ -879,10 +878,6 @@ :set GlobalConfigChanges; :set GlobalConfigMigration; } - - :if ($ScriptInstallUpdateBefore != [ :tostr $ScriptInstallUpdate ]) do={ - $LogPrintExit2 info $0 ("This function changed, you may want to re-run.") false; - } } # lock script against multiple invocation From 7a43bfbc6abc811be42ae9d314c37ffb4c695ea2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 27 May 2021 16:53:12 +0200 Subject: [PATCH 0746/2612] global-functions: make notification functions extensible This allows to add notification functions without overloading functions. Just add it into the array: :set ($NotificationFunctions->"fancy-messager") do={ # notification magic here... } Adding functions $SendFancyMessager and/or $SendFancyMessager2 may be useful. Optionally a function to flush a queue may be required. A BIG FAT WARNING about function parameters: Calling a function from array results in $0 for the function name being skipped. That's why we have to add the function name manually! --- global-functions | 292 ++++++++++++++++++++++++++--------------------- 1 file changed, 159 insertions(+), 133 deletions(-) diff --git a/global-functions b/global-functions index c5996ee..5ceab4f 100644 --- a/global-functions +++ b/global-functions @@ -36,6 +36,7 @@ :global LogPrintExit; :global LogPrintExit2; :global MkDir; +:global NotificationFunctions; :global ParseKeyValueStore; :global QuotedPrintable; :global RandomDelay; @@ -575,6 +576,152 @@ :return $Return; } +# prepare NotificationFunctions array +:if ([ :typeof $NotificationFunctions ] != "array") do={ + :set NotificationFunctions [ :toarray "" ]; +} + +# send notification via e-mail - expects one array argument +:set ($NotificationFunctions->"email") do={ + :local Notification $1; + + :global Identity; + :global EmailGeneralTo; + :global EmailGeneralToOverride; + :global EmailGeneralCc; + :global EmailGeneralCcOverride; + :global EmailQueue; + + :global EitherOr; + :global IfThenElse; + :global LogPrintExit2; + :global QuotedPrintable; + + :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; + :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; + + :if ([ :len $To ] = 0) do={ + :return false; + } + + :if ([ :typeof $EmailQueue ] = "nothing") do={ + :set EmailQueue [ :toarray "" ]; + } + :local Signature [ / system note get note ]; + :set ($EmailQueue->[ :len $EmailQueue ]) { + to=$To; cc=$Cc; + subject=[ $QuotedPrintable ("[" . $Identity . "] " . ($Notification->"subject")) ]; + body=(($Notification->"message") . \ + [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ + [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \ + attach=($Notification->"attach") }; + :if ([ :len [ / system scheduler find where name="FlushEmailQueue" ] ] = 0) do={ + / system scheduler add name=FlushEmailQueue interval=1s start-time=startup \ + on-event=":global FlushEmailQueue; \$FlushEmailQueue;"; + } +} + +# send notification via telegram - expects one array argument +:set ($NotificationFunctions->"telegram") do={ + :local Notification $1; + + :global Identity; + :global TelegramChatId; + :global TelegramChatIdOverride; + :global TelegramFixedWidthFont; + :global TelegramQueue; + :global TelegramTokenId; + :global TelegramTokenIdOverride; + + :global CertificateAvailable; + :global CharacterReplace; + :global EitherOr; + :global IfThenElse; + :global LogPrintExit2; + :global SymbolForNotification; + :global UrlEncode; + + :local EscapeMD do={ + :global TelegramFixedWidthFont; + + :global CharacterReplace; + :global IfThenElse; + + :if ($TelegramFixedWidthFont != true) do={ + :return ($1 . [ $IfThenElse ($2 = "body") "\n" "" ]); + } + + :local Return $1; + :local Chars { + "body"={ "\\"; "`" }; + "hint"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">"; + "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; + } + :foreach Char in=($Chars->$2) do={ + :set Return [ $CharacterReplace $Return $Char ("\\" . $Char) ]; + } + + :if ($2 = "body") do={ + :return ("```\n" . $Return . "\n```"); + } + + :return $Return; + } + + :local ChatId [ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ]; + :local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ]; + + :if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={ + :return false; + } + + :local Truncated false; + :local LenLink [ :len ($Notification->"link") ]; + :local Text ("[" . $Identity . "] " . ($Notification->"subject") . "\n\n" . ($Notification->"message")); + :local LenText [ :len $Text ]; + :if ($LenText > (3968 - $LenLink)) do={ + :set Text [ $EscapeMD ([ :pick $Text 0 (3840 - $LenLink) ] . "...") "body" ]; + :set Truncated true; + } else={ + :set Text [ $EscapeMD $Text "body" ]; + } + :if ($LenLink > 0) do={ + :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD ($Notification->"link") "hint" ]); + } + :if ($Truncated = true) do={ + :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ + [ $EscapeMD ("The Telegram message was too long and has been truncated, cut off " . \ + (($LenText - [ :len $Text ]) * 100 / $LenText) . "%!") "hint" ]); + } + :set Text [ $UrlEncode $Text ]; + :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; + + :do { + :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; + } + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ + http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ + "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; + } on-error={ + $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; + + :if ([ :typeof $TelegramQueue ] = "nothing") do={ + :set TelegramQueue [ :toarray "" ]; + } + :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ + [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ + " " . [ / system clock get time ] . " and may be obsolete.") "hint" ]) ]); + :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; + parsemode=$ParseMode; text=$Text; silent=($Notification->"silent") }; + :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ + / system scheduler add name=FlushTelegramQueue interval=1m start-time=startup \ + on-event=":global FlushTelegramQueue; \$FlushTelegramQueue;"; + } + } +} + # parse key value store :set ParseKeyValueStore do={ :local Source $1; @@ -902,58 +1049,29 @@ :set SendEMail2 do={ :local Notification $1; - :global Identity; - :global EmailGeneralTo; - :global EmailGeneralToOverride; - :global EmailGeneralCc; - :global EmailGeneralCcOverride; - :global EmailQueue; + :global NotificationFunctions; - :global EitherOr; - :global IfThenElse; - :global LogPrintExit2; - :global QuotedPrintable; - - :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; - :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; - - :if ([ :len $To ] = 0) do={ - :return false; - } - - :if ([ :typeof $EmailQueue ] = "nothing") do={ - :set EmailQueue [ :toarray "" ]; - } - :local Signature [ / system note get note ]; - :set ($EmailQueue->[ :len $EmailQueue ]) { - to=$To; cc=$Cc; - subject=[ $QuotedPrintable ("[" . $Identity . "] " . ($Notification->"subject")) ]; - body=(($Notification->"message") . \ - [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ - [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \ - attach=($Notification->"attach") }; - :if ([ :len [ / system scheduler find where name="FlushEmailQueue" ] ] = 0) do={ - / system scheduler add name=FlushEmailQueue interval=1s start-time=startup \ - on-event=":global FlushEmailQueue; \$FlushEmailQueue;"; - } + ($NotificationFunctions->"e-mail") ("\$NotificationFunctions->\"e-mail\"") $Notification; } -# send notification via e-mail and telegram - expects at lease two string arguments +# send notification via NotificationFunctions - expects at lease two string arguments :set SendNotification do={ :global SendNotification2; $SendNotification2 ({ subject=$1; message=$2; link=$3; silent=$4 }); } -# send notification via e-mail and telegram - expects one array argument +# send notification via NotificationFunctions - expects one array argument :set SendNotification2 do={ :local Notification $1; - :global SendEMail2; - :global SendTelegram2; + :global NotificationFunctions; - $SendEMail2 $Notification; - $SendTelegram2 $Notification; + :foreach FunctionName,Discard in=$NotificationFunctions do={ + ($NotificationFunctions->$FunctionName) \ + ("\$NotificationFunctions->\"" . $FunctionName . "\"") \ + $Notification; + } } # send notification via telegram - expects at lease two string arguments @@ -967,101 +1085,9 @@ :set SendTelegram2 do={ :local Notification $1; - :global Identity; - :global TelegramChatId; - :global TelegramChatIdOverride; - :global TelegramFixedWidthFont; - :global TelegramQueue; - :global TelegramTokenId; - :global TelegramTokenIdOverride; + :global NotificationFunctions; - :global CertificateAvailable; - :global CharacterReplace; - :global EitherOr; - :global IfThenElse; - :global LogPrintExit2; - :global SymbolForNotification; - :global UrlEncode; - - :local EscapeMD do={ - :global TelegramFixedWidthFont; - - :global CharacterReplace; - :global IfThenElse; - - :if ($TelegramFixedWidthFont != true) do={ - :return ($1 . [ $IfThenElse ($2 = "body") "\n" "" ]); - } - - :local Return $1; - :local Chars { - "body"={ "\\"; "`" }; - "hint"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">"; - "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; - } - :foreach Char in=($Chars->$2) do={ - :set Return [ $CharacterReplace $Return $Char ("\\" . $Char) ]; - } - - :if ($2 = "body") do={ - :return ("```\n" . $Return . "\n```"); - } - - :return $Return; - } - - :local ChatId [ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ]; - :local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ]; - - :if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={ - :return false; - } - - :local Truncated false; - :local LenLink [ :len ($Notification->"link") ]; - :local Text ("[" . $Identity . "] " . ($Notification->"subject") . "\n\n" . ($Notification->"message")); - :local LenText [ :len $Text ]; - :if ($LenText > (3968 - $LenLink)) do={ - :set Text [ $EscapeMD ([ :pick $Text 0 (3840 - $LenLink) ] . "...") "body" ]; - :set Truncated true; - } else={ - :set Text [ $EscapeMD $Text "body" ]; - } - :if ($LenLink > 0) do={ - :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD ($Notification->"link") "hint" ]); - } - :if ($Truncated = true) do={ - :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ - [ $EscapeMD ("The Telegram message was too long and has been truncated, cut off " . \ - (($LenText - [ :len $Text ]) * 100 / $LenText) . "%!") "hint" ]); - } - :set Text [ $UrlEncode $Text ]; - :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; - - :do { - :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; - } - / tool fetch check-certificate=yes-without-crl output=none http-method=post \ - ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ - http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ - "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; - } on-error={ - $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; - - :if ([ :typeof $TelegramQueue ] = "nothing") do={ - :set TelegramQueue [ :toarray "" ]; - } - :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ - [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ - " " . [ / system clock get time ] . " and may be obsolete.") "hint" ]) ]); - :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; - parsemode=$ParseMode; text=$Text; silent=($Notification->"silent") }; - :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ - / system scheduler add name=FlushTelegramQueue interval=1m start-time=startup \ - on-event=":global FlushTelegramQueue; \$FlushTelegramQueue;"; - } - } + ($NotificationFunctions->"telegram") ("\$NotificationFunctions->\"telegram\"") $Notification; } # return UTF-8 symbol for unicode name From 8375673d93d5481cc575dcb61825eba9b08c1515 Mon Sep 17 00:00:00 2001 From: Michael Gisbers Date: Fri, 28 May 2021 17:30:37 +0200 Subject: [PATCH 0747/2612] global-functions: implement notifications via Matrix Matrix is an open network for secure, decentralized communication - and it has a web api. A warning on message type: Using 'm.notice' breaks rendering on Element for Android (no fixed width font) and does not pop up desktop notification. Thus we use 'm.text'. Should be safe as we do not send the messages in response to other messages. https://matrix.org/ --- doc/check-certificates.md | 4 +- doc/check-health.md | 2 +- doc/check-lte-firmware-upgrade.md | 2 +- doc/cloud-backup.md | 2 +- doc/collect-wireless-mac.md | 2 +- doc/daily-psk.md | 2 +- doc/log-forward.md | 2 +- doc/netwatch-notify.md | 2 +- doc/sms-forward.md | 4 +- doc/upload-backup.md | 2 +- global-config | 18 ++- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- global-functions.d/notification-matrix | 157 +++++++++++++++++++++++++ 15 files changed, 186 insertions(+), 18 deletions(-) create mode 100644 global-functions.d/notification-matrix diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 5b1e3b2..aa4a258 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -22,8 +22,8 @@ Just install the script: Configuration ------------- -The expiry notifications just require notification settings for e-mail and -telegram. +The expiry notifications just require notification settings for e-mail, +matrix and/or telegram. For automatic download and renewal of certificates you need configuration in `global-config-overlay`, these are the parameters: diff --git a/doc/check-health.md b/doc/check-health.md index f1b9d91..de7f9eb 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -39,7 +39,7 @@ The configuration goes to `global-config-overlay`, These are the parameters: * `CheckHealthTemperature`: an array specifying temperature thresholds for sensors * `CheckHealthVoltagePercent`: percentage value to trigger voltage jumps -Also notification settings are required for e-mail and telegram. +Also notification settings are required for e-mail, matrix and/or telegram. --- [◀ Go back to main README](../README.md) diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index a145da8..dea6b82 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -31,7 +31,7 @@ Just install the script: Configuration ------------- -Notification setting are required for e-mail and telegram. +Notification setting are required for e-mail, matrix and/or telegram. See also -------- diff --git a/doc/cloud-backup.md b/doc/cloud-backup.md index 60e71c9..21d287f 100644 --- a/doc/cloud-backup.md +++ b/doc/cloud-backup.md @@ -26,7 +26,7 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupPassword`: password to encrypt the backup with * `BackupRandomDelay`: delay up to amount of seconds when run from scheduler -Also notification settings are required for e-mail and telegram. +Also notification settings are required for e-mail, matrix and/or telegram. Usage and invocation -------------------- diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 4da06b9..8f3ff6f 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -36,7 +36,7 @@ On first run a disabled access list entry acting as marker (with comment "`--- collected above ---`") is added. Move this entry to define where new entries are to be added. -Also notification settings are required for e-mail and telegram. +Also notification settings are required for e-mail, matrix and/or telegram. Usage and invocation -------------------- diff --git a/doc/daily-psk.md b/doc/daily-psk.md index ec55c85..28f9afc 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -47,7 +47,7 @@ Then add an access list entry: / interface wireless access-list add comment="Daily PSK" interface=wl-daily private-pre-shared-key="ToBeChangedDaily"; -Also notification settings are required for e-mail and telegram. +Also notification settings are required for e-mail, matrix and/or telegram. --- [◀ Go back to main README](../README.md) diff --git a/doc/log-forward.md b/doc/log-forward.md index 0993b52..68a6ca1 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -39,7 +39,7 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `LogForwardFilter`: define topics *not* to be forwarded * `LogForwardFilterMessage`: define message text *not* to be forwarded -Also notification settings are required for e-mail and telegram. +Also notification settings are required for e-mail, matrix and/or telegram. --- [◀ Go back to main README](../README.md) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index ff1eae9..2bba8d9 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -61,7 +61,7 @@ But be warned: Dynamic updates will probably cause issues if the name has more than one record in dns - a high rate of configuration changes (and flash writes) at least. -Also notification settings are required for e-mail and telegram. +Also notification settings are required for e-mail, matrix and/or telegram. Tips & Tricks ------------- diff --git a/doc/sms-forward.md b/doc/sms-forward.md index d603daa..69ea5d0 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -27,8 +27,8 @@ Just install the script: Configuration ------------- -Notification settings are required for e-mail and telegram. Also you have -to enable receiving of SMS: +Notification settings are required for e-mail, matrix and/or telegram. Also +you have to enable receiving of SMS: / tool sms set receive-enabled=yes; diff --git a/doc/upload-backup.md b/doc/upload-backup.md index 4b656e4..f9a9b4f 100644 --- a/doc/upload-backup.md +++ b/doc/upload-backup.md @@ -32,7 +32,7 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupUploadUser`: username for server authentication * `BackupUploadPass`: password for server authentication -Also notification settings are required for e-mail and telegram. +Also notification settings are required for e-mail, matrix and/or telegram. ### Issues with SFTP client diff --git a/global-config b/global-config index 6730a45..19d1215 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 52; +:global GlobalConfigVersion 53; # This is used for DNS and backup file. :global Domain "example.com"; @@ -33,9 +33,19 @@ # This is whether or not to send Telegram messages with fixed-width font. :global TelegramFixedWidthFont true; -# It is possible to override e-mail and Telegram setting for every script. -# This is done in arrays EmailGeneralToOverride, EmailGeneralCcOverride, -# TelegramTokenIdOverride and TelegramChatIdOverride like this: +# You can send Matrix notifications. Configure these settings and +# install the module: +# $ScriptInstallUpdate global-functions.d/notification-matrix +:global MatrixHomeServer ""; +:global MatrixAccessToken ""; +:global MatrixRoom ""; +#:global MatrixHomeServer "matrix.org"; +#:global MatrixAccessToken "123456ABCDEFGHI..."; +#:global MatrixRoom "!example:matrix.org"; + +# It is possible to override e-mail, Telegram and Matrix setting for every +# script. This is done in arrays, where 'Override' is appended to the +# variable name, like this: #:global EmailGeneralToOverride { # "check-certificates"="override@example.com"; # "email-backup"="backup@example.com"; diff --git a/global-config-overlay b/global-config-overlay index f90abd6..1cbaedf 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 52; +:global GlobalConfigVersion 53; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index cfaf649..21d4941 100644 --- a/global-config.changes +++ b/global-config.changes @@ -56,6 +56,7 @@ 50="Added support for dynamic address update in 'netwatch-notify'."; 51="Added 'ipsec-to-dns' to add DNS records for IPSec peers from mode-config."; 52="Updated Let's Encrypt trust chain to use root certificate 'ISRG Root X1'. Do not re-import the old chain!"; + 53="Added support to send notifications via Matrix."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 5ceab4f..b3db3dd 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 52; +:global ExpectedConfigVersion 53; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/global-functions.d/notification-matrix b/global-functions.d/notification-matrix new file mode 100644 index 0000000..962924e --- /dev/null +++ b/global-functions.d/notification-matrix @@ -0,0 +1,157 @@ +#!rsc by RouterOS +# RouterOS script: global-functions.d/notification-matrix +# Copyright (c) 2013-2021 Michael Gisbers +# Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global FlushMatrixQueue; +:global NotificationFunctions; +:global SendMatrix; +:global SendMatrix2; + +# flush Matrix queue +:set FlushMatrixQueue do={ + :global MatrixQueue; + + :global LogPrintExit2; + + :local AllDone true; + :local QueueLen [ :len $MatrixQueue ]; + + :if ([ :len [ / system scheduler find where name="FlushMatrixQueue" ] ] > 0 && $QueueLen = 0) do={ + $LogPrintExit2 warning $0 ("Flushing Matrix messages from scheduler, but queue is empty.") false; + } + + :foreach Id,Message in=$MatrixQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :do { + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \ + "/send/m.room.message?access_token=" . $Message->"accesstoken") \ + http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Message->"plain" . "\"," . \ + "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ + $Message->"formatted" . "\" }") as-value; + :set ($MatrixQueue->$Id); + } on-error={ + $LogPrintExit2 debug $0 ("Sending queued Matrix message failed.") false; + :set AllDone false; + } + } + } + + :if ($AllDone = true && $QueueLen = [ :len $MatrixQueue ]) do={ + / system scheduler remove [ find where name="FlushMatrixQueue" ]; + :set MatrixQueue; + } +} + +# send notification via Matrix - expects one array argument +:set ($NotificationFunctions->"matrix") do={ + :local Notification $1; + + :global Identity; + :global MatrixAccessToken; + :global MatrixAccessTokenOverride; + :global MatrixHomeServer; + :global MatrixHomeServerOverride; + :global MatrixQueue; + :global MatrixRoom; + :global MatrixRoomOverride; + + :global EitherOr; + :global LogPrintExit2; + :global SymbolForNotification; + + :local PrepareText do={ + :local Input [ :tostr $1 ]; + + :if ([ :len $Input ] = 0) do={ + :return ""; + } + + :local Return ""; + :local Chars { + "plain"={ "\\"; "\""; "\n" }; + "format"={ "\\"; "\""; "\n"; "&"; "<"; ">" }; + } + :local Subs { + "plain"={ "\\\\"; "\\\""; "\\n" }; + "format"={ "\\\\"; """; "
"; "&"; "<"; ">" }; + } + + :for I from=0 to=([ :len $Input ] - 1) do={ + :local Char [ :pick $Input $I ]; + :local Replace [ :find ($Chars->$2) $Char ]; + + :if ([ :typeof $Replace ] = "num") do={ + :set Char ($Subs->$2->$Replace); + } + :set Return ($Return . $Char); + } + + :return $Return; + } + + :local AccessToken [ $EitherOr ($MatrixAccessTokenOverride->($Notification->"origin")) $MatrixAccessToken ]; + :local HomeServer [ $EitherOr ($MatrixHomeServerOverride->($Notification->"origin")) $MatrixHomeServer ]; + :local Room [ $EitherOr ($MatrixRoomOverride->($Notification->"origin")) $MatrixRoom ]; + + :if ([ :len $AccessToken ] = 0 || [ :len $HomeServer ] = 0 || [ :len $Room ] = 0) do={ + :return false; + } + + :local Plain [ $PrepareText ("## [" . $Identity . "] " . ($Notification->"subject") . "\n```\n" . \ + ($Notification->"message") . "\n```") "plain" ]; + :local Formatted ("

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

" . \ + "
" . [ $PrepareText ($Notification->"message") "format" ] . "
"); + :if ([ :len ($Notification->"link") ] > 0) do={ + :set Plain ($Plain . "\\n" . [ $SymbolForNotification "link" ] . \ + [ $PrepareText ("[" . $Notification->"link" . "](" . $Notification->"link" . ")") "plain" ]); + :set Formatted ($Formatted . "
" . [ $SymbolForNotification "link" ] . \ + ""link") "format" ] . "\\\">" . \ + [ $PrepareText ($Notification->"link") "format" ] . ""); + } + + :do { + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \ + "/send/m.room.message?access_token=" . $AccessToken) \ + http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Plain . "\"," . \ + "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ + $Formatted . "\" }") as-value; + } on-error={ + $LogPrintExit2 info $0 ("Failed sending Matrix notification! Queuing...") false; + + :if ([ :typeof $MatrixQueue ] = "nothing") do={ + :set MatrixQueue [ :toarray "" ]; + } + :local Text ([ $SymbolForNotification "alarm-clock" ] . \ + "This message was queued since " . [ / system clock get date ] . \ + " " . [ / system clock get time ] . " and may be obsolete."); + :set Plain ($Plain . "\\n" . $Text); + :set Formatted ($Formatted . "
" . $Text); + :set ($MatrixQueue->[ :len $MatrixQueue ]) { room=$Room; \ + accesstoken=$AccessToken; homeserver=$HomeServer; \ + plain=$Plain; formatted=$Formatted }; + :if ([ :len [ / system scheduler find where name="FlushMatrixQueue" ] ] = 0) do={ + / system scheduler add name=FlushMatrixQueue interval=1m start-time=startup \ + on-event=":global FlushMatrixQueue; \$FlushMatrixQueue;"; + } + } +} + +# send notification via Matrix - expects at lease two string arguments +:set SendMatrix do={ + :global SendMatrix2; + + $SendMatrix2 ({ subject=$1; message=$2; link=$3 }); +} + +# send notification via Matrix - expects one array argument +:set SendMatrix2 do={ + :local Notification $1; + + :global NotificationFunctions; + + ($NotificationFunctions->"matrix") ("\$NotificationFunctions->\"matrix\"") $Notification; +} From 50d1706a067383ad68cd0b227b7b5b339f1157cb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 2 Jun 2021 22:53:43 +0200 Subject: [PATCH 0748/2612] global-functions: make Telegram notifications a module --- global-config | 5 +- global-config-overlay | 2 +- global-config.changes | 2 + global-functions | 158 +--------------------- global-functions.d/notification-telegram | 162 +++++++++++++++++++++++ 5 files changed, 169 insertions(+), 160 deletions(-) create mode 100644 global-functions.d/notification-telegram diff --git a/global-config b/global-config index 19d1215..d2b1f94 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 53; +:global GlobalConfigVersion 54; # This is used for DNS and backup file. :global Domain "example.com"; @@ -25,7 +25,8 @@ #:global EmailGeneralCc "another@example.com,third@example.com"; # You can send Telegram notifications. Register a bot -# and add the token and chat ids here. +# and add the token and chat ids here, then install the module: +# $ScriptInstallUpdate global-functions.d/notification-telegram :global TelegramTokenId ""; :global TelegramChatId ""; #:global TelegramTokenId "123456:ABCDEF-GHI"; diff --git a/global-config-overlay b/global-config-overlay index 1cbaedf..1466a4d 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 53; +:global GlobalConfigVersion 54; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 21d4941..1721ab0 100644 --- a/global-config.changes +++ b/global-config.changes @@ -57,6 +57,7 @@ 51="Added 'ipsec-to-dns' to add DNS records for IPSec peers from mode-config."; 52="Updated Let's Encrypt trust chain to use root certificate 'ISRG Root X1'. Do not re-import the old chain!"; 53="Added support to send notifications via Matrix."; + 54="Support for Telegram notifications moved to a module. It is installed automatically if required."; }; # Migration steps to be applied on script updates @@ -64,4 +65,5 @@ 41=":global SendNotification; \$SendNotification (\"Migration mechanism\") (\"Congratulations!\nSuccessfully tested the new migration mechanism.\");"; 47="/ certificate remove [ find where fingerprint=\"731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568\" or fingerprint=\"25847d668eb4f04fdd40b12b6b0740c567da7d024308eb6c2c96fe41d9de218d\" ];"; 52=":global CertificateDownload; :if ([ :len [ / certificate find where fingerprint=\"67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd\" or fingerprint=\"96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6\" ] ] < 2) do={ \$CertificateDownload \"R3\"; }; / certificate remove [ find where fingerprint=\"0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739\" ];"; + 54=":global ScriptInstallUpdate; :global TelegramTokenId; :global TelegramChatId; :if ([ :len \$TelegramTokenId ] > 0 && [ :len \$TelegramChatId ] > 0) do={ \$ScriptInstallUpdate global-functions.d/notification-telegram; }"; }; diff --git a/global-functions b/global-functions index b3db3dd..02afd8f 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 53; +:global ExpectedConfigVersion 54; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -27,7 +27,6 @@ :global EitherOr; :global EscapeForRegEx; :global FlushEmailQueue; -:global FlushTelegramQueue; :global GetMacVendor; :global GetRandom20CharHex; :global GetRandomNumber; @@ -48,8 +47,6 @@ :global SendEMail2; :global SendNotification; :global SendNotification2; -:global SendTelegram; -:global SendTelegram2; :global SymbolByUnicodeName; :global SymbolForNotification; :global TimeIsSync; @@ -373,42 +370,6 @@ } } -# flush telegram queue -:set FlushTelegramQueue do={ - :global TelegramQueue; - - :global LogPrintExit2; - - :local AllDone true; - :local QueueLen [ :len $TelegramQueue ]; - - :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] > 0 && $QueueLen = 0) do={ - $LogPrintExit2 warning $0 ("Flushing Telegram messages from scheduler, but queue is empty.") false; - } - - :foreach Id,Message in=$TelegramQueue do={ - :if ([ :typeof $Message ] = "array" ) do={ - :do { - / tool fetch check-certificate=yes-without-crl output=none http-method=post \ - ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ - http-data=("chat_id=" . ($Message->"chatid") . \ - "&disable_notification=" . ($Message->"silent") . \ - "&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \ - "&text=" . ($Message->"text")) as-value; - :set ($TelegramQueue->$Id); - } on-error={ - $LogPrintExit2 debug $0 ("Sending queued Telegram message failed.") false; - :set AllDone false; - } - } - } - - :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ - / system scheduler remove [ find where name="FlushTelegramQueue" ]; - :set TelegramQueue; - } -} - # get MAC vendor :set GetMacVendor do={ :local Mac [ :tostr $1 ]; @@ -621,107 +582,6 @@ } } -# send notification via telegram - expects one array argument -:set ($NotificationFunctions->"telegram") do={ - :local Notification $1; - - :global Identity; - :global TelegramChatId; - :global TelegramChatIdOverride; - :global TelegramFixedWidthFont; - :global TelegramQueue; - :global TelegramTokenId; - :global TelegramTokenIdOverride; - - :global CertificateAvailable; - :global CharacterReplace; - :global EitherOr; - :global IfThenElse; - :global LogPrintExit2; - :global SymbolForNotification; - :global UrlEncode; - - :local EscapeMD do={ - :global TelegramFixedWidthFont; - - :global CharacterReplace; - :global IfThenElse; - - :if ($TelegramFixedWidthFont != true) do={ - :return ($1 . [ $IfThenElse ($2 = "body") "\n" "" ]); - } - - :local Return $1; - :local Chars { - "body"={ "\\"; "`" }; - "hint"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">"; - "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; - } - :foreach Char in=($Chars->$2) do={ - :set Return [ $CharacterReplace $Return $Char ("\\" . $Char) ]; - } - - :if ($2 = "body") do={ - :return ("```\n" . $Return . "\n```"); - } - - :return $Return; - } - - :local ChatId [ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ]; - :local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ]; - - :if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={ - :return false; - } - - :local Truncated false; - :local LenLink [ :len ($Notification->"link") ]; - :local Text ("[" . $Identity . "] " . ($Notification->"subject") . "\n\n" . ($Notification->"message")); - :local LenText [ :len $Text ]; - :if ($LenText > (3968 - $LenLink)) do={ - :set Text [ $EscapeMD ([ :pick $Text 0 (3840 - $LenLink) ] . "...") "body" ]; - :set Truncated true; - } else={ - :set Text [ $EscapeMD $Text "body" ]; - } - :if ($LenLink > 0) do={ - :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD ($Notification->"link") "hint" ]); - } - :if ($Truncated = true) do={ - :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ - [ $EscapeMD ("The Telegram message was too long and has been truncated, cut off " . \ - (($LenText - [ :len $Text ]) * 100 / $LenText) . "%!") "hint" ]); - } - :set Text [ $UrlEncode $Text ]; - :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; - - :do { - :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; - } - / tool fetch check-certificate=yes-without-crl output=none http-method=post \ - ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ - http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ - "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; - } on-error={ - $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; - - :if ([ :typeof $TelegramQueue ] = "nothing") do={ - :set TelegramQueue [ :toarray "" ]; - } - :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ - [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ - " " . [ / system clock get time ] . " and may be obsolete.") "hint" ]) ]); - :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; - parsemode=$ParseMode; text=$Text; silent=($Notification->"silent") }; - :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ - / system scheduler add name=FlushTelegramQueue interval=1m start-time=startup \ - on-event=":global FlushTelegramQueue; \$FlushTelegramQueue;"; - } - } -} - # parse key value store :set ParseKeyValueStore do={ :local Source $1; @@ -1074,22 +934,6 @@ } } -# send notification via telegram - expects at lease two string arguments -:set SendTelegram do={ - :global SendTelegram2; - - $SendTelegram2 ({ subject=$1; message=$2; link=$3; silent=$4 }); -} - -# send notification via telegram - expects one array argument -:set SendTelegram2 do={ - :local Notification $1; - - :global NotificationFunctions; - - ($NotificationFunctions->"telegram") ("\$NotificationFunctions->\"telegram\"") $Notification; -} - # return UTF-8 symbol for unicode name :set SymbolByUnicodeName do={ :local Symbols { diff --git a/global-functions.d/notification-telegram b/global-functions.d/notification-telegram new file mode 100644 index 0000000..1509a2e --- /dev/null +++ b/global-functions.d/notification-telegram @@ -0,0 +1,162 @@ +#!rsc by RouterOS +# RouterOS script: global-functions.d/notification-telegram +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global FlushTelegramQueue; +:global NotificationFunctions; +:global SendTelegram; +:global SendTelegram2; + +# flush telegram queue +:set FlushTelegramQueue do={ + :global TelegramQueue; + + :global LogPrintExit2; + + :local AllDone true; + :local QueueLen [ :len $TelegramQueue ]; + + :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] > 0 && $QueueLen = 0) do={ + $LogPrintExit2 warning $0 ("Flushing Telegram messages from scheduler, but queue is empty.") false; + } + + :foreach Id,Message in=$TelegramQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :do { + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ + http-data=("chat_id=" . ($Message->"chatid") . \ + "&disable_notification=" . ($Message->"silent") . \ + "&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \ + "&text=" . ($Message->"text")) as-value; + :set ($TelegramQueue->$Id); + } on-error={ + $LogPrintExit2 debug $0 ("Sending queued Telegram message failed.") false; + :set AllDone false; + } + } + } + + :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ + / system scheduler remove [ find where name="FlushTelegramQueue" ]; + :set TelegramQueue; + } +} + +# send notification via telegram - expects one array argument +:set ($NotificationFunctions->"telegram") do={ + :local Notification $1; + + :global Identity; + :global TelegramChatId; + :global TelegramChatIdOverride; + :global TelegramFixedWidthFont; + :global TelegramQueue; + :global TelegramTokenId; + :global TelegramTokenIdOverride; + + :global CertificateAvailable; + :global CharacterReplace; + :global EitherOr; + :global IfThenElse; + :global LogPrintExit2; + :global SymbolForNotification; + :global UrlEncode; + + :local EscapeMD do={ + :global TelegramFixedWidthFont; + + :global CharacterReplace; + :global IfThenElse; + + :if ($TelegramFixedWidthFont != true) do={ + :return ($1 . [ $IfThenElse ($2 = "body") "\n" "" ]); + } + + :local Return $1; + :local Chars { + "body"={ "\\"; "`" }; + "hint"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">"; + "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; + } + :foreach Char in=($Chars->$2) do={ + :set Return [ $CharacterReplace $Return $Char ("\\" . $Char) ]; + } + + :if ($2 = "body") do={ + :return ("```\n" . $Return . "\n```"); + } + + :return $Return; + } + + :local ChatId [ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ]; + :local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ]; + + :if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={ + :return false; + } + + :local Truncated false; + :local LenLink [ :len ($Notification->"link") ]; + :local Text ("[" . $Identity . "] " . ($Notification->"subject") . "\n\n" . ($Notification->"message")); + :local LenText [ :len $Text ]; + :if ($LenText > (3968 - $LenLink)) do={ + :set Text [ $EscapeMD ([ :pick $Text 0 (3840 - $LenLink) ] . "...") "body" ]; + :set Truncated true; + } else={ + :set Text [ $EscapeMD $Text "body" ]; + } + :if ($LenLink > 0) do={ + :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD ($Notification->"link") "hint" ]); + } + :if ($Truncated = true) do={ + :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ + [ $EscapeMD ("The Telegram message was too long and has been truncated, cut off " . \ + (($LenText - [ :len $Text ]) * 100 / $LenText) . "%!") "hint" ]); + } + :set Text [ $UrlEncode $Text ]; + :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; + + :do { + :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; + } + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ + http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ + "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; + } on-error={ + $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; + + :if ([ :typeof $TelegramQueue ] = "nothing") do={ + :set TelegramQueue [ :toarray "" ]; + } + :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ + [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ + " " . [ / system clock get time ] . " and may be obsolete.") "hint" ]) ]); + :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; + parsemode=$ParseMode; text=$Text; silent=($Notification->"silent") }; + :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ + / system scheduler add name=FlushTelegramQueue interval=1m start-time=startup \ + on-event=":global FlushTelegramQueue; \$FlushTelegramQueue;"; + } + } +} + +# send notification via telegram - expects at lease two string arguments +:set SendTelegram do={ + :global SendTelegram2; + + $SendTelegram2 ({ subject=$1; message=$2; link=$3; silent=$4 }); +} + +# send notification via telegram - expects one array argument +:set SendTelegram2 do={ + :local Notification $1; + + :global NotificationFunctions; + + ($NotificationFunctions->"telegram") ("\$NotificationFunctions->\"telegram\"") $Notification; +} From 401f179ae93be4199227ef91df87f7e516686e5f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 9 Jun 2021 14:36:49 +0200 Subject: [PATCH 0749/2612] doc/log-forward: mention Matrix --- doc/log-forward.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/log-forward.md b/doc/log-forward.md index 68a6ca1..570516e 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -15,7 +15,7 @@ This has some limitation, however: * does not work early after boot if network connectivity is not yet established * lots of messages generate a flood of mails -* Telegram is not supported +* Matrix and Telegram are not supported The script is intended to be run periodically. It collects log messages and forwards them via notification. From d5f43aa26daa77d4211a3a71c2d8c6f765489891 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 9 Jun 2021 14:25:58 +0200 Subject: [PATCH 0750/2612] log-forward: update comments in global-config --- global-config | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index d2b1f94..b22a05a 100644 --- a/global-config +++ b/global-config @@ -69,10 +69,11 @@ :global BackupUploadUser "mikrotik"; :global BackupUploadPass "v3ry-s3cr3t"; -# This defines a filter on log topics not to be forwarded. +# This defines what log messages to filter by topic or message +# text. Regular expressions are supported. Do *NOT* set an empty string, +# that will filter everything! +# These are filters, so excluding messages from forwarding. :global LogForwardFilter "(debug|info)"; -# ... and the same for log message text. Regular expressions are supported. -# Do *NOT* set an empty string - that will filter everything! :global LogForwardFilterMessage []; #:global LogForwardFilterMessage "message text"; #:global LogForwardFilterMessage "(message text|another text|...)"; From de61c14c6087cc181b057843649147e76b2304eb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 9 Jun 2021 14:32:52 +0200 Subject: [PATCH 0751/2612] log-forward: implement reverse logic to include messages... ... even if a filter matches to exclude them. Let's have an example: :global LogForwardFilter "(debug|info)"; :global LogForwardInclude "account"; This will forward everything about topic *account* (login, logout, failed login, ...) - even with topic *info*. --- doc/log-forward.md | 3 +++ global-config | 12 +++++++++--- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- log-forward | 7 +++++-- 6 files changed, 20 insertions(+), 7 deletions(-) diff --git a/doc/log-forward.md b/doc/log-forward.md index 570516e..8f1c3f0 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -38,6 +38,9 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `LogForwardFilter`: define topics *not* to be forwarded * `LogForwardFilterMessage`: define message text *not* to be forwarded +* `LogForwardInclude`: define topics to be forwarded (even if filter matches) +* `LogForwardIncludeMessage`: define message text to be forwarded (even if + filter matches) Also notification settings are required for e-mail, matrix and/or telegram. diff --git a/global-config b/global-config index b22a05a..05197cf 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 54; +:global GlobalConfigVersion 55; # This is used for DNS and backup file. :global Domain "example.com"; @@ -69,14 +69,20 @@ :global BackupUploadUser "mikrotik"; :global BackupUploadPass "v3ry-s3cr3t"; -# This defines what log messages to filter by topic or message +# This defines what log messages to filter or include by topic or message # text. Regular expressions are supported. Do *NOT* set an empty string, -# that will filter everything! +# that will filter or include everything! # These are filters, so excluding messages from forwarding. :global LogForwardFilter "(debug|info)"; :global LogForwardFilterMessage []; #:global LogForwardFilterMessage "message text"; #:global LogForwardFilterMessage "(message text|another text|...)"; +# ... and another setting with reverse logic. This includes messages even +# if filtered above. +:global LogForwardInclude []; +:global LogForwardIncludeMessage []; +#:global LogForwardInclude "account"; +#:global LogForwardIncludeMessage "message text"; # Specify an address to enable auto update to version assumed safe. # The configured channel (bugfix, current, release-candidate) is appended. diff --git a/global-config-overlay b/global-config-overlay index 1466a4d..e3f3fd7 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 54; +:global GlobalConfigVersion 55; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 1721ab0..c4ccb69 100644 --- a/global-config.changes +++ b/global-config.changes @@ -58,6 +58,7 @@ 52="Updated Let's Encrypt trust chain to use root certificate 'ISRG Root X1'. Do not re-import the old chain!"; 53="Added support to send notifications via Matrix."; 54="Support for Telegram notifications moved to a module. It is installed automatically if required."; + 55="Added reverse logic in 'log-forward', so messages can be included even if filtered before."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 02afd8f..273a6aa 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 54; +:global ExpectedConfigVersion 55; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/log-forward b/log-forward index 8f72893..2e66089 100644 --- a/log-forward +++ b/log-forward @@ -13,6 +13,8 @@ :global Identity; :global LogForwardFilter; :global LogForwardFilterMessage; +:global LogForwardInclude; +:global LogForwardIncludeMessage; :global LogForwardLast; :global LogForwardRateLimit; :global NotificationsWithSymbols; @@ -48,8 +50,9 @@ $WaitFullyConnected; :local LogForwardFilterLogForwarding ("^" . [ $EscapeForRegEx ("Error sending e-mail <" . \ [ $QuotedPrintable ("[" . $Identity . "] " . [ $SymbolForNotification "warning-sign" ] . \ "Log Forwarding") ] . ">:") ]); -:foreach Message in=[ / log find where !(topics~$LogForwardFilter) !(message="") \ - !(message~$LogForwardFilterLogForwarding) !(message~$LogForwardFilterMessage) ] do={ +:foreach Message in=[ / log find where (!(message="") and !(message~$LogForwardFilterLogForwarding) and \ + !(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \ + topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={ :set MessageVal [ / log get $Message ]; :if ($LogForwardLast = ($MessageVal->".id")) do={ From 4cc8a0e1603082598b759344f85ab98d05d9ae27 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 10 Jun 2021 07:52:43 +0200 Subject: [PATCH 0752/2612] global-functions: $SendEMail2: fix name in array This did not send anything at all... Fixes #12 --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 273a6aa..7a6d77a 100644 --- a/global-functions +++ b/global-functions @@ -911,7 +911,7 @@ :global NotificationFunctions; - ($NotificationFunctions->"e-mail") ("\$NotificationFunctions->\"e-mail\"") $Notification; + ($NotificationFunctions->"email") ("\$NotificationFunctions->\"email\"") $Notification; } # send notification via NotificationFunctions - expects at lease two string arguments From babcc00dcd189058433100417d6568a15fe62cf1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 15 Jun 2021 14:38:02 +0200 Subject: [PATCH 0753/2612] global-functions: introduce $HexToNum --- global-functions | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/global-functions b/global-functions index 7a6d77a..d4aa574 100644 --- a/global-functions +++ b/global-functions @@ -30,6 +30,7 @@ :global GetMacVendor; :global GetRandom20CharHex; :global GetRandomNumber; +:global HexToNum; :global IfThenElse; :global IPCalc; :global LogPrintExit; @@ -425,6 +426,21 @@ :return ([ :tonum [ :pick $Num 0 18 ] ] % $Max); } +# convert from hex (string) to num +:set HexToNum do={ + :local Input [ :tostr $1 ]; + :local Hex "0123456789abcdef"; + :local Multi 1; + :local Return 0; + + :for I from=([ :len $Input ] - 1) to=0 do={ + :set Return ($Return + ([ :find $Hex [ :pick $Input $I ] ] * $Multi)); + :set Multi ($Multi * 16); + } + + :return $Return; +} + # mimic conditional/ternary operator (condition ? consequent : alternative) :set IfThenElse do={ :if ([ :tostr $1 ] = "true" || [ :tobool $1 ] = true) do={ From 1ce0f63ef7206e130981a2ab49f3fbda281b0a12 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 15 Jun 2021 14:39:42 +0200 Subject: [PATCH 0754/2612] log-forward: use $HexToNum, do not resend old messages Now we know the order of messages and can compare. Changing the filter does no longer result in old messages being resent. --- log-forward | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/log-forward b/log-forward index 2e66089..e0cb3aa 100644 --- a/log-forward +++ b/log-forward @@ -20,6 +20,7 @@ :global NotificationsWithSymbols; :global EscapeForRegEx; +:global HexToNum; :global IfThenElse; :global LogPrintExit2; :global QuotedPrintable; @@ -43,6 +44,7 @@ $WaitFullyConnected; :local Count 0; :local Duplicates false; +:local Last [ $HexToNum $LogForwardLast ]; :local Messages ""; :local MessageVal; :local MessageDups [ :toarray "" ]; @@ -55,12 +57,7 @@ $WaitFullyConnected; topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={ :set MessageVal [ / log get $Message ]; - :if ($LogForwardLast = ($MessageVal->".id")) do={ - :set Count 0; - :set Duplicates false; - :set Messages ""; - :set MessageDups [ :toarray "" ]; - } else={ + :if ($Last < [ $HexToNum ($MessageVal->".id") ]) do={ :local DupCount ($MessageDups->($MessageVal->"message")); :if ($DupCount < 3) do={ :set Messages ($Messages . "\n" . [ $IfThenElse ($NotificationsWithSymbols = true) (" \E2\97\8F ") ] . \ From c60c96e32a8ab017c93d450d710a650c41fc76a7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 16 Jun 2021 09:01:14 +0200 Subject: [PATCH 0755/2612] global-functions: $HexToNum: properly handle capital characters --- global-functions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index d4aa574..2cfe595 100644 --- a/global-functions +++ b/global-functions @@ -429,12 +429,12 @@ # convert from hex (string) to num :set HexToNum do={ :local Input [ :tostr $1 ]; - :local Hex "0123456789abcdef"; + :local Hex "0123456789abcdef0123456789ABCDEF"; :local Multi 1; :local Return 0; :for I from=([ :len $Input ] - 1) to=0 do={ - :set Return ($Return + ([ :find $Hex [ :pick $Input $I ] ] * $Multi)); + :set Return ($Return + (([ :find $Hex [ :pick $Input $I ] ] % 16) * $Multi)); :set Multi ($Multi * 16); } From 1e1b98b161d0d8a2e9930c4676a44e898dd9049d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 16 Jun 2021 14:44:28 +0200 Subject: [PATCH 0756/2612] upload-backup: remove file after upload --- upload-backup | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/upload-backup b/upload-backup index 8136599..d79039a 100644 --- a/upload-backup +++ b/upload-backup @@ -68,6 +68,8 @@ $WaitFullyConnected; :set BackupFile "failed"; :set Failed 1; } + + / file remove ($FilePath . ".backup"); } # create configuration export @@ -84,6 +86,8 @@ $WaitFullyConnected; :set ConfigFile "failed"; :set Failed 1; } + + / file remove ($FilePath . ".rsc"); } $SendNotification2 ({ origin=$0; \ From 34c9da5aa2c7cb1d8cae3c0441cb29c20022a8b2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 16 Jun 2021 14:56:55 +0200 Subject: [PATCH 0757/2612] global-functions: $NotificationFunctions->"email": support removing attachment --- global-functions | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 2cfe595..422eac0 100644 --- a/global-functions +++ b/global-functions @@ -345,8 +345,9 @@ :foreach Id,Message in=$EmailQueue do={ :if ([ :typeof $Message ] = "array" ) do={ + :local Attach [ $EitherOr ($Message->"attach") "" ]; / tool e-mail send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \ - body=($Message->"body") file=[ $EitherOr ($Message->"attach") "" ]; + body=($Message->"body") file=$Attach; :local Wait true; :do { :delay 1s; @@ -354,6 +355,11 @@ :if ($Status = "succeeded") do={ :set ($EmailQueue->$Id); :set Wait false; + :if (($Message->"remove-attach") = true) do={ + :foreach File in=[ :toarray $Attach ] do={ + / file remove $File; + } + } } :if ($Status = "failed") do={ :set AllDone false; @@ -591,7 +597,7 @@ body=(($Notification->"message") . \ [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \ - attach=($Notification->"attach") }; + attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") }; :if ([ :len [ / system scheduler find where name="FlushEmailQueue" ] ] = 0) do={ / system scheduler add name=FlushEmailQueue interval=1s start-time=startup \ on-event=":global FlushEmailQueue; \$FlushEmailQueue;"; From e375494d0053d67ab76dd20bf4dc0014bfb29a03 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 16 Jun 2021 14:58:14 +0200 Subject: [PATCH 0758/2612] email-backup: remove attachment when sent --- email-backup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/email-backup b/email-backup index d09ae2a..5a74220 100644 --- a/email-backup +++ b/email-backup @@ -75,4 +75,4 @@ $SendEMail2 ({ origin=$0; \ [ $DeviceInfo ] . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ "Config file: " . $ConfigFile); \ - attach=$Attach }); + attach=$Attach; remove-attach=true }); From a1fc02e6671d713e96527286bd37bad2ceebfb41 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Jun 2021 10:21:28 +0200 Subject: [PATCH 0759/2612] Makefile: generate html files for documentation --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 01b9a72..b07d27d 100644 --- a/Makefile +++ b/Makefile @@ -6,13 +6,13 @@ TEMPLATE = $(wildcard *.template) CAPSMAN = $(TEMPLATE:.template=.capsman) LOCAL = $(TEMPLATE:.template=.local) -MARKDOWN = $(wildcard *.md) +MARKDOWN = $(wildcard *.md) $(wildcard doc/*.md) HTML = $(MARKDOWN:.md=.html) all: $(CAPSMAN) $(LOCAL) $(HTML) %.html: %.md Makefile - markdown $< | sed 's/href="\([-[:alnum:]]*\)\.md"/href="\1.html"/g' > $@ + markdown $< | sed 's/href="\([-_\./[:alnum:]]*\)\.md"/href="\1.html"/g' > $@ %.local: %.template Makefile sed -e '/\/ caps-man/d' -e 's|%PATH%|interface wireless|' -e 's|%TEMPL%|$(suffix $@)|' \ From a3efb67ed17619205300b84f77935a98567ae5df Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Jun 2021 10:24:33 +0200 Subject: [PATCH 0760/2612] doc/check-health: no capital character here --- doc/check-health.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/check-health.md b/doc/check-health.md index de7f9eb..39ce3d1 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -34,7 +34,7 @@ Just install the script and create a scheduler: Configuration ------------- -The configuration goes to `global-config-overlay`, These are the parameters: +The configuration goes to `global-config-overlay`, these are the parameters: * `CheckHealthTemperature`: an array specifying temperature thresholds for sensors * `CheckHealthVoltagePercent`: percentage value to trigger voltage jumps From bad6f5a7cc1cf1fe442f66ff1399591236af8efc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 17 Jun 2021 15:23:51 +0200 Subject: [PATCH 0761/2612] doc: add sample notifications --- doc/check-certificates.md | 4 + doc/check-health.md | 16 ++ doc/check-lte-firmware-upgrade.md | 4 + doc/check-routeros-update.md | 4 + doc/cloud-backup.md | 4 + doc/collect-wireless-mac.md | 4 + doc/daily-psk.md | 4 + doc/log-forward.md | 4 + doc/netwatch-notify.md | 5 + doc/notifications/check-certificates.svg | 196 +++++++++++++++ doc/notifications/check-health-psu-fail.svg | 164 ++++++++++++ doc/notifications/check-health-psu-ok.svg | 164 ++++++++++++ .../check-health-temperature-high.svg | 164 ++++++++++++ .../check-health-temperature-ok.svg | 164 ++++++++++++ doc/notifications/check-health-voltage.svg | 176 +++++++++++++ .../check-lte-firmware-upgrade.svg | 184 ++++++++++++++ doc/notifications/check-routeros-update.svg | 235 ++++++++++++++++++ doc/notifications/cloud-backup.svg | 216 ++++++++++++++++ doc/notifications/collect-wireless-mac.svg | 208 ++++++++++++++++ doc/notifications/daily-psk.svg | 204 +++++++++++++++ doc/notifications/log-forward.svg | 192 ++++++++++++++ doc/notifications/netwatch-notify-down.svg | 168 +++++++++++++ doc/notifications/netwatch-notify-up.svg | 172 +++++++++++++ doc/notifications/sms-forward.svg | 176 +++++++++++++ doc/notifications/upload-backup.svg | 212 ++++++++++++++++ doc/sms-forward.md | 4 + doc/upload-backup.md | 4 + 27 files changed, 3052 insertions(+) create mode 100644 doc/notifications/check-certificates.svg create mode 100644 doc/notifications/check-health-psu-fail.svg create mode 100644 doc/notifications/check-health-psu-ok.svg create mode 100644 doc/notifications/check-health-temperature-high.svg create mode 100644 doc/notifications/check-health-temperature-ok.svg create mode 100644 doc/notifications/check-health-voltage.svg create mode 100644 doc/notifications/check-lte-firmware-upgrade.svg create mode 100644 doc/notifications/check-routeros-update.svg create mode 100644 doc/notifications/cloud-backup.svg create mode 100644 doc/notifications/collect-wireless-mac.svg create mode 100644 doc/notifications/daily-psk.svg create mode 100644 doc/notifications/log-forward.svg create mode 100644 doc/notifications/netwatch-notify-down.svg create mode 100644 doc/notifications/netwatch-notify-up.svg create mode 100644 doc/notifications/sms-forward.svg create mode 100644 doc/notifications/upload-backup.svg diff --git a/doc/check-certificates.md b/doc/check-certificates.md index aa4a258..9059034 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -12,6 +12,10 @@ Description This script tries to download and renew certificates, then notifies about certificates that are still about to expire. +### Sample notification + +![check-certificates notification](notifications/check-certificates.svg) + Requirements and installation ----------------------------- diff --git a/doc/check-health.md b/doc/check-health.md index 39ce3d1..7accc62 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -23,6 +23,22 @@ hardware supports: / system health print; +### Sample notifications + +#### Voltage + +![check-health notification voltage](notifications/check-health-voltage.svg) + +#### Temperature + +![check-health notification](notifications/check-health-temperature-high.svg) +![check-health notification](notifications/check-health-temperature-ok.svg) + +#### PSU state + +![check-health notification](notifications/check-health-psu-fail.svg) +![check-health notification](notifications/check-health-psu-ok.svg) + Requirements and installation ----------------------------- diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index dea6b82..55d5cf8 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -17,6 +17,10 @@ upgrades. Currently supported LTE hardware: * R11e-4G * R11e-LTE6 +### Sample notification + +![check-lte-firmware-upgrade notification](notifications/check-lte-firmware-upgrade.svg) + Requirements and installation ----------------------------- diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 416ba98..92ff1b1 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -19,6 +19,10 @@ specifying versions safe to be updated on a web server. Also installing patch updates (where just last digit is increased) automatically is supported. +### Sample notification + +![check-routeros-update notification](notifications/check-routeros-update.svg) + Requirements and installation ----------------------------- diff --git a/doc/cloud-backup.md b/doc/cloud-backup.md index 21d287f..182dd01 100644 --- a/doc/cloud-backup.md +++ b/doc/cloud-backup.md @@ -11,6 +11,10 @@ Description This script uploads [binary backup to Mikrotik cloud](https://wiki.mikrotik.com/wiki/Manual:IP/Cloud#Backup). +### Sample notification + +![cloud-backup notification](notifications/cloud-backup.svg) + Requirements and installation ----------------------------- diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 8f3ff6f..7d3c815 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -15,6 +15,10 @@ address list. In addition a notification is sent. By default the access list entry is disabled, but you can easily enable and modify it to your needs. +### Sample notification + +![collect-wireless-mac notification](notifications/collect-wireless-mac.svg) + Requirements and installation ----------------------------- diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 28f9afc..1d41f76 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -12,6 +12,10 @@ Description This script is supposed to provide a wifi network which changes the passphrase to a pseudo-random string daily. +### Sample notification + +![daily-psk notification](notifications/daily-psk.svg) + Requirements and installation ----------------------------- diff --git a/doc/log-forward.md b/doc/log-forward.md index 8f1c3f0..cdcd479 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -20,6 +20,10 @@ This has some limitation, however: The script is intended to be run periodically. It collects log messages and forwards them via notification. +### Sample notification + +![log-forward notification](notifications/log-forward.svg) + Requirements and installation ----------------------------- diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 2bba8d9..52e4792 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -15,6 +15,11 @@ this script implements a simple state machine and dependency model. Host down events are triggered only if the host is down for several checks and optional parent host is not down to avoid false alerts. +### Sample notifications + +![netwatch-notify notification down](notifications/netwatch-notify-down.svg) +![netwatch-notify notification up](notifications/netwatch-notify-up.svg) + Requirements and installation ----------------------------- diff --git a/doc/notifications/check-certificates.svg b/doc/notifications/check-certificates.svg new file mode 100644 index 0000000..521db39 --- /dev/null +++ b/doc/notifications/check-certificates.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] 🔏 Certificate renewed + +A certificate on MikroTik has been renewed. + +Name: example.com +CommonName: example.com +Private key: available +Fingerprint: cc54cdd01fcd7698ecb71213874be776906eb33d26cd57754d168632f14c4c8b +Issuer: R3 +Validity: may/22/2021 22:29:34 to aug/20/2021 22:29:34 +Expires in: 11w 5d 08:18:06 + + diff --git a/doc/notifications/check-health-psu-fail.svg b/doc/notifications/check-health-psu-fail.svg new file mode 100644 index 0000000..0ca57a4 --- /dev/null +++ b/doc/notifications/check-health-psu-fail.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] ❌ Health warning: psu1-state + +The power supply unit 'psu1-state' on MikroTik failed! + + diff --git a/doc/notifications/check-health-psu-ok.svg b/doc/notifications/check-health-psu-ok.svg new file mode 100644 index 0000000..06f596b --- /dev/null +++ b/doc/notifications/check-health-psu-ok.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] ✅ Health recovery: psu1-state + +The power supply unit 'psu1-state' on MikroTik recovered! + + diff --git a/doc/notifications/check-health-temperature-high.svg b/doc/notifications/check-health-temperature-high.svg new file mode 100644 index 0000000..84c4256 --- /dev/null +++ b/doc/notifications/check-health-temperature-high.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] đŸ”Ĩ Health warning: temperature + +The temperature on MikroTik is above threshold: 51°C + + diff --git a/doc/notifications/check-health-temperature-ok.svg b/doc/notifications/check-health-temperature-ok.svg new file mode 100644 index 0000000..d57ab4e --- /dev/null +++ b/doc/notifications/check-health-temperature-ok.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] ✅ Health recovery: temperature + +The temperature on MikroTik dropped below threshold: 48°C + + diff --git a/doc/notifications/check-health-voltage.svg b/doc/notifications/check-health-voltage.svg new file mode 100644 index 0000000..adc0328 --- /dev/null +++ b/doc/notifications/check-health-voltage.svg @@ -0,0 +1,176 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] ⚡ Health warning: voltage + +The voltage on MikroTik jumped more than 10%. + +old value: 16.2V +new value: 12.4V + + diff --git a/doc/notifications/check-lte-firmware-upgrade.svg b/doc/notifications/check-lte-firmware-upgrade.svg new file mode 100644 index 0000000..01d3d44 --- /dev/null +++ b/doc/notifications/check-lte-firmware-upgrade.svg @@ -0,0 +1,184 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] ✨ LTE firmware upgrade + +A new firmware version R11e-LTE6_V027 is available +for LTE interface lte on MikroTik. + +Interface: MikroTik R11e-LTE6 +Installed: R11e-LTE6_V025 +Available: R11e-LTE6_V027 + + diff --git a/doc/notifications/check-routeros-update.svg b/doc/notifications/check-routeros-update.svg new file mode 100644 index 0000000..9e049a4 --- /dev/null +++ b/doc/notifications/check-routeros-update.svg @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] ✨ RouterOS update + +A new RouterOS version 6.48.3 is available for MikroTik. + +Hostname: MikroTik +Board name: CHR +Architecture: x86_64 +RouterOS: + Channel: stable + Installed: 6.48.2 + Available: 6.48.3 +RouterOS-Scripts: + Current: 55 + +🔗 https://mikrotik.com/download/changelogs/stable-release-tree + + + diff --git a/doc/notifications/cloud-backup.svg b/doc/notifications/cloud-backup.svg new file mode 100644 index 0000000..5a6e0c0 --- /dev/null +++ b/doc/notifications/cloud-backup.svg @@ -0,0 +1,216 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] 💾☁ Cloud backup + +Uploaded backup for MikroTik to cloud. + +Hostname: MikroTik +Board name: CHR +Architecture: x86_64 +RouterOS: + Channel: stable + Installed: 6.48.3 +RouterOS-Scripts: + Current: 55 + +Name: cloud-20210614-092419 +Size: 370767 B (362 KiB) +Download key: LLDBfPcWXxmSetWilqeJX5V + + diff --git a/doc/notifications/collect-wireless-mac.svg b/doc/notifications/collect-wireless-mac.svg new file mode 100644 index 0000000..355fb8d --- /dev/null +++ b/doc/notifications/collect-wireless-mac.svg @@ -0,0 +1,208 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] 📱 48:F1:7F:D0:E5:4E connected to Wifi + +A device with unknown MAC address connected to Wifi +on MikroTik. + +Controller: MikroTik +Interface: wl5-wifi +SSID: Wifi +MAC: 48:F1:7F:D0:E5:4E +Vendor: Intel Corporate +Hostname: host-523c8e0e +Address: 192.168.20.254 +DNS name: host-523c8e0e.dhcp.MikroTik.example.com +Date: jun/15/2021 09:21:56 + + diff --git a/doc/notifications/daily-psk.svg b/doc/notifications/daily-psk.svg new file mode 100644 index 0000000..824ce6b --- /dev/null +++ b/doc/notifications/daily-psk.svg @@ -0,0 +1,204 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] 📅 daily PSK Guest-Wifi + +This is the daily PSK on MikroTik: + +SSID: Guest-Wifi +PSK: S3cr3tStr1ng +Date: jun/17/2021 + +A client device specific rule must not exist! + 🔗 https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi?scale=8&level=1&ssid=Guest-Wifi&pass=S3cr3tStr1ng + + diff --git a/doc/notifications/log-forward.svg b/doc/notifications/log-forward.svg new file mode 100644 index 0000000..7a4da2b --- /dev/null +++ b/doc/notifications/log-forward.svg @@ -0,0 +1,192 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] ⚠ Log Forwarding + +The log on MikroTik contains these 3 messages after 6d23:55:18 uptime. + + ● 13:24:02 script;error cloud-backup: Failed uploading backup for MikroTik to cloud! + ● 13:24:17 system;info;account user admin logged in from 192.168.88.177 via ssh + ● 13:24:57 system;info;account user admin logged out from 192.168.88.177 via ssh + + diff --git a/doc/notifications/netwatch-notify-down.svg b/doc/notifications/netwatch-notify-down.svg new file mode 100644 index 0000000..320c837 --- /dev/null +++ b/doc/notifications/netwatch-notify-down.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] ❌ Netwatch Notify: example.com down + +Host example.com (93.184.216.34) is down since +jun/08/2021 06:55:03. + + diff --git a/doc/notifications/netwatch-notify-up.svg b/doc/notifications/netwatch-notify-up.svg new file mode 100644 index 0000000..9365b00 --- /dev/null +++ b/doc/notifications/netwatch-notify-up.svg @@ -0,0 +1,172 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] ✅ Netwatch Notify: example.com up + +Host example.com (93.184.216.34) is up since +jun/08/2021 07:01:00. +It was down for 6 checks since jun/08/2021 06:55:03. + + diff --git a/doc/notifications/sms-forward.svg b/doc/notifications/sms-forward.svg new file mode 100644 index 0000000..76665cb --- /dev/null +++ b/doc/notifications/sms-forward.svg @@ -0,0 +1,176 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] 📨 SMS Forwarding from 7277 + +Received this message by MikroTik from 7277: + +On Jun/12/2021 13:44:10 GMT -0 type class-0: +Welcome to our network! + + diff --git a/doc/notifications/upload-backup.svg b/doc/notifications/upload-backup.svg new file mode 100644 index 0000000..73d20a8 --- /dev/null +++ b/doc/notifications/upload-backup.svg @@ -0,0 +1,212 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] 💾âŦ† Backup & Config upload + +Backup and config export upload for MikroTik. + +Hostname: MikroTik +Board name: CHR +Architecture: x86_64 +RouterOS: + Channel: stable + Installed: 6.48.3 +RouterOS-Scripts: + Current: 55 + +Backup file: MikroTik_example_com.backup +Config file: MikroTik_example_com.rsc + + diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 69ea5d0..9290b90 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -13,6 +13,10 @@ RouterOS can receive SMS. This script forwards SMS as notification. A broadband interface with SMS support is required. +### Sample notification + +![sms-forward notification](notifications/sms-forward.svg) + Requirements and installation ----------------------------- diff --git a/doc/upload-backup.md b/doc/upload-backup.md index f9a9b4f..f7d7c27 100644 --- a/doc/upload-backup.md +++ b/doc/upload-backup.md @@ -12,6 +12,10 @@ Description This script uploads binary backup (`/ system backup save`) and complete configuration export (`/ export terse`) to external server. +### Sample notification + +![upload-backup notification](notifications/upload-backup.svg) + Requirements and installation ----------------------------- From c0b954abbb67ef4b1d66cce47984b7bdfda8b2c7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 21 Jun 2021 09:15:05 +0200 Subject: [PATCH 0762/2612] doc/netwatch-notify: hint on checking internet connectivity --- doc/netwatch-notify.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 52e4792..7f61d88 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -80,6 +80,20 @@ make `netwatch-notify` check for that by adding several items with same / tool netwatch add comment="notify, hostname=service, count=10" host=10.0.0.10; / tool netwatch add comment="notify, hostname=service, count=10" host=10.0.0.20; +### Checking internet connectivity + +Sometimes you can not check your gateway for internet connectivity, for +example when it does not respond to pings or has a dynamic address. You could +check `1.1.1.1` (Cloudflare DNS), `9.9.9.9` (Quad-nine DNS), `8.8.8.8` +(Google DNS) or any other reliable address that indicates internet +connectivity. + + / tool netwatch add comment="notify, hostname=internet" host=1.1.1.1; + +A target like this suits well to be parent for other checks. + + / tool netwatch add comment="notify, hostname=example.com, parent=internet" host=93.184.216.34; + --- [◀ Go back to main README](../README.md) [▲ Go back to top](#top) From 7fb4fdfca264b9ab481994bed6f3ebc5c9623903 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 21 Jun 2021 21:08:26 +0200 Subject: [PATCH 0763/2612] global-functions: $MkDir: abuse smb share to create directory The smb feature is provided by system package... So we have it anyway. It gives some benefits compared to abusing fetch: * It is faster! * No need to alter, enable and restore a service! (The share is created disabled.) * Firewall rules can not break this. * No temporary file is created. * Less code! Let's hope we do not introduce new breakage. Closes #14 --- global-functions | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/global-functions b/global-functions index 422eac0..a4b4c4c 100644 --- a/global-functions +++ b/global-functions @@ -536,6 +536,7 @@ :local Dir [ :tostr $1 ]; :global CleanFilePath; + :global GetRandom20CharHex; :global WaitForFile; :set Dir [ $CleanFilePath $Dir ]; @@ -545,17 +546,14 @@ } :local Return true; - :local WwwVal [ / ip service get www ]; - / ip service set www address=127.0.0.1/32 disabled=no port=80; + :local Name ($Dir . "-" . [ $GetRandom20CharHex ]) :do { - / tool fetch http://127.0.0.1/ dst-path=($Dir . "/tmp") as-value; - $WaitForFile ($Dir . "/tmp"); - / file remove ($Dir . "/tmp"); + / ip smb share add disabled=yes directory=$Dir name=$Name; + $WaitForFile $Dir; } on-error={ :set Return false; } - / ip service set www address=($WwwVal->"address") \ - disabled=($WwwVal->"disabled") port=($WwwVal->"port"); + / ip smb share remove [ find where name=$Name ]; :return $Return; } From 06a0f42039008120bd256680b9433033eca2f5e1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Jun 2021 08:38:17 +0200 Subject: [PATCH 0764/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index faac400..e76c126 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -26,6 +26,7 @@ Add yourself to the list, * Marek ÄŒÃĄbÃĄk * Peter Holtkamp * Reiner Vehrenkamp +* Sunny Chu (@sunnychuchu) --- [◀ Go back to main README](README.md) From 420986fdfcaee163da10e5e8c6376b6e178c025c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Jun 2021 00:43:42 +0200 Subject: [PATCH 0765/2612] packages-update: use 'provides' to find backup scripts --- cloud-backup | 2 ++ email-backup | 2 ++ packages-update | 2 +- upload-backup | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cloud-backup b/cloud-backup index 5003f8f..3fa0e41 100644 --- a/cloud-backup +++ b/cloud-backup @@ -3,6 +3,8 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# provides: backup-script +# # upload backup to MikroTik cloud # https://git.eworm.de/cgit/routeros-scripts/about/doc/cloud-backup.md diff --git a/email-backup b/email-backup index 5a74220..a819a4a 100644 --- a/email-backup +++ b/email-backup @@ -3,6 +3,8 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# provides: backup-script +# # create and email backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/email-backup.md diff --git a/packages-update b/packages-update index bb138d7..627a7c4 100644 --- a/packages-update +++ b/packages-update @@ -52,7 +52,7 @@ $ScriptLock $0; } } -:foreach Script in=[ / system script find where name~"^(cloud|email|upload)-backup\$" ] do={ +:foreach Script in=[ / system script find where source~"\n# provides: backup-script\n" ] do={ :local ScriptName [ / system script get $Script name ]; :do { $LogPrintExit2 info $0 ("Running backup script " . $ScriptName . " before update.") false; diff --git a/upload-backup b/upload-backup index d79039a..cde847c 100644 --- a/upload-backup +++ b/upload-backup @@ -3,6 +3,8 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# provides: backup-script +# # create and upload backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/upload-backup.md From 2041390f554e70b72113b7d0b68cc658db1bade6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Jun 2021 00:53:19 +0200 Subject: [PATCH 0766/2612] lease-script: use 'provides' to find lease scripts --- collect-wireless-mac.capsman | 2 ++ collect-wireless-mac.local | 2 ++ collect-wireless-mac.template | 2 ++ dhcp-lease-comment.capsman | 2 ++ dhcp-lease-comment.local | 2 ++ dhcp-lease-comment.template | 2 ++ dhcp-to-dns | 3 +++ lease-script | 32 +++++++------------------------- 8 files changed, 22 insertions(+), 25 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 4cf8649..8ec6d61 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -6,6 +6,8 @@ # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # +# provides: lease-script assign +# # !! Do not edit this file, it is generated from template! :local 0 "collect-wireless-mac.capsman"; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index a7c26e6..771986e 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -6,6 +6,8 @@ # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # +# provides: lease-script assign +# # !! Do not edit this file, it is generated from template! :local 0 "collect-wireless-mac.local"; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 41cf299..311b72a 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -6,6 +6,8 @@ # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # +# provides: lease-script assign +# # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index 96b1741..e8db68d 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -3,6 +3,8 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# provides: lease-script assign +# # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md # diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index 74de2c8..76972ee 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -3,6 +3,8 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# provides: lease-script assign +# # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md # diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index 0e31007..58c349c 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -3,6 +3,8 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# provides: lease-script assign +# # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md # diff --git a/dhcp-to-dns b/dhcp-to-dns index bfd6195..32a47cd 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -3,6 +3,9 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# provides: lease-script assign +# provides: lease-script deassign +# # check DHCP leases and add/remove/update DNS entries # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md diff --git a/lease-script b/lease-script index 28f9e20..37d0c39 100644 --- a/lease-script +++ b/lease-script @@ -11,6 +11,7 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global LogPrintExit2; +:global IfThenElse; :if ([ :typeof $leaseActIP ] = "nothing" || \ [ :typeof $leaseActMAC ] = "nothing" || \ @@ -19,35 +20,16 @@ $LogPrintExit2 error $0 ("This script is supposed to run from ip dhcp-server.") true; } -:local Scripts; -:local ScriptsAssign { - "dhcp-to-dns"; - "collect-wireless-mac.local"; - "dhcp-lease-comment.local"; - "collect-wireless-mac.capsman"; - "dhcp-lease-comment.capsman" -} -:local ScriptsDeAssign { - "dhcp-to-dns" -} - -:local State ""; -:if ($leaseBound = 0) do={ - :set State "de"; - :set Scripts $ScriptsDeAssign; -} else={ - :set Scripts $ScriptsAssign; -} +:local State ([ $IfThenElse ($leaseBound = 0) "de" "" ] . "assign"); :log debug ("DHCP Server " . $leaseServerName . " " . \ - $State . "assigned lease " . $leaseActIP . " to " . $leaseActMAC); + $State . "ed lease " . $leaseActIP . " to " . $leaseActMAC); # delay a moment to update the lease table, do not run in parallel for de/assign :delay ((1 + $leaseBound) . "s"); -:foreach Script in=$Scripts do={ - :if ([ :len [ / system script find where name=$Script ] ] > 0) do={ - :log debug ("Running script from lease-script: " . $Script); - / system script run $Script; - } +:foreach Script in=[ / system script find where source~("\n# provides: lease-script " . $State . "\n") ] do={ + :local ScriptName [ / system script get $Script name ]; + :log debug ("Running script from lease-script: " . $ScriptName); + / system script run $Script; } From 96a92bb30cb04d23d1536f5d4ddfda353f2d9819 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Jun 2021 01:37:52 +0200 Subject: [PATCH 0767/2612] lease-script: add error handling --- lease-script | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lease-script b/lease-script index 37d0c39..72f96eb 100644 --- a/lease-script +++ b/lease-script @@ -30,6 +30,10 @@ :foreach Script in=[ / system script find where source~("\n# provides: lease-script " . $State . "\n") ] do={ :local ScriptName [ / system script get $Script name ]; - :log debug ("Running script from lease-script: " . $ScriptName); - / system script run $Script; + :do { + :log debug ("Running script from lease-script: " . $ScriptName); + / system script run $Script; + } on-error={ + :log warning ("Running script '" . $ScriptName . "' from lease-script failed!"); + } } From aad2e062e5005a1acdc689a4042d8c80d025b667 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Jun 2021 10:19:59 +0200 Subject: [PATCH 0768/2612] ppp-on-up: use 'provides' to find ppp-on-up scripts --- ppp-on-up | 13 ++++--------- update-tunnelbroker | 2 ++ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/ppp-on-up b/ppp-on-up index fe1492d..e7b2971 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -23,13 +23,8 @@ / ipv6 dhcp-client release [ find where interface=$IntName !disabled ]; -:local Scripts { - "update-tunnelbroker" -} - -:foreach Script in=$Scripts do={ - :if ([ :len [ / system script find where name=$Script ] ] > 0) do={ - :log debug ("Running script from ppp-on-up: " . $Script); - / system script run $Script; - } +:foreach Script in=[ / system script find where source~("\n# provides: ppp-on-up\n") ] do={ + :local ScriptName [ / system script get $Script name ]; + :log debug ("Running script from ppp-on-up: " . $ScriptName); + / system script run $Script; } diff --git a/update-tunnelbroker b/update-tunnelbroker index e6f50e4..4924516 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -4,6 +4,8 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# provides: ppp-on-up +# # update local address of tunnelbroker interface # https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md From 037d287e5b250ec794f26cb0bef3fd214a35aef2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Jun 2021 10:26:10 +0200 Subject: [PATCH 0769/2612] ppp-on-up: add error handling --- ppp-on-up | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ppp-on-up b/ppp-on-up index e7b2971..017edc3 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -25,6 +25,10 @@ :foreach Script in=[ / system script find where source~("\n# provides: ppp-on-up\n") ] do={ :local ScriptName [ / system script get $Script name ]; - :log debug ("Running script from ppp-on-up: " . $ScriptName); - / system script run $Script; + :do { + :log debug ("Running script from ppp-on-up: " . $ScriptName); + / system script run $Script; + } on-error={ + :log warning ("Running script '" . $ScriptName . "' from ppp-on-up failed!"); + } } From 64496d76c2f450c001f05769a83075b4fe18fbaf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Jun 2021 10:05:41 +0200 Subject: [PATCH 0770/2612] notify about tag in scripts --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 05197cf..92bb4b2 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 55; +:global GlobalConfigVersion 56; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index e3f3fd7..e697b94 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 55; +:global GlobalConfigVersion 56; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index c4ccb69..c4a335a 100644 --- a/global-config.changes +++ b/global-config.changes @@ -59,6 +59,7 @@ 53="Added support to send notifications via Matrix."; 54="Support for Telegram notifications moved to a module. It is installed automatically if required."; 55="Added reverse logic in 'log-forward', so messages can be included even if filtered before."; + 56="Added tags in all backup, lease and ppp-on-up scripts. These are used by 'packages-update', 'lease-script' and 'ppp-on-up' to find the scripts."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index a4b4c4c..c3c6e55 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 55; +:global ExpectedConfigVersion 56; # global variables not to be changed by user :global GlobalFunctionsReady false; From f5b1f9cb97f548a594d50e1835848350b54abf20 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Jun 2021 15:11:40 +0200 Subject: [PATCH 0771/2612] celebrating the 1.000th commit - hooray! --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 92bb4b2..ed7cd24 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 56; +:global GlobalConfigVersion 57; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index e697b94..abea983 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 56; +:global GlobalConfigVersion 57; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index c4a335a..dfbb1b4 100644 --- a/global-config.changes +++ b/global-config.changes @@ -60,6 +60,7 @@ 54="Support for Telegram notifications moved to a module. It is installed automatically if required."; 55="Added reverse logic in 'log-forward', so messages can be included even if filtered before."; 56="Added tags in all backup, lease and ppp-on-up scripts. These are used by 'packages-update', 'lease-script' and 'ppp-on-up' to find the scripts."; + 57="Celebrating the 1.000th commit - Hooray!"; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index c3c6e55..236b211 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 56; +:global ExpectedConfigVersion 57; # global variables not to be changed by user :global GlobalFunctionsReady false; From 1a404195d5f8f58f89bb8671a6b8afc5feebdd94 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Jun 2021 15:58:03 +0200 Subject: [PATCH 0772/2612] hotspot-to-wpa: add optional cleanup script --- doc/hotspot-to-wpa.md | 20 ++++++++++++++++++ doc/lease-script.md | 1 + global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- hotspot-to-wpa-cleanup | 47 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 hotspot-to-wpa-cleanup diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index 108cfd5..13f307a 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -27,6 +27,21 @@ Configure your hotspot to use this script as `on-login` script: / ip hotspot user profile set on-login=hotspot-to-wpa [ find ]; +### Automatic cleanup + +With just `hotspot-to-wpa` installed the mac addresses will last in the +access list forever. Install the optional script for automatic cleanup: + + $ScriptInstallUpdate hotspot-to-wpa-cleanup,lease-script; + +Create a scheduler: + + / system scheduler add interval=1d name=hotspot-to-wpa-cleanup on-event="/ system script run hotspot-to-wpa-cleanup;" start-time=startup; + +And add the lease script to your wpa interfaces' dhcp server: + + / ip dhcp-server set lease-script=lease-script [ find where name~"wpa" ]; + Configuration ------------- @@ -46,6 +61,11 @@ Now let the users connect and login to the hotspot. After that the devices (identified by MAC address) can connect to the WPA2 network, using the passphrase from hotspot credentials. +See also +-------- + +* [Run other scripts on DHCP lease](lease-script.md) + --- [◀ Go back to main README](../README.md) [▲ Go back to top](#top) diff --git a/doc/lease-script.md b/doc/lease-script.md index 6391c40..d437ee5 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -33,6 +33,7 @@ See also * [Collect MAC addresses in wireless access list](collect-wireless-mac.md) * [Comment DHCP leases with info from access list](dhcp-lease-comment.md) * [Create DNS records for DHCP leases](dhcp-to-dns.md) +* [Use WPA2 network with hotspot credentials](doc/hotspot-to-wpa.md) --- [◀ Go back to main README](../README.md) diff --git a/global-config b/global-config index ed7cd24..f411d14 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 57; +:global GlobalConfigVersion 58; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index abea983..202db89 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 57; +:global GlobalConfigVersion 58; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index dfbb1b4..3fe213b 100644 --- a/global-config.changes +++ b/global-config.changes @@ -61,6 +61,7 @@ 55="Added reverse logic in 'log-forward', so messages can be included even if filtered before."; 56="Added tags in all backup, lease and ppp-on-up scripts. These are used by 'packages-update', 'lease-script' and 'ppp-on-up' to find the scripts."; 57="Celebrating the 1.000th commit - Hooray!"; + 58="Added a cleanup script for 'hotspot-to-wpa' to purge old access list entries."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 236b211..677cfc7 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 57; +:global ExpectedConfigVersion 58; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/hotspot-to-wpa-cleanup b/hotspot-to-wpa-cleanup new file mode 100644 index 0000000..2c418cd --- /dev/null +++ b/hotspot-to-wpa-cleanup @@ -0,0 +1,47 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa-cleanup +# Copyright (c) 2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script assign +# +# manage and clean up private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md + +:local 0 "hotspot-to-wpa-cleanup"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global LogPrintExit2; + +:foreach Client in=[ / caps-man registration-table find where comment~"^hotspot-to-wpa:" ] do={ + :local ClientVal [ / caps-man registration-table get $Client ]; + :local Lease [ / ip dhcp-server lease find where mac-address=($ClientVal->"mac-address") dynamic ]; + :if ([ :len $Lease ] > 0) do={ + $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ + " connected to WPA, making lease static.") false; + / ip dhcp-server lease make-static $Lease; + / ip dhcp-server lease set comment=($ClientVal->"comment") $Lease; + } +} + +:foreach Client in=[ / caps-man access-list find where comment~"^hotspot-to-wpa:" and \ + !(comment~[ / system clock get date ]) ] do={ + :local ClientVal [ / caps-man access-list get $Client ]; + :if ([ :len [ / ip dhcp-server lease find where mac-address=($ClientVal->"mac-address") \ + !dynamic ] ] = 0) do={ + $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ + " did not connect to WPA, removing from access list.") false; + / caps-man access-list remove $Client; + } +} + +:foreach Lease in=[ / ip dhcp-server lease find where !dynamic status=waiting \ + last-seen>4w comment~"^hotspot-to-wpa:" ] do={ + :local LeaseVal [ / ip dhcp-server lease get $Lease ]; + $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ + " was not seen for long time, removing.") false; + / caps-man access-list remove [ find where comment~"^hotspot-to-wpa:" \ + mac-address=($LeaseVal->"mac-address") ]; + / ip dhcp-server lease remove $Lease; +} From cd0398acf9ccfcd488f0b8e9044f9789368937a1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Jun 2021 10:54:24 +0200 Subject: [PATCH 0773/2612] ipv6-update: use $LogPrintExit2 This will never print to terminal, nevertheless we want proper log with script name in prefix. --- ipv6-update | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ipv6-update b/ipv6-update index 45efccd..260b03b 100644 --- a/ipv6-update +++ b/ipv6-update @@ -22,13 +22,13 @@ :local Pool [ / ipv6 pool get [ find where prefix=$PdPrefix ] name ]; :if ([ :len [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={ / ipv6 firewall address-list add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool); - :log warning ("Added ipv6 address list entry for ipv6-pool-" . $Pool . "."); + $LogPrintExit2 warning $0 ("Added ipv6 address list entry for ipv6-pool-" . $Pool) false; } :local AddrList [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ]; :local OldPrefix [ / ipv6 firewall address-list get ($AddrList->0) address ]; :if ($OldPrefix != $PdPrefix) do={ - :log info ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix); + $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix) false; / ipv6 firewall address-list set address=$PdPrefix $AddrList; # give the interfaces a moment to receive their addresses @@ -41,7 +41,8 @@ :local Address [ / ipv6 address find where from-pool=$Pool interface=($Comment->"interface") ]; :if ([ :len $Address ] = 1) do={ :set Address [ / ipv6 address get $Address address ]; - :log info ("Updating IPv6 address list with new IPv6 prefix " . $Address . " from interface " . ($Comment->"interface")); + $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $Address . \ + " from interface " . ($Comment->"interface")) false; / ipv6 firewall address-list set address=$Address $ListEntry; } } @@ -54,7 +55,8 @@ :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); - :log info ("Updating DNS record for " . ($RecordVal->"name") . ($RecordVal->"regexp") . " to " . $Address); + $LogPrintExit2 info $0 ("Updating DNS record for " . ($RecordVal->"name") . \ + ($RecordVal->"regexp") . " to " . $Address) false; / ip dns static set address=$Address $Record; } } From f26b3da34224a6b4827f785ab82b1e9eaa40f021 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Jun 2021 10:56:30 +0200 Subject: [PATCH 0774/2612] lease-script: use $LogPrintExit2 This will never print to terminal, nevertheless we want proper log with script name in prefix. --- lease-script | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lease-script b/lease-script index 72f96eb..b7a4976 100644 --- a/lease-script +++ b/lease-script @@ -22,8 +22,8 @@ :local State ([ $IfThenElse ($leaseBound = 0) "de" "" ] . "assign"); -:log debug ("DHCP Server " . $leaseServerName . " " . \ - $State . "ed lease " . $leaseActIP . " to " . $leaseActMAC); +$LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . \ + $State . "ed lease " . $leaseActIP . " to " . $leaseActMAC) false; # delay a moment to update the lease table, do not run in parallel for de/assign :delay ((1 + $leaseBound) . "s"); @@ -31,9 +31,9 @@ :foreach Script in=[ / system script find where source~("\n# provides: lease-script " . $State . "\n") ] do={ :local ScriptName [ / system script get $Script name ]; :do { - :log debug ("Running script from lease-script: " . $ScriptName); + $LogPrintExit2 debug $0 ("Running script: " . $ScriptName) false; / system script run $Script; } on-error={ - :log warning ("Running script '" . $ScriptName . "' from lease-script failed!"); + $LogPrintExit2 warning $0 ("Running script '" . $ScriptName . "' failed!") false; } } From 39b7bddf497b26a56c20b2dd5722776be11a35ec Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Jun 2021 10:59:04 +0200 Subject: [PATCH 0775/2612] ppp-on-up: use $LogPrintExit2 This will never print to terminal, nevertheless we want proper log with script name in prefix. --- ppp-on-up | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ppp-on-up b/ppp-on-up index 017edc3..70c5cd6 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -19,16 +19,16 @@ } :local IntName [ / interface get $Interface name ]; -:log info ("PPP interface " . $IntName . " is up."); +$LogPrintExit2 info $0 ("PPP interface " . $IntName . " is up.") false; / ipv6 dhcp-client release [ find where interface=$IntName !disabled ]; :foreach Script in=[ / system script find where source~("\n# provides: ppp-on-up\n") ] do={ :local ScriptName [ / system script get $Script name ]; :do { - :log debug ("Running script from ppp-on-up: " . $ScriptName); + $LogPrintExit2 debug $0 ("Running script: " . $ScriptName) false; / system script run $Script; } on-error={ - :log warning ("Running script '" . $ScriptName . "' from ppp-on-up failed!"); + $LogPrintExit2 warning $0 ("Running script '" . $ScriptName . "' failed!") false; } } From 855399b2bc888e592a2a440425fd07430b18f24b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 24 Jun 2021 16:48:49 +0200 Subject: [PATCH 0776/2612] global-functions: $RandomDelay: allow to specify unit in second argument --- global-functions | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 677cfc7..da718f3 100644 --- a/global-functions +++ b/global-functions @@ -658,9 +658,10 @@ # delay a random amount of seconds :set RandomDelay do={ + :global EitherOr; :global GetRandomNumber; - :delay ([ $GetRandomNumber $1 ] . "s"); + :delay ([ $GetRandomNumber $1 ] . [ $EitherOr $2 "s" ]); } # check for required RouterOS version From 407a379f1dd18d12d2cd518cf9be26b69681e164 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 24 Jun 2021 17:17:43 +0200 Subject: [PATCH 0777/2612] lease-script: do not run in parallel on simultaneous deassign --- lease-script | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lease-script b/lease-script index b7a4976..eacba9f 100644 --- a/lease-script +++ b/lease-script @@ -10,8 +10,9 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit2; :global IfThenElse; +:global LogPrintExit2; +:global RandomDelay; :if ([ :typeof $leaseActIP ] = "nothing" || \ [ :typeof $leaseActMAC ] = "nothing" || \ @@ -25,8 +26,10 @@ $LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . \ $State . "ed lease " . $leaseActIP . " to " . $leaseActMAC) false; -# delay a moment to update the lease table, do not run in parallel for de/assign +# delay a moment to update the lease table, do not run in parallel for de/assign... :delay ((1 + $leaseBound) . "s"); +# ... or simultaneous deassign +$RandomDelay (([ :tonum $leaseBound ] ^ 1) * 750) "ms"; :foreach Script in=[ / system script find where source~("\n# provides: lease-script " . $State . "\n") ] do={ :local ScriptName [ / system script get $Script name ]; From 7f2314d9995dc8bb8658d7c4b90045d087e07d0f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 25 Jun 2021 00:01:04 +0200 Subject: [PATCH 0778/2612] doc/notifications: change stroke color This makes the stroke visible on black background. --- doc/notifications/check-certificates.svg | 6 +++--- doc/notifications/check-health-psu-fail.svg | 6 +++--- doc/notifications/check-health-psu-ok.svg | 6 +++--- doc/notifications/check-health-temperature-high.svg | 6 +++--- doc/notifications/check-health-temperature-ok.svg | 6 +++--- doc/notifications/check-health-voltage.svg | 6 +++--- doc/notifications/check-lte-firmware-upgrade.svg | 6 +++--- doc/notifications/check-routeros-update.svg | 11 +++-------- doc/notifications/cloud-backup.svg | 6 +++--- doc/notifications/collect-wireless-mac.svg | 6 +++--- doc/notifications/daily-psk.svg | 6 +++--- doc/notifications/log-forward.svg | 6 +++--- doc/notifications/netwatch-notify-down.svg | 6 +++--- doc/notifications/netwatch-notify-up.svg | 6 +++--- doc/notifications/sms-forward.svg | 6 +++--- doc/notifications/upload-backup.svg | 6 +++--- 16 files changed, 48 insertions(+), 53 deletions(-) diff --git a/doc/notifications/check-certificates.svg b/doc/notifications/check-certificates.svg index 521db39..a299963 100644 --- a/doc/notifications/check-certificates.svg +++ b/doc/notifications/check-certificates.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.375002,11.083333)"> + style="stroke-width:2"> + style="stroke-width:2"> diff --git a/doc/notifications/check-health-psu-fail.svg b/doc/notifications/check-health-psu-fail.svg index 0ca57a4..5d5d573 100644 --- a/doc/notifications/check-health-psu-fail.svg +++ b/doc/notifications/check-health-psu-fail.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.375001,11.083333)"> + style="stroke-width:2"> + style="stroke-width:2"> diff --git a/doc/notifications/check-health-psu-ok.svg b/doc/notifications/check-health-psu-ok.svg index 06f596b..aae56c9 100644 --- a/doc/notifications/check-health-psu-ok.svg +++ b/doc/notifications/check-health-psu-ok.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.375001,11.083333)"> + style="stroke-width:2"> + style="stroke-width:2"> diff --git a/doc/notifications/check-health-temperature-high.svg b/doc/notifications/check-health-temperature-high.svg index 84c4256..15250f8 100644 --- a/doc/notifications/check-health-temperature-high.svg +++ b/doc/notifications/check-health-temperature-high.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.375,11.083332)"> + style="stroke-width:2"> + style="stroke-width:2"> diff --git a/doc/notifications/check-health-temperature-ok.svg b/doc/notifications/check-health-temperature-ok.svg index d57ab4e..d517e57 100644 --- a/doc/notifications/check-health-temperature-ok.svg +++ b/doc/notifications/check-health-temperature-ok.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.375,11.083333)"> + style="stroke-width:2"> + style="stroke-width:2"> diff --git a/doc/notifications/check-health-voltage.svg b/doc/notifications/check-health-voltage.svg index adc0328..81f7178 100644 --- a/doc/notifications/check-health-voltage.svg +++ b/doc/notifications/check-health-voltage.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.375001,11.083333)"> + style="stroke-width:2"> + style="stroke-width:2"> diff --git a/doc/notifications/check-lte-firmware-upgrade.svg b/doc/notifications/check-lte-firmware-upgrade.svg index 01d3d44..70aad88 100644 --- a/doc/notifications/check-lte-firmware-upgrade.svg +++ b/doc/notifications/check-lte-firmware-upgrade.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.375001,11.083332)"> + style="stroke-width:2"> + style="stroke-width:2"> diff --git a/doc/notifications/check-routeros-update.svg b/doc/notifications/check-routeros-update.svg index 9e049a4..1eabdbb 100644 --- a/doc/notifications/check-routeros-update.svg +++ b/doc/notifications/check-routeros-update.svg @@ -86,7 +86,7 @@ id="layer1" transform="translate(16.375,11.083333)"> + style="stroke-width:2"> + style="stroke-width:2"> @@ -226,10 +226,5 @@ x="61.890625" y="258.7301" id="tspan13569">🔗 https://mikrotik.com/download/changelogs/stable-release-tree - diff --git a/doc/notifications/cloud-backup.svg b/doc/notifications/cloud-backup.svg index 5a6e0c0..8b84b8f 100644 --- a/doc/notifications/cloud-backup.svg +++ b/doc/notifications/cloud-backup.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.375,11.083332)"> + style="stroke-width:2"> + style="stroke-width:2"> diff --git a/doc/notifications/collect-wireless-mac.svg b/doc/notifications/collect-wireless-mac.svg index 355fb8d..fe1d20f 100644 --- a/doc/notifications/collect-wireless-mac.svg +++ b/doc/notifications/collect-wireless-mac.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.375001,11.083333)"> + style="stroke-width:2"> + style="stroke-width:2"> diff --git a/doc/notifications/daily-psk.svg b/doc/notifications/daily-psk.svg index 824ce6b..6c7d13a 100644 --- a/doc/notifications/daily-psk.svg +++ b/doc/notifications/daily-psk.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.374997,11.08333)"> + style="stroke-width:2"> + style="stroke-width:2"> diff --git a/doc/notifications/log-forward.svg b/doc/notifications/log-forward.svg index 7a4da2b..b3389fe 100644 --- a/doc/notifications/log-forward.svg +++ b/doc/notifications/log-forward.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.374996,11.083327)"> + style="stroke-width:2"> + style="stroke-width:2"> diff --git a/doc/notifications/netwatch-notify-down.svg b/doc/notifications/netwatch-notify-down.svg index 320c837..5cab5fe 100644 --- a/doc/notifications/netwatch-notify-down.svg +++ b/doc/notifications/netwatch-notify-down.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.374999,11.083332)"> + style="stroke-width:2"> + style="stroke-width:2"> diff --git a/doc/notifications/netwatch-notify-up.svg b/doc/notifications/netwatch-notify-up.svg index 9365b00..8e03981 100644 --- a/doc/notifications/netwatch-notify-up.svg +++ b/doc/notifications/netwatch-notify-up.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.375001,11.083333)"> + style="stroke-width:2"> + style="stroke-width:2"> diff --git a/doc/notifications/sms-forward.svg b/doc/notifications/sms-forward.svg index 76665cb..298b43e 100644 --- a/doc/notifications/sms-forward.svg +++ b/doc/notifications/sms-forward.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.374999,11.083331)"> + style="stroke-width:2"> + style="stroke-width:2"> diff --git a/doc/notifications/upload-backup.svg b/doc/notifications/upload-backup.svg index 73d20a8..a85bd5c 100644 --- a/doc/notifications/upload-backup.svg +++ b/doc/notifications/upload-backup.svg @@ -74,7 +74,7 @@ id="layer1" transform="translate(16.374996,11.083328)"> + style="stroke-width:2"> + style="stroke-width:2"> From cfc400b3d5dd200644673f4dc39636e231979724 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Jun 2021 00:26:20 +0200 Subject: [PATCH 0779/2612] global-functions: $GetRandom20CharHex: do not remove otp... ... as it is instantly invalid anyway. --- global-functions | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/global-functions b/global-functions index da718f3..14b045e 100644 --- a/global-functions +++ b/global-functions @@ -405,9 +405,7 @@ # generate random 20 chars hex (0-9 and a-f) :set GetRandom20CharHex do={ - :local Random ([ / certificate scep-server otp generate minutes-valid=0 as-value ]->"password"); - / certificate scep-server otp remove [ find where password=$Random ]; - :return $Random; + :return ([ / certificate scep-server otp generate minutes-valid=0 as-value ]->"password"); } # generate random number From 679917390bbb71b33d82be55ff55e21ed041dadd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Jun 2021 00:46:27 +0200 Subject: [PATCH 0780/2612] global-functions: $GetRandomNumber: use $HexToNum --- global-functions | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/global-functions b/global-functions index 14b045e..654642e 100644 --- a/global-functions +++ b/global-functions @@ -416,18 +416,9 @@ } :global GetRandom20CharHex; + :global HexToNum; - :local Num; - :local 40CharHex ([ $GetRandom20CharHex ] . [ $GetRandom20CharHex ]); - - :for I from=0 to=39 do={ - :local Char [ :pick $40CharHex $I ]; - :if ($Char~"[0-9]") do={ - :set Num ($Num . $Char); - } - } - - :return ([ :tonum [ :pick $Num 0 18 ] ] % $Max); + :return ([ $HexToNum [ :pick [ $GetRandom20CharHex ] 0 15 ] ] % $Max); } # convert from hex (string) to num From 89f8dc712001872783c8b3be7208bc1d726a12dd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 29 Jun 2021 15:35:59 +0200 Subject: [PATCH 0781/2612] global-functions: $LogPrintExit2: allow origin-specific debug Add something like this in global-config-overlay: :global PrintDebugOverride { "dhcp-to-dns"=true; } --- global-functions | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 654642e..63c0e21 100644 --- a/global-functions +++ b/global-functions @@ -489,6 +489,11 @@ :local Exit [ :tostr $4 ]; :global PrintDebug; + :global PrintDebugOverride; + + :global EitherOr; + + :local Debug [ $EitherOr ($PrintDebugOverride->$Name) $PrintDebug ]; :local PrintSeverity do={ :global TerminalColorOutput; @@ -511,7 +516,7 @@ :set Severity "warning"; } - :if ($Severity != "debug" || $PrintDebug = true) do={ + :if ($Severity != "debug" || $Debug = true) do={ :if ($Exit = "true") do={ :error ([ $PrintSeverity $Severity ] . ": " . $Message); } else={ From 301ad4b3e570a362dd8f7b7fe4448d7638803509 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 27 Jun 2021 20:40:22 +0200 Subject: [PATCH 0782/2612] global-functions: $ScriptLock: allow to return... ... with true instead of breaking with error. --- global-functions | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 63c0e21..d15d176 100644 --- a/global-functions +++ b/global-functions @@ -904,13 +904,18 @@ # lock script against multiple invocation :set ScriptLock do={ + :local Script [ :tostr $1 ]; + :local DoReturn $2; + + :global IfThenElse; :global LogPrintExit2; - :local Script [ :tostr $1 ]; - :if ([ :len [ / system script job find where script=$Script ] ] > 1) do={ - $LogPrintExit2 info $0 ("Script " . $Script . " started more than once... Aborting.") true; + $LogPrintExit2 info $0 ("Script " . $Script . " started more than once... Aborting.") \ + [ $IfThenElse ($DoReturn = true) false true ]; + :return true; } + :return false; } # send notification via e-mail - expects at lease two string arguments From e13e3cfe34b2ac0c1ec859d05ba2d0df8adc2e0f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 30 Jun 2021 21:10:58 +0200 Subject: [PATCH 0783/2612] global-functions: $ScriptLock: check if script exists --- global-functions | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/global-functions b/global-functions index d15d176..7b68701 100644 --- a/global-functions +++ b/global-functions @@ -910,6 +910,10 @@ :global IfThenElse; :global LogPrintExit2; + :if ([ :len [ / system script find where name=$Script ] ] = 0) do={ + $LogPrintExit2 error $0 ("A script named '" . $Script . "' does not exist!") true; + } + :if ([ :len [ / system script job find where script=$Script ] ] > 1) do={ $LogPrintExit2 info $0 ("Script " . $Script . " started more than once... Aborting.") \ [ $IfThenElse ($DoReturn = true) false true ]; From b2d0ed1240e5ae5a0e48dfd706e8496e6492fd10 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 30 Jun 2021 21:18:38 +0200 Subject: [PATCH 0784/2612] global-functions: $ScriptLock: check if script is running --- global-functions | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/global-functions b/global-functions index 7b68701..255c30a 100644 --- a/global-functions +++ b/global-functions @@ -914,6 +914,10 @@ $LogPrintExit2 error $0 ("A script named '" . $Script . "' does not exist!") true; } + :if ([ :len [ / system script job find where script=$Script ] ] = 0) do={ + $LogPrintExit2 error $0 ("No script '" . $Script . "' is running!") true; + } + :if ([ :len [ / system script job find where script=$Script ] ] > 1) do={ $LogPrintExit2 info $0 ("Script " . $Script . " started more than once... Aborting.") \ [ $IfThenElse ($DoReturn = true) false true ]; From 5d30886e597aa3ea0b5bc4ccbf7f62713df0de3d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 27 Jun 2021 23:31:25 +0200 Subject: [PATCH 0785/2612] global-functions: $ScriptLock: rework with tickets Getting the order right is not easy... We use a global variable to store "tickets" in an array. Based on that scripts know their order. --- global-functions | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/global-functions b/global-functions index 255c30a..6c11258 100644 --- a/global-functions +++ b/global-functions @@ -907,23 +907,57 @@ :local Script [ :tostr $1 ]; :local DoReturn $2; + :global GetRandomNumber; :global IfThenElse; :global LogPrintExit2; + :global ScriptLockOrder; + :if ([ :typeof $ScriptLockOrder ] = "nothing") do={ + :set ScriptLockOrder [ :toarray "" ]; + } + + :local AddTicket do={ + :return ($1, $2); + } + + :local RemoveTicket do={ + :local Return [ :toarray "" ]; + :foreach Ticket in=$1 do={ + :if ($Ticket != $2) do={ + :set Return ($Return, $Ticket); + } + } + :return $Return; + } + :if ([ :len [ / system script find where name=$Script ] ] = 0) do={ $LogPrintExit2 error $0 ("A script named '" . $Script . "' does not exist!") true; } - :if ([ :len [ / system script job find where script=$Script ] ] = 0) do={ + :local JobCount [ :len [ / system script job find where script=$Script ] ]; + + :if ($JobCount = 0) do={ $LogPrintExit2 error $0 ("No script '" . $Script . "' is running!") true; } - :if ([ :len [ / system script job find where script=$Script ] ] > 1) do={ - $LogPrintExit2 info $0 ("Script " . $Script . " started more than once... Aborting.") \ - [ $IfThenElse ($DoReturn = true) false true ]; - :return true; + :if ([ :len ($ScriptLockOrder->$Script) ] > $JobCount) do={ + $LogPrintExit2 error $0 ("More tickets than running scripts '" . $Script . "', resetting!") false; + :set ($ScriptLockOrder->$Script); + / system script job remove [ find where script=$Script ]; + } + + :local MyTicket [ $GetRandomNumber ]; + :set ($ScriptLockOrder->$Script) [ $AddTicket ($ScriptLockOrder->$Script) $MyTicket ]; + + :if ([ :len ($ScriptLockOrder->$Script) ] = $JobCount && ($ScriptLockOrder->$Script->0) = $MyTicket) do={ + :set ($ScriptLockOrder->$Script) [ $RemoveTicket ($ScriptLockOrder->$Script) $MyTicket ]; + :return false; } - :return false; + + :set ($ScriptLockOrder->$Script) [ $RemoveTicket ($ScriptLockOrder->$Script) $MyTicket ]; + $LogPrintExit2 info $0 ("Script '" . $Script . "' started more than once... Aborting.") \ + [ $IfThenElse ($DoReturn = true) false true ]; + :return true; } # send notification via e-mail - expects at lease two string arguments From 7de3457f449bcb37f39a12ea81e3c73cfb14e7ba Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 30 Jun 2021 21:27:39 +0200 Subject: [PATCH 0786/2612] global-functions: $ScriptLock: allow to wait for lock --- global-functions | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/global-functions b/global-functions index 6c11258..a19e44b 100644 --- a/global-functions +++ b/global-functions @@ -906,6 +906,7 @@ :set ScriptLock do={ :local Script [ :tostr $1 ]; :local DoReturn $2; + :local DoWait $3; :global GetRandomNumber; :global IfThenElse; @@ -949,6 +950,11 @@ :local MyTicket [ $GetRandomNumber ]; :set ($ScriptLockOrder->$Script) [ $AddTicket ($ScriptLockOrder->$Script) $MyTicket ]; + :while ($DoWait = true && (($ScriptLockOrder->$Script->0) != $MyTicket || [ :len ($ScriptLockOrder->$Script) ] < $JobCount)) do={ + :delay 100ms; + :set JobCount [ :len [ / system script job find where script=$Script ] ]; + } + :if ([ :len ($ScriptLockOrder->$Script) ] = $JobCount && ($ScriptLockOrder->$Script->0) = $MyTicket) do={ :set ($ScriptLockOrder->$Script) [ $RemoveTicket ($ScriptLockOrder->$Script) $MyTicket ]; :return false; From 0b4c1861cf54a017bbe1e7cf6e0e91f4b63e9e73 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 1 Jul 2021 10:26:16 +0200 Subject: [PATCH 0787/2612] global-functions: $ScriptLock: use a limit on lock... ... to make sure it does not lock forever. --- global-functions | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/global-functions b/global-functions index a19e44b..9c4a53e 100644 --- a/global-functions +++ b/global-functions @@ -906,7 +906,7 @@ :set ScriptLock do={ :local Script [ :tostr $1 ]; :local DoReturn $2; - :local DoWait $3; + :local WaitMax ([ :tonum $3 ] * 10); :global GetRandomNumber; :global IfThenElse; @@ -950,8 +950,10 @@ :local MyTicket [ $GetRandomNumber ]; :set ($ScriptLockOrder->$Script) [ $AddTicket ($ScriptLockOrder->$Script) $MyTicket ]; - :while ($DoWait = true && (($ScriptLockOrder->$Script->0) != $MyTicket || [ :len ($ScriptLockOrder->$Script) ] < $JobCount)) do={ + :local WaitCount 0; + :while ($WaitMax > $WaitCount && (($ScriptLockOrder->$Script->0) != $MyTicket || [ :len ($ScriptLockOrder->$Script) ] < $JobCount)) do={ :delay 100ms; + :set WaitCount ($WaitCount + 1); :set JobCount [ :len [ / system script job find where script=$Script ] ]; } @@ -961,8 +963,8 @@ } :set ($ScriptLockOrder->$Script) [ $RemoveTicket ($ScriptLockOrder->$Script) $MyTicket ]; - $LogPrintExit2 info $0 ("Script '" . $Script . "' started more than once... Aborting.") \ - [ $IfThenElse ($DoReturn = true) false true ]; + $LogPrintExit2 info $0 ("Script '" . $Script . "' started more than once" . [ $IfThenElse ($WaitCount > 0) \ + " and timed out waiting for lock" "" ] . "... Aborting.") [ $IfThenElse ($DoReturn = true) false true ]; :return true; } From aad91d90ea3c4cbe21b5c4f61fed94aaa337bddb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Jun 2021 01:13:31 +0200 Subject: [PATCH 0788/2612] global-functions: $ScriptLock: use hex string for ticket Does not matter what the ticket looks like, but using hex string it is not converted to number. --- global-functions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 9c4a53e..e7080e4 100644 --- a/global-functions +++ b/global-functions @@ -908,7 +908,7 @@ :local DoReturn $2; :local WaitMax ([ :tonum $3 ] * 10); - :global GetRandomNumber; + :global GetRandom20CharHex; :global IfThenElse; :global LogPrintExit2; @@ -947,7 +947,7 @@ / system script job remove [ find where script=$Script ]; } - :local MyTicket [ $GetRandomNumber ]; + :local MyTicket [ $GetRandom20CharHex ]; :set ($ScriptLockOrder->$Script) [ $AddTicket ($ScriptLockOrder->$Script) $MyTicket ]; :local WaitCount 0; From df43f6101814f241279919ba482ca700c80d6ca6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Jun 2021 00:07:59 +0200 Subject: [PATCH 0789/2612] collect-wireless-mac: wait when locking script --- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 8ec6d61..3137aa6 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -22,7 +22,7 @@ :global SendNotification2; :global SymbolForNotification; -$ScriptLock $0; +$ScriptLock $0 false 10; :if ([ :len [ / caps-man access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ / caps-man access-list add comment="--- collected above ---" disabled=yes; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 771986e..0284acf 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -22,7 +22,7 @@ :global SendNotification2; :global SymbolForNotification; -$ScriptLock $0; +$ScriptLock $0 false 10; :if ([ :len [ / interface wireless access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ / interface wireless access-list add comment="--- collected above ---" disabled=yes; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 311b72a..8ccfeff 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -23,7 +23,7 @@ :global SendNotification2; :global SymbolForNotification; -$ScriptLock $0; +$ScriptLock $0 false 10; :if ([ :len [ / %PATH% access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ / %PATH% access-list add comment="--- collected above ---" disabled=yes; From 64b53d23224e6e4852910105774adf4529732189 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Jun 2021 00:06:38 +0200 Subject: [PATCH 0790/2612] dhcp-to-dns: lock script (and wait) --- dhcp-to-dns | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dhcp-to-dns b/dhcp-to-dns index 32a47cd..a794e67 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -22,6 +22,9 @@ :global CharacterReplace; :global IfThenElse; :global LogPrintExit2; +:global ScriptLock; + +$ScriptLock $0 false 10; :local Zone \ ([ $IfThenElse ($PrefixInZone = true) "dhcp." ] . \ From 08b1b72fa9bda0f08eeaf28fd7d83d6e0e06389f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Jun 2021 00:13:16 +0200 Subject: [PATCH 0791/2612] hotspot-to-wpa-cleanup: lock script (and wait) --- hotspot-to-wpa-cleanup | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hotspot-to-wpa-cleanup b/hotspot-to-wpa-cleanup index 2c418cd..69a1119 100644 --- a/hotspot-to-wpa-cleanup +++ b/hotspot-to-wpa-cleanup @@ -13,6 +13,9 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global LogPrintExit2; +:global ScriptLock; + +$ScriptLock $0 false 10; :foreach Client in=[ / caps-man registration-table find where comment~"^hotspot-to-wpa:" ] do={ :local ClientVal [ / caps-man registration-table get $Client ]; From 5f2bc87b2244382fdff968df9e643722fcf26a68 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Jun 2021 00:16:13 +0200 Subject: [PATCH 0792/2612] lease-script: drop the delay magic... ... as this should be handled by $ScriptLock in lease scripts now. --- lease-script | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lease-script b/lease-script index eacba9f..537c832 100644 --- a/lease-script +++ b/lease-script @@ -12,7 +12,6 @@ :global IfThenElse; :global LogPrintExit2; -:global RandomDelay; :if ([ :typeof $leaseActIP ] = "nothing" || \ [ :typeof $leaseActMAC ] = "nothing" || \ @@ -26,11 +25,6 @@ $LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . \ $State . "ed lease " . $leaseActIP . " to " . $leaseActMAC) false; -# delay a moment to update the lease table, do not run in parallel for de/assign... -:delay ((1 + $leaseBound) . "s"); -# ... or simultaneous deassign -$RandomDelay (([ :tonum $leaseBound ] ^ 1) * 750) "ms"; - :foreach Script in=[ / system script find where source~("\n# provides: lease-script " . $State . "\n") ] do={ :local ScriptName [ / system script get $Script name ]; :do { From 9c9fb46e4a95a7020b1fefb8fb0db3aafa9b2844 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 1 Jul 2021 18:07:23 +0200 Subject: [PATCH 0793/2612] lease-script: do not run too many instances of scripts Every instance of the scripts does all the work. If one script is running and a second script is waiting we do not have to start a third one. --- lease-script | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lease-script b/lease-script index 537c832..2f67cb0 100644 --- a/lease-script +++ b/lease-script @@ -27,10 +27,12 @@ $LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . \ :foreach Script in=[ / system script find where source~("\n# provides: lease-script " . $State . "\n") ] do={ :local ScriptName [ / system script get $Script name ]; - :do { - $LogPrintExit2 debug $0 ("Running script: " . $ScriptName) false; - / system script run $Script; - } on-error={ - $LogPrintExit2 warning $0 ("Running script '" . $ScriptName . "' failed!") false; + :if ([ :len [ / system script job find where script=$ScriptName ] ] < 2) do={ + :do { + $LogPrintExit2 debug $0 ("Running script: " . $ScriptName) false; + / system script run $Script; + } on-error={ + $LogPrintExit2 warning $0 ("Running script '" . $ScriptName . "' failed!") false; + } } } From 23daea2354172bb7235f91393b73c401f8188829 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 29 Jun 2021 15:24:23 +0200 Subject: [PATCH 0794/2612] dhcp-to-dns: properly handle vanished lease --- dhcp-to-dns | 54 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index a794e67..a7a05ad 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -52,34 +52,42 @@ $ScriptLock $0 false 10; } :foreach Lease in=[ / ip dhcp-server lease find where status=bound ] do={ - :local LeaseVal [ / ip dhcp-server lease get $Lease ]; - :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); - :local HostName [ $IfThenElse ([ :len ($LeaseVal->"host-name") ] = 0) \ - [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ] \ - [ $CharacterReplace ($LeaseVal->"host-name") " " "" ] ]; + :local LeaseVal; + :do { + :set LeaseVal [ / ip dhcp-server lease get $Lease ]; + } on-error={ + $LogPrintExit2 debug $0 ("A lease just vanished, ignoring.") false; + } - :local Fqdn ($HostName . "." . [ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); - :local DnsRecord [ / ip dns static find where name=$Fqdn ]; - :if ([ :len $DnsRecord ] > 0) do={ - :local DnsIp [ / ip dns static get $DnsRecord address ]; + :if ([ :typeof $LeaseVal ] = "array") do={ + :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); + :local HostName [ $IfThenElse ([ :len ($LeaseVal->"host-name") ] = 0) \ + [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ] \ + [ $CharacterReplace ($LeaseVal->"host-name") " " "" ] ]; - :local DupMacLeases [ / ip dhcp-server lease find where mac-address=($LeaseVal->"mac-address") status=bound ]; - :if ([ :len $DupMacLeases ] > 1) do={ - :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; - } + :local Fqdn ($HostName . "." . [ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); + :local DnsRecord [ / ip dns static find where name=$Fqdn ]; + :if ([ :len $DnsRecord ] > 0) do={ + :local DnsIp [ / ip dns static get $DnsRecord address ]; - :if ([ :len ($LeaseVal->"host-name") ] > 0) do={ - :set ($LeaseVal->"address") [ / ip dhcp-server lease get ([ find where host-name=($LeaseVal->"host-name") status=bound ]->0) address ]; - } + :local DupMacLeases [ / ip dhcp-server lease find where mac-address=($LeaseVal->"mac-address") status=bound ]; + :if ([ :len $DupMacLeases ] > 1) do={ + :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; + } - :if ($DnsIp = $LeaseVal->"address") do={ - $LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false; + :if ([ :len ($LeaseVal->"host-name") ] > 0) do={ + :set ($LeaseVal->"address") [ / ip dhcp-server lease get ([ find where host-name=($LeaseVal->"host-name") status=bound ]->0) address ]; + } + + :if ($DnsIp = $LeaseVal->"address") do={ + $LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false; + } else={ + $LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . ".") false; + / ip dns static set name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; + } } else={ - $LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . ".") false; - / ip dns static set name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; + $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false; + / ip dns static add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } - } else={ - $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false; - / ip dns static add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } From 5f357fd242c8798769e505817bb075eb9abf8a88 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 30 Jun 2021 13:49:03 +0200 Subject: [PATCH 0795/2612] dhcp-to-dns: fix static lease that lost bound status --- dhcp-to-dns | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index a7a05ad..1dc3b42 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -76,7 +76,10 @@ $ScriptLock $0 false 10; } :if ([ :len ($LeaseVal->"host-name") ] > 0) do={ - :set ($LeaseVal->"address") [ / ip dhcp-server lease get ([ find where host-name=($LeaseVal->"host-name") status=bound ]->0) address ]; + :local HostNameLeases [ / ip dhcp-server lease find where host-name=($LeaseVal->"host-name") status=bound ]; + :if ([ :len $HostNameLeases ] > 1) do={ + :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($HostNameLeases->0) address ]; + } } :if ($DnsIp = $LeaseVal->"address") do={ From 877e95d4be240835e2153ba4ce5fe615a127eda1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 1 Jul 2021 09:56:34 +0200 Subject: [PATCH 0796/2612] collect-wireless-mac: properly handle vanished device --- collect-wireless-mac.capsman | 21 +++++++++++++++------ collect-wireless-mac.local | 21 +++++++++++++++------ collect-wireless-mac.template | 21 +++++++++++++++------ 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 3137aa6..0e65dcd 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -31,9 +31,21 @@ $ScriptLock $0 false 10; :local PlaceBefore ([ / caps-man access-list find where comment="--- collected above ---" disabled ]->0); :foreach RegTbl in=[ / caps-man registration-table find ] do={ - :local Mac [ / caps-man registration-table get $RegTbl mac-address ]; - :local AccessList ([ / caps-man access-list find where mac-address=$Mac ]->0); - :if ([ :len $AccessList ] = 0) do={ + :local Mac; + :local AccessList; + :do { + :set Mac [ / caps-man registration-table get $RegTbl mac-address ]; + :set AccessList ([ / caps-man access-list find where mac-address=$Mac ]->0); + } on-error={ + $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; + } + + :if ([ :len $AccessList ] > 0) do={ + $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ + [ / caps-man access-list get $AccessList comment ]) false; + } + + :if ([ :typeof $Mac ] = "str" && [ :len $AccessList ] = 0) do={ :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; @@ -70,8 +82,5 @@ $ScriptLock $0 false 10; "Address: " . $Address . "\n" . \ "DNS name: " . $DnsName . "\n" . \ "Date: " . $DateTime) }); - } else={ - $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ - [ / caps-man access-list get $AccessList comment ]) false; } } diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 0284acf..bb4cafe 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -31,9 +31,21 @@ $ScriptLock $0 false 10; :local PlaceBefore ([ / interface wireless access-list find where comment="--- collected above ---" disabled ]->0); :foreach RegTbl in=[ / interface wireless registration-table find ] do={ - :local Mac [ / interface wireless registration-table get $RegTbl mac-address ]; - :local AccessList ([ / interface wireless access-list find where mac-address=$Mac ]->0); - :if ([ :len $AccessList ] = 0) do={ + :local Mac; + :local AccessList; + :do { + :set Mac [ / interface wireless registration-table get $RegTbl mac-address ]; + :set AccessList ([ / interface wireless access-list find where mac-address=$Mac ]->0); + } on-error={ + $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; + } + + :if ([ :len $AccessList ] > 0) do={ + $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ + [ / interface wireless access-list get $AccessList comment ]) false; + } + + :if ([ :typeof $Mac ] = "str" && [ :len $AccessList ] = 0) do={ :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; @@ -70,8 +82,5 @@ $ScriptLock $0 false 10; "Address: " . $Address . "\n" . \ "DNS name: " . $DnsName . "\n" . \ "Date: " . $DateTime) }); - } else={ - $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ - [ / interface wireless access-list get $AccessList comment ]) false; } } diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 8ccfeff..2be6447 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -32,9 +32,21 @@ $ScriptLock $0 false 10; :local PlaceBefore ([ / %PATH% access-list find where comment="--- collected above ---" disabled ]->0); :foreach RegTbl in=[ / %PATH% registration-table find ] do={ - :local Mac [ / %PATH% registration-table get $RegTbl mac-address ]; - :local AccessList ([ / %PATH% access-list find where mac-address=$Mac ]->0); - :if ([ :len $AccessList ] = 0) do={ + :local Mac; + :local AccessList; + :do { + :set Mac [ / %PATH% registration-table get $RegTbl mac-address ]; + :set AccessList ([ / %PATH% access-list find where mac-address=$Mac ]->0); + } on-error={ + $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; + } + + :if ([ :len $AccessList ] > 0) do={ + $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ + [ / %PATH% access-list get $AccessList comment ]) false; + } + + :if ([ :typeof $Mac ] = "str" && [ :len $AccessList ] = 0) do={ :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; @@ -72,8 +84,5 @@ $ScriptLock $0 false 10; "Address: " . $Address . "\n" . \ "DNS name: " . $DnsName . "\n" . \ "Date: " . $DateTime) }); - } else={ - $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ - [ / %PATH% access-list get $AccessList comment ]) false; } } From d5edcbd3b6396f47358428dc376c5c9a81035f6d Mon Sep 17 00:00:00 2001 From: Michael Gisbers Date: Mon, 28 Jun 2021 18:00:25 +0200 Subject: [PATCH 0797/2612] check-routeros-update: allow update for cap If CAPsMAN is running on a device with just 16MB flash downloading the packages is not possible (or at least lost at reboot). So allow a CAP to update with opt-in. --- check-routeros-update | 4 +++- doc/check-routeros-update.md | 1 + global-config | 4 +++- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 6 files changed, 10 insertions(+), 4 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index 0309730..d21a7d0 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -12,6 +12,7 @@ :global Identity; :global SafeUpdateNeighbor; +:global SafeUpdateOnCap; :global SafeUpdatePatch; :global SafeUpdateUrl; :global SentRouterosUpdateNotification; @@ -37,7 +38,8 @@ $WaitFullyConnected; :if ([ :len [ / system package find where name="wireless" disabled=no ] ] > 0) do={ :if ([ / interface wireless cap get enabled ] = true && \ - [ / caps-man manager get enabled ] = false) do={ + [ / caps-man manager get enabled ] = false && \ + $SafeUpdateOnCap != true) do={ $LogPrintExit2 error $0 ("System is managed by CAPsMAN, not checking for RouterOS version.") true; } } diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 92ff1b1..5ebdede 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -42,6 +42,7 @@ safe versions from a web server. The configuration goes to `global-config-overlay`, this is the parameter: * `SafeUpdateNeighbor`: install updates automatically if seen in neighbor list +* `SafeUpdateOnCap`: check for updates even if device is managed by CAPsMAN * `SafeUpdatePatch`: install patch updates automatically * `SafeUpdateUrl`: url to check for safe update, the channel (`long-term`, `stable` or `testing`) is appended diff --git a/global-config b/global-config index f411d14..06f43e0 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 58; +:global GlobalConfigVersion 59; # This is used for DNS and backup file. :global Domain "example.com"; @@ -92,6 +92,8 @@ :global SafeUpdatePatch false; # Allow to install updates automatically if seen in neighbor list. :global SafeUpdateNeighbor false; +# Allow to install updates even if device is managed by CAPsMAN. +:global SafeUpdateOnCap false; # These thresholds control when to send health notification # on temperature and voltage. diff --git a/global-config-overlay b/global-config-overlay index 202db89..0888452 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 58; +:global GlobalConfigVersion 59; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 3fe213b..0cc6b1e 100644 --- a/global-config.changes +++ b/global-config.changes @@ -62,6 +62,7 @@ 56="Added tags in all backup, lease and ppp-on-up scripts. These are used by 'packages-update', 'lease-script' and 'ppp-on-up' to find the scripts."; 57="Celebrating the 1.000th commit - Hooray!"; 58="Added a cleanup script for 'hotspot-to-wpa' to purge old access list entries."; + 59="Updating CAP with 'check-routeros-update' is now possible with opt-in."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index e7080e4..d11f8e2 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 58; +:global ExpectedConfigVersion 59; # global variables not to be changed by user :global GlobalFunctionsReady false; From fcc0d1551a0da553fc2a64cd67bd867a23b00659 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 5 Jul 2021 14:56:51 +0200 Subject: [PATCH 0798/2612] doc/netwatch-notify: hint on checking specific isp --- doc/netwatch-notify.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 7f61d88..199f050 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -94,6 +94,23 @@ A target like this suits well to be parent for other checks. / tool netwatch add comment="notify, hostname=example.com, parent=internet" host=93.184.216.34; +### Checking specific ISP + +Having several ISPs for redundancy a failed link may go unnoticed without +proper monitoring. You can use routing-mark to monitor specific connections. +Create a route and firewall mangle rule. + + / ip route add distance=1 gateway=isp1 routing-mark=via-isp1; + / ip firewall mangle add action=mark-routing chain=output new-routing-mark=via-isp1 dst-address=1.0.0.1 passthrough=yes; + +Finally monitor the address with `netwatch-notify`. + + / tool netwatch add comment="notify, hostname=quad-one via isp1" host=1.0.0.1; + +Note that *all* traffic to the given address is routed that way. In case of +link failure this address is not available, so use something reliable but +non-essential. In this example the address `1.0.0.1` is used, the same service +(Cloudflare DNS) is available at `1.1.1.1`. --- [◀ Go back to main README](../README.md) [▲ Go back to top](#top) From 92a97b12ca45c9653b02aa0edb9b167f895c490d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 6 Jul 2021 21:41:02 +0200 Subject: [PATCH 0799/2612] ospf-to-leds: do not flood but log properly --- ospf-to-leds | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ospf-to-leds b/ospf-to-leds index 727f33b..40fbbb3 100644 --- a/ospf-to-leds +++ b/ospf-to-leds @@ -18,11 +18,12 @@ :local LED ([ $ParseKeyValueStore ($InstanceVal->"comment") ]->"leds"); :local LEDType [ / system leds get [ find where leds=$LED ] type ]; - $LogPrintExit2 debug $0 ("OSPF instance " . $InstanceVal->"name" . " is " . $InstanceVal->"state" . ".") false; :if ($InstanceVal->"state" = "running" && $LEDType = "off") do={ + $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " is running, led on!") false; / system leds set type=on [ find where leds=$LED ]; } :if ($InstanceVal->"state" = "down" && $LEDType = "on") do={ + $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " is down, led off!") false; / system leds set type=off [ find where leds=$LED ]; } } From 5083ffd12f1a5eb59115b41a345f755e5a88e9e9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 6 Jul 2021 16:44:36 +0200 Subject: [PATCH 0800/2612] collect-wireless-mac: rework, more use of arrays --- collect-wireless-mac.capsman | 36 +++++++++++++++------------------ collect-wireless-mac.local | 37 ++++++++++++++++------------------ collect-wireless-mac.template | 38 ++++++++++++++++------------------- 3 files changed, 50 insertions(+), 61 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 0e65dcd..0cf10a7 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -30,26 +30,25 @@ $ScriptLock $0 false 10; } :local PlaceBefore ([ / caps-man access-list find where comment="--- collected above ---" disabled ]->0); -:foreach RegTbl in=[ / caps-man registration-table find ] do={ - :local Mac; - :local AccessList; +:foreach Reg in=[ / caps-man registration-table find ] do={ + :local RegVal; :do { - :set Mac [ / caps-man registration-table get $RegTbl mac-address ]; - :set AccessList ([ / caps-man access-list find where mac-address=$Mac ]->0); + :set RegVal [ / caps-man registration-table get $Reg ]; } on-error={ $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; } + :local AccessList ([ / caps-man access-list find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ + $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ [ / caps-man access-list get $AccessList comment ]) false; } - :if ([ :typeof $Mac ] = "str" && [ :len $AccessList ] = 0) do={ + :if ([ :typeof $RegVal ] = "array" && [ :len $AccessList ] = 0) do={ :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease ([ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]->0); + :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); :if ([ :len $Lease ] > 0) do={ :set Address [ / ip dhcp-server lease get $Lease address ]; :set HostName [ / ip dhcp-server lease get $Lease host-name ]; @@ -61,22 +60,19 @@ $ScriptLock $0 false 10; :set DnsName "no dns name"; } } - :local RegEntry [ / caps-man registration-table find where mac-address=$Mac ]; - :local Interface [ / caps-man registration-table get $RegEntry interface ]; - :local Ssid [ / caps-man registration-table get $RegEntry ssid ]; :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); - :local Vendor [ $GetMacVendor $Mac ]; - :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); + :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; + :local Message ("unknown 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=$Mac disabled=yes; + / caps-man access-list add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid); \ - message=("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ + subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ + message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ "Controller: " . $Identity . "\n" . \ - "Interface: " . $Interface . "\n" . \ - "SSID: " . $Ssid . "\n" . \ - "MAC: " . $Mac . "\n" . \ + "Interface: " . $RegVal->"interface" . "\n" . \ + "SSID: " . $RegVal->"ssid" . "\n" . \ + "MAC: " . $RegVal->"mac-address" . "\n" . \ "Vendor: " . $Vendor . "\n" . \ "Hostname: " . $HostName . "\n" . \ "Address: " . $Address . "\n" . \ diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index bb4cafe..41fe296 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -30,26 +30,25 @@ $ScriptLock $0 false 10; } :local PlaceBefore ([ / interface wireless access-list find where comment="--- collected above ---" disabled ]->0); -:foreach RegTbl in=[ / interface wireless registration-table find ] do={ - :local Mac; - :local AccessList; +:foreach Reg in=[ / interface wireless registration-table find ] do={ + :local RegVal; :do { - :set Mac [ / interface wireless registration-table get $RegTbl mac-address ]; - :set AccessList ([ / interface wireless access-list find where mac-address=$Mac ]->0); + :set RegVal [ / interface wireless registration-table get $Reg ]; } on-error={ $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; } + :local AccessList ([ / interface wireless access-list find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ + $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ [ / interface wireless access-list get $AccessList comment ]) false; } - :if ([ :typeof $Mac ] = "str" && [ :len $AccessList ] = 0) do={ + :if ([ :typeof $RegVal ] = "array" && [ :len $AccessList ] = 0) do={ :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease ([ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]->0); + :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); :if ([ :len $Lease ] > 0) do={ :set Address [ / ip dhcp-server lease get $Lease address ]; :set HostName [ / ip dhcp-server lease get $Lease host-name ]; @@ -61,22 +60,20 @@ $ScriptLock $0 false 10; :set DnsName "no dns name"; } } - :local RegEntry [ / interface wireless registration-table find where mac-address=$Mac ]; - :local Interface [ / interface wireless registration-table get $RegEntry interface ]; - :local Ssid [ / interface wireless get [ find where name=$Interface ] ssid ]; + :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 $Mac ]; - :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); + :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; + :local Message ("unknown 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=$Mac 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" ] . $Mac . " connected to " . $Ssid); \ - message=("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ + subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ + message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ "Controller: " . $Identity . "\n" . \ - "Interface: " . $Interface . "\n" . \ - "SSID: " . $Ssid . "\n" . \ - "MAC: " . $Mac . "\n" . \ + "Interface: " . $RegVal->"interface" . "\n" . \ + "SSID: " . $RegVal->"ssid" . "\n" . \ + "MAC: " . $RegVal->"mac-address" . "\n" . \ "Vendor: " . $Vendor . "\n" . \ "Hostname: " . $HostName . "\n" . \ "Address: " . $Address . "\n" . \ diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 2be6447..9b817a4 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -31,26 +31,25 @@ $ScriptLock $0 false 10; } :local PlaceBefore ([ / %PATH% access-list find where comment="--- collected above ---" disabled ]->0); -:foreach RegTbl in=[ / %PATH% registration-table find ] do={ - :local Mac; - :local AccessList; +:foreach Reg in=[ / %PATH% registration-table find ] do={ + :local RegVal; :do { - :set Mac [ / %PATH% registration-table get $RegTbl mac-address ]; - :set AccessList ([ / %PATH% access-list find where mac-address=$Mac ]->0); + :set RegVal [ / %PATH% registration-table get $Reg ]; } on-error={ $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; } + :local AccessList ([ / %PATH% access-list find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $Mac . " already known: " . \ + $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ [ / %PATH% access-list get $AccessList comment ]) false; } - :if ([ :typeof $Mac ] = "str" && [ :len $AccessList ] = 0) do={ + :if ([ :typeof $RegVal ] = "array" && [ :len $AccessList ] = 0) do={ :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease ([ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]->0); + :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); :if ([ :len $Lease ] > 0) do={ :set Address [ / ip dhcp-server lease get $Lease address ]; :set HostName [ / ip dhcp-server lease get $Lease host-name ]; @@ -62,23 +61,20 @@ $ScriptLock $0 false 10; :set DnsName "no dns name"; } } - :local RegEntry [ / %PATH% registration-table find where mac-address=$Mac ]; - :local Interface [ / %PATH% registration-table get $RegEntry interface ]; - :local Ssid [ / caps-man registration-table get $RegEntry ssid ]; - :local Ssid [ / interface wireless get [ find where name=$Interface ] ssid ]; + :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 $Mac ]; - :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); + :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; + :local Message ("unknown MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ + "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); $LogPrintExit2 info $0 $Message false; - / %PATH% access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; + / %PATH% access-list add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid); \ - message=("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ + subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ + message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ "Controller: " . $Identity . "\n" . \ - "Interface: " . $Interface . "\n" . \ - "SSID: " . $Ssid . "\n" . \ - "MAC: " . $Mac . "\n" . \ + "Interface: " . $RegVal->"interface" . "\n" . \ + "SSID: " . $RegVal->"ssid" . "\n" . \ + "MAC: " . $RegVal->"mac-address" . "\n" . \ "Vendor: " . $Vendor . "\n" . \ "Hostname: " . $HostName . "\n" . \ "Address: " . $Address . "\n" . \ From c982cde0bd01ed27b030ab83593cdc87c328b3d9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 6 Jul 2021 22:32:42 +0200 Subject: [PATCH 0801/2612] collect-wireless-mac: do not fail on missing dns record --- collect-wireless-mac.capsman | 7 ++++--- collect-wireless-mac.local | 7 ++++--- collect-wireless-mac.template | 7 ++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 0cf10a7..0373982 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -55,9 +55,10 @@ $ScriptLock $0 false 10; :if ([ :len $HostName ] = 0) do={ :set HostName "no hostname"; } - :set DnsName [ / ip dns static get ([ find where address=$Address ]->0) name ]; - :if ([ :len $DnsName ] = 0) do={ - :set DnsName "no dns name"; + :set DnsName "no dns name"; + :local DnsRec ([ / ip dns static find where address=$Address ]->0); + :if ([ :len $DnsRec ] > 0) do={ + :set DnsName [ / ip dns static get $DnsRec name ]; } } :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 41fe296..109ec5c 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -55,9 +55,10 @@ $ScriptLock $0 false 10; :if ([ :len $HostName ] = 0) do={ :set HostName "no hostname"; } - :set DnsName [ / ip dns static get ([ find where address=$Address ]->0) name ]; - :if ([ :len $DnsName ] = 0) do={ - :set DnsName "no dns name"; + :set DnsName "no dns name"; + :local DnsRec ([ / ip dns static find where address=$Address ]->0); + :if ([ :len $DnsRec ] > 0) do={ + :set DnsName [ / ip dns static get $DnsRec name ]; } } :set ($RegVal->"ssid") [ / interface wireless get [ find where name=($RegVal->"interface") ] ssid ]; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 9b817a4..e8579f0 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -56,9 +56,10 @@ $ScriptLock $0 false 10; :if ([ :len $HostName ] = 0) do={ :set HostName "no hostname"; } - :set DnsName [ / ip dns static get ([ find where address=$Address ]->0) name ]; - :if ([ :len $DnsName ] = 0) do={ - :set DnsName "no dns name"; + :set DnsName "no dns name"; + :local DnsRec ([ / ip dns static find where address=$Address ]->0); + :if ([ :len $DnsRec ] > 0) do={ + :set DnsName [ / ip dns static get $DnsRec name ]; } } :set ($RegVal->"ssid") [ / interface wireless get [ find where name=($RegVal->"interface") ] ssid ]; From e5674dec240cb3abfa71d9a3be76403b40301722 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 6 Jul 2021 22:37:49 +0200 Subject: [PATCH 0802/2612] collect-wireless-mac: use $EitherOr and simplify code --- collect-wireless-mac.capsman | 6 ++---- collect-wireless-mac.local | 6 ++---- collect-wireless-mac.template | 6 ++---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 0373982..f61d058 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -16,6 +16,7 @@ :global Identity; +:global EitherOr; :global GetMacVendor; :global LogPrintExit2; :global ScriptLock; @@ -51,10 +52,7 @@ $ScriptLock $0 false 10; :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); :if ([ :len $Lease ] > 0) do={ :set Address [ / ip dhcp-server lease get $Lease address ]; - :set HostName [ / ip dhcp-server lease get $Lease host-name ]; - :if ([ :len $HostName ] = 0) do={ - :set HostName "no hostname"; - } + :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={ diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 109ec5c..6c07044 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -16,6 +16,7 @@ :global Identity; +:global EitherOr; :global GetMacVendor; :global LogPrintExit2; :global ScriptLock; @@ -51,10 +52,7 @@ $ScriptLock $0 false 10; :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); :if ([ :len $Lease ] > 0) do={ :set Address [ / ip dhcp-server lease get $Lease address ]; - :set HostName [ / ip dhcp-server lease get $Lease host-name ]; - :if ([ :len $HostName ] = 0) do={ - :set HostName "no hostname"; - } + :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={ diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index e8579f0..f190084 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -17,6 +17,7 @@ :global Identity; +:global EitherOr; :global GetMacVendor; :global LogPrintExit2; :global ScriptLock; @@ -52,10 +53,7 @@ $ScriptLock $0 false 10; :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); :if ([ :len $Lease ] > 0) do={ :set Address [ / ip dhcp-server lease get $Lease address ]; - :set HostName [ / ip dhcp-server lease get $Lease host-name ]; - :if ([ :len $HostName ] = 0) do={ - :set HostName "no hostname"; - } + :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={ From d7170bf13855cc8088272ed145bbad017f005922 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 6 Jul 2021 23:50:24 +0200 Subject: [PATCH 0803/2612] doc/lease-script: fix link --- doc/lease-script.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/lease-script.md b/doc/lease-script.md index d437ee5..67c9ed8 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -33,7 +33,7 @@ See also * [Collect MAC addresses in wireless access list](collect-wireless-mac.md) * [Comment DHCP leases with info from access list](dhcp-lease-comment.md) * [Create DNS records for DHCP leases](dhcp-to-dns.md) -* [Use WPA2 network with hotspot credentials](doc/hotspot-to-wpa.md) +* [Use WPA2 network with hotspot credentials](hotspot-to-wpa.md) --- [◀ Go back to main README](../README.md) From 1eb337d87f899945237e9b8406d2073ee9ba9b97 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 6 Jul 2021 23:51:48 +0200 Subject: [PATCH 0804/2612] doc/lease-script: hint on script installation/execution order --- doc/lease-script.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/lease-script.md b/doc/lease-script.md index 67c9ed8..55c5430 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -12,9 +12,14 @@ Description This script is supposed to run from dhcp server as lease script. Currently it does: -* run [dhcp-to-dns](dhcp-to-dns.md) * run [collect-wireless-mac](collect-wireless-mac.md) * run [dhcp-lease-comment](dhcp-lease-comment.md) +* run [dhcp-to-dns](dhcp-to-dns.md) +* run [hotspot-to-wpa](hotspot-to-wpa.md) + +Note that installation order influences execution order. You may want to +install `dhcp-to-dns` before `collect-wireless-mac` for dns name in +notification. Requirements and installation ----------------------------- From 87ce4a86b7d06df746c5ecd70dc59ba4d8b88037 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Jul 2021 13:02:57 +0200 Subject: [PATCH 0805/2612] netwatch-notify: add error handling for hooks We already had syntax validation, but a script with valid synctax can still fail to run... --- netwatch-notify | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index c630678..9e269c2 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -66,7 +66,11 @@ :if ([ $ValidateSyntax ($HostInfo->"up-hook") ] = true) do={ $LogPrintExit2 info $0 ("Running hook on host " . $HostName . " up: " . ($HostInfo->"up-hook")) false; :set Message ($Message . "\n\nRunning hook:\n" . $HostInfo->"up-hook"); - [ :parse ($HostInfo->"up-hook") ]; + :do { + [ :parse ($HostInfo->"up-hook") ]; + } on-error={ + $LogPrintExit2 warning $0 ("The up-hook for host " . $HostName . " failed to run.") false; + } } else={ $LogPrintExit2 warning $0 ("The up-hook for host " . $HostName . " failed syntax validation.") false; } @@ -106,7 +110,11 @@ :if ([ $ValidateSyntax ($HostInfo->"down-hook") ] = true) do={ $LogPrintExit2 info $0 ("Running hook on host " . $HostName . " down: " . ($HostInfo->"down-hook")) false; :set Message ($Message . "\n\nRunning hook:\n" . $HostInfo->"down-hook"); - [ :parse ($HostInfo->"down-hook") ]; + :do { + [ :parse ($HostInfo->"down-hook") ]; + } on-error={ + $LogPrintExit2 warning $0 ("The down-hook for host " . $HostName . " failed to run.") false; + } } else={ $LogPrintExit2 warning $0 ("The down-hook for host " . $HostName . " failed syntax validation.") false; } From c5d49b37f317ed3caef5cda890d35b2a5550f2c6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Jul 2021 13:34:52 +0200 Subject: [PATCH 0806/2612] netwatch-notify: run hook from a function --- netwatch-notify | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 9e269c2..eecfa9f 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -18,7 +18,30 @@ :global ParseKeyValueStore; :global SendNotification2; :global SymbolForNotification; -:global ValidateSyntax; + +:local NetwatchNotifyHook do={ + :local Name [ :tostr $1 ]; + :local Type [ :tostr $2 ]; + :local Hook [ :tostr $3 ]; + + :global LogPrintExit2; + :global ValidateSyntax; + + :if ([ $ValidateSyntax $Hook ] = true) do={ + :do { + [ :parse $Hook ]; + } on-error={ + $LogPrintExit2 warning $0 ("The " . $Type . "-hook for host " . $Name . " failed to run.") false; + :return ("The hook failed to run."); + } + } else={ + $LogPrintExit2 warning $0 ("The " . $Type . "-hook for host " . $Name . " failed syntax validation.") false; + :return ("The hook failed syntax validation."); + } + + $LogPrintExit2 info $0 ("Ran hook on host " . $Name . " " . $Type . ": " . $Hook) false; + :return ("Ran hook:\n" . $Hook); +} :if ([ :typeof $NetwatchNotify ] = "nothing") do={ :set NetwatchNotify [ :toarray "" ]; @@ -63,17 +86,7 @@ :local Message ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ - :if ([ $ValidateSyntax ($HostInfo->"up-hook") ] = true) do={ - $LogPrintExit2 info $0 ("Running hook on host " . $HostName . " up: " . ($HostInfo->"up-hook")) false; - :set Message ($Message . "\n\nRunning hook:\n" . $HostInfo->"up-hook"); - :do { - [ :parse ($HostInfo->"up-hook") ]; - } on-error={ - $LogPrintExit2 warning $0 ("The up-hook for host " . $HostName . " failed to run.") false; - } - } else={ - $LogPrintExit2 warning $0 ("The up-hook for host " . $HostName . " failed syntax validation.") false; - } + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $HostName "up" ($HostInfo->"up-hook") ]); } $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $HostName . " up"); \ @@ -107,17 +120,7 @@ :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ :local Message ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ - :if ([ $ValidateSyntax ($HostInfo->"down-hook") ] = true) do={ - $LogPrintExit2 info $0 ("Running hook on host " . $HostName . " down: " . ($HostInfo->"down-hook")) false; - :set Message ($Message . "\n\nRunning hook:\n" . $HostInfo->"down-hook"); - :do { - [ :parse ($HostInfo->"down-hook") ]; - } on-error={ - $LogPrintExit2 warning $0 ("The down-hook for host " . $HostName . " failed to run.") false; - } - } else={ - $LogPrintExit2 warning $0 ("The down-hook for host " . $HostName . " failed syntax validation.") false; - } + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $HostName "down" ($HostInfo->"down-hook") ]); } $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down"); \ From 623fd707c4e9340af35ad11ad09e3a87413423f6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Jul 2021 16:05:11 +0200 Subject: [PATCH 0807/2612] lease-script: modify the tag --- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- dhcp-lease-comment.capsman | 2 +- dhcp-lease-comment.local | 2 +- dhcp-lease-comment.template | 2 +- dhcp-to-dns | 4 ++-- hotspot-to-wpa-cleanup | 2 +- lease-script | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index f61d058..96c204a 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -6,7 +6,7 @@ # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # -# provides: lease-script assign +# provides: lease-script, assign # # !! Do not edit this file, it is generated from template! diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 6c07044..63cd63c 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -6,7 +6,7 @@ # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # -# provides: lease-script assign +# provides: lease-script, assign # # !! Do not edit this file, it is generated from template! diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index f190084..3b35fc9 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -6,7 +6,7 @@ # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # -# provides: lease-script assign +# provides: lease-script, assign # # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index e8db68d..43697ed 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -3,7 +3,7 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script assign +# provides: lease-script, assign # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index 76972ee..32adc4c 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -3,7 +3,7 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script assign +# provides: lease-script, assign # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index 58c349c..3302031 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -3,7 +3,7 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script assign +# provides: lease-script, assign # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-to-dns b/dhcp-to-dns index 1dc3b42..4fa1621 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -3,8 +3,8 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script assign -# provides: lease-script deassign +# provides: lease-script, assign +# provides: lease-script, deassign # # check DHCP leases and add/remove/update DNS entries # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md diff --git a/hotspot-to-wpa-cleanup b/hotspot-to-wpa-cleanup index 69a1119..34b76c8 100644 --- a/hotspot-to-wpa-cleanup +++ b/hotspot-to-wpa-cleanup @@ -3,7 +3,7 @@ # Copyright (c) 2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script assign +# provides: lease-script, assign # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/lease-script b/lease-script index 2f67cb0..780d122 100644 --- a/lease-script +++ b/lease-script @@ -25,7 +25,7 @@ $LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . \ $State . "ed lease " . $leaseActIP . " to " . $leaseActMAC) false; -:foreach Script in=[ / system script find where source~("\n# provides: lease-script " . $State . "\n") ] do={ +:foreach Script in=[ / system script find where source~("\n# provides: lease-script, " . $State . "\n") ] do={ :local ScriptName [ / system script get $Script name ]; :if ([ :len [ / system script job find where script=$ScriptName ] ] < 2) do={ :do { From 6bf8cd5fac77aa5db804c3180777d495b5d2ed26 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Jul 2021 16:05:11 +0200 Subject: [PATCH 0808/2612] lease-script: implement script order The order may be important: `collect-wireless-mac` can add a dns name in notification, thus `dhcp-to-dns` should run first. --- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- dhcp-lease-comment.capsman | 2 +- dhcp-lease-comment.local | 2 +- dhcp-lease-comment.template | 2 +- dhcp-to-dns | 3 +-- doc/lease-script.md | 4 ---- hotspot-to-wpa-cleanup | 2 +- lease-script | 24 +++++++++++++++++++----- 10 files changed, 27 insertions(+), 18 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 96c204a..18f30d6 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -6,7 +6,7 @@ # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # -# provides: lease-script, assign +# provides: lease-script, assign, order=40 # # !! Do not edit this file, it is generated from template! diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 63cd63c..1e8086e 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -6,7 +6,7 @@ # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # -# provides: lease-script, assign +# provides: lease-script, assign, order=40 # # !! Do not edit this file, it is generated from template! diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 3b35fc9..18bab89 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -6,7 +6,7 @@ # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # -# provides: lease-script, assign +# provides: lease-script, assign, order=40 # # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index 43697ed..33c1b6a 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -3,7 +3,7 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, assign +# provides: lease-script, assign, order=60 # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index 32adc4c..b05754d 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -3,7 +3,7 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, assign +# provides: lease-script, assign, order=60 # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index 3302031..04a6261 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -3,7 +3,7 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, assign +# provides: lease-script, assign, order=60 # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-to-dns b/dhcp-to-dns index 4fa1621..44fd673 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -3,8 +3,7 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, assign -# provides: lease-script, deassign +# provides: lease-script, assign, deassign, order=20 # # check DHCP leases and add/remove/update DNS entries # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md diff --git a/doc/lease-script.md b/doc/lease-script.md index 55c5430..3d8a29b 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -17,10 +17,6 @@ it does: * run [dhcp-to-dns](dhcp-to-dns.md) * run [hotspot-to-wpa](hotspot-to-wpa.md) -Note that installation order influences execution order. You may want to -install `dhcp-to-dns` before `collect-wireless-mac` for dns name in -notification. - Requirements and installation ----------------------------- diff --git a/hotspot-to-wpa-cleanup b/hotspot-to-wpa-cleanup index 34b76c8..c29aa7c 100644 --- a/hotspot-to-wpa-cleanup +++ b/hotspot-to-wpa-cleanup @@ -3,7 +3,7 @@ # Copyright (c) 2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, assign +# provides: lease-script, assign, order=80 # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/lease-script b/lease-script index 780d122..97d5372 100644 --- a/lease-script +++ b/lease-script @@ -12,6 +12,7 @@ :global IfThenElse; :global LogPrintExit2; +:global ParseKeyValueStore; :if ([ :typeof $leaseActIP ] = "nothing" || \ [ :typeof $leaseActMAC ] = "nothing" || \ @@ -21,18 +22,31 @@ } :local State ([ $IfThenElse ($leaseBound = 0) "de" "" ] . "assign"); +:local RunOrder [ :toarray "" ]; $LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . \ $State . "ed lease " . $leaseActIP . " to " . $leaseActMAC) false; -:foreach Script in=[ / system script find where source~("\n# provides: lease-script, " . $State . "\n") ] do={ - :local ScriptName [ / system script get $Script name ]; - :if ([ :len [ / system script job find where script=$ScriptName ] ] < 2) do={ +:foreach Script in=[ / system script find where source~("\n# provides: lease-script, ") ] do={ + :local Name [ / system script get $Script name ]; + :local Store [ / system script get $Script source ]; + + :set Store [ :pick $Store ([ :find $Store "\n# provides: lease-script, " ] + 27) [ :len $Store ] ]; + :set Store [ :pick $Store 0 [ :find $Store "\n" ] ]; + :set Store [ $ParseKeyValueStore $Store ]; + + :if (($Store->$State) = true) do={ + :set ($RunOrder->($Store->"order")) $Name; + } +} + +:foreach Script in=$RunOrder do={ + :if ([ :len [ / system script job find where script=$Script ] ] < 2) do={ :do { - $LogPrintExit2 debug $0 ("Running script: " . $ScriptName) false; + $LogPrintExit2 debug $0 ("Running script: " . $Script) false; / system script run $Script; } on-error={ - $LogPrintExit2 warning $0 ("Running script '" . $ScriptName . "' failed!") false; + $LogPrintExit2 warning $0 ("Running script '" . $Script . "' failed!") false; } } } From 6c9f733d9623d0c774b3d62a1161ea56d2cae181 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Jul 2021 17:51:55 +0200 Subject: [PATCH 0809/2612] lease-script: add the order in log --- lease-script | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lease-script b/lease-script index 97d5372..44360a4 100644 --- a/lease-script +++ b/lease-script @@ -40,10 +40,10 @@ $LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . \ } } -:foreach Script in=$RunOrder do={ +:foreach Order,Script in=$RunOrder do={ :if ([ :len [ / system script job find where script=$Script ] ] < 2) do={ :do { - $LogPrintExit2 debug $0 ("Running script: " . $Script) false; + $LogPrintExit2 debug $0 ("Running script with order " . $Order . ": " . $Script) false; / system script run $Script; } on-error={ $LogPrintExit2 warning $0 ("Running script '" . $Script . "' failed!") false; From a4e548eb809664208f55318ac033b68e2381c6cf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Jul 2021 20:57:53 +0200 Subject: [PATCH 0810/2612] global-functions: $ScriptLock: make ticket management more reliable --- global-functions | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/global-functions b/global-functions index d11f8e2..6af914f 100644 --- a/global-functions +++ b/global-functions @@ -918,17 +918,34 @@ } :local AddTicket do={ - :return ($1, $2); + :local Script [ :tostr $1 ]; + :local Add [ :tostr $2 ]; + + :global ScriptLockOrder; + + :local Ok false; + :while ($Ok = false) do={ + :set ($ScriptLockOrder->$Script) (($ScriptLockOrder->$Script), $Add); + :delay 10ms; + :foreach Ticket in=($ScriptLockOrder->$Script) do={ + :if ($Ticket = $Add) do={ :set Ok true; } + } + } } :local RemoveTicket do={ - :local Return [ :toarray "" ]; - :foreach Ticket in=$1 do={ - :if ($Ticket != $2) do={ - :set Return ($Return, $Ticket); + :local Script [ :tostr $1 ]; + :local Remove [ :tostr $2 ]; + + :global ScriptLockOrder; + + :local New [ :toarray "" ]; + :foreach Ticket in=($ScriptLockOrder->$Script) do={ + :if ($Ticket != $Remove) do={ + :set New ($New, $Ticket); } } - :return $Return; + :set ($ScriptLockOrder->$Script) $New; } :if ([ :len [ / system script find where name=$Script ] ] = 0) do={ @@ -945,10 +962,10 @@ $LogPrintExit2 error $0 ("More tickets than running scripts '" . $Script . "', resetting!") false; :set ($ScriptLockOrder->$Script); / system script job remove [ find where script=$Script ]; - } + } :local MyTicket [ $GetRandom20CharHex ]; - :set ($ScriptLockOrder->$Script) [ $AddTicket ($ScriptLockOrder->$Script) $MyTicket ]; + $AddTicket $Script $MyTicket; :local WaitCount 0; :while ($WaitMax > $WaitCount && (($ScriptLockOrder->$Script->0) != $MyTicket || [ :len ($ScriptLockOrder->$Script) ] < $JobCount)) do={ @@ -958,11 +975,11 @@ } :if ([ :len ($ScriptLockOrder->$Script) ] = $JobCount && ($ScriptLockOrder->$Script->0) = $MyTicket) do={ - :set ($ScriptLockOrder->$Script) [ $RemoveTicket ($ScriptLockOrder->$Script) $MyTicket ]; + $RemoveTicket $Script $MyTicket; :return false; } - :set ($ScriptLockOrder->$Script) [ $RemoveTicket ($ScriptLockOrder->$Script) $MyTicket ]; + $RemoveTicket $Script $MyTicket; $LogPrintExit2 info $0 ("Script '" . $Script . "' started more than once" . [ $IfThenElse ($WaitCount > 0) \ " and timed out waiting for lock" "" ] . "... Aborting.") [ $IfThenElse ($DoReturn = true) false true ]; :return true; From 4192d30d7ebc3b2bc51663ce48e99198a9036348 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 9 Jul 2021 10:38:28 +0200 Subject: [PATCH 0811/2612] global-functions: $ScriptLock: drop variable, just return --- global-functions | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 6af914f..7b5227a 100644 --- a/global-functions +++ b/global-functions @@ -923,12 +923,11 @@ :global ScriptLockOrder; - :local Ok false; - :while ($Ok = false) do={ + :while (true) do={ :set ($ScriptLockOrder->$Script) (($ScriptLockOrder->$Script), $Add); :delay 10ms; :foreach Ticket in=($ScriptLockOrder->$Script) do={ - :if ($Ticket = $Add) do={ :set Ok true; } + :if ($Ticket = $Add) do={ :return true; } } } } From 12d34e4a7c40203aadfb536077c3c2b2cd1492d5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Jul 2021 21:04:56 +0200 Subject: [PATCH 0812/2612] collect-wireless-mac: remove 'unknown' from message and comment This was true, but the mac address is no longer unknown after it was added to address list in comment. --- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 18f30d6..cddc5fa 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -61,7 +61,7 @@ $ScriptLock $0 false 10; } :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("unknown MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ + :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; diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 1e8086e..7ef6b18 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -62,7 +62,7 @@ $ScriptLock $0 false 10; :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 ("unknown MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ + :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; diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 18bab89..aa3f5bf 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -63,7 +63,7 @@ $ScriptLock $0 false 10; :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 ("unknown MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ + :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); $LogPrintExit2 info $0 $Message false; / %PATH% access-list add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; From bccb7c3452466aea0f8c1790643b3aeb21e9b1af Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 9 Jul 2021 11:27:26 +0200 Subject: [PATCH 0813/2612] netwatch-notify: implement pre-down hook --- doc/netwatch-notify.md | 4 ++++ global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- netwatch-notify | 3 +++ 6 files changed, 11 insertions(+), 3 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 199f050..14efe0b 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -44,6 +44,10 @@ comment: / tool netwatch add comment="notify, hostname=poe-device, down-hook=/ interface ethernet poe power-cycle en21;" host=10.0.0.20; +Also there is a `pre-down-hook` that fires at two thirds of failed checks +required for the notification. The idea is to fix the issue before a +notification is sent. + The count threshould (default is 5 checks) is configurable as well: / tool netwatch add comment="notify, hostname=example.com, count=10" host=104.18.144.11; diff --git a/global-config b/global-config index 06f43e0..efc5c2d 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 59; +:global GlobalConfigVersion 60; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 0888452..c65322b 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 59; +:global GlobalConfigVersion 60; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 0cc6b1e..e3a035d 100644 --- a/global-config.changes +++ b/global-config.changes @@ -63,6 +63,7 @@ 57="Celebrating the 1.000th commit - Hooray!"; 58="Added a cleanup script for 'hotspot-to-wpa' to purge old access list entries."; 59="Updating CAP with 'check-routeros-update' is now possible with opt-in."; + 60="Implemented a pre-down hook in 'netwatch-notify' that fires at two thirds of failed checks."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 7b5227a..0a031ba 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 59; +:global ExpectedConfigVersion 60; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/netwatch-notify b/netwatch-notify index eecfa9f..966d415 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -117,6 +117,9 @@ $Metric->"count" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ ($Metric->"notified" = true) ("already notified.") ($Count - $Metric->"count" . " to go.") ] \ ("parent host " . $Parent . " is down.") ]) false; + :if ((($Count * 2) - ($Metric->"count" * 3)) / 2 = 0 && [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ + $NetwatchNotifyHook $HostName "pre-down" ($HostInfo->"pre-down-hook"); + } :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ :local Message ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ From d80a7efb7c5383420e493f9f812b0075c8d09cca Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 9 Jul 2021 11:57:40 +0200 Subject: [PATCH 0814/2612] doc/netwatch-notify: hint on escaping, with example --- doc/netwatch-notify.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 14efe0b..81e28b0 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -40,9 +40,9 @@ The hosts to be checked have to be added to netwatch with specific comment: It is possible to run an up hook command (`up-hook`) or down hook command (`down-hook`) when a notification is triggered. This has to be added in -comment: +comment, note that some characters need extra escaping: - / tool netwatch add comment="notify, hostname=poe-device, down-hook=/ interface ethernet poe power-cycle en21;" host=10.0.0.20; + / tool netwatch add comment=("notify, hostname=device, down-hook=/ interface ethernet \\{ disable \\\"en2\\\"; enable \\\"en2\\\"; \\}") host=10.0.0.20; Also there is a `pre-down-hook` that fires at two thirds of failed checks required for the notification. The idea is to fix the issue before a From 81cba72bec1b81dc636499926102d226a5ffad54 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 9 Jul 2021 12:06:40 +0200 Subject: [PATCH 0815/2612] global-functions: $ScriptInstallUpdate: drop the migration pattern --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 0a031ba..4ee8897 100644 --- a/global-functions +++ b/global-functions @@ -734,7 +734,7 @@ :local ReloadGlobalFunctions false; :local ReloadGlobalConfig false; - :foreach Script in=[ / system script find where source~"^#!rsc( by RouterOS)\?\n" ] do={ + :foreach Script in=[ / system script find where source~"^#!rsc by RouterOS\n" ] do={ :local ScriptVal [ / system script get $Script ]; :local ScriptFile [ / file find where name=("script-updates/" . $ScriptVal->"name") ]; :local SourceNew; From f694e1e54d5264f7c442456427c501cac5bfb778 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 9 Jul 2021 12:28:45 +0200 Subject: [PATCH 0816/2612] global-functions: $ScriptInstallUpdate: drop unused variable This was a left-over from re-run message. --- global-functions | 1 - 1 file changed, 1 deletion(-) diff --git a/global-functions b/global-functions index 4ee8897..2e393cb 100644 --- a/global-functions +++ b/global-functions @@ -714,7 +714,6 @@ :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; - :global ScriptInstallUpdate; :global SendNotification2; :global SymbolForNotification; :global ValidateSyntax; From b864db1e389cb262ef35a2ee2d679c98b6ff3bbb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 9 Jul 2021 12:30:35 +0200 Subject: [PATCH 0817/2612] global-functions: $ScriptInstallUpdate: add error handling for migration --- global-functions | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 2e393cb..ad489a9 100644 --- a/global-functions +++ b/global-functions @@ -852,7 +852,11 @@ :if ([ :typeof $Migration ] = "str") do={ :if ([ $ValidateSyntax $Migration ] = true) do={ $LogPrintExit2 info $0 ("Applying migration for change " . $I . ": " . $Migration) false; - [ :parse $Migration ]; + :do { + [ :parse $Migration ]; + } on-error={ + $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed to run!") false; + } } else={ $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed syntax validation!") false; } From dc7fc0d38510371a1d97c02a938fd7be16b7ae7c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 9 Jul 2021 11:57:19 +0200 Subject: [PATCH 0818/2612] finally remove old scripts --- early-errors | 6 ------ global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 2 ++ global-functions | 2 +- global-wait | 11 ----------- mode-button-event | 6 ------ mode-button-scheduler | 6 ------ script-updates | 6 ------ 9 files changed, 5 insertions(+), 38 deletions(-) delete mode 100644 early-errors delete mode 100644 global-wait delete mode 100644 mode-button-event delete mode 100644 mode-button-scheduler delete mode 100644 script-updates diff --git a/early-errors b/early-errors deleted file mode 100644 index 7c2e509..0000000 --- a/early-errors +++ /dev/null @@ -1,6 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: early-errors - -:global LogPrintExit2; - -$LogPrintExit2 warning "early-errors" ("This script has been replaced. Please migrate to 'log-forward'.") true; diff --git a/global-config b/global-config index efc5c2d..b4f4a28 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 60; +:global GlobalConfigVersion 61; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index c65322b..f8d2cee 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 60; +:global GlobalConfigVersion 61; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index e3a035d..4fd107b 100644 --- a/global-config.changes +++ b/global-config.changes @@ -64,6 +64,7 @@ 58="Added a cleanup script for 'hotspot-to-wpa' to purge old access list entries."; 59="Updating CAP with 'check-routeros-update' is now possible with opt-in."; 60="Implemented a pre-down hook in 'netwatch-notify' that fires at two thirds of failed checks."; + 61="Finally removed old scripts."; }; # Migration steps to be applied on script updates @@ -72,4 +73,5 @@ 47="/ certificate remove [ find where fingerprint=\"731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568\" or fingerprint=\"25847d668eb4f04fdd40b12b6b0740c567da7d024308eb6c2c96fe41d9de218d\" ];"; 52=":global CertificateDownload; :if ([ :len [ / certificate find where fingerprint=\"67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd\" or fingerprint=\"96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6\" ] ] < 2) do={ \$CertificateDownload \"R3\"; }; / certificate remove [ find where fingerprint=\"0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739\" ];"; 54=":global ScriptInstallUpdate; :global TelegramTokenId; :global TelegramChatId; :if ([ :len \$TelegramTokenId ] > 0 && [ :len \$TelegramChatId ] > 0) do={ \$ScriptInstallUpdate global-functions.d/notification-telegram; }"; + 61="/ system script remove [ find where name~\"^(early-errors|global-wait|mode-button-(event|scheduler)|script-updates)\\\$\" source~\"^#!rsc by RouterOS\\n\" ];"; }; diff --git a/global-functions b/global-functions index ad489a9..df2cc54 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 60; +:global ExpectedConfigVersion 61; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/global-wait b/global-wait deleted file mode 100644 index 3ce6d27..0000000 --- a/global-wait +++ /dev/null @@ -1,11 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: global-wait - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ - :delay 500ms; -} - -:global LogPrintExit2; - -$LogPrintExit2 warning "global-wait" ("This script is now useless, please remove it from configuration.") true; diff --git a/mode-button-event b/mode-button-event deleted file mode 100644 index 09c0283..0000000 --- a/mode-button-event +++ /dev/null @@ -1,6 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mode-button-event - -:global LogPrintExit2; - -$LogPrintExit2 warning "mode-button-event" ("This script's functionality has been merged into 'mode-button'.") true; diff --git a/mode-button-scheduler b/mode-button-scheduler deleted file mode 100644 index f7045b2..0000000 --- a/mode-button-scheduler +++ /dev/null @@ -1,6 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mode-button-scheduler - -:global LogPrintExit2; - -$LogPrintExit2 warning "mode-button-scheduler" ("This script's functionality has been merged into 'mode-button'.") true; diff --git a/script-updates b/script-updates deleted file mode 100644 index e35f15c..0000000 --- a/script-updates +++ /dev/null @@ -1,6 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: script-updates - -:global LogPrintExit2; - -$LogPrintExit2 warning "script-updates" ("This script has been replaced by function '\$ScriptInstallUpdate'.") true; From 574c50908bcd6e68aa14b59d838865ac0d9ee98d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 9 Jul 2021 16:50:08 +0200 Subject: [PATCH 0819/2612] global-functions.d/notification-telegram: subject in bold & underline This makes the subject visually delimited. --- global-functions.d/notification-telegram | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/global-functions.d/notification-telegram b/global-functions.d/notification-telegram index 1509a2e..5643e58 100644 --- a/global-functions.d/notification-telegram +++ b/global-functions.d/notification-telegram @@ -77,8 +77,8 @@ :local Return $1; :local Chars { "body"={ "\\"; "`" }; - "hint"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">"; - "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; + "plain"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">"; + "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; } :foreach Char in=($Chars->$2) do={ :set Return [ $CharacterReplace $Return $Char ("\\" . $Char) ]; @@ -99,22 +99,23 @@ } :local Truncated false; + :local Text ("*__" . [ $EscapeMD ("[" . $Identity . "] " . ($Notification->"subject")) "plain" ] . "__*\n\n"); + :local LenSubject [ :len $Text ]; + :local LenMessage [ :len ($Notification->"message") ]; :local LenLink [ :len ($Notification->"link") ]; - :local Text ("[" . $Identity . "] " . ($Notification->"subject") . "\n\n" . ($Notification->"message")); - :local LenText [ :len $Text ]; - :if ($LenText > (3968 - $LenLink)) do={ - :set Text [ $EscapeMD ([ :pick $Text 0 (3840 - $LenLink) ] . "...") "body" ]; + :if ($LenSubject + $LenMessage + $LenLink > 3968) do={ + :set Text ($Text . [ $EscapeMD ([ :pick ($Notification->"message") 0 (3840 - $LenSubject - $LenLink) ] . "...") "body" ]); :set Truncated true; } else={ - :set Text [ $EscapeMD $Text "body" ]; + :set Text ($Text . [ $EscapeMD ($Notification->"message") "body" ]); } :if ($LenLink > 0) do={ - :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD ($Notification->"link") "hint" ]); + :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD ($Notification->"link") "plain" ]); } :if ($Truncated = true) do={ :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ [ $EscapeMD ("The Telegram message was too long and has been truncated, cut off " . \ - (($LenText - [ :len $Text ]) * 100 / $LenText) . "%!") "hint" ]); + (($LenText - [ :len $Text ]) * 100 / $LenText) . "%!") "plain" ]); } :set Text [ $UrlEncode $Text ]; :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; @@ -135,7 +136,7 @@ } :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ - " " . [ / system clock get time ] . " and may be obsolete.") "hint" ]) ]); + " " . [ / system clock get time ] . " and may be obsolete.") "plain" ]) ]); :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; parsemode=$ParseMode; text=$Text; silent=($Notification->"silent") }; :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ From d1ef710093eb6c747f8a54a0ec4355f5035aff4e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 9 Jul 2021 22:04:15 +0200 Subject: [PATCH 0820/2612] global-functions: $ScriptInstallUpdate: add error handling for changelog --- global-functions | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index df2cc54..47d70f1 100644 --- a/global-functions +++ b/global-functions @@ -840,7 +840,11 @@ :if ([ :len $ChangeLogCode ] > 0) do={ :if ([ $ValidateSyntax $ChangeLogCode ] = true) do={ - [ :parse $ChangeLogCode ]; + :do { + [ :parse $ChangeLogCode ]; + } on-error={ + $LogPrintExit2 warning $0 ("The changelog failed to run!") false; + } } else={ $LogPrintExit2 warning $0 ("The changelog failed syntax validation!") false; } From 483506b1898464366a30411a1f8ed336b508f870 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 9 Jul 2021 22:05:45 +0200 Subject: [PATCH 0821/2612] global-functions: introduce $ScriptRunOnce --- global-config | 6 +++++- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 43 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index b4f4a28..98c65d9 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 61; +:global GlobalConfigVersion 62; # This is used for DNS and backup file. :global Domain "example.com"; @@ -167,6 +167,10 @@ # use next branch with default url (git.eworm.de) #:global ScriptUpdatesUrlSuffix "\?h=next"; +# Use this for defaults with $ScriptRunOnce +:global ScriptRunOnceBaseUrl ""; +:global ScriptRunOnceUrlSuffix ""; + # This project is developed in private spare time and usage is free of charge # for you. If you like the scripts and think this is of value for you or your # business please consider a donation: diff --git a/global-config-overlay b/global-config-overlay index f8d2cee..f4ea04d 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 61; +:global GlobalConfigVersion 62; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 4fd107b..23a1dac 100644 --- a/global-config.changes +++ b/global-config.changes @@ -65,6 +65,7 @@ 59="Updating CAP with 'check-routeros-update' is now possible with opt-in."; 60="Implemented a pre-down hook in 'netwatch-notify' that fires at two thirds of failed checks."; 61="Finally removed old scripts."; + 62="Added '\$ScriptRunOnce' to run a script from URL once without installation, intended to aid configuration management and the like."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 47d70f1..1c20636 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 61; +:global ExpectedConfigVersion 62; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -44,6 +44,7 @@ :global ScriptFromTerminal; :global ScriptInstallUpdate; :global ScriptLock; +:global ScriptRunOnce; :global SendEMail; :global SendEMail2; :global SendNotification; @@ -991,6 +992,46 @@ :return true; } +# fetch and run script(s) once +:set ScriptRunOnce do={ + :local Scripts [ :toarray $1 ]; + + :global ScriptRunOnceBaseUrl; + :global ScriptRunOnceUrlSuffix; + + :global LogPrintExit2; + :global ValidateSyntax; + + :foreach Script in=$Scripts do={ + :if (!($Script ~ "^(ftp|https\?|sftp)://")) do={ + :if ([ :len $ScriptRunOnceBaseUrl ] = 0) do={ + $LogPrintExit2 warning $0 ("Script '" . $Script . "' is not an url and base url is not available.") true; + } + :set Script ($ScriptRunOnceBaseUrl . $Script . $ScriptRunOnceUrlSuffix); + } + + :local Source; + :do { + :set Source ([ / tool fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data"); + } on-error={ + $LogPrintExit2 warning $0 ("Failed fetching script '" . $Script . "'!") false; + } + + :if ([ :len $Source ] > 0) do={ + :if ([ $ValidateSyntax $Source ] = true) do={ + :do { + $LogPrintExit2 info $0 ("Running script '" . $Script . "' now.") false; + [ :parse $Source ]; + } on-error={ + $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed to run!") false; + } + } else={ + $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed syntax validation!") false; + } + } + } +} + # send notification via e-mail - expects at lease two string arguments :set SendEMail do={ :global SendEMail2; From 29ececda9b9bbb16392b778bd8ff012ed88427ca Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 11 Jul 2021 22:21:47 +0200 Subject: [PATCH 0822/2612] collect-wireless-mac: check for existence of mac address Chance are that $RegVal is an array with just an id - no idea why this happens. So do not check for array but existence of mac address. --- collect-wireless-mac.capsman | 78 ++++++++++++++++++---------------- collect-wireless-mac.local | 80 ++++++++++++++++++----------------- collect-wireless-mac.template | 80 ++++++++++++++++++----------------- 3 files changed, 125 insertions(+), 113 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index cddc5fa..5f6d750 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -39,43 +39,47 @@ $ScriptLock $0 false 10; $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; } - :local AccessList ([ / caps-man access-list find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ / caps-man access-list get $AccessList comment ]) false; - } - - :if ([ :typeof $RegVal ] = "array" && [ :len $AccessList ] = 0) do={ - :local Address "no dhcp lease"; - :local DnsName "no dhcp lease"; - :local HostName "no dhcp lease"; - :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); - :if ([ :len $Lease ] > 0) do={ - :set Address [ / ip dhcp-server lease get $Lease address ]; - :set HostName [ $EitherOr [ / ip dhcp-server lease get $Lease host-name ] "no hostname" ]; - :set DnsName "no dns name"; - :local DnsRec ([ / ip dns static find where address=$Address ]->0); - :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ / ip dns static get $DnsRec name ]; - } + :if ([ :len ($RegVal->"mac-address") ] > 0) do={ + :local AccessList ([ / caps-man access-list find where mac-address=($RegVal->"mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ + [ / caps-man access-list get $AccessList comment ]) false; } - :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrintExit2 info $0 $Message false; - / caps-man access-list add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - "Controller: " . $Identity . "\n" . \ - "Interface: " . $RegVal->"interface" . "\n" . \ - "SSID: " . $RegVal->"ssid" . "\n" . \ - "MAC: " . $RegVal->"mac-address" . "\n" . \ - "Vendor: " . $Vendor . "\n" . \ - "Hostname: " . $HostName . "\n" . \ - "Address: " . $Address . "\n" . \ - "DNS name: " . $DnsName . "\n" . \ - "Date: " . $DateTime) }); + + :if ([ :len $AccessList ] = 0) do={ + :local Address "no dhcp lease"; + :local DnsName "no dhcp lease"; + :local HostName "no dhcp lease"; + :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); + :if ([ :len $Lease ] > 0) do={ + :set Address [ / ip dhcp-server lease get $Lease address ]; + :set HostName [ $EitherOr [ / ip dhcp-server lease get $Lease host-name ] "no hostname" ]; + :set DnsName "no dns name"; + :local DnsRec ([ / ip dns static find where address=$Address ]->0); + :if ([ :len $DnsRec ] > 0) do={ + :set DnsName [ / ip dns static get $DnsRec name ]; + } + } + :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); + :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; + :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ + "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); + $LogPrintExit2 info $0 $Message false; + / caps-man access-list add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ + message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ + "Controller: " . $Identity . "\n" . \ + "Interface: " . $RegVal->"interface" . "\n" . \ + "SSID: " . $RegVal->"ssid" . "\n" . \ + "MAC: " . $RegVal->"mac-address" . "\n" . \ + "Vendor: " . $Vendor . "\n" . \ + "Hostname: " . $HostName . "\n" . \ + "Address: " . $Address . "\n" . \ + "DNS name: " . $DnsName . "\n" . \ + "Date: " . $DateTime) }); + } + } else={ + $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; } } diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 7ef6b18..a2bcf5b 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -39,44 +39,48 @@ $ScriptLock $0 false 10; $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; } - :local AccessList ([ / interface wireless access-list find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ / interface wireless access-list get $AccessList comment ]) false; - } - - :if ([ :typeof $RegVal ] = "array" && [ :len $AccessList ] = 0) do={ - :local Address "no dhcp lease"; - :local DnsName "no dhcp lease"; - :local HostName "no dhcp lease"; - :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); - :if ([ :len $Lease ] > 0) do={ - :set Address [ / ip dhcp-server lease get $Lease address ]; - :set HostName [ $EitherOr [ / ip dhcp-server lease get $Lease host-name ] "no hostname" ]; - :set DnsName "no dns name"; - :local DnsRec ([ / ip dns static find where address=$Address ]->0); - :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ / ip dns static get $DnsRec name ]; - } + :if ([ :len ($RegVal->"mac-address") ] > 0) do={ + :local AccessList ([ / interface wireless access-list find where mac-address=($RegVal->"mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ + [ / interface wireless access-list get $AccessList comment ]) false; } - :set ($RegVal->"ssid") [ / interface wireless get [ find where name=($RegVal->"interface") ] ssid ]; - :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrintExit2 info $0 $Message false; - / interface wireless access-list add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - "Controller: " . $Identity . "\n" . \ - "Interface: " . $RegVal->"interface" . "\n" . \ - "SSID: " . $RegVal->"ssid" . "\n" . \ - "MAC: " . $RegVal->"mac-address" . "\n" . \ - "Vendor: " . $Vendor . "\n" . \ - "Hostname: " . $HostName . "\n" . \ - "Address: " . $Address . "\n" . \ - "DNS name: " . $DnsName . "\n" . \ - "Date: " . $DateTime) }); + + :if ([ :len $AccessList ] = 0) do={ + :local Address "no dhcp lease"; + :local DnsName "no dhcp lease"; + :local HostName "no dhcp lease"; + :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); + :if ([ :len $Lease ] > 0) do={ + :set Address [ / ip dhcp-server lease get $Lease address ]; + :set HostName [ $EitherOr [ / ip dhcp-server lease get $Lease host-name ] "no hostname" ]; + :set DnsName "no dns name"; + :local DnsRec ([ / ip dns static find where address=$Address ]->0); + :if ([ :len $DnsRec ] > 0) do={ + :set DnsName [ / ip dns static get $DnsRec name ]; + } + } + :set ($RegVal->"ssid") [ / interface wireless get [ find where name=($RegVal->"interface") ] ssid ]; + :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); + :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; + :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ + "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); + $LogPrintExit2 info $0 $Message false; + / interface wireless access-list add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ + message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ + "Controller: " . $Identity . "\n" . \ + "Interface: " . $RegVal->"interface" . "\n" . \ + "SSID: " . $RegVal->"ssid" . "\n" . \ + "MAC: " . $RegVal->"mac-address" . "\n" . \ + "Vendor: " . $Vendor . "\n" . \ + "Hostname: " . $HostName . "\n" . \ + "Address: " . $Address . "\n" . \ + "DNS name: " . $DnsName . "\n" . \ + "Date: " . $DateTime) }); + } + } else={ + $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; } } diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index aa3f5bf..7b6848b 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -40,44 +40,48 @@ $ScriptLock $0 false 10; $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; } - :local AccessList ([ / %PATH% access-list find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ / %PATH% access-list get $AccessList comment ]) false; - } - - :if ([ :typeof $RegVal ] = "array" && [ :len $AccessList ] = 0) do={ - :local Address "no dhcp lease"; - :local DnsName "no dhcp lease"; - :local HostName "no dhcp lease"; - :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); - :if ([ :len $Lease ] > 0) do={ - :set Address [ / ip dhcp-server lease get $Lease address ]; - :set HostName [ $EitherOr [ / ip dhcp-server lease get $Lease host-name ] "no hostname" ]; - :set DnsName "no dns name"; - :local DnsRec ([ / ip dns static find where address=$Address ]->0); - :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ / ip dns static get $DnsRec name ]; - } + :if ([ :len ($RegVal->"mac-address") ] > 0) do={ + :local AccessList ([ / %PATH% access-list find where mac-address=($RegVal->"mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ + [ / %PATH% access-list get $AccessList comment ]) false; } - :set ($RegVal->"ssid") [ / interface wireless get [ find where name=($RegVal->"interface") ] ssid ]; - :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrintExit2 info $0 $Message false; - / %PATH% access-list add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - "Controller: " . $Identity . "\n" . \ - "Interface: " . $RegVal->"interface" . "\n" . \ - "SSID: " . $RegVal->"ssid" . "\n" . \ - "MAC: " . $RegVal->"mac-address" . "\n" . \ - "Vendor: " . $Vendor . "\n" . \ - "Hostname: " . $HostName . "\n" . \ - "Address: " . $Address . "\n" . \ - "DNS name: " . $DnsName . "\n" . \ - "Date: " . $DateTime) }); + + :if ([ :len $AccessList ] = 0) do={ + :local Address "no dhcp lease"; + :local DnsName "no dhcp lease"; + :local HostName "no dhcp lease"; + :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); + :if ([ :len $Lease ] > 0) do={ + :set Address [ / ip dhcp-server lease get $Lease address ]; + :set HostName [ $EitherOr [ / ip dhcp-server lease get $Lease host-name ] "no hostname" ]; + :set DnsName "no dns name"; + :local DnsRec ([ / ip dns static find where address=$Address ]->0); + :if ([ :len $DnsRec ] > 0) do={ + :set DnsName [ / ip dns static get $DnsRec name ]; + } + } + :set ($RegVal->"ssid") [ / interface wireless get [ find where name=($RegVal->"interface") ] ssid ]; + :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); + :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; + :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ + "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); + $LogPrintExit2 info $0 $Message false; + / %PATH% access-list add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ + message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ + "Controller: " . $Identity . "\n" . \ + "Interface: " . $RegVal->"interface" . "\n" . \ + "SSID: " . $RegVal->"ssid" . "\n" . \ + "MAC: " . $RegVal->"mac-address" . "\n" . \ + "Vendor: " . $Vendor . "\n" . \ + "Hostname: " . $HostName . "\n" . \ + "Address: " . $Address . "\n" . \ + "DNS name: " . $DnsName . "\n" . \ + "Date: " . $DateTime) }); + } + } else={ + $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; } } From 9fba3dd8df8848cf5b0b34f10049a46699baab3f Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Thu, 15 Jul 2021 08:57:45 +0800 Subject: [PATCH 0823/2612] global-functions: $ScriptLock: fix off-by-one check... ... for stale job tickets Signed-off-by: Christian Hesse --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 1c20636..7a0bb39 100644 --- a/global-functions +++ b/global-functions @@ -965,7 +965,7 @@ $LogPrintExit2 error $0 ("No script '" . $Script . "' is running!") true; } - :if ([ :len ($ScriptLockOrder->$Script) ] > $JobCount) do={ + :if ([ :len ($ScriptLockOrder->$Script) ] >= $JobCount) do={ $LogPrintExit2 error $0 ("More tickets than running scripts '" . $Script . "', resetting!") false; :set ($ScriptLockOrder->$Script); / system script job remove [ find where script=$Script ]; From 698c795eeeb76fb2911cbff0acb54c93bea2f846 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 15 Jul 2021 11:25:46 +0200 Subject: [PATCH 0824/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index e76c126..e9cab81 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -9,6 +9,7 @@ Thanks a lot for your contributions! These persons contributed code. See the git history for details! +* [Ben Harris](mailto:mail@bharr.is) (@bharrisau) * [Daniel Ziegenberg](mailto:daniel@ziegenberg.at) (@ziegenberg) * [Michael Gisbers](mailto:michael@gisbers.de) (@mgisbers) * [netztrip](mailto:dave-tvg@netztrip.de) (@netztrip) From 9509371690c26bb67918448458f7b2989df4635c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 15 Jul 2021 11:45:35 +0200 Subject: [PATCH 0825/2612] lease-script: use $ScriptLock There were still ways to produce errors from lease scripts... Let's lock earlier, this should fix it. --- lease-script | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lease-script b/lease-script index 44360a4..3134cb6 100644 --- a/lease-script +++ b/lease-script @@ -13,6 +13,7 @@ :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; +:global ScriptLock; :if ([ :typeof $leaseActIP ] = "nothing" || \ [ :typeof $leaseActMAC ] = "nothing" || \ @@ -21,6 +22,12 @@ $LogPrintExit2 error $0 ("This script is supposed to run from ip dhcp-server.") true; } +$ScriptLock $0 false 10; + +:if ([ :len [ / system script job find where script=$0 ] ] > 1) do={ + $LogPrintExit2 debug $0 ("More invocations are waiting, exiting early.") true; +} + :local State ([ $IfThenElse ($leaseBound = 0) "de" "" ] . "assign"); :local RunOrder [ :toarray "" ]; @@ -41,12 +48,10 @@ $LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . \ } :foreach Order,Script in=$RunOrder do={ - :if ([ :len [ / system script job find where script=$Script ] ] < 2) do={ - :do { - $LogPrintExit2 debug $0 ("Running script with order " . $Order . ": " . $Script) false; - / system script run $Script; - } on-error={ - $LogPrintExit2 warning $0 ("Running script '" . $Script . "' failed!") false; - } + :do { + $LogPrintExit2 debug $0 ("Running script with order " . $Order . ": " . $Script) false; + / system script run $Script; + } on-error={ + $LogPrintExit2 warning $0 ("Running script '" . $Script . "' failed!") false; } } From 8e2c783068829c523c3b8fa8835f77f3a6ef56e0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 15 Jul 2021 12:47:05 +0200 Subject: [PATCH 0826/2612] lease-script: drop differentiation of assign / deassign... ... not that we have early locking. --- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- dhcp-lease-comment.capsman | 2 +- dhcp-lease-comment.local | 2 +- dhcp-lease-comment.template | 2 +- dhcp-to-dns | 2 +- hotspot-to-wpa-cleanup | 2 +- lease-script | 11 ++++------- 9 files changed, 12 insertions(+), 15 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 5f6d750..34e022d 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -6,7 +6,7 @@ # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # -# provides: lease-script, assign, order=40 +# provides: lease-script, order=40 # # !! Do not edit this file, it is generated from template! diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index a2bcf5b..2149dd6 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -6,7 +6,7 @@ # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # -# provides: lease-script, assign, order=40 +# provides: lease-script, order=40 # # !! Do not edit this file, it is generated from template! diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 7b6848b..7bb84dd 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -6,7 +6,7 @@ # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # -# provides: lease-script, assign, order=40 +# provides: lease-script, order=40 # # !! This is just a template! Replace '%PATH%' with 'caps-man' # !! or 'interface wireless'! diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index 33c1b6a..83a9d79 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -3,7 +3,7 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, assign, order=60 +# provides: lease-script, order=60 # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index b05754d..eb4b915 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -3,7 +3,7 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, assign, order=60 +# provides: lease-script, order=60 # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index 04a6261..2f070b4 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -3,7 +3,7 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, assign, order=60 +# provides: lease-script, order=60 # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-to-dns b/dhcp-to-dns index 44fd673..8afbf54 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -3,7 +3,7 @@ # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, assign, deassign, order=20 +# provides: lease-script, order=20 # # check DHCP leases and add/remove/update DNS entries # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md diff --git a/hotspot-to-wpa-cleanup b/hotspot-to-wpa-cleanup index c29aa7c..1321f83 100644 --- a/hotspot-to-wpa-cleanup +++ b/hotspot-to-wpa-cleanup @@ -3,7 +3,7 @@ # Copyright (c) 2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, assign, order=80 +# provides: lease-script, order=80 # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/lease-script b/lease-script index 3134cb6..6de6fd9 100644 --- a/lease-script +++ b/lease-script @@ -28,11 +28,10 @@ $ScriptLock $0 false 10; $LogPrintExit2 debug $0 ("More invocations are waiting, exiting early.") true; } -:local State ([ $IfThenElse ($leaseBound = 0) "de" "" ] . "assign"); -:local RunOrder [ :toarray "" ]; +$LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \ + "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC) false; -$LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . \ - $State . "ed lease " . $leaseActIP . " to " . $leaseActMAC) false; +:local RunOrder [ :toarray "" ]; :foreach Script in=[ / system script find where source~("\n# provides: lease-script, ") ] do={ :local Name [ / system script get $Script name ]; @@ -42,9 +41,7 @@ $LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . \ :set Store [ :pick $Store 0 [ :find $Store "\n" ] ]; :set Store [ $ParseKeyValueStore $Store ]; - :if (($Store->$State) = true) do={ - :set ($RunOrder->($Store->"order")) $Name; - } + :set ($RunOrder->($Store->"order")) $Name; } :foreach Order,Script in=$RunOrder do={ From 4269bc9548ecbbd8d0b1fd8dfcfa590175dd3a30 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 25 Jul 2021 23:08:23 +0200 Subject: [PATCH 0827/2612] global-functions: $ScriptLock: check for successful removal of ticket The script is already locked, so there is no second script to remove a ticket at the same time. However a new script can add a new ticket and overwrite the removal... Thus check for successful removal anyway. --- global-functions | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/global-functions b/global-functions index 7a0bb39..bbea143 100644 --- a/global-functions +++ b/global-functions @@ -946,13 +946,17 @@ :global ScriptLockOrder; - :local New [ :toarray "" ]; - :foreach Ticket in=($ScriptLockOrder->$Script) do={ - :if ($Ticket != $Remove) do={ - :set New ($New, $Ticket); + :while (true) do={ + :local New [ :toarray "" ]; + :foreach Ticket in=($ScriptLockOrder->$Script) do={ + :if ($Ticket != $Remove) do={ + :set New ($New, $Ticket); + } } + :set ($ScriptLockOrder->$Script) $New; + :delay 12ms; + :if (($ScriptLockOrder->$Script->0) != $Remove) do={ :return true; } } - :set ($ScriptLockOrder->$Script) $New; } :if ([ :len [ / system script find where name=$Script ] ] = 0) do={ From d4896f2585ecd9bfa4f2be0fbec164a18a7b5730 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 Aug 2021 12:39:53 +0200 Subject: [PATCH 0828/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index e9cab81..9fcb2a1 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -25,6 +25,7 @@ Add yourself to the list, * Linux-Schmie.de Michael Gisbers * Manuel Kuhn * Marek ÄŒÃĄbÃĄk +* Oleksandr Yukhymchuk * Peter Holtkamp * Reiner Vehrenkamp * Sunny Chu (@sunnychuchu) From 772e66b6226f5f9a345bbef29a7453380b693ea1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 25 Aug 2021 00:35:08 +0200 Subject: [PATCH 0829/2612] global-functions.d/notification-telegram: for syntax for ROS 7.x Strings with escape sequence have to be enclosed in parentheses. Looks like RouterOS 7.x is stricter here... --- global-functions.d/notification-telegram | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.d/notification-telegram b/global-functions.d/notification-telegram index 5643e58..4a05c9a 100644 --- a/global-functions.d/notification-telegram +++ b/global-functions.d/notification-telegram @@ -71,7 +71,7 @@ :global IfThenElse; :if ($TelegramFixedWidthFont != true) do={ - :return ($1 . [ $IfThenElse ($2 = "body") "\n" "" ]); + :return ($1 . [ $IfThenElse ($2 = "body") ("\n") "" ]); } :local Return $1; From d556e97a465b27fad7aa1cec6be48b7867b401c6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Aug 2021 11:08:55 +0200 Subject: [PATCH 0830/2612] dhcp-to-dns: check for existence of address Chances are that $LeaseVal is an array with just an id - no idea why this happens. So do not check for array but existence of address. --- dhcp-to-dns | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index 8afbf54..3d01ff8 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -58,7 +58,7 @@ $ScriptLock $0 false 10; $LogPrintExit2 debug $0 ("A lease just vanished, ignoring.") false; } - :if ([ :typeof $LeaseVal ] = "array") do={ + :if ([ :len ($LeaseVal->"address") ] > 0) do={ :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); :local HostName [ $IfThenElse ([ :len ($LeaseVal->"host-name") ] = 0) \ [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ] \ @@ -91,5 +91,7 @@ $ScriptLock $0 false 10; $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false; / ip dns static add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } + } else={ + $LogPrintExit2 debug $0 ("No address available... Ignoring.") false; } } From 7afce17f70555e1dd07e4a3a54af789cc408bed9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Aug 2021 11:20:57 +0200 Subject: [PATCH 0831/2612] netwatch-notify: use $ScriptLock --- netwatch-notify | 3 +++ 1 file changed, 3 insertions(+) diff --git a/netwatch-notify b/netwatch-notify index 966d415..7fdf5b5 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -16,6 +16,7 @@ :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; +:global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -47,6 +48,8 @@ :set NetwatchNotify [ :toarray "" ]; } +$ScriptLock $0; + :foreach Host in=[ / tool netwatch find where comment~"^notify," disabled=no ] do={ :local HostVal [ / tool netwatch get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; From 73dfb0c8eeafa7a5614500b8d8a8df08130bf4e6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Aug 2021 11:21:56 +0200 Subject: [PATCH 0832/2612] check-health: use $ScriptLock --- check-health | 3 +++ 1 file changed, 3 insertions(+) diff --git a/check-health b/check-health index ec89545..bf0e441 100644 --- a/check-health +++ b/check-health @@ -18,6 +18,7 @@ :global Identity; :global LogPrintExit2; +:global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -36,6 +37,8 @@ :set CheckHealthTemperatureNotified [ :toarray "" ]; } +$ScriptLock $0; + :foreach Name,Voltage in=$CheckHealthCurrent do={ :if ($Name ~ "(battery|voltage)" && \ [ :typeof ($CheckHealthLast->$Name) ] = "num" && \ From 6b04fff3eb2214eafa8dab01bfef672508d2440e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 30 Aug 2021 16:03:29 +0200 Subject: [PATCH 0833/2612] lease-script: move debug output up --- lease-script | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lease-script b/lease-script index 6de6fd9..ab35ee5 100644 --- a/lease-script +++ b/lease-script @@ -22,15 +22,15 @@ $LogPrintExit2 error $0 ("This script is supposed to run from ip dhcp-server.") true; } +$LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \ + "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC) false; + $ScriptLock $0 false 10; :if ([ :len [ / system script job find where script=$0 ] ] > 1) do={ $LogPrintExit2 debug $0 ("More invocations are waiting, exiting early.") true; } -$LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \ - "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC) false; - :local RunOrder [ :toarray "" ]; :foreach Script in=[ / system script find where source~("\n# provides: lease-script, ") ] do={ From d356d6f57c3cd35b078811110a79802f49ed9529 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 30 Aug 2021 20:44:02 +0200 Subject: [PATCH 0834/2612] global-functions: $ScriptLock: do not store but calculate job count This should mitigate some more race conditions. --- global-functions | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/global-functions b/global-functions index bbea143..f2b8ea1 100644 --- a/global-functions +++ b/global-functions @@ -925,6 +925,12 @@ :set ScriptLockOrder [ :toarray "" ]; } + :local JobCount do={ + :local Script [ :tostr $1 ]; + + :return [ :len [ / system script job find where script=$Script ] ]; + } + :local AddTicket do={ :local Script [ :tostr $1 ]; :local Add [ :tostr $2 ]; @@ -963,13 +969,11 @@ $LogPrintExit2 error $0 ("A script named '" . $Script . "' does not exist!") true; } - :local JobCount [ :len [ / system script job find where script=$Script ] ]; - - :if ($JobCount = 0) do={ + :if ([ $JobCount $Script ] = 0) do={ $LogPrintExit2 error $0 ("No script '" . $Script . "' is running!") true; } - :if ([ :len ($ScriptLockOrder->$Script) ] >= $JobCount) do={ + :if ([ :len ($ScriptLockOrder->$Script) ] >= [ $JobCount $Script ]) do={ $LogPrintExit2 error $0 ("More tickets than running scripts '" . $Script . "', resetting!") false; :set ($ScriptLockOrder->$Script); / system script job remove [ find where script=$Script ]; @@ -979,13 +983,12 @@ $AddTicket $Script $MyTicket; :local WaitCount 0; - :while ($WaitMax > $WaitCount && (($ScriptLockOrder->$Script->0) != $MyTicket || [ :len ($ScriptLockOrder->$Script) ] < $JobCount)) do={ + :while ($WaitMax > $WaitCount && (($ScriptLockOrder->$Script->0) != $MyTicket || [ :len ($ScriptLockOrder->$Script) ] < [ $JobCount $Script ])) do={ :delay 100ms; :set WaitCount ($WaitCount + 1); - :set JobCount [ :len [ / system script job find where script=$Script ] ]; } - :if ([ :len ($ScriptLockOrder->$Script) ] = $JobCount && ($ScriptLockOrder->$Script->0) = $MyTicket) do={ + :if (($ScriptLockOrder->$Script->0) = $MyTicket && [ :len ($ScriptLockOrder->$Script) ] = [ $JobCount $Script ]) do={ $RemoveTicket $Script $MyTicket; :return false; } From ae8e22941ebb31d472ca185d0a5bb2fa9b7a19ca Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 30 Aug 2021 21:50:46 +0200 Subject: [PATCH 0835/2612] global-functions: $ScriptLock: handle array by index This should mitigate race conditions while rewriting the array. --- global-functions | 67 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/global-functions b/global-functions index f2b8ea1..17075f9 100644 --- a/global-functions +++ b/global-functions @@ -931,18 +931,48 @@ :return [ :len [ / system script job find where script=$Script ] ]; } + :local TicketCount do={ + :local Script [ :tostr $1 ]; + + :global ScriptLockOrder; + + :local Count 0; + :foreach Ticket in=($ScriptLockOrder->$Script) do={ + :if ([ :typeof $Ticket ] != "nothing") do={ + :set Count ($Count + 1); + } + } + :return $Count; + } + + :local IsFirstTicket do={ + :local Script [ :tostr $1 ]; + :local Check [ :tostr $2 ]; + + :global ScriptLockOrder; + + :foreach Ticket in=($ScriptLockOrder->$Script) do={ + :if ($Ticket = $Check) do={ :return true; } + :if ([ :typeof $Ticket ] != "nothing" && $Ticket != $Check) do={ :return false; } + } + :return false; + } + :local AddTicket do={ :local Script [ :tostr $1 ]; :local Add [ :tostr $2 ]; :global ScriptLockOrder; + :if ([ :typeof ($ScriptLockOrder->$Script) ] = "nothing") do={ + :set ($ScriptLockOrder->$Script) [ :toarray "" ]; + } + :while (true) do={ - :set ($ScriptLockOrder->$Script) (($ScriptLockOrder->$Script), $Add); + :local Pos [ :len ($ScriptLockOrder->$Script) ]; + :set ($ScriptLockOrder->$Script->$Pos) $Add; :delay 10ms; - :foreach Ticket in=($ScriptLockOrder->$Script) do={ - :if ($Ticket = $Add) do={ :return true; } - } + :if (($ScriptLockOrder->$Script->$Pos) = $Add) do={ :return true; } } } @@ -952,16 +982,19 @@ :global ScriptLockOrder; - :while (true) do={ - :local New [ :toarray "" ]; - :foreach Ticket in=($ScriptLockOrder->$Script) do={ - :if ($Ticket != $Remove) do={ - :set New ($New, $Ticket); - } + :local Count 0; + :foreach Id,Ticket in=($ScriptLockOrder->$Script) do={ + :if (($ScriptLockOrder->$Script->$Id) = $Remove) do={ + :set ($ScriptLockOrder->$Script->$Id); } - :set ($ScriptLockOrder->$Script) $New; - :delay 12ms; - :if (($ScriptLockOrder->$Script->0) != $Remove) do={ :return true; } + + :if ([ :typeof ($ScriptLockOrder->$Script->$Id) ] != "nothing") do={ + :set Count ($Count + 1); + } + } + + :if ($Count = 0) do={ + :set ($ScriptLockOrder->$Script); } } @@ -973,7 +1006,7 @@ $LogPrintExit2 error $0 ("No script '" . $Script . "' is running!") true; } - :if ([ :len ($ScriptLockOrder->$Script) ] >= [ $JobCount $Script ]) do={ + :if ([ $TicketCount $Script ] >= [ $JobCount $Script ]) do={ $LogPrintExit2 error $0 ("More tickets than running scripts '" . $Script . "', resetting!") false; :set ($ScriptLockOrder->$Script); / system script job remove [ find where script=$Script ]; @@ -983,12 +1016,12 @@ $AddTicket $Script $MyTicket; :local WaitCount 0; - :while ($WaitMax > $WaitCount && (($ScriptLockOrder->$Script->0) != $MyTicket || [ :len ($ScriptLockOrder->$Script) ] < [ $JobCount $Script ])) do={ - :delay 100ms; + :while ($WaitMax > $WaitCount && ([ $IsFirstTicket $Script $MyTicket ] = false || [ $TicketCount $Script ] < [ $JobCount $Script ])) do={ :set WaitCount ($WaitCount + 1); + :delay 100ms; } - :if (($ScriptLockOrder->$Script->0) = $MyTicket && [ :len ($ScriptLockOrder->$Script) ] = [ $JobCount $Script ]) do={ + :if ([ $IsFirstTicket $Script $MyTicket ] = true && [ $TicketCount $Script ] = [ $JobCount $Script ]) do={ $RemoveTicket $Script $MyTicket; :return false; } From 832e899cdac69736cc4f7e0ec9ef30fd0c71f5f3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Sep 2021 14:05:55 +0200 Subject: [PATCH 0836/2612] global-functions: $RequiredRouterOS: allow to use without warning --- global-functions | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/global-functions b/global-functions index 17075f9..69fda07 100644 --- a/global-functions +++ b/global-functions @@ -84,7 +84,7 @@ } } - :if ([ $RequiredRouterOS $0 "6.47" ] = false) do={ + :if ([ $RequiredRouterOS $0 "6.47" true ] = false) do={ :return true; } @@ -661,16 +661,19 @@ # check for required RouterOS version :set RequiredRouterOS do={ - :local Caller [ :tostr $1 ]; - :local Required [ :tostr $2 ]; + :local Caller [ :tostr $1 ]; + :local Required [ :tostr $2 ]; + :local Warn [ :tobool $3 ]; :global IfThenElse; :global LogPrintExit2; :global VersionToNum; :if ([ $VersionToNum $Required ] > [ $VersionToNum [ / system package update get installed-version ] ]) do={ - $LogPrintExit2 warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = "\$") "function" "script" ] . \ - " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!") false; + :if ($Warn = true) do={ + $LogPrintExit2 warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = "\$") "function" "script" ] . \ + " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!") false; + } :return false; } :return true; @@ -1316,7 +1319,7 @@ } # check for required RouterOS version -$RequiredRouterOS "global-functions" "6.47"; +$RequiredRouterOS "global-functions" "6.47" true; # signal we are ready :set GlobalFunctionsReady true; From 150c2281973ff28b764637b3df83d3b8005cfe0e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Sep 2021 08:55:34 +0200 Subject: [PATCH 0837/2612] global-functions: $CertificateAvailable: drop version check --- global-functions | 5 ----- 1 file changed, 5 deletions(-) diff --git a/global-functions b/global-functions index 69fda07..30512f6 100644 --- a/global-functions +++ b/global-functions @@ -68,7 +68,6 @@ :global CertificateDownload; :global LogPrintExit2; :global ParseKeyValueStore; - :global RequiredRouterOS; :if ([ / system resource get free-hdd-space ] < 8388608 && \ [ / certificate settings get crl-download ] = true && \ @@ -84,10 +83,6 @@ } } - :if ([ $RequiredRouterOS $0 "6.47" true ] = false) do={ - :return true; - } - :local CertVal [ / certificate get [ find where common-name=$CommonName ] ]; :while (($CertVal->"akid") != "" && ($CertVal->"akid") != ($CertVal->"skid")) do={ :if ([ :len [ / certificate find where skid=($CertVal->"akid") ] ] = 0) do={ From 70f9c7926b31d7d7e4e48157e83e0e3acf8352e0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 Sep 2021 14:33:02 +0200 Subject: [PATCH 0838/2612] global-functions*: syntax for ROS 7.x Strings with escape sequence have to be enclosed in parentheses. Looks like RouterOS 7.x is stricter here... --- global-functions | 12 ++++++------ global-functions.d/notification-matrix | 2 +- global-functions.d/notification-telegram | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/global-functions b/global-functions index 30512f6..e6b6527 100644 --- a/global-functions +++ b/global-functions @@ -310,7 +310,7 @@ } :local Return ""; - :local Chars "^.[]\$()|*+\?{}\\"; + :local Chars ("^.[]\$()|*+\?{}\\"); :for I from=0 to=([ :len $Input ] - 1) do={ :local Char [ :pick $Input $I ]; @@ -503,7 +503,7 @@ } :local Log ($Name . ": " . $Message); - :if ($Severity ~ "^(debug|error|info)\$") do={ + :if ($Severity ~ ("^(debug|error|info)\$")) do={ :if ($Severity = "debug") do={ :log debug $Log; } :if ($Severity = "error") do={ :log error $Log; } :if ($Severity = "info" ) do={ :log info $Log; } @@ -588,7 +588,7 @@ attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") }; :if ([ :len [ / system scheduler find where name="FlushEmailQueue" ] ] = 0) do={ / system scheduler add name=FlushEmailQueue interval=1s start-time=startup \ - on-event=":global FlushEmailQueue; \$FlushEmailQueue;"; + on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); } } @@ -666,7 +666,7 @@ :if ([ $VersionToNum $Required ] > [ $VersionToNum [ / system package update get installed-version ] ]) do={ :if ($Warn = true) do={ - $LogPrintExit2 warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = "\$") "function" "script" ] . \ + $LogPrintExit2 warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = ("\$")) "function" "script" ] . \ " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!") false; } :return false; @@ -782,7 +782,7 @@ :if ($ScriptVal->"name" = "global-config") do={ :set ReloadGlobalConfig true; } - :if ($ScriptVal->"name" ~ "^global-functions(\$|\\.d/.)") do={ + :if ($ScriptVal->"name" ~ ("^global-functions(\$|\\.d/.)")) do={ :set ReloadGlobalFunctions true; } } else={ @@ -1183,7 +1183,7 @@ } :local Return ""; - :local Chars "\n\r !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~"; + :local Chars ("\n\r !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~"); :local Subs { "%0A"; "%0D"; "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27"; "%28"; "%29"; "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; "%3F"; "%40"; "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; "%7E" }; diff --git a/global-functions.d/notification-matrix b/global-functions.d/notification-matrix index 962924e..a2f7af0 100644 --- a/global-functions.d/notification-matrix +++ b/global-functions.d/notification-matrix @@ -135,7 +135,7 @@ plain=$Plain; formatted=$Formatted }; :if ([ :len [ / system scheduler find where name="FlushMatrixQueue" ] ] = 0) do={ / system scheduler add name=FlushMatrixQueue interval=1m start-time=startup \ - on-event=":global FlushMatrixQueue; \$FlushMatrixQueue;"; + on-event=(":global FlushMatrixQueue; \$FlushMatrixQueue;"); } } } diff --git a/global-functions.d/notification-telegram b/global-functions.d/notification-telegram index 4a05c9a..d8fe448 100644 --- a/global-functions.d/notification-telegram +++ b/global-functions.d/notification-telegram @@ -141,7 +141,7 @@ parsemode=$ParseMode; text=$Text; silent=($Notification->"silent") }; :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ / system scheduler add name=FlushTelegramQueue interval=1m start-time=startup \ - on-event=":global FlushTelegramQueue; \$FlushTelegramQueue;"; + on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;"); } } } From a3798ff656a029d40cd2905133a1d8ae66ad4a8c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 20 Sep 2021 14:53:24 +0200 Subject: [PATCH 0839/2612] certs: add new intermediate cert DigiCert TLS Hybrid ECC SHA384 2020 CA1 This is used by Cloudflare DNS (1.1.1.1) and Quard9 (9.9.9.9). $CertificateAvailable "DigiCert TLS Hybrid ECC SHA384 2020 CA1" /ip dns set use-doh-server=https://1.1.1.1/dns-query verify-doh-cert=yes $CertificateAvailable "DigiCert TLS Hybrid ECC SHA384 2020 CA1" /ip dns set use-doh-server=https://9.9.9.9/dns-query verify-doh-cert=yes --- ...igiCert TLS Hybrid ECC SHA384 2020 CA1.pem | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 certs/DigiCert TLS Hybrid ECC SHA384 2020 CA1.pem diff --git a/certs/DigiCert TLS Hybrid ECC SHA384 2020 CA1.pem b/certs/DigiCert TLS Hybrid ECC SHA384 2020 CA1.pem new file mode 100644 index 0000000..446f56f --- /dev/null +++ b/certs/DigiCert TLS Hybrid ECC SHA384 2020 CA1.pem @@ -0,0 +1,174 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 07:f2:f3:5c:87:a8:77:af:7a:ef:e9:47:99:35:25:bd + Signature Algorithm: sha384WithRSAEncryption + Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA + Validity + Not Before: Apr 14 00:00:00 2021 GMT + Not After : Apr 13 23:59:59 2031 GMT + Subject: C = US, O = DigiCert Inc, CN = DigiCert TLS Hybrid ECC SHA384 2020 CA1 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:c1:1b:c6:9a:5b:98:d9:a4:29:a0:e9:d4:04:b5: + db:eb:a6:b2:6c:55:c0:ff:ed:98:c6:49:2f:06:27: + 51:cb:bf:70:c1:05:7a:c3:b1:9d:87:89:ba:ad:b4: + 13:17:c9:a8:b4:83:c8:b8:90:d1:cc:74:35:36:3c: + 83:72:b0:b5:d0:f7:22:69:c8:f1:80:c4:7b:40:8f: + cf:68:87:26:5c:39:89:f1:4d:91:4d:da:89:8b:e4: + 03:c3:43:e5:bf:2f:73 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + 0A:BC:08:29:17:8C:A5:39:6D:7A:0E:CE:33:C7:2E:B3:ED:FB:C3:7A + X509v3 Authority Key Identifier: + keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + CA Issuers - URI:http://cacerts.digicert.com/DigiCertGlobalRootCA.crt + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl3.digicert.com/DigiCertGlobalRootCA.crl + + X509v3 Certificate Policies: + Policy: 2.16.840.1.114412.2.1 + Policy: 2.23.140.1.1 + Policy: 2.23.140.1.2.1 + Policy: 2.23.140.1.2.2 + Policy: 2.23.140.1.2.3 + + Signature Algorithm: sha384WithRSAEncryption + 47:59:81:7f:d4:1b:1f:b0:71:f6:98:5d:18:ba:98:47:98:b0: + 7e:76:2b:ea:ff:1a:8b:ac:26:b3:42:8d:31:e6:4a:e8:19:d0: + ef:da:14:e7:d7:14:92:a1:92:f2:a7:2e:2d:af:fb:1d:f6:fb: + 53:b0:8a:3f:fc:d8:16:0a:e9:b0:2e:b6:a5:0b:18:90:35:26: + a2:da:f6:a8:b7:32:fc:95:23:4b:c6:45:b9:c4:cf:e4:7c:ee: + e6:c9:f8:90:bd:72:e3:99:c3:1d:0b:05:7c:6a:97:6d:b2:ab: + 02:36:d8:c2:bc:2c:01:92:3f:04:a3:8b:75:11:c7:b9:29:bc: + 11:d0:86:ba:92:bc:26:f9:65:c8:37:cd:26:f6:86:13:0c:04: + aa:89:e5:78:b1:c1:4e:79:bc:76:a3:0b:51:e4:c5:d0:9e:6a: + fe:1a:2c:56:ae:06:36:27:a3:73:1c:08:7d:93:32:d0:c2:44: + 19:da:8d:f4:0e:7b:1d:28:03:2b:09:8a:76:ca:77:dc:87:7a: + ac:7b:52:26:55:a7:72:0f:9d:d2:88:4f:fe:b1:21:c5:1a:a1: + aa:39:f5:56:db:c2:84:c4:35:1f:70:da:bb:46:f0:86:bf:64: + 00:c4:3e:f7:9f:46:1b:9d:23:05:b9:7d:b3:4f:0f:a9:45:3a: + e3:74:30:98 +-----BEGIN CERTIFICATE----- +MIIEFzCCAv+gAwIBAgIQB/LzXIeod6967+lHmTUlvTANBgkqhkiG9w0BAQwFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0yMTA0MTQwMDAwMDBaFw0zMTA0MTMyMzU5NTlaMFYxCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMDAuBgNVBAMTJ0RpZ2lDZXJ0IFRMUyBI +eWJyaWQgRUNDIFNIQTM4NCAyMDIwIENBMTB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BMEbxppbmNmkKaDp1AS12+umsmxVwP/tmMZJLwYnUcu/cMEFesOxnYeJuq20ExfJ +qLSDyLiQ0cx0NTY8g3KwtdD3ImnI8YDEe0CPz2iHJlw5ifFNkU3aiYvkA8ND5b8v +c6OCAYIwggF+MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFAq8CCkXjKU5 +bXoOzjPHLrPt+8N6MB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA4G +A1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYI +KwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j +b20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp +Q2VydEdsb2JhbFJvb3RDQS5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2Ny +bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDA9BgNVHSAE +NjA0MAsGCWCGSAGG/WwCATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgG +BmeBDAECAzANBgkqhkiG9w0BAQwFAAOCAQEAR1mBf9QbH7Bx9phdGLqYR5iwfnYr +6v8ai6wms0KNMeZK6BnQ79oU59cUkqGS8qcuLa/7Hfb7U7CKP/zYFgrpsC62pQsY +kDUmotr2qLcy/JUjS8ZFucTP5Hzu5sn4kL1y45nDHQsFfGqXbbKrAjbYwrwsAZI/ +BKOLdRHHuSm8EdCGupK8JvllyDfNJvaGEwwEqonleLHBTnm8dqMLUeTF0J5q/hos +Vq4GNiejcxwIfZMy0MJEGdqN9A57HSgDKwmKdsp33Id6rHtSJlWncg+d0ohP/rEh +xRqhqjn1VtvChMQ1H3Dau0bwhr9kAMQ+959GG50jBbl9s08PqUU643QwmA== +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 08:3b:e0:56:90:42:46:b1:a1:75:6a:c9:59:91:c7:4a + Signature Algorithm: sha1WithRSAEncryption + Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA + Validity + Not Before: Nov 10 00:00:00 2006 GMT + Not After : Nov 10 00:00:00 2031 GMT + Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:e2:3b:e1:11:72:de:a8:a4:d3:a3:57:aa:50:a2: + 8f:0b:77:90:c9:a2:a5:ee:12:ce:96:5b:01:09:20: + cc:01:93:a7:4e:30:b7:53:f7:43:c4:69:00:57:9d: + e2:8d:22:dd:87:06:40:00:81:09:ce:ce:1b:83:bf: + df:cd:3b:71:46:e2:d6:66:c7:05:b3:76:27:16:8f: + 7b:9e:1e:95:7d:ee:b7:48:a3:08:da:d6:af:7a:0c: + 39:06:65:7f:4a:5d:1f:bc:17:f8:ab:be:ee:28:d7: + 74:7f:7a:78:99:59:85:68:6e:5c:23:32:4b:bf:4e: + c0:e8:5a:6d:e3:70:bf:77:10:bf:fc:01:f6:85:d9: + a8:44:10:58:32:a9:75:18:d5:d1:a2:be:47:e2:27: + 6a:f4:9a:33:f8:49:08:60:8b:d4:5f:b4:3a:84:bf: + a1:aa:4a:4c:7d:3e:cf:4f:5f:6c:76:5e:a0:4b:37: + 91:9e:dc:22:e6:6d:ce:14:1a:8e:6a:cb:fe:cd:b3: + 14:64:17:c7:5b:29:9e:32:bf:f2:ee:fa:d3:0b:42: + d4:ab:b7:41:32:da:0c:d4:ef:f8:81:d5:bb:8d:58: + 3f:b5:1b:e8:49:28:a2:70:da:31:04:dd:f7:b2:16: + f2:4c:0a:4e:07:a8:ed:4a:3d:5e:b5:7f:a3:90:c3: + af:27 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 + X509v3 Authority Key Identifier: + keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 + + Signature Algorithm: sha1WithRSAEncryption + cb:9c:37:aa:48:13:12:0a:fa:dd:44:9c:4f:52:b0:f4:df:ae: + 04:f5:79:79:08:a3:24:18:fc:4b:2b:84:c0:2d:b9:d5:c7:fe: + f4:c1:1f:58:cb:b8:6d:9c:7a:74:e7:98:29:ab:11:b5:e3:70: + a0:a1:cd:4c:88:99:93:8c:91:70:e2:ab:0f:1c:be:93:a9:ff: + 63:d5:e4:07:60:d3:a3:bf:9d:5b:09:f1:d5:8e:e3:53:f4:8e: + 63:fa:3f:a7:db:b4:66:df:62:66:d6:d1:6e:41:8d:f2:2d:b5: + ea:77:4a:9f:9d:58:e2:2b:59:c0:40:23:ed:2d:28:82:45:3e: + 79:54:92:26:98:e0:80:48:a8:37:ef:f0:d6:79:60:16:de:ac: + e8:0e:cd:6e:ac:44:17:38:2f:49:da:e1:45:3e:2a:b9:36:53: + cf:3a:50:06:f7:2e:e8:c4:57:49:6c:61:21:18:d5:04:ad:78: + 3c:2c:3a:80:6b:a7:eb:af:15:14:e9:d8:89:c1:b9:38:6c:e2: + 91:6c:8a:ff:64:b9:77:25:57:30:c0:1b:24:a3:e1:dc:e9:df: + 47:7c:b5:b4:24:08:05:30:ec:2d:bd:0b:bf:45:bf:50:b9:a9: + f3:eb:98:01:12:ad:c8:88:c6:98:34:5f:8d:0a:3c:c6:e9:d5: + 95:95:6d:de +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- From ec7c88a78097af0cc1300800bde448accc2eb977 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 20 Sep 2021 15:10:29 +0200 Subject: [PATCH 0840/2612] certs: drop old intermediate cert DigiCert ECC Secure Server CA --- certs/DigiCert ECC Secure Server CA.pem | 166 ------------------------ 1 file changed, 166 deletions(-) delete mode 100644 certs/DigiCert ECC Secure Server CA.pem diff --git a/certs/DigiCert ECC Secure Server CA.pem b/certs/DigiCert ECC Secure Server CA.pem deleted file mode 100644 index 3eca7fc..0000000 --- a/certs/DigiCert ECC Secure Server CA.pem +++ /dev/null @@ -1,166 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 0a:cb:28:ba:46:5e:e5:39:08:76:74:70:f3:cd:c6:12 - Signature Algorithm: sha384WithRSAEncryption - Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA - Validity - Not Before: Mar 8 12:00:00 2013 GMT - Not After : Mar 8 12:00:00 2023 GMT - Subject: C = US, O = DigiCert Inc, CN = DigiCert ECC Secure Server CA - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (384 bit) - pub: - 04:e2:08:42:ea:77:d8:24:de:a0:2c:64:a4:13:ce: - 40:9c:23:72:a9:02:0a:0e:37:3f:21:36:b8:8d:53: - 14:f6:d5:91:95:4b:f3:96:02:8d:71:1e:c4:d8:cb: - a7:9f:5e:ef:a0:e6:7f:5a:92:11:96:53:6f:eb:c0: - cb:3f:ae:fd:5b:3f:47:24:e7:9a:07:2e:96:be:a8: - 2f:bb:57:18:af:71:a4:bd:78:3a:1e:e8:5b:3c:6b: - 64:11:2b:cc:34:2b:8c - ASN1 OID: secp384r1 - NIST CURVE: P-384 - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - Authority Information Access: - OCSP - URI:http://ocsp.digicert.com - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://crl3.digicert.com/DigiCertGlobalRootCA.crl - - X509v3 Certificate Policies: - Policy: X509v3 Any Policy - CPS: https://www.digicert.com/CPS - - X509v3 Subject Key Identifier: - A3:9D:E6:1F:F9:DA:39:4F:C0:6E:E8:91:CB:95:A5:DA:31:E2:0A:9F - X509v3 Authority Key Identifier: - keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 - - Signature Algorithm: sha384WithRSAEncryption - c7:8a:a0:43:4b:ec:74:c9:c5:ab:d5:1f:30:35:36:6e:98:56: - 7b:48:ac:05:63:ae:7b:9a:57:24:57:cc:6f:fa:de:ab:6d:9c: - c7:b6:ba:ec:ce:e7:ca:73:64:db:df:04:37:0a:00:49:b3:3f: - 9f:26:ad:91:8c:20:e8:1f:88:0e:2a:fb:66:37:c8:30:e8:d2: - c2:24:a7:45:48:2d:ea:01:50:4a:31:94:13:df:8d:5f:da:2a: - bb:49:3c:61:f3:79:c8:9c:66:92:1a:96:2a:f4:7b:36:58:a3: - 2c:41:10:74:1a:d3:ed:48:b6:d2:bb:8a:06:45:71:33:10:30: - 7a:7a:98:21:dd:24:b9:ec:9c:b5:92:07:ad:83:c6:c4:6a:f8: - 77:e6:35:be:13:0f:27:64:b2:43:bf:83:e9:77:56:db:08:87: - 94:47:14:f5:5f:28:af:a3:68:4c:83:8f:60:f7:96:80:79:85: - 6a:76:26:9d:95:0c:20:03:8d:3e:ee:7a:28:65:64:66:a4:d9: - 83:ea:99:74:cd:6e:4d:7d:1c:eb:8d:b2:c5:af:16:1b:4e:c8: - f3:55:ea:88:38:11:34:1d:11:af:3f:07:a8:4f:6a:d2:74:11: - 2f:2a:fc:73:b7:5f:c2:15:43:05:6c:d6:7d:da:02:bd:22:9b: - 4f:d3:f9:77 ------BEGIN CERTIFICATE----- -MIIDrDCCApSgAwIBAgIQCssoukZe5TkIdnRw883GEjANBgkqhkiG9w0BAQwFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaMEwxCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJjAkBgNVBAMTHURpZ2lDZXJ0IEVDQyBT -ZWN1cmUgU2VydmVyIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4ghC6nfYJN6g -LGSkE85AnCNyqQIKDjc/ITa4jVMU9tWRlUvzlgKNcR7E2Munn17voOZ/WpIRllNv -68DLP679Wz9HJOeaBy6Wvqgvu1cYr3GkvXg6HuhbPGtkESvMNCuMo4IBITCCAR0w -EgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwNAYIKwYBBQUHAQEE -KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYDVR0f -BDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xv -YmFsUm9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYc -aHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUo53mH/naOU/A -buiRy5Wl2jHiCp8wHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJ -KoZIhvcNAQEMBQADggEBAMeKoENL7HTJxavVHzA1Nm6YVntIrAVjrnuaVyRXzG/6 -3qttnMe2uuzO58pzZNvfBDcKAEmzP58mrZGMIOgfiA4q+2Y3yDDo0sIkp0VILeoB -UEoxlBPfjV/aKrtJPGHzecicZpIalir0ezZYoyxBEHQa0+1IttK7igZFcTMQMHp6 -mCHdJLnsnLWSB62DxsRq+HfmNb4TDydkskO/g+l3VtsIh5RHFPVfKK+jaEyDj2D3 -loB5hWp2Jp2VDCADjT7ueihlZGak2YPqmXTNbk19HOuNssWvFhtOyPNV6og4ETQd -Ea8/B6hPatJ0ES8q/HO3X8IVQwVs1n3aAr0im0/T+Xc= ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 08:3b:e0:56:90:42:46:b1:a1:75:6a:c9:59:91:c7:4a - Signature Algorithm: sha1WithRSAEncryption - Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA - Validity - Not Before: Nov 10 00:00:00 2006 GMT - Not After : Nov 10 00:00:00 2031 GMT - Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:e2:3b:e1:11:72:de:a8:a4:d3:a3:57:aa:50:a2: - 8f:0b:77:90:c9:a2:a5:ee:12:ce:96:5b:01:09:20: - cc:01:93:a7:4e:30:b7:53:f7:43:c4:69:00:57:9d: - e2:8d:22:dd:87:06:40:00:81:09:ce:ce:1b:83:bf: - df:cd:3b:71:46:e2:d6:66:c7:05:b3:76:27:16:8f: - 7b:9e:1e:95:7d:ee:b7:48:a3:08:da:d6:af:7a:0c: - 39:06:65:7f:4a:5d:1f:bc:17:f8:ab:be:ee:28:d7: - 74:7f:7a:78:99:59:85:68:6e:5c:23:32:4b:bf:4e: - c0:e8:5a:6d:e3:70:bf:77:10:bf:fc:01:f6:85:d9: - a8:44:10:58:32:a9:75:18:d5:d1:a2:be:47:e2:27: - 6a:f4:9a:33:f8:49:08:60:8b:d4:5f:b4:3a:84:bf: - a1:aa:4a:4c:7d:3e:cf:4f:5f:6c:76:5e:a0:4b:37: - 91:9e:dc:22:e6:6d:ce:14:1a:8e:6a:cb:fe:cd:b3: - 14:64:17:c7:5b:29:9e:32:bf:f2:ee:fa:d3:0b:42: - d4:ab:b7:41:32:da:0c:d4:ef:f8:81:d5:bb:8d:58: - 3f:b5:1b:e8:49:28:a2:70:da:31:04:dd:f7:b2:16: - f2:4c:0a:4e:07:a8:ed:4a:3d:5e:b5:7f:a3:90:c3: - af:27 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - 03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 - X509v3 Authority Key Identifier: - keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 - - Signature Algorithm: sha1WithRSAEncryption - cb:9c:37:aa:48:13:12:0a:fa:dd:44:9c:4f:52:b0:f4:df:ae: - 04:f5:79:79:08:a3:24:18:fc:4b:2b:84:c0:2d:b9:d5:c7:fe: - f4:c1:1f:58:cb:b8:6d:9c:7a:74:e7:98:29:ab:11:b5:e3:70: - a0:a1:cd:4c:88:99:93:8c:91:70:e2:ab:0f:1c:be:93:a9:ff: - 63:d5:e4:07:60:d3:a3:bf:9d:5b:09:f1:d5:8e:e3:53:f4:8e: - 63:fa:3f:a7:db:b4:66:df:62:66:d6:d1:6e:41:8d:f2:2d:b5: - ea:77:4a:9f:9d:58:e2:2b:59:c0:40:23:ed:2d:28:82:45:3e: - 79:54:92:26:98:e0:80:48:a8:37:ef:f0:d6:79:60:16:de:ac: - e8:0e:cd:6e:ac:44:17:38:2f:49:da:e1:45:3e:2a:b9:36:53: - cf:3a:50:06:f7:2e:e8:c4:57:49:6c:61:21:18:d5:04:ad:78: - 3c:2c:3a:80:6b:a7:eb:af:15:14:e9:d8:89:c1:b9:38:6c:e2: - 91:6c:8a:ff:64:b9:77:25:57:30:c0:1b:24:a3:e1:dc:e9:df: - 47:7c:b5:b4:24:08:05:30:ec:2d:bd:0b:bf:45:bf:50:b9:a9: - f3:eb:98:01:12:ad:c8:88:c6:98:34:5f:8d:0a:3c:c6:e9:d5: - 95:95:6d:de ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB -CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 -nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt -43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P -T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 -gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR -TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw -DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr -hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg -06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF -PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls -YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- From 44d2f04e0ebaaf01642bc6ccf8d558605781e2b0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 20 Sep 2021 20:38:09 +0200 Subject: [PATCH 0841/2612] certs: add new chain GTS CA 1C3 / GTS Root R1 This is used by Google DNS (8.8.8.8). $CertificateAvailable "GTS CA 1C3" /ip dns set use-doh-server=https://8.8.8.8/dns-query verify-doh-cert=yes --- certs/GTS CA 1C3.pem | 242 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 certs/GTS CA 1C3.pem diff --git a/certs/GTS CA 1C3.pem b/certs/GTS CA 1C3.pem new file mode 100644 index 0000000..a8432d2 --- /dev/null +++ b/certs/GTS CA 1C3.pem @@ -0,0 +1,242 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 02:03:bc:53:59:6b:34:c7:18:f5:01:50:66 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, O = Google Trust Services LLC, CN = GTS Root R1 + Validity + Not Before: Aug 13 00:00:42 2020 GMT + Not After : Sep 30 00:00:42 2027 GMT + Subject: C = US, O = Google Trust Services LLC, CN = GTS CA 1C3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:f5:88:df:e7:62:8c:1e:37:f8:37:42:90:7f:6c: + 87:d0:fb:65:82:25:fd:e8:cb:6b:a4:ff:6d:e9:5a: + 23:e2:99:f6:1c:e9:92:03:99:13:7c:09:0a:8a:fa: + 42:d6:5e:56:24:aa:7a:33:84:1f:d1:e9:69:bb:b9: + 74:ec:57:4c:66:68:93:77:37:55:53:fe:39:10:4d: + b7:34:bb:5f:25:77:37:3b:17:94:ea:3c:e5:9d:d5: + bc:c3:b4:43:eb:2e:a7:47:ef:b0:44:11:63:d8:b4: + 41:85:dd:41:30:48:93:1b:bf:b7:f6:e0:45:02:21: + e0:96:42:17:cf:d9:2b:65:56:34:07:26:04:0d:a8: + fd:7d:ca:2e:ef:ea:48:7c:37:4d:3f:00:9f:83:df: + ef:75:84:2e:79:57:5c:fc:57:6e:1a:96:ff:fc:8c: + 9a:a6:99:be:25:d9:7f:96:2c:06:f7:11:2a:02:80: + 80:eb:63:18:3c:50:49:87:e5:8a:ca:5f:19:2b:59: + 96:81:00:a0:fb:51:db:ca:77:0b:0b:c9:96:4f:ef: + 70:49:c7:5c:6d:20:fd:99:b4:b4:e2:ca:2e:77:fd: + 2d:dc:0b:b6:6b:13:0c:8c:19:2b:17:96:98:b9:f0: + 8b:f6:a0:27:bb:b6:e3:8d:51:8f:bd:ae:c7:9b:b1: + 89:9d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + 8A:74:7F:AF:85:CD:EE:95:CD:3D:9C:D0:E2:46:14:F3:71:35:1D:27 + X509v3 Authority Key Identifier: + keyid:E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E + + Authority Information Access: + OCSP - URI:http://ocsp.pki.goog/gtsr1 + CA Issuers - URI:http://pki.goog/repo/certs/gtsr1.der + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.pki.goog/gtsr1/gtsr1.crl + + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.11129.2.5.3 + CPS: https://pki.goog/repository/ + Policy: 2.23.140.1.2.1 + Policy: 2.23.140.1.2.2 + + Signature Algorithm: sha256WithRSAEncryption + 89:7d:ac:20:5c:0c:3c:be:9a:a8:57:95:1b:b4:ae:fa:ab:a5: + 72:71:b4:36:95:fd:df:40:11:03:4c:c2:46:14:bb:14:24:ab: + f0:50:71:22:db:ad:c4:6e:7f:cf:f1:6a:6f:c8:83:1b:d8:ce: + 89:5f:87:6c:87:b8:a9:0c:a3:9b:a1:62:94:93:95:df:5b:ae: + 66:19:0b:02:96:9e:fc:b5:e7:10:69:3e:7a:cb:46:49:5f:46: + e1:41:b1:d7:98:4d:65:34:00:80:1a:3f:4f:9f:6c:7f:49:00: + 81:53:41:a4:92:21:82:82:1a:f1:a3:44:5b:2a:50:12:13:4d: + c1:53:36:f3:42:08:af:54:fa:8e:77:53:1b:64:38:27:17:09: + bd:58:c9:1b:7c:39:2d:5b:f3:ce:d4:ed:97:db:14:03:bf:09: + 53:24:1f:c2:0c:04:79:98:26:f2:61:f1:53:52:fd:42:8c:1b: + 66:2b:3f:15:a1:bb:ff:f6:9b:e3:81:9a:01:06:71:89:35:28: + 24:dd:e1:bd:eb:19:2d:e1:48:cb:3d:59:83:51:b4:74:c6:9d: + 7c:c6:b1:86:5b:af:cc:34:c4:d3:cc:d4:81:11:95:00:a1:f4: + 12:22:01:fa:b4:83:71:af:8c:b7:8c:73:24:ac:37:53:c2:00: + 90:3f:11:fe:5c:ed:36:94:10:3b:bd:29:ae:e2:c7:3a:62:3b: + 6c:63:d9:80:bf:59:71:ac:63:27:b9:4c:17:a0:da:f6:73:15: + bf:2a:de:8f:f3:a5:6c:32:81:33:03:d0:86:51:71:99:34:ba: + 93:8d:5d:b5:51:58:f7:b2:93:e8:01:f6:59:be:71:9b:fd:4d: + 28:ce:cf:6d:c7:16:dc:f7:d1:d6:46:9b:a7:ca:6b:e9:77:0f: + fd:a0:b6:1b:23:83:1d:10:1a:d9:09:00:84:e0:44:d3:a2:75: + 23:b3:34:86:f6:20:b0:a4:5e:10:1d:e0:52:46:00:9d:b1:0f: + 1f:21:70:51:f5:9a:dd:06:fc:55:f4:2b:0e:33:77:c3:4b:42: + c2:f1:77:13:fc:73:80:94:eb:1f:bb:37:3f:ce:02:2a:66:b0: + 73:1d:32:a5:32:6c:32:b0:8e:e0:c4:23:ff:5b:7d:4d:65:70: + ac:2b:9b:3d:ce:db:e0:6d:8e:32:80:be:96:9f:92:63:bc:97: + bb:5d:b9:f4:e1:71:5e:2a:e4:ef:03:22:b1:8a:65:3a:8f:c0: + 93:65:d4:85:cd:0f:0f:5b:83:59:16:47:16:2d:9c:24:3a:c8: + 80:a6:26:14:85:9b:f6:37:9b:ac:6f:f9:c5:c3:06:51:f3:e2: + 7f:c5:b1:10:ba:51:f4:dd +-----BEGIN CERTIFICATE----- +MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw +MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFDMzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAPWI3+dijB43+DdCkH9sh9D7ZYIl/ejLa6T/belaI+KZ9hzp +kgOZE3wJCor6QtZeViSqejOEH9Hpabu5dOxXTGZok3c3VVP+ORBNtzS7XyV3NzsX +lOo85Z3VvMO0Q+sup0fvsEQRY9i0QYXdQTBIkxu/t/bgRQIh4JZCF8/ZK2VWNAcm +BA2o/X3KLu/qSHw3TT8An4Pf73WELnlXXPxXbhqW//yMmqaZviXZf5YsBvcRKgKA +gOtjGDxQSYflispfGStZloEAoPtR28p3CwvJlk/vcEnHXG0g/Zm0tOLKLnf9LdwL +tmsTDIwZKxeWmLnwi/agJ7u2441Rj72ux5uxiZ0CAwEAAaOCAYAwggF8MA4GA1Ud +DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T +AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUinR/r4XN7pXNPZzQ4kYU83E1HScwHwYD +VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG +CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw +AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt +MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMFcG +A1UdIARQME4wOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br +aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcN +AQELBQADggIBAIl9rCBcDDy+mqhXlRu0rvqrpXJxtDaV/d9AEQNMwkYUuxQkq/BQ +cSLbrcRuf8/xam/IgxvYzolfh2yHuKkMo5uhYpSTld9brmYZCwKWnvy15xBpPnrL +RklfRuFBsdeYTWU0AIAaP0+fbH9JAIFTQaSSIYKCGvGjRFsqUBITTcFTNvNCCK9U ++o53UxtkOCcXCb1YyRt8OS1b887U7ZfbFAO/CVMkH8IMBHmYJvJh8VNS/UKMG2Yr +PxWhu//2m+OBmgEGcYk1KCTd4b3rGS3hSMs9WYNRtHTGnXzGsYZbr8w0xNPM1IER +lQCh9BIiAfq0g3GvjLeMcySsN1PCAJA/Ef5c7TaUEDu9Ka7ixzpiO2xj2YC/WXGs +Yye5TBeg2vZzFb8q3o/zpWwygTMD0IZRcZk0upONXbVRWPeyk+gB9lm+cZv9TSjO +z23HFtz30dZGm6fKa+l3D/2gthsjgx0QGtkJAITgRNOidSOzNIb2ILCkXhAd4FJG +AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw +juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl +1IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 6e:47:a9:c5:4b:47:0c:0d:ec:33:d0:89:b9:1c:f4:e1 + Signature Algorithm: sha384WithRSAEncryption + Issuer: C = US, O = Google Trust Services LLC, CN = GTS Root R1 + Validity + Not Before: Jun 22 00:00:00 2016 GMT + Not After : Jun 22 00:00:00 2036 GMT + Subject: C = US, O = Google Trust Services LLC, CN = GTS Root R1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:b6:11:02:8b:1e:e3:a1:77:9b:3b:dc:bf:94:3e: + b7:95:a7:40:3c:a1:fd:82:f9:7d:32:06:82:71:f6: + f6:8c:7f:fb:e8:db:bc:6a:2e:97:97:a3:8c:4b:f9: + 2b:f6:b1:f9:ce:84:1d:b1:f9:c5:97:de:ef:b9:f2: + a3:e9:bc:12:89:5e:a7:aa:52:ab:f8:23:27:cb:a4: + b1:9c:63:db:d7:99:7e:f0:0a:5e:eb:68:a6:f4:c6: + 5a:47:0d:4d:10:33:e3:4e:b1:13:a3:c8:18:6c:4b: + ec:fc:09:90:df:9d:64:29:25:23:07:a1:b4:d2:3d: + 2e:60:e0:cf:d2:09:87:bb:cd:48:f0:4d:c2:c2:7a: + 88:8a:bb:ba:cf:59:19:d6:af:8f:b0:07:b0:9e:31: + f1:82:c1:c0:df:2e:a6:6d:6c:19:0e:b5:d8:7e:26: + 1a:45:03:3d:b0:79:a4:94:28:ad:0f:7f:26:e5:a8: + 08:fe:96:e8:3c:68:94:53:ee:83:3a:88:2b:15:96: + 09:b2:e0:7a:8c:2e:75:d6:9c:eb:a7:56:64:8f:96: + 4f:68:ae:3d:97:c2:84:8f:c0:bc:40:c0:0b:5c:bd: + f6:87:b3:35:6c:ac:18:50:7f:84:e0:4c:cd:92:d3: + 20:e9:33:bc:52:99:af:32:b5:29:b3:25:2a:b4:48: + f9:72:e1:ca:64:f7:e6:82:10:8d:e8:9d:c2:8a:88: + fa:38:66:8a:fc:63:f9:01:f9:78:fd:7b:5c:77:fa: + 76:87:fa:ec:df:b1:0e:79:95:57:b4:bd:26:ef:d6: + 01:d1:eb:16:0a:bb:8e:0b:b5:c5:c5:8a:55:ab:d3: + ac:ea:91:4b:29:cc:19:a4:32:25:4e:2a:f1:65:44: + d0:02:ce:aa:ce:49:b4:ea:9f:7c:83:b0:40:7b:e7: + 43:ab:a7:6c:a3:8f:7d:89:81:fa:4c:a5:ff:d5:8e: + c3:ce:4b:e0:b5:d8:b3:8e:45:cf:76:c0:ed:40:2b: + fd:53:0f:b0:a7:d5:3b:0d:b1:8a:a2:03:de:31:ad: + cc:77:ea:6f:7b:3e:d6:df:91:22:12:e6:be:fa:d8: + 32:fc:10:63:14:51:72:de:5d:d6:16:93:bd:29:68: + 33:ef:3a:66:ec:07:8a:26:df:13:d7:57:65:78:27: + de:5e:49:14:00:a2:00:7f:9a:a8:21:b6:a9:b1:95: + b0:a5:b9:0d:16:11:da:c7:6c:48:3c:40:e0:7e:0d: + 5a:cd:56:3c:d1:97:05:b9:cb:4b:ed:39:4b:9c:c4: + 3f:d2:55:13:6e:24:b0:d6:71:fa:f4:c1:ba:cc:ed: + 1b:f5:fe:81:41:d8:00:98:3d:3a:c8:ae:7a:98:37: + 18:05:95 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E + Signature Algorithm: sha384WithRSAEncryption + 38:96:0a:ee:3d:b4:96:1e:5f:ef:9d:9c:0b:33:9f:2b:e0:ca: + fd:d2:8e:0a:1f:41:74:a5:7c:aa:84:d4:e5:f2:1e:e6:37:52: + 32:9c:0b:d1:61:1d:bf:28:c1:b6:44:29:35:75:77:98:b2:7c: + d9:bd:74:ac:8a:68:e3:a9:31:09:29:01:60:73:e3:47:7c:53: + a8:90:4a:27:ef:4b:d7:9f:93:e7:82:36:ce:9a:68:0c:82:e7: + cf:d4:10:16:6f:5f:0e:99:5c:f6:1f:71:7d:ef:ef:7b:2f:7e: + ea:36:d6:97:70:0b:15:ee:d7:5c:56:6a:33:a5:e3:49:38:0c: + b8:7d:fb:8d:85:a4:b1:59:5e:f4:6a:e1:dd:a1:f6:64:44:ae: + e6:51:83:21:66:c6:11:3e:f3:ce:47:ee:9c:28:1f:25:da:ff: + ac:66:95:dd:35:0f:5c:ef:20:2c:62:fd:91:ba:a9:cc:fc:5a: + 9c:93:81:83:29:97:4a:7c:5a:72:b4:39:d0:b7:77:cb:79:fd: + 69:3a:92:37:ed:6e:38:65:46:7e:e9:60:bd:79:88:97:5f:38: + 12:f4:ee:af:5b:82:c8:86:d5:e1:99:6d:8c:04:f2:76:ba:49: + f6:6e:e9:6d:1e:5f:a0:ef:27:82:76:40:f8:a6:d3:58:5c:0f: + 2c:42:da:42:c6:7b:88:34:c7:c1:d8:45:9b:c1:3e:c5:61:1d: + d9:63:50:49:f6:34:85:6a:e0:18:c5:6e:47:ab:41:42:29:9b: + f6:60:0d:d2:31:d3:63:98:23:93:5a:00:81:48:b4:ef:cd:8a: + cd:c9:cf:99:ee:d9:9e:aa:36:e1:68:4b:71:49:14:36:28:3a: + 3d:1d:ce:9a:8f:25:e6:80:71:61:2b:b5:7b:cc:f9:25:16:81: + e1:31:5f:a1:a3:7e:16:a4:9c:16:6a:97:18:bd:76:72:a5:0b: + 9e:1d:36:e6:2f:a1:2f:be:70:91:0f:a8:e6:da:f8:c4:92:40: + 6c:25:7e:7b:b3:09:dc:b2:17:ad:80:44:f0:68:a5:8f:94:75: + ff:74:5a:e8:a8:02:7c:0c:09:e2:a9:4b:0b:a0:85:0b:62:b9: + ef:a1:31:92:fb:ef:f6:51:04:89:6c:e8:a9:74:a1:bb:17:b3: + b5:fd:49:0f:7c:3c:ec:83:18:20:43:4e:d5:93:ba:b4:34:b1: + 1f:16:36:1f:0c:e6:64:39:16:4c:dc:e0:fe:1d:c8:a9:62:3d: + 40:ea:ca:c5:34:02:b4:ae:89:88:33:35:dc:2c:13:73:d8:27: + f1:d0:72:ee:75:3b:22:de:98:68:66:5b:f1:c6:63:47:55:1c: + ba:a5:08:51:75:a6:48:25 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM +f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX +mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7 +zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P +fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc +vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4 +Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp +zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO +Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW +k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+ +DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF +lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW +Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 +d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z +XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR +gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3 +d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv +J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg +DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM ++SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy +F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9 +SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws +E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl +-----END CERTIFICATE----- From 15e60da7f01bb41955f4b321380b31c24fdad7e8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 20 Sep 2021 20:39:51 +0200 Subject: [PATCH 0842/2612] certs: drop old chain GTS CA 1O1 / GlobalSign --- certs/GTS CA 1O1.pem | 186 ------------------------------------------- 1 file changed, 186 deletions(-) delete mode 100644 certs/GTS CA 1O1.pem diff --git a/certs/GTS CA 1O1.pem b/certs/GTS CA 1O1.pem deleted file mode 100644 index ccdba4d..0000000 --- a/certs/GTS CA 1O1.pem +++ /dev/null @@ -1,186 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 01:e3:b4:9a:a1:8d:8a:a9:81:25:69:50:b8 - Signature Algorithm: sha256WithRSAEncryption - Issuer: OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign - Validity - Not Before: Jun 15 00:00:42 2017 GMT - Not After : Dec 15 00:00:42 2021 GMT - Subject: C = US, O = Google Trust Services, CN = GTS CA 1O1 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:d0:18:cf:45:d4:8b:cd:d3:9c:e4:40:ef:7e:b4: - dd:69:21:1b:c9:cf:3c:8e:4c:75:b9:0f:31:19:84: - 3d:9e:3c:29:ef:50:0d:10:93:6f:05:80:80:9f:2a: - a0:bd:12:4b:02:e1:3d:9f:58:16:24:fe:30:9f:0b: - 74:77:55:93:1d:4b:f7:4d:e1:92:82:10:f6:51:ac: - 0c:c3:b2:22:94:0f:34:6b:98:10:49:e7:0b:9d:83: - 39:dd:20:c6:1c:2d:ef:d1:18:61:65:e7:23:83:20: - a8:23:12:ff:d2:24:7f:d4:2f:e7:44:6a:5b:4d:d7: - 50:66:b0:af:9e:42:63:05:fb:e0:1c:c4:63:61:af: - 9f:6a:33:ff:62:97:bd:48:d9:d3:7c:14:67:dc:75: - dc:2e:69:e8:f8:6d:78:69:d0:b7:10:05:b8:f1:31: - c2:3b:24:fd:1a:33:74:f8:23:e0:ec:6b:19:8a:16: - c6:e3:cd:a4:cd:0b:db:b3:a4:59:60:38:88:3b:ad: - 1d:b9:c6:8c:a7:53:1b:fc:bc:d9:a4:ab:bc:dd:3c: - 61:d7:93:15:98:ee:81:bd:8f:e2:64:47:20:40:06: - 4e:d7:ac:97:e8:b9:c0:59:12:a1:49:25:23:e4:ed: - 70:34:2c:a5:b4:63:7c:f9:a3:3d:83:d1:cd:6d:24: - ac:07 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - 98:D1:F8:6E:10:EB:CF:9B:EC:60:9F:18:90:1B:A0:EB:7D:09:FD:2B - X509v3 Authority Key Identifier: - keyid:9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E - - Authority Information Access: - OCSP - URI:http://ocsp.pki.goog/gsr2 - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://crl.pki.goog/gsr2/gsr2.crl - - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.2 - CPS: https://pki.goog/repository/ - - Signature Algorithm: sha256WithRSAEncryption - 1a:80:3e:36:79:fb:f3:2e:a9:46:37:7d:5e:54:16:35:ae:c7: - 4e:08:99:fe:bd:d1:34:69:26:52:66:07:3d:0a:ba:49:cb:62: - f4:f1:1a:8e:fc:11:4f:68:96:4c:74:2b:d3:67:de:b2:a3:aa: - 05:8d:84:4d:4c:20:65:0f:a5:96:da:0d:16:f8:6c:3b:db:6f: - 04:23:88:6b:3a:6c:c1:60:bd:68:9f:71:8e:ee:2d:58:34:07: - f0:d5:54:e9:86:59:fd:7b:5e:0d:21:94:f5:8c:c9:a8:f8:d8: - f2:ad:cc:0f:1a:f3:9a:a7:a9:04:27:f9:a3:c9:b0:ff:02:78: - 6b:61:ba:c7:35:2b:e8:56:fa:4f:c3:1c:0c:ed:b6:3c:b4:4b: - ea:ed:cc:e1:3c:ec:dc:0d:8c:d6:3e:9b:ca:42:58:8b:cc:16: - 21:17:40:bc:a2:d6:66:ef:da:c4:15:5b:cd:89:aa:9b:09:26: - e7:32:d2:0d:6e:67:20:02:5b:10:b0:90:09:9c:0c:1f:9e:ad: - d8:3b:ea:a1:fc:6c:e8:10:5c:08:52:19:51:2a:71:bb:ac:7a: - b5:dd:15:ed:2b:c9:08:2a:2c:8a:b4:a6:21:ab:63:ff:d7:52: - 49:50:d0:89:b7:ad:f2:af:fb:50:ae:2f:e1:95:0d:f3:46:ad: - 9d:9c:f5:ca ------BEGIN CERTIFICATE----- -MIIESjCCAzKgAwIBAgINAeO0mqGNiqmBJWlQuDANBgkqhkiG9w0BAQsFADBMMSAw -HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFs -U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xNzA2MTUwMDAwNDJaFw0yMTEy -MTUwMDAwNDJaMEIxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVHb29nbGUgVHJ1c3Qg -U2VydmljZXMxEzARBgNVBAMTCkdUUyBDQSAxTzEwggEiMA0GCSqGSIb3DQEBAQUA -A4IBDwAwggEKAoIBAQDQGM9F1IvN05zkQO9+tN1pIRvJzzyOTHW5DzEZhD2ePCnv -UA0Qk28FgICfKqC9EksC4T2fWBYk/jCfC3R3VZMdS/dN4ZKCEPZRrAzDsiKUDzRr -mBBJ5wudgzndIMYcLe/RGGFl5yODIKgjEv/SJH/UL+dEaltN11BmsK+eQmMF++Ac -xGNhr59qM/9il71I2dN8FGfcddwuaej4bXhp0LcQBbjxMcI7JP0aM3T4I+DsaxmK -FsbjzaTNC9uzpFlgOIg7rR25xoynUxv8vNmkq7zdPGHXkxWY7oG9j+JkRyBABk7X -rJfoucBZEqFJJSPk7XA0LKW0Y3z5oz2D0c1tJKwHAgMBAAGjggEzMIIBLzAOBgNV -HQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1Ud -EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJjR+G4Q68+b7GCfGJAboOt9Cf0rMB8G -A1UdIwQYMBaAFJviB1dnHB7AagbeWbSaLd/cGYYuMDUGCCsGAQUFBwEBBCkwJzAl -BggrBgEFBQcwAYYZaHR0cDovL29jc3AucGtpLmdvb2cvZ3NyMjAyBgNVHR8EKzAp -MCegJaAjhiFodHRwOi8vY3JsLnBraS5nb29nL2dzcjIvZ3NyMi5jcmwwPwYDVR0g -BDgwNjA0BgZngQwBAgIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly9wa2kuZ29vZy9y -ZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAGoA+Nnn78y6pRjd9XlQWNa7H -TgiZ/r3RNGkmUmYHPQq6Scti9PEajvwRT2iWTHQr02fesqOqBY2ETUwgZQ+lltoN -FvhsO9tvBCOIazpswWC9aJ9xju4tWDQH8NVU6YZZ/XteDSGU9YzJqPjY8q3MDxrz -mqepBCf5o8mw/wJ4a2G6xzUr6Fb6T8McDO22PLRL6u3M4Tzs3A2M1j6bykJYi8wW -IRdAvKLWZu/axBVbzYmqmwkm5zLSDW5nIAJbELCQCZwMH56t2Dvqofxs6BBcCFIZ -USpxu6x6td0V7SvJCCosirSmIatj/9dSSVDQibet8q/7UK4v4ZUN80atnZz1yg== ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 04:00:00:00:00:01:0f:86:26:e6:0d - Signature Algorithm: sha1WithRSAEncryption - Issuer: OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign - Validity - Not Before: Dec 15 08:00:00 2006 GMT - Not After : Dec 15 08:00:00 2021 GMT - Subject: OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:a6:cf:24:0e:be:2e:6f:28:99:45:42:c4:ab:3e: - 21:54:9b:0b:d3:7f:84:70:fa:12:b3:cb:bf:87:5f: - c6:7f:86:d3:b2:30:5c:d6:fd:ad:f1:7b:dc:e5:f8: - 60:96:09:92:10:f5:d0:53:de:fb:7b:7e:73:88:ac: - 52:88:7b:4a:a6:ca:49:a6:5e:a8:a7:8c:5a:11:bc: - 7a:82:eb:be:8c:e9:b3:ac:96:25:07:97:4a:99:2a: - 07:2f:b4:1e:77:bf:8a:0f:b5:02:7c:1b:96:b8:c5: - b9:3a:2c:bc:d6:12:b9:eb:59:7d:e2:d0:06:86:5f: - 5e:49:6a:b5:39:5e:88:34:ec:bc:78:0c:08:98:84: - 6c:a8:cd:4b:b4:a0:7d:0c:79:4d:f0:b8:2d:cb:21: - ca:d5:6c:5b:7d:e1:a0:29:84:a1:f9:d3:94:49:cb: - 24:62:91:20:bc:dd:0b:d5:d9:cc:f9:ea:27:0a:2b: - 73:91:c6:9d:1b:ac:c8:cb:e8:e0:a0:f4:2f:90:8b: - 4d:fb:b0:36:1b:f6:19:7a:85:e0:6d:f2:61:13:88: - 5c:9f:e0:93:0a:51:97:8a:5a:ce:af:ab:d5:f7:aa: - 09:aa:60:bd:dc:d9:5f:df:72:a9:60:13:5e:00:01: - c9:4a:fa:3f:a4:ea:07:03:21:02:8e:82:ca:03:c2: - 9b:8f - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - 9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E - X509v3 CRL Distribution Points: - - Full Name: - URI:http://crl.globalsign.net/root-r2.crl - - X509v3 Authority Key Identifier: - keyid:9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E - - Signature Algorithm: sha1WithRSAEncryption - 99:81:53:87:1c:68:97:86:91:ec:e0:4a:b8:44:0b:ab:81:ac: - 27:4f:d6:c1:b8:1c:43:78:b3:0c:9a:fc:ea:2c:3c:6e:61:1b: - 4d:4b:29:f5:9f:05:1d:26:c1:b8:e9:83:00:62:45:b6:a9:08: - 93:b9:a9:33:4b:18:9a:c2:f8:87:88:4e:db:dd:71:34:1a:c1: - 54:da:46:3f:e0:d3:2a:ab:6d:54:22:f5:3a:62:cd:20:6f:ba: - 29:89:d7:dd:91:ee:d3:5c:a2:3e:a1:5b:41:f5:df:e5:64:43: - 2d:e9:d5:39:ab:d2:a2:df:b7:8b:d0:c0:80:19:1c:45:c0:2d: - 8c:e8:f8:2d:a4:74:56:49:c5:05:b5:4f:15:de:6e:44:78:39: - 87:a8:7e:bb:f3:79:18:91:bb:f4:6f:9d:c1:f0:8c:35:8c:5d: - 01:fb:c3:6d:b9:ef:44:6d:79:46:31:7e:0a:fe:a9:82:c1:ff: - ef:ab:6e:20:c4:50:c9:5f:9d:4d:9b:17:8c:0c:e5:01:c9:a0: - 41:6a:73:53:fa:a5:50:b4:6e:25:0f:fb:4c:18:f4:fd:52:d9: - 8e:69:b1:e8:11:0f:de:88:d8:fb:1d:49:f7:aa:de:95:cf:20: - 78:c2:60:12:db:25:40:8c:6a:fc:7e:42:38:40:64:12:f7:9e: - 81:e1:93:2e ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 -MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL -v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 -eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq -tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd -C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa -zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB -mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH -V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n -bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG -3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs -J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO -291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS -ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd -AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 -TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== ------END CERTIFICATE----- From 1bacfaf12be1f92fbd40ca744c68724e1ce2bab2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Sep 2021 21:08:59 +0200 Subject: [PATCH 0843/2612] email-backup: warn on missing sensitive information with ROS 7.x --- email-backup | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/email-backup b/email-backup index a819a4a..682cfbc 100644 --- a/email-backup +++ b/email-backup @@ -24,6 +24,7 @@ :global LogPrintExit2; :global MkDir; :global RandomDelay; +:global RequiredRouterOS; :global ScriptFromTerminal; :global SendEMail2; :global SymbolForNotification; @@ -62,6 +63,11 @@ $WaitFullyConnected; # create configuration export :if ($BackupSendExport = true) do={ + :if ([ $RequiredRouterOS $0 "7.1rc1" false ] = true) do={ + $LogPrintExit2 warning $0 ("RouterOS v7 hides sensitive information on export. " . \ + "Switch to branch 'routeros-v7' for full export.") false; + } + / export terse file=$FilePath; $WaitForFile ($FilePath . ".rsc"); :set ConfigFile ($FileName . ".rsc"); From 5391045bd5ea85f4ee61f90b5a9ddd90f0b62df9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Sep 2021 21:09:40 +0200 Subject: [PATCH 0844/2612] upload-backup: warn on missing sensitive information with ROS 7.x --- upload-backup | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/upload-backup b/upload-backup index cde847c..088c495 100644 --- a/upload-backup +++ b/upload-backup @@ -28,6 +28,7 @@ :global LogPrintExit2; :global MkDir; :global RandomDelay; +:global RequiredRouterOS; :global ScriptFromTerminal; :global SendNotification2; :global SymbolForNotification; @@ -76,6 +77,11 @@ $WaitFullyConnected; # create configuration export :if ($BackupSendExport = true) do={ + :if ([ $RequiredRouterOS $0 "7.1rc1" false ] = true) do={ + $LogPrintExit2 warning $0 ("RouterOS v7 hides sensitive information on export. " . \ + "Switch to branch 'routeros-v7' for full export.") false; + } + / export terse file=$FilePath; $WaitForFile ($FilePath . ".rsc"); From 8b05d254871f5c04184aca6c992b1871fc8f98b8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Sep 2021 16:23:53 +0200 Subject: [PATCH 0845/2612] global-functions: move $IPCalc to optional module --- global-functions | 30 ------------------------------ global-functions.d/ipcalc | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 30 deletions(-) create mode 100644 global-functions.d/ipcalc diff --git a/global-functions b/global-functions index e6b6527..1a13588 100644 --- a/global-functions +++ b/global-functions @@ -32,7 +32,6 @@ :global GetRandomNumber; :global HexToNum; :global IfThenElse; -:global IPCalc; :global LogPrintExit; :global LogPrintExit2; :global MkDir; @@ -440,35 +439,6 @@ :return $3; } -# calculate and print netmask, network, min host, max host and broadcast -:set IPCalc do={ - :local Input [ :tostr $1 ]; - :local Address [ :toip [ :pick $Input 0 [ :find $Input "/" ] ] ]; - :local Bits [ :tonum [ :pick $Input ([ :find $Input "/" ] + 1) [ :len $Input ] ] ]; - :local Mask ((255.255.255.255 << (32 - $Bits)) & 255.255.255.255); - - :local Return { - "address"=$Address; - "netmask"=$Mask; - "networkaddress"=($Address & $Mask); - "networkbits"=$Bits; - "network"=(($Address & $Mask) . "/" . $Bits); - "hostmin"=(($Address & $Mask) | 0.0.0.1); - "hostmax"=(($Address | ~$Mask) ^ 0.0.0.1); - "broadcast"=($Address | ~$Mask); - } - - :put ( \ - "Address: " . $Return->"address" . "\n\r" . \ - "Netmask: " . $Return->"netmask" . "\n\r" . \ - "Network: " . $Return->"network" . "\n\r" . \ - "HostMin: " . $Return->"hostmin" . "\n\r" . \ - "HostMax: " . $Return->"hostmax" . "\n\r" . \ - "Broadcast: " . $Return->"broadcast"); - - :return $Return; -} - # deprecated compatibility wrapper :set LogPrintExit do={ :global LogPrintExit2; diff --git a/global-functions.d/ipcalc b/global-functions.d/ipcalc new file mode 100644 index 0000000..f146fbe --- /dev/null +++ b/global-functions.d/ipcalc @@ -0,0 +1,35 @@ +#!rsc by RouterOS +# RouterOS script: global-functions.d/ipcalc +# Copyright (c) 2020-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global IPCalc; + +# calculate and print netmask, network, min host, max host and broadcast +:set IPCalc do={ + :local Input [ :tostr $1 ]; + :local Address [ :toip [ :pick $Input 0 [ :find $Input "/" ] ] ]; + :local Bits [ :tonum [ :pick $Input ([ :find $Input "/" ] + 1) [ :len $Input ] ] ]; + :local Mask ((255.255.255.255 << (32 - $Bits)) & 255.255.255.255); + + :local Return { + "address"=$Address; + "netmask"=$Mask; + "networkaddress"=($Address & $Mask); + "networkbits"=$Bits; + "network"=(($Address & $Mask) . "/" . $Bits); + "hostmin"=(($Address & $Mask) | 0.0.0.1); + "hostmax"=(($Address | ~$Mask) ^ 0.0.0.1); + "broadcast"=($Address | ~$Mask); + } + + :put ( \ + "Address: " . $Return->"address" . "\n\r" . \ + "Netmask: " . $Return->"netmask" . "\n\r" . \ + "Network: " . $Return->"network" . "\n\r" . \ + "HostMin: " . $Return->"hostmin" . "\n\r" . \ + "HostMax: " . $Return->"hostmax" . "\n\r" . \ + "Broadcast: " . $Return->"broadcast"); + + :return $Return; +} From 012db05a9350311ddac85a95e487d4fc0ebabcb6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Sep 2021 16:32:59 +0200 Subject: [PATCH 0846/2612] global-functions: move $ScriptRunOnce to optional module --- global-config | 2 ++ global-functions | 41 ---------------------------- global-functions.d/scriptrunonce | 46 ++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 41 deletions(-) create mode 100644 global-functions.d/scriptrunonce diff --git a/global-config b/global-config index 98c65d9..6b2cd84 100644 --- a/global-config +++ b/global-config @@ -168,6 +168,8 @@ #:global ScriptUpdatesUrlSuffix "\?h=next"; # Use this for defaults with $ScriptRunOnce +# Install module with: +# $ScriptInstallUpdate global-functions.d/scriptrunonce :global ScriptRunOnceBaseUrl ""; :global ScriptRunOnceUrlSuffix ""; diff --git a/global-functions b/global-functions index 1a13588..e3340eb 100644 --- a/global-functions +++ b/global-functions @@ -43,7 +43,6 @@ :global ScriptFromTerminal; :global ScriptInstallUpdate; :global ScriptLock; -:global ScriptRunOnce; :global SendEMail; :global SendEMail2; :global SendNotification; @@ -1000,46 +999,6 @@ :return true; } -# fetch and run script(s) once -:set ScriptRunOnce do={ - :local Scripts [ :toarray $1 ]; - - :global ScriptRunOnceBaseUrl; - :global ScriptRunOnceUrlSuffix; - - :global LogPrintExit2; - :global ValidateSyntax; - - :foreach Script in=$Scripts do={ - :if (!($Script ~ "^(ftp|https\?|sftp)://")) do={ - :if ([ :len $ScriptRunOnceBaseUrl ] = 0) do={ - $LogPrintExit2 warning $0 ("Script '" . $Script . "' is not an url and base url is not available.") true; - } - :set Script ($ScriptRunOnceBaseUrl . $Script . $ScriptRunOnceUrlSuffix); - } - - :local Source; - :do { - :set Source ([ / tool fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data"); - } on-error={ - $LogPrintExit2 warning $0 ("Failed fetching script '" . $Script . "'!") false; - } - - :if ([ :len $Source ] > 0) do={ - :if ([ $ValidateSyntax $Source ] = true) do={ - :do { - $LogPrintExit2 info $0 ("Running script '" . $Script . "' now.") false; - [ :parse $Source ]; - } on-error={ - $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed to run!") false; - } - } else={ - $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed syntax validation!") false; - } - } - } -} - # send notification via e-mail - expects at lease two string arguments :set SendEMail do={ :global SendEMail2; diff --git a/global-functions.d/scriptrunonce b/global-functions.d/scriptrunonce new file mode 100644 index 0000000..ce9425b --- /dev/null +++ b/global-functions.d/scriptrunonce @@ -0,0 +1,46 @@ +#!rsc by RouterOS +# RouterOS script: global-functions.d/scriptrunonece +# Copyright (c) 2020-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global ScriptRunOnce; + +# fetch and run script(s) once +:set ScriptRunOnce do={ + :local Scripts [ :toarray $1 ]; + + :global ScriptRunOnceBaseUrl; + :global ScriptRunOnceUrlSuffix; + + :global LogPrintExit2; + :global ValidateSyntax; + + :foreach Script in=$Scripts do={ + :if (!($Script ~ "^(ftp|https\?|sftp)://")) do={ + :if ([ :len $ScriptRunOnceBaseUrl ] = 0) do={ + $LogPrintExit2 warning $0 ("Script '" . $Script . "' is not an url and base url is not available.") true; + } + :set Script ($ScriptRunOnceBaseUrl . $Script . $ScriptRunOnceUrlSuffix); + } + + :local Source; + :do { + :set Source ([ / tool fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data"); + } on-error={ + $LogPrintExit2 warning $0 ("Failed fetching script '" . $Script . "'!") false; + } + + :if ([ :len $Source ] > 0) do={ + :if ([ $ValidateSyntax $Source ] = true) do={ + :do { + $LogPrintExit2 info $0 ("Running script '" . $Script . "' now.") false; + [ :parse $Source ]; + } on-error={ + $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed to run!") false; + } + } else={ + $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed syntax validation!") false; + } + } + } +} From ce78d7d9e9ad1c2ab0e5ffab716b40975c6bd0eb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 20 Sep 2021 15:24:52 +0200 Subject: [PATCH 0847/2612] global-functions: notify about move of $IPCalc and $ScriptRunOnce to modules Just install with... $ScriptInstallUpdate global-functions.d/ipcalc ... and/or... $ScriptInstallUpdate global-functions.d/scriptrunonce ... and use the functions as before. --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 6b2cd84..cc0e389 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 62; +:global GlobalConfigVersion 63; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index f4ea04d..854d4f8 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 62; +:global GlobalConfigVersion 63; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 23a1dac..7504693 100644 --- a/global-config.changes +++ b/global-config.changes @@ -66,6 +66,7 @@ 60="Implemented a pre-down hook in 'netwatch-notify' that fires at two thirds of failed checks."; 61="Finally removed old scripts."; 62="Added '\$ScriptRunOnce' to run a script from URL once without installation, intended to aid configuration management and the like."; + 63="Moved optional functions '\$IPCalc' and '\$ScriptRunOnce' to modules."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index e3340eb..34be4fd 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 62; +:global ExpectedConfigVersion 63; # global variables not to be changed by user :global GlobalFunctionsReady false; From 9295d06fe2fce058b6b21d69ea6eac8282d23337 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 20 Sep 2021 13:19:34 +0200 Subject: [PATCH 0848/2612] global-functions.d/inspectvar: add $InspectVar... to inspect variables. This is useful for variables with (nested) arrays, for example inspecting $NetwatchNotify (from netwatch-notify): [admin@Mikrotik] > $InspectVar $NetwatchNotify -type-> array -key-> quad-one -type-> array -key-> count -type-> num -value-> 0 -key-> notified -type-> bool -value-> false -key-> parent -type-> nothing -key-> resolve-failed -type-> nothing -key-> since -type-> nothing -key-> example.com -type-> array -key-> count -type-> num -value-> 0 -key-> notified -type-> bool -value-> false -key-> parent -type-> str -value-> quad-one -key-> resolve-failed -type-> nothing -key-> since -type-> nothing --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- global-functions.d/inspectvar | 40 +++++++++++++++++++++++++++++++++++ 5 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 global-functions.d/inspectvar diff --git a/global-config b/global-config index cc0e389..bf3b0e4 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 63; +:global GlobalConfigVersion 64; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 854d4f8..78d34b0 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 63; +:global GlobalConfigVersion 64; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 7504693..1ef2792 100644 --- a/global-config.changes +++ b/global-config.changes @@ -67,6 +67,7 @@ 61="Finally removed old scripts."; 62="Added '\$ScriptRunOnce' to run a script from URL once without installation, intended to aid configuration management and the like."; 63="Moved optional functions '\$IPCalc' and '\$ScriptRunOnce' to modules."; + 64="Implemented '\$InspectVar' in module to inspect variables."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 34be4fd..4443431 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 63; +:global ExpectedConfigVersion 64; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/global-functions.d/inspectvar b/global-functions.d/inspectvar new file mode 100644 index 0000000..15da04a --- /dev/null +++ b/global-functions.d/inspectvar @@ -0,0 +1,40 @@ +#!rsc by RouterOS +# RouterOS script: global-functions.d/inspectvar +# Copyright (c) 2020-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global InspectVar; + +# inspect variable +:set InspectVar do={ + :local Input $1; + :local Level (0 + [ :tonum $2 ]); + + :global InspectVar; + + :local PutIndent do={ + :local Prefix [ :tostr $1 ]; + :local Value [ :tostr $2 ]; + :local Level [ :tonum $3 ]; + + :local Indent ""; + :for I from=1 to=$Level step=1 do={ + :set Indent ($Indent . " "); + } + :put ($Indent . "-" . $Prefix . "-> " . $Value); + } + + :local TypeOf [ :typeof $Input ]; + $PutIndent "type" $TypeOf $Level; + + :if ($TypeOf = "array") do={ + :foreach Key,Value in=$Input do={ + $PutIndent "key" $Key ($Level + 1); + $InspectVar $Value ($Level + 2); + } + } else={ + :if ($TypeOf != "nothing") do={ + $PutIndent "value" $Input $Level; + } + } +} From 7952a6afac12028514584c6c0a81bffd481a9ae3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 20 Sep 2021 22:06:40 +0200 Subject: [PATCH 0849/2612] hotspot-to-wpa-cleanup: match dhcp server name ... as we do not want the hotspot's lease to become static. --- hotspot-to-wpa-cleanup | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hotspot-to-wpa-cleanup b/hotspot-to-wpa-cleanup index 1321f83..d9bd3ec 100644 --- a/hotspot-to-wpa-cleanup +++ b/hotspot-to-wpa-cleanup @@ -19,7 +19,8 @@ $ScriptLock $0 false 10; :foreach Client in=[ / caps-man registration-table find where comment~"^hotspot-to-wpa:" ] do={ :local ClientVal [ / caps-man registration-table get $Client ]; - :local Lease [ / ip dhcp-server lease find where mac-address=($ClientVal->"mac-address") dynamic ]; + :local Lease [ / ip dhcp-server lease find where server~"wpa" dynamic \ + mac-address=($ClientVal->"mac-address") ]; :if ([ :len $Lease ] > 0) do={ $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ " connected to WPA, making lease static.") false; @@ -31,8 +32,8 @@ $ScriptLock $0 false 10; :foreach Client in=[ / caps-man access-list find where comment~"^hotspot-to-wpa:" and \ !(comment~[ / system clock get date ]) ] do={ :local ClientVal [ / caps-man access-list get $Client ]; - :if ([ :len [ / ip dhcp-server lease find where mac-address=($ClientVal->"mac-address") \ - !dynamic ] ] = 0) do={ + :if ([ :len [ / ip dhcp-server lease find where server~"wpa" !dynamic \ + mac-address=($ClientVal->"mac-address") ] ] = 0) do={ $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ " did not connect to WPA, removing from access list.") false; / caps-man access-list remove $Client; From 4bdfcf16435c0af723433df78192465bec9682bf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Sep 2021 13:58:09 +0200 Subject: [PATCH 0850/2612] README: use real screenshots... ... and make sure copy-and-paste with code does not fail. Also end all commands with a semicolon for Github copy button. --- README.d/01-download-certs.png | Bin 0 -> 4827 bytes README.d/02-import-certs.png | Bin 0 -> 4824 bytes README.d/03-check-certs.png | Bin 0 -> 8366 bytes README.d/04-import-scripts.png | Bin 0 -> 5446 bytes README.d/05-edit-global-config-overlay.png | Bin 0 -> 12301 bytes README.d/06-run-and-schedule-scripts.png | Bin 0 -> 5416 bytes README.d/07-schedule-update.png | Bin 0 -> 3654 bytes README.d/08-update-scripts.png | Bin 0 -> 2985 bytes README.d/09-install-scripts.png | Bin 0 -> 4320 bytes README.d/10-schedule-script.png | Bin 0 -> 3292 bytes README.d/11-setup-lease-script.png | Bin 0 -> 7041 bytes README.md | 68 +++++++++++++-------- 12 files changed, 41 insertions(+), 27 deletions(-) create mode 100644 README.d/01-download-certs.png create mode 100644 README.d/02-import-certs.png create mode 100644 README.d/03-check-certs.png create mode 100644 README.d/04-import-scripts.png create mode 100644 README.d/05-edit-global-config-overlay.png create mode 100644 README.d/06-run-and-schedule-scripts.png create mode 100644 README.d/07-schedule-update.png create mode 100644 README.d/08-update-scripts.png create mode 100644 README.d/09-install-scripts.png create mode 100644 README.d/10-schedule-script.png create mode 100644 README.d/11-setup-lease-script.png diff --git a/README.d/01-download-certs.png b/README.d/01-download-certs.png new file mode 100644 index 0000000000000000000000000000000000000000..d33040b5f4132aea24198d8ae3677968a66fdb28 GIT binary patch literal 4827 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 B4nhC` literal 0 HcmV?d00001 diff --git a/README.d/02-import-certs.png b/README.d/02-import-certs.png new file mode 100644 index 0000000000000000000000000000000000000000..09bef7aef91bb3cc0fe1a5bad730da8570d33749 GIT binary patch literal 4824 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 literal 0 HcmV?d00001 diff --git a/README.d/04-import-scripts.png b/README.d/04-import-scripts.png new file mode 100644 index 0000000000000000000000000000000000000000..0db8c4d13e03bdedd9665fab87cfb1163f4b1bee GIT binary patch literal 5446 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 SR|MJs0000 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 literal 0 HcmV?d00001 diff --git a/README.d/09-install-scripts.png b/README.d/09-install-scripts.png new file mode 100644 index 0000000000000000000000000000000000000000..6adee16f5ec7ce9e228ac5d86c06336db1fa3d05 GIT binary patch literal 4320 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 O0000 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 aAb$a23jzid6)w*J0000 zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3&uk}aujh5s`O4*?`VFdRS-;Td@N{*>p@-M2e# zIBZw->8je5I}@a(^`O%Ium61MKlrF6ORCLApS@>3>a0^1-;Dgn$Nl+r=KSLO%D?jS zwetI_lK%3GU*8oz|Ma@NpT8AeQNHSrAAdhj<3{?Y8};8`%Rjwd+P}Q6zaKAuS<&df zpDcfV-DZCI&mZHDfA9Ht>^a5Nb=6LN`p-@M+T!;e7j6op-`hH$#=pk*_I*x1M_&1) zQnTliH=n1>B1Q8nwRlvmSB$SBNA!DbsL7P0S&P=BRcm=-I@NWk=#i_+ ztMYp-<$Lb@9(T&%!Ctsh3O6gf+@efXe>9WToq*=Y;fiM;}*M>Kd`0gYqWA<<7@r#X7isnphP^ov6!NC zAorrJ^pZ`)N}-N}{w!85nyPGCP+Ajbl~PqZ%^4EU<~>%vYo*DLml+`%(X^}4nyHIk z)!J%L)#?C4t7)sPwcf0aHrwjjYj3@G>oJSV)T%Y>W;Sfv8anD|qYoQn%(2pxsmyAd zecBvz&b4^x;?9eAud#Sx%hp|Y+kM*}d+v3B -Ke(a1h&q^+?UcGsD^WoFiEf*-= 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 literal 0 HcmV?d00001 diff --git a/README.md b/README.md index c5c0ba5..95ef750 100644 --- a/README.md +++ b/README.md @@ -50,11 +50,9 @@ download the certificates. If you intend to download the scripts from a different location (for example from github.com) install the corresponding certificate chain. - [admin@MikroTik] > / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem" - status: finished - downloaded: 4KiBC-z pause] - total: 4KiB - duration: 1s + / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem"; + +![screenshot: download certs](README.d/01-download-certs.png) Note that the commands above do *not* verify server certificate, so if you want to be safe download with your workstations's browser and transfer the @@ -65,49 +63,59 @@ files to your MikroTik device. Then we import the certificates. - [admin@MikroTik] > / certificate import file-name=letsencrypt-R3.pem passphrase="" - certificates-imported: 2 - private-keys-imported: 0 - files-imported: 1 - decryption-failures: 0 - keys-with-no-certificate: 0 + / certificate import file-name=letsencrypt-R3.pem passphrase=""; + +![screenshot: import certs](README.d/02-import-certs.png) For basic verification we rename the certificates and print their count. Make sure the certificate count is **two**. - [admin@MikroTik] > / certificate set name="R3" [ find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" ] - [admin@MikroTik] > / certificate set name="ISRG-Root-X1" [ find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ] - [admin@MikroTik] > / certificate print count-only where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" - 2 + / certificate set name="R3" [ find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" ]; + / certificate set name="ISRG-Root-X1" [ find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ]; + / certificate print count-only where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6"; + +![screenshot: check certs](README.d/03-check-certs.png) Always make sure there are no certificates installed you do not know or want! Now let's download the main scripts and add them in configuration on the fly. - [admin@MikroTik] > :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } + :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); }; + +![screenshot: import scripts](README.d/04-import-scripts.png) The configuration needs to be tweaked for your needs. Edit `global-config-overlay`, copy configuration from [`global-config`](global-config) (the one without `-overlay`). +Save changes and exit with `Ctrl-o`. - [admin@MikroTik] > / system script edit global-config-overlay source + / system script edit global-config-overlay source; + +![screenshot: edit global-config-overlay](README.d/05-edit-global-config-overlay.png) And finally load configuration and functions and add the scheduler. - [admin@MikroTik] > / system script { run global-config; run global-config-overlay; run global-functions; } - [admin@MikroTik] > / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }" + / system script { run global-config; run global-config-overlay; run global-functions; }; + / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }"; + +![screenshot: run and schedule scripts](README.d/06-run-and-schedule-scripts.png) The last step is optional: Add this scheduler **only** if you want the scripts to be updated automatically! - [admin@MikroTik] > / system scheduler add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;" + / system scheduler add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; + +![screenshot: schedule update](README.d/07-schedule-update.png) Updating scripts ---------------- -To update existing scripts just run function `$ScriptInstallUpdate`. +To update existing scripts just run function `$ScriptInstallUpdate`. If +everything is up-to-date it will not produce any output. - [admin@MikroTik] > $ScriptInstallUpdate + $ScriptInstallUpdate; + +![screenshot: update scripts](README.d/08-update-scripts.png) Adding a script --------------- @@ -115,7 +123,9 @@ Adding a script To add a script from the repository run function `$ScriptInstallUpdate` with a comma separated list of script names. - [admin@MikroTik] > $ScriptInstallUpdate check-certificates,check-routeros-update + $ScriptInstallUpdate check-certificates,check-routeros-update; + +![screenshot: install scripts](README.d/09-install-scripts.png) Scheduler and events -------------------- @@ -125,15 +135,19 @@ Most scripts are designed to run regularly from added `check-routeros-update`, so let's run it every hour to make sure not to miss an update. - [admin@MikroTik] > / system scheduler add name="check-routeros-update" interval=1h on-event="/ system script run check-routeros-update;" + / system scheduler add name="check-routeros-update" interval=1h on-event="/ system script run check-routeros-update;"; + +![screenshot: schedule script](README.d/10-schedule-script.png) Some events can run a script. If you want your DHCP hostnames to be available in DNS use `dhcp-to-dns` with the events from dhcp server. For a regular cleanup add a scheduler entry. - [admin@MikroTik] > $ScriptInstallUpdate dhcp-to-dns,lease-script - [admin@MikroTik] > / ip dhcp-server set lease-script=lease-script [ find ] - [admin@MikroTik] > / system scheduler add name="dhcp-to-dns" interval=5m on-event="/ system script run dhcp-to-dns;" + $ScriptInstallUpdate dhcp-to-dns,lease-script; + / ip dhcp-server set lease-script=lease-script [ find ]; + / system scheduler add name="dhcp-to-dns" interval=5m on-event="/ system script run dhcp-to-dns;"; + +![screenshot: setup lease script](README.d/11-setup-lease-script.png) There's much more to explore... Have fun! From 0d09121d6890e6b5c92dc404487b6f733c5ca8af Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Sep 2021 21:53:51 +0200 Subject: [PATCH 0851/2612] README: add a note about date and time --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 95ef750..ca3554f 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,10 @@ sure the certificate count is **two**. Always make sure there are no certificates installed you do not know or want! +All following commands will verify the server certificate. For validity the +certificate's lifetime is checked with local time, so make sure the device's +date and time is set correctly! + Now let's download the main scripts and add them in configuration on the fly. :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); }; From 72d50aa13ffb4b80859b6ef191ddaec7541a21ad Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Sep 2021 10:33:21 +0200 Subject: [PATCH 0852/2612] doc/accesslist-duplicates: use real screenshot --- doc/accesslist-duplicates.d/01-example.png | Bin 0 -> 13646 bytes doc/accesslist-duplicates.md | 11 ++--------- 2 files changed, 2 insertions(+), 9 deletions(-) create mode 100644 doc/accesslist-duplicates.d/01-example.png diff --git a/doc/accesslist-duplicates.d/01-example.png b/doc/accesslist-duplicates.d/01-example.png new file mode 100644 index 0000000000000000000000000000000000000000..0922984c230e4a42b896749a14cc412ecd348dc3 GIT binary patch literal 13646 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 UaOZsXUm#XNR#m1}$}H@E0my`I-~a#s literal 0 HcmV?d00001 diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index 0f08284..64a5fea 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -31,16 +31,9 @@ Usage and invocation Run this script from a terminal: - [admin@kalyke] > / system script run accesslist-duplicates.local - Flags: X - disabled - 0 ;;; First entry with identical mac address... - mac-address=00:11:22:33:44:55 interface=any signal-range=-120..120 allow-signal-out-of-range=10s authentication=yes forwarding=yes ap-tx-limit=0 client-tx-limit=0 private-algo=none private-key="" private-pre-shared-key="" management-protection-key="" vlan-mode=default vlan-id=1 + / system script run accesslist-duplicates.local; - 1 ;;; Second entry with identical mac address... - mac-address=00:11:22:33:44:55 interface=any signal-range=-120..120 allow-signal-out-of-range=10s authentication=yes forwarding=yes ap-tx-limit=0 client-tx-limit=0 private-algo=none private-key="" private-pre-shared-key="" management-protection-key="" vlan-mode=default vlan-id=1 - - Numeric id to remove, any key to skip! - Removing numeric id 1... +![screenshot: example](accesslist-duplicates.d/01-example.png) See also -------- From 4ebe2628b0819000fe359afbb7d17a883148eabd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 28 Sep 2021 16:26:26 +0200 Subject: [PATCH 0853/2612] global-functions.d/notification-telegram: fix calculation on cut off --- global-functions.d/notification-telegram | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions.d/notification-telegram b/global-functions.d/notification-telegram index d8fe448..faf02d7 100644 --- a/global-functions.d/notification-telegram +++ b/global-functions.d/notification-telegram @@ -103,7 +103,8 @@ :local LenSubject [ :len $Text ]; :local LenMessage [ :len ($Notification->"message") ]; :local LenLink [ :len ($Notification->"link") ]; - :if ($LenSubject + $LenMessage + $LenLink > 3968) do={ + :local LenSum ($LenSubject + $LenMessage + $LenLink); + :if ($LenSum > 3968) do={ :set Text ($Text . [ $EscapeMD ([ :pick ($Notification->"message") 0 (3840 - $LenSubject - $LenLink) ] . "...") "body" ]); :set Truncated true; } else={ @@ -115,7 +116,7 @@ :if ($Truncated = true) do={ :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ [ $EscapeMD ("The Telegram message was too long and has been truncated, cut off " . \ - (($LenText - [ :len $Text ]) * 100 / $LenText) . "%!") "plain" ]); + (($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%!") "plain" ]); } :set Text [ $UrlEncode $Text ]; :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; From f780b205a9b1dfc7b3229916309661c7c115d965 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 1 Oct 2021 09:00:36 +0200 Subject: [PATCH 0854/2612] global-functions: $DeviceInfo: do not fail on non-RouterBoard with ROS 7.x --- global-functions | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 4443431..22af3e2 100644 --- a/global-functions +++ b/global-functions @@ -198,7 +198,10 @@ :global IfThenElse; :local Resource [ / system resource get ]; - :local RouterBoard [ / system routerboard get ]; + :local RouterBoard; + :do { + :set RouterBoard [ / system routerboard get ]; + } on-error={ } :local Update [ / system package update get ]; :return ( \ From 99a95d310e87af7e498eac886993f5f1a8f9f174 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 1 Oct 2021 20:39:59 +0200 Subject: [PATCH 0855/2612] global-functions: $NotificationFunctions->"email": check for valid settings No need to queue mails if 'address' and 'from' are not specified... --- global-functions | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 22af3e2..80d6e6a 100644 --- a/global-functions +++ b/global-functions @@ -543,7 +543,8 @@ :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; - :if ([ :len $To ] = 0) do={ + :local EMailSettings [ / tool e-mail get ]; + :if ([ :len $To ] = 0 || ($EMailSettings->"address") = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={ :return false; } From 8a941fcd8d604a0add5b2b5f237b67334553d439 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 3 Nov 2021 15:21:01 +0100 Subject: [PATCH 0856/2612] hotspot-to-wpa: drop support for tx limits ... if you need to limit bandwidth use queues instead. --- hotspot-to-wpa | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/hotspot-to-wpa b/hotspot-to-wpa index 68f887f..dbb1f49 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -27,14 +27,5 @@ $LogPrintExit2 info $0 ("Adding/updating accesslist entry for mac address " . $M " (user " . $UserName . ").") false; / caps-man access-list remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; - -:local Limits [ / caps-man access-list get $PlaceBefore ]; -:if (($Limits->"ap-tx-limit") > 0 && ($Limits->"client-tx-limit") > 0) do={ - / caps-man access-list add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - mac-address=$MacAddress private-passphrase=$PassWord ssid-regexp="-wpa\$" \ - ap-tx-limit=($Limits->"ap-tx-limit") client-tx-limit=($Limits->"client-tx-limit") \ - place-before=$PlaceBefore; -} else={ - / caps-man access-list add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - mac-address=$MacAddress private-passphrase=$PassWord ssid-regexp="-wpa\$" place-before=$PlaceBefore; -} +/ caps-man access-list add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + mac-address=$MacAddress private-passphrase=$PassWord ssid-regexp="-wpa\$" place-before=$PlaceBefore; From a9f81c7a14a5001bcdb5516c369886c41e42dc22 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Nov 2021 22:42:54 +0100 Subject: [PATCH 0857/2612] doc: move notification images to script-specific directories --- .../notification.svg} | 0 doc/check-certificates.md | 2 +- .../notification-01-voltage.svg} | 0 .../notification-02-temperature-high.svg} | 0 .../notification-03-temperature-ok.svg} | 0 .../notification-04-psu-fail.svg} | 0 .../notification-05-psu-ok.svg} | 0 doc/check-health.md | 10 +++++----- .../notification.svg} | 0 doc/check-lte-firmware-upgrade.md | 2 +- .../notification.svg} | 0 doc/check-routeros-update.md | 2 +- .../notification.svg} | 0 doc/cloud-backup.md | 2 +- .../notification.svg} | 0 doc/collect-wireless-mac.md | 2 +- .../daily-psk.svg => daily-psk.d/notification.svg} | 0 doc/daily-psk.md | 2 +- .../log-forward.svg => log-forward.d/notification.svg} | 0 doc/log-forward.md | 2 +- .../notification-01-down.svg} | 0 .../notification-02-up.svg} | 0 doc/netwatch-notify.md | 4 ++-- .../sms-forward.svg => sms-forward.d/notification.svg} | 0 doc/sms-forward.md | 2 +- .../notification.svg} | 0 doc/upload-backup.md | 2 +- 27 files changed, 16 insertions(+), 16 deletions(-) rename doc/{notifications/check-certificates.svg => check-certificates.d/notification.svg} (100%) rename doc/{notifications/check-health-voltage.svg => check-health.d/notification-01-voltage.svg} (100%) rename doc/{notifications/check-health-temperature-high.svg => check-health.d/notification-02-temperature-high.svg} (100%) rename doc/{notifications/check-health-temperature-ok.svg => check-health.d/notification-03-temperature-ok.svg} (100%) rename doc/{notifications/check-health-psu-fail.svg => check-health.d/notification-04-psu-fail.svg} (100%) rename doc/{notifications/check-health-psu-ok.svg => check-health.d/notification-05-psu-ok.svg} (100%) rename doc/{notifications/check-lte-firmware-upgrade.svg => check-lte-firmware-upgrade.d/notification.svg} (100%) rename doc/{notifications/check-routeros-update.svg => check-routeros-update.d/notification.svg} (100%) rename doc/{notifications/cloud-backup.svg => cloud-backup.d/notification.svg} (100%) rename doc/{notifications/collect-wireless-mac.svg => collect-wireless-mac.d/notification.svg} (100%) rename doc/{notifications/daily-psk.svg => daily-psk.d/notification.svg} (100%) rename doc/{notifications/log-forward.svg => log-forward.d/notification.svg} (100%) rename doc/{notifications/netwatch-notify-down.svg => netwatch-notify.d/notification-01-down.svg} (100%) rename doc/{notifications/netwatch-notify-up.svg => netwatch-notify.d/notification-02-up.svg} (100%) rename doc/{notifications/sms-forward.svg => sms-forward.d/notification.svg} (100%) rename doc/{notifications/upload-backup.svg => upload-backup.d/notification.svg} (100%) diff --git a/doc/notifications/check-certificates.svg b/doc/check-certificates.d/notification.svg similarity index 100% rename from doc/notifications/check-certificates.svg rename to doc/check-certificates.d/notification.svg diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 9059034..44bee7a 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -14,7 +14,7 @@ certificates that are still about to expire. ### Sample notification -![check-certificates notification](notifications/check-certificates.svg) +![check-certificates notification](check-certificates.d/notification.svg) Requirements and installation ----------------------------- diff --git a/doc/notifications/check-health-voltage.svg b/doc/check-health.d/notification-01-voltage.svg similarity index 100% rename from doc/notifications/check-health-voltage.svg rename to doc/check-health.d/notification-01-voltage.svg diff --git a/doc/notifications/check-health-temperature-high.svg b/doc/check-health.d/notification-02-temperature-high.svg similarity index 100% rename from doc/notifications/check-health-temperature-high.svg rename to doc/check-health.d/notification-02-temperature-high.svg diff --git a/doc/notifications/check-health-temperature-ok.svg b/doc/check-health.d/notification-03-temperature-ok.svg similarity index 100% rename from doc/notifications/check-health-temperature-ok.svg rename to doc/check-health.d/notification-03-temperature-ok.svg diff --git a/doc/notifications/check-health-psu-fail.svg b/doc/check-health.d/notification-04-psu-fail.svg similarity index 100% rename from doc/notifications/check-health-psu-fail.svg rename to doc/check-health.d/notification-04-psu-fail.svg diff --git a/doc/notifications/check-health-psu-ok.svg b/doc/check-health.d/notification-05-psu-ok.svg similarity index 100% rename from doc/notifications/check-health-psu-ok.svg rename to doc/check-health.d/notification-05-psu-ok.svg diff --git a/doc/check-health.md b/doc/check-health.md index 7accc62..9e9e501 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -27,17 +27,17 @@ hardware supports: #### Voltage -![check-health notification voltage](notifications/check-health-voltage.svg) +![check-health notification voltage](check-health.d/notification-01-voltage.svg) #### Temperature -![check-health notification](notifications/check-health-temperature-high.svg) -![check-health notification](notifications/check-health-temperature-ok.svg) +![check-health notification](check-health.d/notification-02-temperature-high.svg) +![check-health notification](check-health.d/notification-03-temperature-ok.svg) #### PSU state -![check-health notification](notifications/check-health-psu-fail.svg) -![check-health notification](notifications/check-health-psu-ok.svg) +![check-health notification](check-health.d/notification-04-psu-fail.svg) +![check-health notification](check-health.d/notification-05-psu-ok.svg) Requirements and installation ----------------------------- diff --git a/doc/notifications/check-lte-firmware-upgrade.svg b/doc/check-lte-firmware-upgrade.d/notification.svg similarity index 100% rename from doc/notifications/check-lte-firmware-upgrade.svg rename to doc/check-lte-firmware-upgrade.d/notification.svg diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index 55d5cf8..ef68bcb 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -19,7 +19,7 @@ upgrades. Currently supported LTE hardware: ### Sample notification -![check-lte-firmware-upgrade notification](notifications/check-lte-firmware-upgrade.svg) +![check-lte-firmware-upgrade notification](check-lte-firmware-upgrade.d/notification.svg) Requirements and installation ----------------------------- diff --git a/doc/notifications/check-routeros-update.svg b/doc/check-routeros-update.d/notification.svg similarity index 100% rename from doc/notifications/check-routeros-update.svg rename to doc/check-routeros-update.d/notification.svg diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 5ebdede..9385341 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -21,7 +21,7 @@ automatically is supported. ### Sample notification -![check-routeros-update notification](notifications/check-routeros-update.svg) +![check-routeros-update notification](check-routeros-update.d/notification.svg) Requirements and installation ----------------------------- diff --git a/doc/notifications/cloud-backup.svg b/doc/cloud-backup.d/notification.svg similarity index 100% rename from doc/notifications/cloud-backup.svg rename to doc/cloud-backup.d/notification.svg diff --git a/doc/cloud-backup.md b/doc/cloud-backup.md index 182dd01..7522bc1 100644 --- a/doc/cloud-backup.md +++ b/doc/cloud-backup.md @@ -13,7 +13,7 @@ This script uploads [binary backup to Mikrotik cloud](https://wiki.mikrotik.com/ ### Sample notification -![cloud-backup notification](notifications/cloud-backup.svg) +![cloud-backup notification](cloud-backup.d/notification.svg) Requirements and installation ----------------------------- diff --git a/doc/notifications/collect-wireless-mac.svg b/doc/collect-wireless-mac.d/notification.svg similarity index 100% rename from doc/notifications/collect-wireless-mac.svg rename to doc/collect-wireless-mac.d/notification.svg diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 7d3c815..380c89f 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -17,7 +17,7 @@ and modify it to your needs. ### Sample notification -![collect-wireless-mac notification](notifications/collect-wireless-mac.svg) +![collect-wireless-mac notification](collect-wireless-mac.d/notification.svg) Requirements and installation ----------------------------- diff --git a/doc/notifications/daily-psk.svg b/doc/daily-psk.d/notification.svg similarity index 100% rename from doc/notifications/daily-psk.svg rename to doc/daily-psk.d/notification.svg diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 1d41f76..105737a 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -14,7 +14,7 @@ passphrase to a pseudo-random string daily. ### Sample notification -![daily-psk notification](notifications/daily-psk.svg) +![daily-psk notification](daily-psk.d/notification.svg) Requirements and installation ----------------------------- diff --git a/doc/notifications/log-forward.svg b/doc/log-forward.d/notification.svg similarity index 100% rename from doc/notifications/log-forward.svg rename to doc/log-forward.d/notification.svg diff --git a/doc/log-forward.md b/doc/log-forward.md index cdcd479..e3603b5 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -22,7 +22,7 @@ and forwards them via notification. ### Sample notification -![log-forward notification](notifications/log-forward.svg) +![log-forward notification](log-forward.d/notification.svg) Requirements and installation ----------------------------- diff --git a/doc/notifications/netwatch-notify-down.svg b/doc/netwatch-notify.d/notification-01-down.svg similarity index 100% rename from doc/notifications/netwatch-notify-down.svg rename to doc/netwatch-notify.d/notification-01-down.svg diff --git a/doc/notifications/netwatch-notify-up.svg b/doc/netwatch-notify.d/notification-02-up.svg similarity index 100% rename from doc/notifications/netwatch-notify-up.svg rename to doc/netwatch-notify.d/notification-02-up.svg diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 81e28b0..7fd47d4 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -17,8 +17,8 @@ optional parent host is not down to avoid false alerts. ### Sample notifications -![netwatch-notify notification down](notifications/netwatch-notify-down.svg) -![netwatch-notify notification up](notifications/netwatch-notify-up.svg) +![netwatch-notify notification down](netwatch-notify.d/notification-01-down.svg) +![netwatch-notify notification up](netwatch-notify.d/notification-02-up.svg) Requirements and installation ----------------------------- diff --git a/doc/notifications/sms-forward.svg b/doc/sms-forward.d/notification.svg similarity index 100% rename from doc/notifications/sms-forward.svg rename to doc/sms-forward.d/notification.svg diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 9290b90..873ccac 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -15,7 +15,7 @@ A broadband interface with SMS support is required. ### Sample notification -![sms-forward notification](notifications/sms-forward.svg) +![sms-forward notification](sms-forward.d/notification.svg) Requirements and installation ----------------------------- diff --git a/doc/notifications/upload-backup.svg b/doc/upload-backup.d/notification.svg similarity index 100% rename from doc/notifications/upload-backup.svg rename to doc/upload-backup.d/notification.svg diff --git a/doc/upload-backup.md b/doc/upload-backup.md index f7d7c27..9566853 100644 --- a/doc/upload-backup.md +++ b/doc/upload-backup.md @@ -14,7 +14,7 @@ configuration export (`/ export terse`) to external server. ### Sample notification -![upload-backup notification](notifications/upload-backup.svg) +![upload-backup notification](upload-backup.d/notification.svg) Requirements and installation ----------------------------- From b6215ba95899328bd13fabbf6488b602763b9352 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Nov 2021 14:44:26 +0100 Subject: [PATCH 0858/2612] add global-functions.d/bridge-port-vlan --- README.md | 5 ++ doc/bridge-port.md | 5 ++ doc/global-functions.d/bridge-port-vlan.md | 83 ++++++++++++++++++++++ global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- global-functions.d/bridge-port-vlan | 62 ++++++++++++++++ 8 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 doc/global-functions.d/bridge-port-vlan.md create mode 100644 global-functions.d/bridge-port-vlan diff --git a/README.md b/README.md index ca3554f..1787ab5 100644 --- a/README.md +++ b/README.md @@ -201,6 +201,11 @@ Available Scripts [comment]: # (* learn-mac-based-vlan) [comment]: # (* manage-umts) +Available modules +----------------- + +* [Manage VLANs on bridge ports](doc/global-functions.d/bridge-port-vlan.md) + Contact ------- diff --git a/doc/bridge-port.md b/doc/bridge-port.md index d5435b4..924bd6a 100644 --- a/doc/bridge-port.md +++ b/doc/bridge-port.md @@ -76,6 +76,11 @@ More configuration can be loaded by setting `BridgePortTo`: * Interfaces `en1` and `en2` are unchanged. * Interface `en3` is put in bridge `br-intern`. +See also +-------- + +* [Manage VLANs on bridge ports](global-functions.d/bridge-port-vlan.md) + --- [◀ Go back to main README](../README.md) [▲ Go back to top](#top) diff --git a/doc/global-functions.d/bridge-port-vlan.md b/doc/global-functions.d/bridge-port-vlan.md new file mode 100644 index 0000000..f59cb83 --- /dev/null +++ b/doc/global-functions.d/bridge-port-vlan.md @@ -0,0 +1,83 @@ +Manage VLANs on bridge ports +============================ + +[◀ Go back to main README](../../README.md) + +🛈 This module can not be used on its own but requires the base installation. +See [main README](../../README.md) for details. + +Description +----------- + +This module and its function are supposed to handle VLANs on bridge ports. + +Requirements and installation +----------------------------- + +Just install the module: + + $ScriptInstallUpdate global-functions.d/bridge-port-vlan; + +Configuration +------------- + +Using named VLANs you have to add comments in bridge vlan menu: + + / interface bridge vlan add bridge=bridge comment=intern tagged=br-local vlan-ids=10; + / interface bridge vlan add bridge=bridge comment=geust tagged=br-local vlan-ids=20; + / interface bridge vlan add bridge=bridge comment=extra tagged=br-local vlan-ids=30; + +The configuration goes to ports' comments (`/ interface bridge port`). + + / interface bridge port add bridge=bridge comment="default=dhcp-client, alt=guest" disabled=yes interface=en1; + / interface bridge port add bridge=bridge comment="default=intern, alt=guest, extra=30" interface=en2; + / interface bridge port add bridge=bridge comment="default=guest, extra=extra" interface=en3; + +Also dhcp client can be handled: + + / ip dhcp-client add comment="toggle with bridge port" disabled=no interface=en1; + +Add a scheduler to start with default setup on system startup: + + / system scheduler add name=bridge-port-vlan on-event=":global GlobalFunctionsReady; :while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }; :global BridgePortVlan; \$BridgePortVlan default;" start-time=startup; + +Usage and invocation +-------------------- + +The usage examples show what happens with the configuration from above. + +Running the function `$BridgePortVlan` with parameter `default` applies all +configuration given with `default=`: + + $BridgePortVlan default; + +For the three interfaces we get this configuration: + +* The special value `dhcp-client` enables the dhcp client for interface `en1`. The bridge port entry is disabled. +* Primary VLAN `intern` (ID `10`) is configured on `en2`. +* Primary VLAN `guest` (ID `20`) is configured on `en3`. + +Running the function `$BridgePortVlan` with parameter `alt` applies all +configuration given with `alt=`: + + $BridgePortVlan alt; + +* Primary VLAN `guest` (ID `20`) is configured on `en1`, dhcp client for the interface is disabled. +* Primary VLAN `guest` (ID `20`) is configured on `en2`. +* Interface `en3` is unchanged, primary VLAN `guest` (ID `20`) is unchanged. + +Running the function `$BridgePortVlan` with parameter `extra` applies another +configuration: + +* Interface `en1` is unchanged. +* Primary VLAN `extra` (via its ID `30`) is configured on `en2`. +* Primary VLAN `extra` (ID `30`) is configured on `en3`. + +See also +-------- + +* [Manage ports in bridge](../bridge-port.md) + +--- +[◀ Go back to main README](../../README.md) +[▲ Go back to top](#top) diff --git a/global-config b/global-config index bf3b0e4..5dc9a20 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 64; +:global GlobalConfigVersion 65; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 78d34b0..7bdc516 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 64; +:global GlobalConfigVersion 65; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 1ef2792..6a8b145 100644 --- a/global-config.changes +++ b/global-config.changes @@ -68,6 +68,7 @@ 62="Added '\$ScriptRunOnce' to run a script from URL once without installation, intended to aid configuration management and the like."; 63="Moved optional functions '\$IPCalc' and '\$ScriptRunOnce' to modules."; 64="Implemented '\$InspectVar' in module to inspect variables."; + 65="Added module to manage VLANs on bridge ports."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 80d6e6a..dbfeaa1 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 64; +:global ExpectedConfigVersion 65; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/global-functions.d/bridge-port-vlan b/global-functions.d/bridge-port-vlan new file mode 100644 index 0000000..754579a --- /dev/null +++ b/global-functions.d/bridge-port-vlan @@ -0,0 +1,62 @@ +#!rsc by RouterOS +# RouterOS script: global-functions.d/bridge-port-vlan +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# manage VLANs on bridge ports +# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-functions.d/bridge-port-vlan.md + +:global BridgePortVlan; + +# TODO +:global BridgePortVlan do={ + :local ConfigTo [ :tostr $1 ]; + + :global IfThenElse; + :global LogPrintExit2; + :global ParseKeyValueStore; + + :foreach BridgePort in=[ / interface bridge port find where !(comment=[]) ] do={ + :local BridgePortVal [ / interface bridge port get $BridgePort ]; + :foreach Config,Vlan in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ + :if ($Config = $ConfigTo) do={ + :local DHCPClient [ / ip dhcp-client find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; + + :if ($Vlan = "dhcp-client") do={ + :if ([ :len $DHCPClient ] != 1) do={ + $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ + " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; + } + :local DHCPClientDisabled [ / ip dhcp-client get $DHCPClient disabled ]; + + :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ + $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; + / interface bridge port disable $BridgePort; + :delay 200ms; + / ip dhcp-client enable $DHCPClient; + } + } else={ + :if ($Vlan != [ :tostr [ :tonum $Vlan ] ]) do={ + :do { + :set $Vlan ([ / interface bridge vlan get [ find where comment=$Vlan ] vlan-ids ]->0); + } on-error={ + $LogPrintExit2 warning $0 ("Could not find VLAN '" . $Vlan . "' for interface " . $BridgePortVal->"interface" . "!") true; + } + } + :if ($BridgePortVal->"disabled" = true || $Vlan != $BridgePortVal->"pvid") do={ + $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $ConfigTo . \ + " vlan " . $Vlan . ", disabling dhcp client.") false; + :if ([ :len $DHCPClient ] = 1) do={ + / ip dhcp-client disable $DHCPClient; + :delay 200ms; + } + / interface bridge port set disabled=no pvid=$Vlan $BridgePort; + } else={ + $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \ + " vlan " . $Vlan . ".") false; + } + } + } + } + } +} From f484e45b6a1fe5284462da19c90219d0716d916a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 12 Nov 2021 14:10:13 +0100 Subject: [PATCH 0859/2612] bridge-port-to-default -> global-functions.d/bridge-port-to --- README.md | 2 +- bridge-port-to-default | 53 ------------------ bridge-port-toggle | 21 -------- .../bridge-port-to.md} | 39 ++++++-------- doc/global-functions.d/bridge-port-vlan.md | 2 +- global-config | 9 ++-- global-config-overlay | 2 +- global-config.changes | 2 + global-functions | 2 +- global-functions.d/bridge-port-to | 54 +++++++++++++++++++ 10 files changed, 79 insertions(+), 107 deletions(-) delete mode 100644 bridge-port-to-default delete mode 100644 bridge-port-toggle rename doc/{bridge-port.md => global-functions.d/bridge-port-to.md} (60%) create mode 100644 global-functions.d/bridge-port-to diff --git a/README.md b/README.md index 1787ab5..7eb646d 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,6 @@ Available Scripts ----------------- * [Find and remove access list duplicates](doc/accesslist-duplicates.md) -* [Manage ports in bridge](doc/bridge-port.md) * [Download packages for CAP upgrade from CAPsMAN](doc/capsman-download-packages.md) * [Run rolling CAP upgrades from CAPsMAN](doc/capsman-rolling-upgrade.md) * [Renew locally issued certificates](doc/certificate-renew-issued.md) @@ -204,6 +203,7 @@ Available Scripts Available modules ----------------- +* [Manage ports in bridge](doc/global-functions.d/bridge-port-to.md) * [Manage VLANs on bridge ports](doc/global-functions.d/bridge-port-vlan.md) Contact diff --git a/bridge-port-to-default b/bridge-port-to-default deleted file mode 100644 index b8503df..0000000 --- a/bridge-port-to-default +++ /dev/null @@ -1,53 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: bridge-port-to-default -# Copyright (c) 2013-2021 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# reset bridge ports to default bridge -# https://git.eworm.de/cgit/routeros-scripts/about/doc/bridge-port.md - -:local 0 "bridge-port-to-default"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global BridgePortTo; - -:global IfThenElse; -:global LogPrintExit2; -:global ParseKeyValueStore; - -:foreach BridgePort in=[ / interface bridge port find where !(comment=[]) ] do={ - :local BridgePortVal [ / interface bridge port get $BridgePort ]; - :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ - :if ($Config = $BridgePortTo) do={ - :local DHCPClient [ / ip dhcp-client find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; - - :if ($BridgeDefault = "dhcp-client") do={ - :if ([ :len $DHCPClient ] != 1) do={ - $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ - " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; - } - :local DHCPClientDisabled [ / ip dhcp-client get $DHCPClient disabled ]; - - :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ - $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; - / interface bridge port disable $BridgePort; - / ip dhcp-client enable $DHCPClient; - } - } else={ - :if ($BridgePortVal->"disabled" = true || $BridgeDefault != $BridgePortVal->"bridge") do={ - $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ - " bridge " . $BridgeDefault . ", disabling dhcp client.") false; - :if ([ :len $DHCPClient ] = 1) do={ - / ip dhcp-client disable $DHCPClient; - :delay 200ms; - } - / interface bridge port set disabled=no bridge=$BridgeDefault $BridgePort; - } else={ - $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ - " bridge " . $BridgeDefault . ".") false; - } - } - } - } -} diff --git a/bridge-port-toggle b/bridge-port-toggle deleted file mode 100644 index 9eeab35..0000000 --- a/bridge-port-toggle +++ /dev/null @@ -1,21 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: bridge-port-toggle -# Copyright (c) 2013-2021 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# toggle bridge ports between default and alt bridge -# https://git.eworm.de/cgit/routeros-scripts/about/doc/bridge-port.md - -:local 0 "bridge-port-toggle"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global BridgePortTo; - -:if ($BridgePortTo != "default") do={ - :set BridgePortTo "default"; -} else={ - :set BridgePortTo "alt"; -} - -/ system script run bridge-port-to-default; diff --git a/doc/bridge-port.md b/doc/global-functions.d/bridge-port-to.md similarity index 60% rename from doc/bridge-port.md rename to doc/global-functions.d/bridge-port-to.md index 924bd6a..e0eba1e 100644 --- a/doc/bridge-port.md +++ b/doc/global-functions.d/bridge-port-to.md @@ -3,21 +3,21 @@ Manage ports in bridge [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. +🛈 This module can not be used on its own but requires the base installation. See [main README](../README.md) for details. Description ----------- -These scripts are supposed to handle interfaces and switching them from -one bridge to another. +This module and its functio are are supposed to handle interfaces and +switching them from one bridge to another. Requirements and installation ----------------------------- -Just install the scripts: +Just install the module: - $ScriptInstallUpdate bridge-port-to-default,bridge-port-toggle; + $ScriptInstallUpdate global-functions.d/bridge-port-to; Configuration ------------- @@ -32,23 +32,19 @@ Also dhcp client can be handled: / ip dhcp-client add comment="toggle with bridge port" disabled=no interface=en1; -There is also global configuration: - -* `BridgePortTo`: specify the configuration to be applied by default - Add a scheduler to start with default setup on system startup: - / system scheduler add name=bridge-port-to-default on-event="/ system script run bridge-port-to-default;" start-time=startup; + / system scheduler add name=bridge-port-to on-event=":global GlobalFunctionsReady; :while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }; :global BridgePortTo; \$BridgePortTo default;" start-time=startup; Usage and invocation -------------------- The usage examples show what happens with the configuration from above. -Running the script `bridge-port-to-default` applies all configuration given -with `default=`: +Running the function `$BridgePortTo` with parameter `default` applies all +configuration given with `default=`: - / system script run bridge-port-to-default; + $BridgePortTo default; For the three interfaces we get this configuration: @@ -56,22 +52,19 @@ For the three interfaces we get this configuration: * Interface `en2` is put in bridge `br-intern`. * Interface `en3` is put in bridge `br-guest`. -Running the script `bridge-port-toggle` toggles to configuration given -with `alt=`: +Running the function `$BridgePortTo` with parameter `alt` applies all +configuration given with `alt=`: - / system script run bridge-port-toggle; + $BridgePortTo alt; * Interface `en1` is put in bridge `br-guest`, dhcp client for the interface is disabled. * Interface `en2` is put in bridge `br-guest`. * Interface `en3` is unchanged, stays in bridge `br-guest`. -Running the script `bridge-port-toggle` again toggles back to configuration -given with `default=`. +Running the function `$BridgePortTo` with parameter `extra` applies another +configuration: -More configuration can be loaded by setting `BridgePortTo`: - - :set BridgePortTo "extra"; - / system script run bridge-port-to-default; + $BridgePortTo extra; * Interfaces `en1` and `en2` are unchanged. * Interface `en3` is put in bridge `br-intern`. @@ -79,7 +72,7 @@ More configuration can be loaded by setting `BridgePortTo`: See also -------- -* [Manage VLANs on bridge ports](global-functions.d/bridge-port-vlan.md) +* [Manage VLANs on bridge ports](bridge-port-vlan.md) --- [◀ Go back to main README](../README.md) diff --git a/doc/global-functions.d/bridge-port-vlan.md b/doc/global-functions.d/bridge-port-vlan.md index f59cb83..9df46b0 100644 --- a/doc/global-functions.d/bridge-port-vlan.md +++ b/doc/global-functions.d/bridge-port-vlan.md @@ -76,7 +76,7 @@ configuration: See also -------- -* [Manage ports in bridge](../bridge-port.md) +* [Manage ports in bridge](bridge-port-to.md) --- [◀ Go back to main README](../../README.md) diff --git a/global-config b/global-config index 5dc9a20..3905c8e 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 65; +:global GlobalConfigVersion 66; # This is used for DNS and backup file. :global Domain "example.com"; @@ -107,9 +107,6 @@ :global CheckHealthTemperatureDeviation 2; :global CheckHealthVoltagePercent 10; -# This controls what configuration is activated by bridge-port-to-default. -:global BridgePortTo "default"; - # Access-list entries matching this comment are updated # with daily pseudo-random PSK. :global DailyPskMatchComment "Daily PSK"; @@ -134,7 +131,7 @@ 2=":global SendNotification; :global Identity; \$SendNotification (\"Hello...\") (\"Hello world, \" . \$Identity . \" calling!\");"; 3="/ system shutdown;"; 4="/ system reboot;"; - 5="/ system script run bridge-port-toggle;"; + 5=":global BridgePortVlan; \$BridgePortVlan alt;"; # add more here... }; # This led gives visual feedback if type is 'on' or 'off'. @@ -142,7 +139,7 @@ # Run commands on SMS action. :global SmsAction { - bridge-port-toggle="/ system script run bridge-port-toggle;"; + bridge-port-vlan-alt=":global BridgePortVlan; \$BridgePortVlan alt;"; reboot="/ system reboot;"; shutdown="/ system shutdown;"; # add more here... diff --git a/global-config-overlay b/global-config-overlay index 7bdc516..1570461 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 65; +:global GlobalConfigVersion 66; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 6a8b145..2561506 100644 --- a/global-config.changes +++ b/global-config.changes @@ -69,6 +69,7 @@ 63="Moved optional functions '\$IPCalc' and '\$ScriptRunOnce' to modules."; 64="Implemented '\$InspectVar' in module to inspect variables."; 65="Added module to manage VLANs on bridge ports."; + 66="Moved script 'bridge-port-to-default' to new module."; }; # Migration steps to be applied on script updates @@ -78,4 +79,5 @@ 52=":global CertificateDownload; :if ([ :len [ / certificate find where fingerprint=\"67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd\" or fingerprint=\"96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6\" ] ] < 2) do={ \$CertificateDownload \"R3\"; }; / certificate remove [ find where fingerprint=\"0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739\" ];"; 54=":global ScriptInstallUpdate; :global TelegramTokenId; :global TelegramChatId; :if ([ :len \$TelegramTokenId ] > 0 && [ :len \$TelegramChatId ] > 0) do={ \$ScriptInstallUpdate global-functions.d/notification-telegram; }"; 61="/ system script remove [ find where name~\"^(early-errors|global-wait|mode-button-(event|scheduler)|script-updates)\\\$\" source~\"^#!rsc by RouterOS\\n\" ];"; + 66=":global ScriptInstallUpdate; :if ([ :len [ / system script find where name=\"bridge-port-to-default\" ] ] > 0) do={ / system script remove [ find where name~\"^bridge-port-to(-default|ggle)\\\$\" ]; \$ScriptInstallUpdate global-functions.d/bridge-port-to; }"; }; diff --git a/global-functions b/global-functions index dbfeaa1..813e4b4 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 65; +:global ExpectedConfigVersion 66; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/global-functions.d/bridge-port-to b/global-functions.d/bridge-port-to new file mode 100644 index 0000000..437cba7 --- /dev/null +++ b/global-functions.d/bridge-port-to @@ -0,0 +1,54 @@ +#!rsc by RouterOS +# RouterOS script: global-functions.d/bridge-port-to +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# reset bridge ports to default bridge +# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-functions.d/bridge-port-to.md + +:global BridgePortTo; + +:set BridgePortTo do={ + :local BridgePortTo [ :tostr $1 ]; + + :global IfThenElse; + :global LogPrintExit2; + :global ParseKeyValueStore; + + :foreach BridgePort in=[ / interface bridge port find where !(comment=[]) ] do={ + :local BridgePortVal [ / interface bridge port get $BridgePort ]; + :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ + :if ($Config = $BridgePortTo) do={ + :local DHCPClient [ / ip dhcp-client find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; + + :if ($BridgeDefault = "dhcp-client") do={ + :if ([ :len $DHCPClient ] != 1) do={ + $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ + " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; + } + :local DHCPClientDisabled [ / ip dhcp-client get $DHCPClient disabled ]; + + :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ + $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; + / interface bridge port disable $BridgePort; + :delay 200ms; + / ip dhcp-client enable $DHCPClient; + } + } else={ + :if ($BridgePortVal->"disabled" = true || $BridgeDefault != $BridgePortVal->"bridge") do={ + $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ + " bridge " . $BridgeDefault . ", disabling dhcp client.") false; + :if ([ :len $DHCPClient ] = 1) do={ + / ip dhcp-client disable $DHCPClient; + :delay 200ms; + } + / interface bridge port set disabled=no bridge=$BridgeDefault $BridgePort; + } else={ + $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ + " bridge " . $BridgeDefault . ".") false; + } + } + } + } + } +} From 8fc88c73f8cb99774727e7b96f9b85a8bf216c2c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 15 Nov 2021 20:22:56 +0100 Subject: [PATCH 0860/2612] shorten modules directory name (global-functions.d -> mod) --- README.md | 4 ++-- doc/{global-functions.d => mod}/bridge-port-to.md | 2 +- doc/{global-functions.d => mod}/bridge-port-vlan.md | 2 +- global-config | 8 ++++---- global-config-overlay | 2 +- global-config.changes | 6 ++++-- global-functions | 6 +++--- {global-functions.d => mod}/bridge-port-to | 4 ++-- {global-functions.d => mod}/bridge-port-vlan | 4 ++-- {global-functions.d => mod}/inspectvar | 2 +- {global-functions.d => mod}/ipcalc | 2 +- {global-functions.d => mod}/notification-matrix | 2 +- {global-functions.d => mod}/notification-telegram | 2 +- {global-functions.d => mod}/scriptrunonce | 2 +- 14 files changed, 25 insertions(+), 23 deletions(-) rename doc/{global-functions.d => mod}/bridge-port-to.md (97%) rename doc/{global-functions.d => mod}/bridge-port-vlan.md (97%) rename {global-functions.d => mod}/bridge-port-to (94%) rename {global-functions.d => mod}/bridge-port-vlan (94%) rename {global-functions.d => mod}/inspectvar (94%) rename {global-functions.d => mod}/ipcalc (96%) rename {global-functions.d => mod}/notification-matrix (98%) rename {global-functions.d => mod}/notification-telegram (99%) rename {global-functions.d => mod}/scriptrunonce (96%) diff --git a/README.md b/README.md index 7eb646d..d252deb 100644 --- a/README.md +++ b/README.md @@ -203,8 +203,8 @@ Available Scripts Available modules ----------------- -* [Manage ports in bridge](doc/global-functions.d/bridge-port-to.md) -* [Manage VLANs on bridge ports](doc/global-functions.d/bridge-port-vlan.md) +* [Manage ports in bridge](doc/mod/bridge-port-to.md) +* [Manage VLANs on bridge ports](doc/mod/bridge-port-vlan.md) Contact ------- diff --git a/doc/global-functions.d/bridge-port-to.md b/doc/mod/bridge-port-to.md similarity index 97% rename from doc/global-functions.d/bridge-port-to.md rename to doc/mod/bridge-port-to.md index e0eba1e..89ee5d0 100644 --- a/doc/global-functions.d/bridge-port-to.md +++ b/doc/mod/bridge-port-to.md @@ -17,7 +17,7 @@ Requirements and installation Just install the module: - $ScriptInstallUpdate global-functions.d/bridge-port-to; + $ScriptInstallUpdate mod/bridge-port-to; Configuration ------------- diff --git a/doc/global-functions.d/bridge-port-vlan.md b/doc/mod/bridge-port-vlan.md similarity index 97% rename from doc/global-functions.d/bridge-port-vlan.md rename to doc/mod/bridge-port-vlan.md index 9df46b0..8b88777 100644 --- a/doc/global-functions.d/bridge-port-vlan.md +++ b/doc/mod/bridge-port-vlan.md @@ -16,7 +16,7 @@ Requirements and installation Just install the module: - $ScriptInstallUpdate global-functions.d/bridge-port-vlan; + $ScriptInstallUpdate mod/bridge-port-vlan; Configuration ------------- diff --git a/global-config b/global-config index 3905c8e..2ad80d7 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 66; +:global GlobalConfigVersion 67; # This is used for DNS and backup file. :global Domain "example.com"; @@ -26,7 +26,7 @@ # You can send Telegram notifications. Register a bot # and add the token and chat ids here, then install the module: -# $ScriptInstallUpdate global-functions.d/notification-telegram +# $ScriptInstallUpdate mod/notification-telegram :global TelegramTokenId ""; :global TelegramChatId ""; #:global TelegramTokenId "123456:ABCDEF-GHI"; @@ -36,7 +36,7 @@ # You can send Matrix notifications. Configure these settings and # install the module: -# $ScriptInstallUpdate global-functions.d/notification-matrix +# $ScriptInstallUpdate mod/notification-matrix :global MatrixHomeServer ""; :global MatrixAccessToken ""; :global MatrixRoom ""; @@ -166,7 +166,7 @@ # Use this for defaults with $ScriptRunOnce # Install module with: -# $ScriptInstallUpdate global-functions.d/scriptrunonce +# $ScriptInstallUpdate mod/scriptrunonce :global ScriptRunOnceBaseUrl ""; :global ScriptRunOnceUrlSuffix ""; diff --git a/global-config-overlay b/global-config-overlay index 1570461..07280cd 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 66; +:global GlobalConfigVersion 67; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 2561506..2f30563 100644 --- a/global-config.changes +++ b/global-config.changes @@ -70,6 +70,7 @@ 64="Implemented '\$InspectVar' in module to inspect variables."; 65="Added module to manage VLANs on bridge ports."; 66="Moved script 'bridge-port-to-default' to new module."; + 67="Moved modules to directory with shorter name."; }; # Migration steps to be applied on script updates @@ -77,7 +78,8 @@ 41=":global SendNotification; \$SendNotification (\"Migration mechanism\") (\"Congratulations!\nSuccessfully tested the new migration mechanism.\");"; 47="/ certificate remove [ find where fingerprint=\"731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568\" or fingerprint=\"25847d668eb4f04fdd40b12b6b0740c567da7d024308eb6c2c96fe41d9de218d\" ];"; 52=":global CertificateDownload; :if ([ :len [ / certificate find where fingerprint=\"67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd\" or fingerprint=\"96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6\" ] ] < 2) do={ \$CertificateDownload \"R3\"; }; / certificate remove [ find where fingerprint=\"0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739\" ];"; - 54=":global ScriptInstallUpdate; :global TelegramTokenId; :global TelegramChatId; :if ([ :len \$TelegramTokenId ] > 0 && [ :len \$TelegramChatId ] > 0) do={ \$ScriptInstallUpdate global-functions.d/notification-telegram; }"; + 54=":global ScriptInstallUpdate; :global TelegramTokenId; :global TelegramChatId; :if ([ :len \$TelegramTokenId ] > 0 && [ :len \$TelegramChatId ] > 0) do={ \$ScriptInstallUpdate mod/notification-telegram; }"; 61="/ system script remove [ find where name~\"^(early-errors|global-wait|mode-button-(event|scheduler)|script-updates)\\\$\" source~\"^#!rsc by RouterOS\\n\" ];"; - 66=":global ScriptInstallUpdate; :if ([ :len [ / system script find where name=\"bridge-port-to-default\" ] ] > 0) do={ / system script remove [ find where name~\"^bridge-port-to(-default|ggle)\\\$\" ]; \$ScriptInstallUpdate global-functions.d/bridge-port-to; }"; + 66=":global ScriptInstallUpdate; :if ([ :len [ / system script find where name=\"bridge-port-to-default\" ] ] > 0) do={ / system script remove [ find where name~\"^bridge-port-to(-default|ggle)\\\$\" ]; \$ScriptInstallUpdate mod/bridge-port-to; }"; + 67=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Script in=[ / system script find where name~\"^global-functions.d/\" ] do={ / system script set name=[ \$CharacterReplace [ / system script get \$Script name ] \"global-functions.d/\" \"mod/\" ] \$Script; }; \$ScriptInstallUpdate;"; }; diff --git a/global-functions b/global-functions index 813e4b4..85fdf40 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 66; +:global ExpectedConfigVersion 67; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -755,7 +755,7 @@ :if ($ScriptVal->"name" = "global-config") do={ :set ReloadGlobalConfig true; } - :if ($ScriptVal->"name" ~ ("^global-functions(\$|\\.d/.)")) do={ + :if ($ScriptVal->"name" = "global-functions" || $ScriptVal->"name" ~ ("^mod/.")) do={ :set ReloadGlobalFunctions true; } } else={ @@ -1242,7 +1242,7 @@ } # load modules -:foreach Script in=[ / system script find where name ~ "^global-functions\\.d/." ] do={ +:foreach Script in=[ / system script find where name ~ "^mod/." ] do={ / system script run $Script; } diff --git a/global-functions.d/bridge-port-to b/mod/bridge-port-to similarity index 94% rename from global-functions.d/bridge-port-to rename to mod/bridge-port-to index 437cba7..40b216c 100644 --- a/global-functions.d/bridge-port-to +++ b/mod/bridge-port-to @@ -1,10 +1,10 @@ #!rsc by RouterOS -# RouterOS script: global-functions.d/bridge-port-to +# RouterOS script: mod/bridge-port-to # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # reset bridge ports to default bridge -# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-functions.d/bridge-port-to.md +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-to.md :global BridgePortTo; diff --git a/global-functions.d/bridge-port-vlan b/mod/bridge-port-vlan similarity index 94% rename from global-functions.d/bridge-port-vlan rename to mod/bridge-port-vlan index 754579a..bfe00e9 100644 --- a/global-functions.d/bridge-port-vlan +++ b/mod/bridge-port-vlan @@ -1,10 +1,10 @@ #!rsc by RouterOS -# RouterOS script: global-functions.d/bridge-port-vlan +# RouterOS script: mod/bridge-port-vlan # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # manage VLANs on bridge ports -# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-functions.d/bridge-port-vlan.md +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-vlan.md :global BridgePortVlan; diff --git a/global-functions.d/inspectvar b/mod/inspectvar similarity index 94% rename from global-functions.d/inspectvar rename to mod/inspectvar index 15da04a..4e10fd6 100644 --- a/global-functions.d/inspectvar +++ b/mod/inspectvar @@ -1,5 +1,5 @@ #!rsc by RouterOS -# RouterOS script: global-functions.d/inspectvar +# RouterOS script: mod/inspectvar # Copyright (c) 2020-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/global-functions.d/ipcalc b/mod/ipcalc similarity index 96% rename from global-functions.d/ipcalc rename to mod/ipcalc index f146fbe..64a03a9 100644 --- a/global-functions.d/ipcalc +++ b/mod/ipcalc @@ -1,5 +1,5 @@ #!rsc by RouterOS -# RouterOS script: global-functions.d/ipcalc +# RouterOS script: mod/ipcalc # Copyright (c) 2020-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/global-functions.d/notification-matrix b/mod/notification-matrix similarity index 98% rename from global-functions.d/notification-matrix rename to mod/notification-matrix index a2f7af0..a78539f 100644 --- a/global-functions.d/notification-matrix +++ b/mod/notification-matrix @@ -1,5 +1,5 @@ #!rsc by RouterOS -# RouterOS script: global-functions.d/notification-matrix +# RouterOS script: mod/notification-matrix # Copyright (c) 2013-2021 Michael Gisbers # Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/global-functions.d/notification-telegram b/mod/notification-telegram similarity index 99% rename from global-functions.d/notification-telegram rename to mod/notification-telegram index faf02d7..d575103 100644 --- a/global-functions.d/notification-telegram +++ b/mod/notification-telegram @@ -1,5 +1,5 @@ #!rsc by RouterOS -# RouterOS script: global-functions.d/notification-telegram +# RouterOS script: mod/notification-telegram # Copyright (c) 2013-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/global-functions.d/scriptrunonce b/mod/scriptrunonce similarity index 96% rename from global-functions.d/scriptrunonce rename to mod/scriptrunonce index ce9425b..0b519c3 100644 --- a/global-functions.d/scriptrunonce +++ b/mod/scriptrunonce @@ -1,5 +1,5 @@ #!rsc by RouterOS -# RouterOS script: global-functions.d/scriptrunonece +# RouterOS script: mod/scriptrunonece # Copyright (c) 2020-2021 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md From 3b997d30870b08b18adc051af5ecca639bd12add Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 15 Nov 2021 22:07:52 +0100 Subject: [PATCH 0861/2612] global-functions: drop deprecated function $LogPrintExit ... which has been replaced by $LogPrintExit2 some time ago. --- global-functions | 9 --------- 1 file changed, 9 deletions(-) diff --git a/global-functions b/global-functions index 85fdf40..ad6b555 100644 --- a/global-functions +++ b/global-functions @@ -32,7 +32,6 @@ :global GetRandomNumber; :global HexToNum; :global IfThenElse; -:global LogPrintExit; :global LogPrintExit2; :global MkDir; :global NotificationFunctions; @@ -441,14 +440,6 @@ :return $3; } -# deprecated compatibility wrapper -:set LogPrintExit do={ - :global LogPrintExit2; - - $LogPrintExit2 warning $0 ("This function is deprecated. Please use \$LogPrintExit2 instead.") false; - $LogPrintExit2 $1 "unknown" $2 $3; -} - # log and print with same text, optionally exit :set LogPrintExit2 do={ :local Severity [ :tostr $1 ]; From 185fe2c73035b66b2c8e0048eedca47fd438e3e6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 15 Nov 2021 22:17:43 +0100 Subject: [PATCH 0862/2612] reintroduce global-wait --- README.md | 1 + doc/global-wait.md | 40 +++++++++++++++++++++++++++++++++++++ doc/mod/bridge-port-to.md | 4 +++- doc/mod/bridge-port-vlan.md | 4 +++- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 3 ++- global-functions | 2 +- global-wait | 13 ++++++++++++ 9 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 doc/global-wait.md create mode 100644 global-wait diff --git a/README.md b/README.md index d252deb..dfec35a 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,7 @@ Available Scripts * [Comment DHCP leases with info from access list](doc/dhcp-lease-comment.md) * [Create DNS records for DHCP leases](doc/dhcp-to-dns.md) * [Send backup via e-mail](doc/email-backup.md) +* [Wait for global functions und modules](doc/global-wait.md) * [Send GPS position to server](doc/gps-track.md) * [Use WPA2 network with hotspot credentials](doc/hotspot-to-wpa.md) * [Create DNS records for IPSec peers](doc/ipsec-to-dns.md) diff --git a/doc/global-wait.md b/doc/global-wait.md new file mode 100644 index 0000000..2d9dad3 --- /dev/null +++ b/doc/global-wait.md @@ -0,0 +1,40 @@ +Wait for global functions and modules +===================================== + +[◀ Go back to main README](../README.md) + +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + +Description +----------- + +The global functions from `global-functions` and modules are loaded by +scheduler at system startup. Running these functions at system startup may +result in race condition where configuration and/or function are not yet +available. This script is supposed to wait for everything being prepared. + +Do **not** add this script `global-wait` to the `global-scripts` scheduler! +It would inhibit the initialization of configuration and functions. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate global-wait; + +... and add it to your scheduler, for example in combination with the module +to [manage VLANs on bridge ports](mod/bridge-port-vlan.md): + + / system scheduler add name=bridge-port-vlan on-event="/ system script run global-wait; :global BridgePortVlan; \$BridgePortVlan default;" start-time=startup; + +See also +-------- + +* [Manage ports in bridge](mod/bridge-port-to.md) +* [Manage VLANs on bridge ports](mod/bridge-port-vlan.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/mod/bridge-port-to.md b/doc/mod/bridge-port-to.md index 89ee5d0..5b2817b 100644 --- a/doc/mod/bridge-port-to.md +++ b/doc/mod/bridge-port-to.md @@ -34,7 +34,8 @@ Also dhcp client can be handled: Add a scheduler to start with default setup on system startup: - / system scheduler add name=bridge-port-to on-event=":global GlobalFunctionsReady; :while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }; :global BridgePortTo; \$BridgePortTo default;" start-time=startup; + $ScriptInstallUpdate global-wait; + / system scheduler add name=bridge-port-vlan on-event="/ system script run global-wait; :global BridgePortTo; \$BridgePortTo default;" start-time=startup; Usage and invocation -------------------- @@ -72,6 +73,7 @@ configuration: See also -------- +* [Wait for global functions und modules](../global-wait.md) * [Manage VLANs on bridge ports](bridge-port-vlan.md) --- diff --git a/doc/mod/bridge-port-vlan.md b/doc/mod/bridge-port-vlan.md index 8b88777..67dd04d 100644 --- a/doc/mod/bridge-port-vlan.md +++ b/doc/mod/bridge-port-vlan.md @@ -39,7 +39,8 @@ Also dhcp client can be handled: Add a scheduler to start with default setup on system startup: - / system scheduler add name=bridge-port-vlan on-event=":global GlobalFunctionsReady; :while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }; :global BridgePortVlan; \$BridgePortVlan default;" start-time=startup; + $ScriptInstallUpdate global-wait; + / system scheduler add name=bridge-port-vlan on-event="/ system script run global-wait; :global BridgePortVlan; \$BridgePortVlan default;" start-time=startup; Usage and invocation -------------------- @@ -76,6 +77,7 @@ configuration: See also -------- +* [Wait for global functions und modules](../global-wait.md) * [Manage ports in bridge](bridge-port-to.md) --- diff --git a/global-config b/global-config index 2ad80d7..5f533b4 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 67; +:global GlobalConfigVersion 68; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 07280cd..4f8eee5 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 67; +:global GlobalConfigVersion 68; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 2f30563..2914ea9 100644 --- a/global-config.changes +++ b/global-config.changes @@ -71,6 +71,7 @@ 65="Added module to manage VLANs on bridge ports."; 66="Moved script 'bridge-port-to-default' to new module."; 67="Moved modules to directory with shorter name."; + 68="Reintroduced 'global-wait' for functions in scheduler."; }; # Migration steps to be applied on script updates @@ -79,7 +80,7 @@ 47="/ certificate remove [ find where fingerprint=\"731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568\" or fingerprint=\"25847d668eb4f04fdd40b12b6b0740c567da7d024308eb6c2c96fe41d9de218d\" ];"; 52=":global CertificateDownload; :if ([ :len [ / certificate find where fingerprint=\"67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd\" or fingerprint=\"96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6\" ] ] < 2) do={ \$CertificateDownload \"R3\"; }; / certificate remove [ find where fingerprint=\"0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739\" ];"; 54=":global ScriptInstallUpdate; :global TelegramTokenId; :global TelegramChatId; :if ([ :len \$TelegramTokenId ] > 0 && [ :len \$TelegramChatId ] > 0) do={ \$ScriptInstallUpdate mod/notification-telegram; }"; - 61="/ system script remove [ find where name~\"^(early-errors|global-wait|mode-button-(event|scheduler)|script-updates)\\\$\" source~\"^#!rsc by RouterOS\\n\" ];"; + 61="/ system script remove [ find where name~\"^(early-errors|mode-button-(event|scheduler)|script-updates)\\\$\" source~\"^#!rsc by RouterOS\\n\" ];"; 66=":global ScriptInstallUpdate; :if ([ :len [ / system script find where name=\"bridge-port-to-default\" ] ] > 0) do={ / system script remove [ find where name~\"^bridge-port-to(-default|ggle)\\\$\" ]; \$ScriptInstallUpdate mod/bridge-port-to; }"; 67=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Script in=[ / system script find where name~\"^global-functions.d/\" ] do={ / system script set name=[ \$CharacterReplace [ / system script get \$Script name ] \"global-functions.d/\" \"mod/\" ] \$Script; }; \$ScriptInstallUpdate;"; }; diff --git a/global-functions b/global-functions index ad6b555..f5bca7a 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 67; +:global ExpectedConfigVersion 68; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/global-wait b/global-wait new file mode 100644 index 0000000..c601f69 --- /dev/null +++ b/global-wait @@ -0,0 +1,13 @@ +#!rsc by RouterOS +# RouterOS script: global-wait +# Copyright (c) 2020-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: backup-script +# +# wait for global-functions to finish +# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md + +:local 0 "global-wait"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From d87c50cf68356e02e89620e445981776c7b4f4c3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Nov 2021 14:53:25 +0100 Subject: [PATCH 0863/2612] check-health: indicate voltage increase or decrease --- check-health | 4 +++- doc/check-health.d/notification-01-voltage.svg | 2 +- global-functions | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/check-health b/check-health index bf0e441..9fef8bc 100644 --- a/check-health +++ b/check-health @@ -17,6 +17,7 @@ :global CheckHealthVoltagePercent; :global Identity; +:global IfThenElse; :global LogPrintExit2; :global ScriptLock; :global SendNotification2; @@ -46,7 +47,8 @@ $ScriptLock $0; :if ($CheckHealthLast->$Name * (100 + $CheckHealthVoltagePercent) < $Voltage * 100 || \ $CheckHealthLast->$Name * 100 > $Voltage * (100 + $CheckHealthVoltagePercent)) do={ $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "high-voltage-sign" ] . "Health warning: " . $Name); \ + subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($CheckHealthLast->$Name < \ + $Voltage) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ "old value: " . [ $FormatVoltage ($CheckHealthLast->$Name) ] . "\n" . \ "new value: " . [ $FormatVoltage $Voltage ]) }); diff --git a/doc/check-health.d/notification-01-voltage.svg b/doc/check-health.d/notification-01-voltage.svg index 81f7178..b762f61 100644 --- a/doc/check-health.d/notification-01-voltage.svg +++ b/doc/check-health.d/notification-01-voltage.svg @@ -151,7 +151,7 @@ y="0">[MikroTik] ⚡ Health warning: voltage + id="tspan13643">[MikroTik] ⚡📉 Health warning: voltage Date: Sat, 13 Nov 2021 21:29:33 +0100 Subject: [PATCH 0864/2612] check-health: support hard lower limit for voltage ... to detect slow decrease of voltage, for example with UPS. --- check-health | 12 ++++++++++++ doc/check-health.md | 3 ++- global-config | 3 ++- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 6 files changed, 19 insertions(+), 4 deletions(-) diff --git a/check-health b/check-health index 9fef8bc..56413c1 100644 --- a/check-health +++ b/check-health @@ -14,6 +14,7 @@ :global CheckHealthTemperature; :global CheckHealthTemperatureDeviation; :global CheckHealthTemperatureNotified; +:global CheckHealthVoltageLow; :global CheckHealthVoltagePercent; :global Identity; @@ -52,6 +53,17 @@ $ScriptLock $0; message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ "old value: " . [ $FormatVoltage ($CheckHealthLast->$Name) ] . "\n" . \ "new value: " . [ $FormatVoltage $Voltage ]) }); + } else={ + :if ($Voltage <= $CheckHealthVoltageLow && $CheckHealthLast->$Name > $CheckHealthVoltageLow) do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \ + message=("The " . $Name . " on " . $Identity . " dropped to " . [ $FormatVoltage $Voltage ] . " below hard limit.") }); + } + :if ($Voltage > $CheckHealthVoltageLow && $CheckHealthLast->$Name <= $CheckHealthVoltageLow) do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ + message=("The " . $Name . " on " . $Identity . " recovered to " . [ $FormatVoltage $Voltage ] . " above hard limit.") }); + } } } } diff --git a/doc/check-health.md b/doc/check-health.md index 9e9e501..8e271d6 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -12,7 +12,7 @@ Description This script is run from scheduler periodically, sending notification on health related events: -* voltage jumps up or down more than configured threshold +* voltage jumps up or down more than configured threshold or drops below limit * power supply failed or recovered * temperature is above or below threshold @@ -53,6 +53,7 @@ Configuration The configuration goes to `global-config-overlay`, these are the parameters: * `CheckHealthTemperature`: an array specifying temperature thresholds for sensors +* `CheckHealthVoltageLow`: value (in volt*10) giving a hard lower limit * `CheckHealthVoltagePercent`: percentage value to trigger voltage jumps Also notification settings are required for e-mail, matrix and/or telegram. diff --git a/global-config b/global-config index 5f533b4..26e1a76 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 68; +:global GlobalConfigVersion 69; # This is used for DNS and backup file. :global Domain "example.com"; @@ -105,6 +105,7 @@ } # This is deviation on recovery threshold against notification flooding. :global CheckHealthTemperatureDeviation 2; +:global CheckHealthVoltageLow 115; :global CheckHealthVoltagePercent 10; # Access-list entries matching this comment are updated diff --git a/global-config-overlay b/global-config-overlay index 4f8eee5..87abb87 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 68; +:global GlobalConfigVersion 69; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 2914ea9..a8198db 100644 --- a/global-config.changes +++ b/global-config.changes @@ -72,6 +72,7 @@ 66="Moved script 'bridge-port-to-default' to new module."; 67="Moved modules to directory with shorter name."; 68="Reintroduced 'global-wait' for functions in scheduler."; + 69="Support hard lower limit for voltage in 'check-health'."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 19f5777..3ec3e3e 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 68; +:global ExpectedConfigVersion 69; # global variables not to be changed by user :global GlobalFunctionsReady false; From 868879ec8d431b6e50ed4bfc098b562a319270f5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Nov 2021 10:27:44 +0100 Subject: [PATCH 0865/2612] README: no capitals here... --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dfec35a..3590ea1 100644 --- a/README.md +++ b/README.md @@ -155,7 +155,7 @@ cleanup add a scheduler entry. There's much more to explore... Have fun! -Available Scripts +Available scripts ----------------- * [Find and remove access list duplicates](doc/accesslist-duplicates.md) From 15d8652c296597e42582e7248362fed70656e0df Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Nov 2021 18:05:33 +0100 Subject: [PATCH 0866/2612] accesslist-duplicates: read more than a single digit With RouterOS 6.x a print always starts with numeric id zero, then counts up. This is no longer true with RouterOS 7.x... Thus we have to handle two or more digits in input. --- accesslist-duplicates.capsman | 6 ++++-- accesslist-duplicates.local | 6 ++++-- accesslist-duplicates.template | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman index 5fcf6ae..3992991 100644 --- a/accesslist-duplicates.capsman +++ b/accesslist-duplicates.capsman @@ -12,6 +12,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local Read do={ :return; } + :local Seen [ :toarray "" ]; :local Shown [ :toarray "" ]; @@ -28,8 +30,8 @@ :set Shown ($Shown, $Mac); :put "\nNumeric id to remove, any key to skip!"; - :local Remove ([ :terminal inkey ] - 48); - :if ($Remove >= 0 && $Remove <= 9) do={ + :local Remove [ :tonum [ $Read ] ]; + :if ([ :typeof $Remove ] = "num") do={ :put ("Removing numeric id " . $Remove . "...\n"); / caps-man access-list remove $Remove; } diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local index 4d058d4..cb2e7c3 100644 --- a/accesslist-duplicates.local +++ b/accesslist-duplicates.local @@ -12,6 +12,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local Read do={ :return; } + :local Seen [ :toarray "" ]; :local Shown [ :toarray "" ]; @@ -28,8 +30,8 @@ :set Shown ($Shown, $Mac); :put "\nNumeric id to remove, any key to skip!"; - :local Remove ([ :terminal inkey ] - 48); - :if ($Remove >= 0 && $Remove <= 9) do={ + :local Remove [ :tonum [ $Read ] ]; + :if ([ :typeof $Remove ] = "num") do={ :put ("Removing numeric id " . $Remove . "...\n"); / interface wireless access-list remove $Remove; } diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template index 8878bcc..25923e1 100644 --- a/accesslist-duplicates.template +++ b/accesslist-duplicates.template @@ -13,6 +13,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local Read do={ :return; } + :local Seen [ :toarray "" ]; :local Shown [ :toarray "" ]; @@ -29,8 +31,8 @@ :set Shown ($Shown, $Mac); :put "\nNumeric id to remove, any key to skip!"; - :local Remove ([ :terminal inkey ] - 48); - :if ($Remove >= 0 && $Remove <= 9) do={ + :local Remove [ :tonum [ $Read ] ]; + :if ([ :typeof $Remove ] = "num") do={ :put ("Removing numeric id " . $Remove . "...\n"); / %PATH% access-list remove $Remove; } From 5b786e10c87f0fd9bf2e297a32af2deabc2946d7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 22 Nov 2021 09:57:57 +0100 Subject: [PATCH 0867/2612] global-functions: $DeviceInfo: add current firmware (I would like to show a note if the upgrade is pending... But did not find a way to get that information. Is there?) --- global-functions | 2 ++ 1 file changed, 2 insertions(+) diff --git a/global-functions b/global-functions index 3ec3e3e..4ec903a 100644 --- a/global-functions +++ b/global-functions @@ -218,6 +218,8 @@ [ $IfThenElse ([ :typeof ($Update->"latest-version") ] != "nothing" && \ $Update->"installed-version" != $Update->"latest-version") \ ("\n Available: " . $Update->"latest-version") ] . \ + [ $IfThenElse ($RouterBoard->"routerboard" = true) \ + ("\n Firmware: " . $RouterBoard->"current-firmware") ] . \ "\nRouterOS-Scripts:" . \ "\n Current: " . $GlobalConfigVersion . \ [ $IfThenElse ($GlobalConfigVersion != $ExpectedConfigVersion) \ From 95062a3dbc63ea07bf24c112e33c83073c56c4cb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Dec 2021 22:59:13 +0100 Subject: [PATCH 0868/2612] doc/netwatch-notify: add missing empty line --- doc/netwatch-notify.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 7fd47d4..ef6f37e 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -115,6 +115,7 @@ Note that *all* traffic to the given address is routed that way. In case of link failure this address is not available, so use something reliable but non-essential. In this example the address `1.0.0.1` is used, the same service (Cloudflare DNS) is available at `1.1.1.1`. + --- [◀ Go back to main README](../README.md) [▲ Go back to top](#top) From dab04fd63e61618a8ef4996e3322d60f37f1d911 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Dec 2021 11:04:50 +0100 Subject: [PATCH 0869/2612] README: changes for RouterOS v7 --- README.md | 14 ++++++++++++++ global-config | 7 +++++-- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3590ea1..f98cf6b 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,20 @@ to be updated automatically! ![screenshot: schedule update](README.d/07-schedule-update.png) +### Changes for RouterOS v7 + +RouterOS v7 is developed in paralled to RouterOS v6. The former brings some +shiny new features, the latter provides proven stability. + +The changes require incompatible changes to scripts, so these changes go to +a separate branch. If you decide to run RouterOS v7 please switch to branch +`routeros-v7` by adding these lines to your `global-config-overlay`: + + # Use branch routeros-v7 with RouterOS v7: + :global ScriptUpdatesUrlSuffix "\?h=routeros-v7"; + +Then reload the configuration and continue below to update scripts. + Updating scripts ---------------- diff --git a/global-config b/global-config index 26e1a76..e03b5eb 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 69; +:global GlobalConfigVersion 70; # This is used for DNS and backup file. :global Domain "example.com"; @@ -159,11 +159,14 @@ # alternative urls - main: stable code - next: currently in development #:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/main/"; #:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/next/"; +#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/routeros-v7/"; #:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/main/"; #:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/next/"; +#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/routeros-v7/"; :global ScriptUpdatesUrlSuffix ""; -# use next branch with default url (git.eworm.de) +# use next or routeros-v7 branch with default url (git.eworm.de) #:global ScriptUpdatesUrlSuffix "\?h=next"; +#:global ScriptUpdatesUrlSuffix "\?h=routeros-v7"; # Use this for defaults with $ScriptRunOnce # Install module with: diff --git a/global-config-overlay b/global-config-overlay index 87abb87..fe3bfee 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 69; +:global GlobalConfigVersion 70; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index a8198db..102bc41 100644 --- a/global-config.changes +++ b/global-config.changes @@ -73,6 +73,7 @@ 67="Moved modules to directory with shorter name."; 68="Reintroduced 'global-wait' for functions in scheduler."; 69="Support hard lower limit for voltage in 'check-health'."; + 70="MikroTik started pushing RouterOS v7. Changes are required if you run it, see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v7"; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 4ec903a..ba6419d 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 69; +:global ExpectedConfigVersion 70; # global variables not to be changed by user :global GlobalFunctionsReady false; From 8f8130775f9dc2590e3408621c8a5ceb80b76d76 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Dec 2021 15:40:14 +0100 Subject: [PATCH 0870/2612] check-routeros-update: lock against multiple invocation --- check-routeros-update | 3 +++ 1 file changed, 3 insertions(+) diff --git a/check-routeros-update b/check-routeros-update index d21a7d0..b82df24 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -20,6 +20,7 @@ :global DeviceInfo; :global LogPrintExit2; :global ScriptFromTerminal; +:global ScriptLock; :global SendNotification2; :global SymbolForNotification; :global VersionToNum; @@ -34,6 +35,8 @@ :error "Waiting for system to reboot."; } +$ScriptLock $0; + $WaitFullyConnected; :if ([ :len [ / system package find where name="wireless" disabled=no ] ] > 0) do={ From 1f5cc39b3cb388e69e479d8b2b1a774c2abde37d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Dec 2021 15:40:14 +0100 Subject: [PATCH 0871/2612] global-config: load overlay automatically --- README.d/06-run-and-schedule-scripts.png | Bin 5416 -> 4526 bytes README.md | 4 ++-- global-config | 8 ++++++++ global-functions | 8 ++++---- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/README.d/06-run-and-schedule-scripts.png b/README.d/06-run-and-schedule-scripts.png index bd8aa9f0600c326a105db50e6c2db1175bf4b476..23b4d7b8017ba2f19dd30db30b3ca09281a145b9 100644 GIT binary patch delta 4461 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 delta 5358 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 M07*qoM6N<$f>y>utpET3 diff --git a/README.md b/README.md index f98cf6b..eea9014 100644 --- a/README.md +++ b/README.md @@ -99,8 +99,8 @@ Save changes and exit with `Ctrl-o`. And finally load configuration and functions and add the scheduler. - / system script { run global-config; run global-config-overlay; run global-functions; }; - / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }"; + / system script { run global-config; run global-functions; }; + / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-functions; }"; ![screenshot: run and schedule scripts](README.d/06-run-and-schedule-scripts.png) diff --git a/global-config b/global-config index e03b5eb..522155e 100644 --- a/global-config +++ b/global-config @@ -193,3 +193,11 @@ "cert1-cn"="v3ry-s3cr3t"; "cert2-cn"="4n0th3r-s3cr3t"; } + +# load custom settings from overlay +# Warning: Do *NOT* copy this code to overlay! +:do { + / system script run global-config-overlay; +} on-error={ + :log error ("Loading configuration from overlay failed!"); +} diff --git a/global-functions b/global-functions index ba6419d..b313b70 100644 --- a/global-functions +++ b/global-functions @@ -777,11 +777,11 @@ } :if ($ReloadGlobalConfig = true) do={ - $LogPrintExit2 info $0 ("Reloading global configuration and overlay.") false; + $LogPrintExit2 info $0 ("Reloading global configuration.") false; :do { - / system script { run global-config; run global-config-overlay; } + / system script run global-config; } on-error={ - $LogPrintExit2 error $0 ("Reloading global configuration and overlay failed!" . \ + $LogPrintExit2 error $0 ("Reloading global configuration failed!" . \ " Syntax error or missing overlay\?") false; } } @@ -838,7 +838,7 @@ :local NotificationMessage ("Current configuration on " . $Identity . \ " is out of date. Please update global-config-overlay, then increase " . \ "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \ - ") to " . $ExpectedConfigVersion . " and re-run global-config-overlay."); + ") to " . $ExpectedConfigVersion . " and re-run global-config."); $LogPrintExit2 info $0 ($NotificationMessage) false; :if ([ :len $GlobalConfigChanges ] > 0) do={ From a98965d727fe574bc57b63e3b0f9db30d96ff3fd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Dec 2021 22:58:39 +0100 Subject: [PATCH 0872/2612] global-functions: give a hint on RouterOS v7 --- global-functions | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/global-functions b/global-functions index b313b70..9977504 100644 --- a/global-functions +++ b/global-functions @@ -1244,5 +1244,11 @@ # check for required RouterOS version $RequiredRouterOS "global-functions" "6.47" true; +# ... and give a hint on RouterOS v7. +:if ([ $RequiredRouterOS "global-functions" "7.0" false ] = true) do={ + $LogPrintExit2 warning $0 ("RouterOS v7 brings some incompatible changes. Please switch to branch " . \ + "'routeros-v7', see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v7") false; +} + # signal we are ready :set GlobalFunctionsReady true; From 899085e831d8870cb0cfba400b85032805a3f5c1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Dec 2021 23:02:50 +0100 Subject: [PATCH 0873/2612] email-backup: drop warning on RouterOS v7... ... now that we have it in global-functions. --- email-backup | 6 ------ 1 file changed, 6 deletions(-) diff --git a/email-backup b/email-backup index 682cfbc..a819a4a 100644 --- a/email-backup +++ b/email-backup @@ -24,7 +24,6 @@ :global LogPrintExit2; :global MkDir; :global RandomDelay; -:global RequiredRouterOS; :global ScriptFromTerminal; :global SendEMail2; :global SymbolForNotification; @@ -63,11 +62,6 @@ $WaitFullyConnected; # create configuration export :if ($BackupSendExport = true) do={ - :if ([ $RequiredRouterOS $0 "7.1rc1" false ] = true) do={ - $LogPrintExit2 warning $0 ("RouterOS v7 hides sensitive information on export. " . \ - "Switch to branch 'routeros-v7' for full export.") false; - } - / export terse file=$FilePath; $WaitForFile ($FilePath . ".rsc"); :set ConfigFile ($FileName . ".rsc"); From 7b770b2fb8e523eb434fcf97bea0058673e23bf3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Dec 2021 23:03:30 +0100 Subject: [PATCH 0874/2612] upload-backup: drop warning on RouterOS v7... ... now that we have it in global-functions. --- upload-backup | 6 ------ 1 file changed, 6 deletions(-) diff --git a/upload-backup b/upload-backup index 088c495..cde847c 100644 --- a/upload-backup +++ b/upload-backup @@ -28,7 +28,6 @@ :global LogPrintExit2; :global MkDir; :global RandomDelay; -:global RequiredRouterOS; :global ScriptFromTerminal; :global SendNotification2; :global SymbolForNotification; @@ -77,11 +76,6 @@ $WaitFullyConnected; # create configuration export :if ($BackupSendExport = true) do={ - :if ([ $RequiredRouterOS $0 "7.1rc1" false ] = true) do={ - $LogPrintExit2 warning $0 ("RouterOS v7 hides sensitive information on export. " . \ - "Switch to branch 'routeros-v7' for full export.") false; - } - / export terse file=$FilePath; $WaitForFile ($FilePath . ".rsc"); From 9c87b5a2221ba507422232d7fd2bd08bbc5587ff Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 Dec 2021 12:21:03 +0100 Subject: [PATCH 0875/2612] global-functions: $ScriptLock: initialize empty array on cleanup --- global-functions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 9977504..1dd4642 100644 --- a/global-functions +++ b/global-functions @@ -958,7 +958,7 @@ } :if ($Count = 0) do={ - :set ($ScriptLockOrder->$Script); + :set ($ScriptLockOrder->$Script) [ :toarray "" ]; } } @@ -972,7 +972,7 @@ :if ([ $TicketCount $Script ] >= [ $JobCount $Script ]) do={ $LogPrintExit2 error $0 ("More tickets than running scripts '" . $Script . "', resetting!") false; - :set ($ScriptLockOrder->$Script); + :set ($ScriptLockOrder->$Script) [ :toarray "" ]; / system script job remove [ find where script=$Script ]; } From cdcab4599a3d5fc6c2f6b8554e969eef536f0f1a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 Dec 2021 12:51:19 +0100 Subject: [PATCH 0876/2612] global-functions: $ScriptLock: initialize earlier --- global-functions | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/global-functions b/global-functions index 1dd4642..f5682be 100644 --- a/global-functions +++ b/global-functions @@ -888,6 +888,9 @@ :if ([ :typeof $ScriptLockOrder ] = "nothing") do={ :set ScriptLockOrder [ :toarray "" ]; } + :if ([ :typeof ($ScriptLockOrder->$Script) ] = "nothing") do={ + :set ($ScriptLockOrder->$Script) [ :toarray "" ]; + } :local JobCount do={ :local Script [ :tostr $1 ]; @@ -928,10 +931,6 @@ :global ScriptLockOrder; - :if ([ :typeof ($ScriptLockOrder->$Script) ] = "nothing") do={ - :set ($ScriptLockOrder->$Script) [ :toarray "" ]; - } - :while (true) do={ :local Pos [ :len ($ScriptLockOrder->$Script) ]; :set ($ScriptLockOrder->$Script->$Pos) $Add; From b872615e897c1cf0a0a4c6d0ccf9dd155d86ec54 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 Dec 2021 16:13:00 +0100 Subject: [PATCH 0877/2612] mod/inspectvar: introduce $InspectVarReturn --- mod/inspectvar | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/mod/inspectvar b/mod/inspectvar index 4e10fd6..27a47fa 100644 --- a/mod/inspectvar +++ b/mod/inspectvar @@ -4,15 +4,24 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global InspectVar; +:global InspectVarReturn; -# inspect variable +# inspect variable and print on terminal :set InspectVar do={ + :global CharacterReplace; + :global InspectVarReturn; + + :put [ $CharacterReplace [ $InspectVarReturn $1 ] ("\n") ("\n\r") ]; +} + +# inspect variable and return formatted string +:set InspectVarReturn do={ :local Input $1; :local Level (0 + [ :tonum $2 ]); - :global InspectVar; + :global InspectVarReturn; - :local PutIndent do={ + :local IndentReturn do={ :local Prefix [ :tostr $1 ]; :local Value [ :tostr $2 ]; :local Level [ :tonum $3 ]; @@ -21,20 +30,23 @@ :for I from=1 to=$Level step=1 do={ :set Indent ($Indent . " "); } - :put ($Indent . "-" . $Prefix . "-> " . $Value); + :return ($Indent . "-" . $Prefix . "-> " . $Value); } :local TypeOf [ :typeof $Input ]; - $PutIndent "type" $TypeOf $Level; + :local Return [ $IndentReturn "type" $TypeOf $Level ]; :if ($TypeOf = "array") do={ :foreach Key,Value in=$Input do={ - $PutIndent "key" $Key ($Level + 1); - $InspectVar $Value ($Level + 2); + :set $Return ($Return . "\n" . \ + [ $IndentReturn "key" $Key ($Level + 1) ] . "\n" . \ + [ $InspectVarReturn $Value ($Level + 2) ]); } } else={ :if ($TypeOf != "nothing") do={ - $PutIndent "value" $Input $Level; + :set $Return ($Return . "\n" . \ + [ $IndentReturn "value" $Input $Level ]); } } + :return $Return; } From 004621a327948526d3fffd4de0db1d722d68a172 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 Dec 2021 20:50:51 +0100 Subject: [PATCH 0878/2612] mod/inspectvar: truncate value if too long --- mod/inspectvar | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mod/inspectvar b/mod/inspectvar index 27a47fa..c78b3f0 100644 --- a/mod/inspectvar +++ b/mod/inspectvar @@ -19,6 +19,7 @@ :local Input $1; :local Level (0 + [ :tonum $2 ]); + :global IfThenElse; :global InspectVarReturn; :local IndentReturn do={ @@ -45,7 +46,8 @@ } else={ :if ($TypeOf != "nothing") do={ :set $Return ($Return . "\n" . \ - [ $IndentReturn "value" $Input $Level ]); + [ $IndentReturn "value" [ $IfThenElse ([ :len $Input ] > 80) \ + ([ :pick $Input 0 77 ] . "...") $Input ] $Level ]); } } :return $Return; From 327740d25592c12c17bb9b87a853cc86abc4548a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 Dec 2021 20:55:15 +0100 Subject: [PATCH 0879/2612] mod/ipcalc: introduce $IPCalcReturn --- mod/ipcalc | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/mod/ipcalc b/mod/ipcalc index 64a03a9..bbb9577 100644 --- a/mod/ipcalc +++ b/mod/ipcalc @@ -4,10 +4,28 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global IPCalc; +:global IPCalcReturn; -# calculate and print netmask, network, min host, max host and broadcast +# print netmask, network, min host, max host and broadcast :set IPCalc do={ :local Input [ :tostr $1 ]; + + :global IPCalcReturn; + + :local Values [ $IPCalcReturn $1 ]; + + :put ( \ + "Address: " . $Values->"address" . "\n\r" . \ + "Netmask: " . $Values->"netmask" . "\n\r" . \ + "Network: " . $Values->"network" . "\n\r" . \ + "HostMin: " . $Values->"hostmin" . "\n\r" . \ + "HostMax: " . $Values->"hostmax" . "\n\r" . \ + "Broadcast: " . $Values->"broadcast"); +} + +# calculate and return netmask, network, min host, max host and broadcast +:set IPCalcReturn do={ + :local Input [ :tostr $1 ]; :local Address [ :toip [ :pick $Input 0 [ :find $Input "/" ] ] ]; :local Bits [ :tonum [ :pick $Input ([ :find $Input "/" ] + 1) [ :len $Input ] ] ]; :local Mask ((255.255.255.255 << (32 - $Bits)) & 255.255.255.255); @@ -23,13 +41,6 @@ "broadcast"=($Address | ~$Mask); } - :put ( \ - "Address: " . $Return->"address" . "\n\r" . \ - "Netmask: " . $Return->"netmask" . "\n\r" . \ - "Network: " . $Return->"network" . "\n\r" . \ - "HostMin: " . $Return->"hostmin" . "\n\r" . \ - "HostMax: " . $Return->"hostmax" . "\n\r" . \ - "Broadcast: " . $Return->"broadcast"); - :return $Return; } + From b423e6ed0f382ecdfd24e0b7b6d8e3dc4b43fede Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 Dec 2021 22:28:06 +0100 Subject: [PATCH 0880/2612] global-functions: $ScriptLock: cleanup in dedicated function --- global-functions | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/global-functions b/global-functions index f5682be..ce538f3 100644 --- a/global-functions +++ b/global-functions @@ -945,18 +945,26 @@ :global ScriptLockOrder; - :local Count 0; :foreach Id,Ticket in=($ScriptLockOrder->$Script) do={ :if (($ScriptLockOrder->$Script->$Id) = $Remove) do={ :set ($ScriptLockOrder->$Script->$Id); } + } + } - :if ([ :typeof ($ScriptLockOrder->$Script->$Id) ] != "nothing") do={ - :set Count ($Count + 1); + :local CleanupTickets do={ + :local Script [ :tostr $1 ]; + + :global ScriptLockOrder; + + :local Clean true; + :foreach Ticket in=($ScriptLockOrder->$Script) do={ + :if ([ :typeof $Ticket ] != "nothing") do={ + :set Clean false; } } - :if ($Count = 0) do={ + :if ($Clean = true) do={ :set ($ScriptLockOrder->$Script) [ :toarray "" ]; } } @@ -986,6 +994,7 @@ :if ([ $IsFirstTicket $Script $MyTicket ] = true && [ $TicketCount $Script ] = [ $JobCount $Script ]) do={ $RemoveTicket $Script $MyTicket; + $CleanupTickets $Script; :return false; } From a46fd481874b2277b191faf35ae035febdc045d6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 Dec 2021 22:30:43 +0100 Subject: [PATCH 0881/2612] global-functions: $ScriptLock: remove ticket in a loop This was not required with RouterOS v6, but for any reason removing a ticket may fail with RouterOS v7 in very rare cases. So remove in a loop... --- global-functions | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index ce538f3..0e4c514 100644 --- a/global-functions +++ b/global-functions @@ -946,8 +946,9 @@ :global ScriptLockOrder; :foreach Id,Ticket in=($ScriptLockOrder->$Script) do={ - :if (($ScriptLockOrder->$Script->$Id) = $Remove) do={ + :while (($ScriptLockOrder->$Script->$Id) = $Remove) do={ :set ($ScriptLockOrder->$Script->$Id); + :delay 10ms; } } } From 6dede0c49b94e5323106ce4bef475d36f1c018bd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 10 Dec 2021 07:34:09 +0100 Subject: [PATCH 0882/2612] global-functions: $ScriptLock: simplify cleanup code --- global-functions | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/global-functions b/global-functions index 0e4c514..42d0b43 100644 --- a/global-functions +++ b/global-functions @@ -958,16 +958,13 @@ :global ScriptLockOrder; - :local Clean true; :foreach Ticket in=($ScriptLockOrder->$Script) do={ :if ([ :typeof $Ticket ] != "nothing") do={ - :set Clean false; + :return false; } } - :if ($Clean = true) do={ - :set ($ScriptLockOrder->$Script) [ :toarray "" ]; - } + :set ($ScriptLockOrder->$Script) [ :toarray "" ]; } :if ([ :len [ / system script find where name=$Script ] ] = 0) do={ From 40dea016700fd88bfee2838d740d46517f677601 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 13 Dec 2021 11:36:03 +0100 Subject: [PATCH 0883/2612] README: changes for RouterOS v6 --- README.md | 12 ++++++++++++ global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index eea9014..ec6b863 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,18 @@ to be updated automatically! ![screenshot: schedule update](README.d/07-schedule-update.png) +### Changes for RouterOS v6 + +RouterOS v6 will become deprecated at some time in the future, but to date +it is still the default for these scripts (in branch `main`). This will +change however, so if you want to stay with RouterOS v6 for some time add +these lines to your `global-config-overlay`: + + # Use branch routeros-v6 with RouterOS v6: + :global ScriptUpdatesUrlSuffix "\?h=routeros-v6"; + +Then reload the configuration. + ### Changes for RouterOS v7 RouterOS v7 is developed in paralled to RouterOS v6. The former brings some diff --git a/global-config b/global-config index 522155e..1622ef5 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 70; +:global GlobalConfigVersion 71; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index fe3bfee..ec0955a 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 70; +:global GlobalConfigVersion 71; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 102bc41..4c31080 100644 --- a/global-config.changes +++ b/global-config.changes @@ -74,6 +74,7 @@ 68="Reintroduced 'global-wait' for functions in scheduler."; 69="Support hard lower limit for voltage in 'check-health'."; 70="MikroTik started pushing RouterOS v7. Changes are required if you run it, see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v7"; + 71="MikroTik is pushing RouterOS v7 even more, in parallel branches. If you want to keep RouterOS v6 for some time see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v6"; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 42d0b43..7c34a5c 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 70; +:global ExpectedConfigVersion 71; # global variables not to be changed by user :global GlobalFunctionsReady false; From 0fab371d1a9ec5f8110620d103516ab03a1e3d1f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 13 Dec 2021 15:37:20 +0100 Subject: [PATCH 0884/2612] global-functions: $DeviceInfo: show license level if available This now shows license level for CHR. The property is named different for Routerboards. As these have the license bundled to hardware anyway we do not show it there. --- global-functions | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global-functions b/global-functions index 7c34a5c..ba83bcb 100644 --- a/global-functions +++ b/global-functions @@ -201,6 +201,7 @@ :do { :set RouterBoard [ / system routerboard get ]; } on-error={ } + :local License [ / system license get ]; :local Update [ / system package update get ]; :return ( \ @@ -212,6 +213,8 @@ [ $IfThenElse ([ :len ($RouterBoard->"revision") ] > 0) \ (" " . $RouterBoard->"revision") ] . \ "\nSerial number: " . $RouterBoard->"serial-number") ] . \ + [ $IfThenElse ([ :len ($License->"level") ] > 0) \ + ("\nLicense: " . $License->"level") ] . \ "\nRouterOS:" . \ "\n Channel: " . $Update->"channel" . \ "\n Installed: " . $Update->"installed-version" . \ From e111832462d4ad9746cf90daa2486e3646cb03cc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Dec 2021 00:05:01 +0100 Subject: [PATCH 0885/2612] global-functions: $NotificationFunctions->"email": do not declare unused function --- global-functions | 1 - 1 file changed, 1 deletion(-) diff --git a/global-functions b/global-functions index ba83bcb..e0d770a 100644 --- a/global-functions +++ b/global-functions @@ -533,7 +533,6 @@ :global EitherOr; :global IfThenElse; - :global LogPrintExit2; :global QuotedPrintable; :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; From 5846b85e287186d85c6e194debacae47af77d06a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 13 Dec 2021 23:54:30 +0100 Subject: [PATCH 0886/2612] global-functions: $MkDir: log error --- global-functions | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index e0d770a..2163f73 100644 --- a/global-functions +++ b/global-functions @@ -495,6 +495,7 @@ :global CleanFilePath; :global GetRandom20CharHex; + :global LogPrintExit2; :global WaitForFile; :set Dir [ $CleanFilePath $Dir ]; @@ -504,11 +505,12 @@ } :local Return true; - :local Name ($Dir . "-" . [ $GetRandom20CharHex ]) + :local Name ($Dir . "-" . [ $GetRandom20CharHex ]); :do { / ip smb share add disabled=yes directory=$Dir name=$Name; $WaitForFile $Dir; } on-error={ + $LogPrintExit2 warning $0 ("Making directory '" . $Dir . "' failed!") false; :set Return false; } / ip smb share remove [ find where name=$Name ]; From 229a7d18c94149514d6fcbe209852f3820f57231 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Dec 2021 00:00:23 +0100 Subject: [PATCH 0887/2612] global-functions: $DownloadPackage: make directory first The fetch command creates the directory itself, however using $MkDir gives better error message when creating directory fails. --- global-functions | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/global-functions b/global-functions index 2163f73..4ff2a7a 100644 --- a/global-functions +++ b/global-functions @@ -251,6 +251,7 @@ :global CertificateAvailable; :global CleanFilePath; :global LogPrintExit2; + :global MkDir; :global WaitForFile; :if ([ :len $PkgName ] = 0) do={ :return false; } @@ -263,6 +264,11 @@ } :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; + :if ([ $MkDir $PkgDir ] = false) do={ + $LogPrintExit2 warning $0 ("Failed creating directory, not downloading package.") false; + :return false; + } + :if ([ :len [ / file find where name=$PkgDest type="package" ] ] > 0) do={ $LogPrintExit2 info $0 ("Package file " . $PkgName . " already exists.") false; :return true; From bf078867a79464e1eb34f552271e6ca450727320 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Dec 2021 20:24:41 +0100 Subject: [PATCH 0888/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 9fcb2a1..d07049b 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -29,6 +29,7 @@ Add yourself to the list, * Peter Holtkamp * Reiner Vehrenkamp * Sunny Chu (@sunnychuchu) +* Zac Kornilakis --- [◀ Go back to main README](README.md) From 28ff5e2aabfbf2ad8a77134e9481006813e796e7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Dec 2021 11:34:11 +0100 Subject: [PATCH 0889/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index d07049b..33f82f9 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -19,6 +19,7 @@ These persons contributed code. See the git history for details! Add yourself to the list, [donate with PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)! +* Abdul Mannan Abbasi * Andrew Cox * Christoph Boss (@Kampfwurst) * Klaus Michael RÃŧbsam From 4a5c55ca2b782982dbbcf5ab5f8dbe9291c2d2c3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Dec 2021 16:20:44 +0100 Subject: [PATCH 0890/2612] doc/ssh-keys-import: handle RSA keys only Sadly RouterOS does not (yet) support ed25519 keys... --- doc/ssh-keys-import.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ssh-keys-import.md b/doc/ssh-keys-import.md index d221072..e6ae96c 100644 --- a/doc/ssh-keys-import.md +++ b/doc/ssh-keys-import.md @@ -26,7 +26,7 @@ Then run the script: Starting with an `authorized_keys` file you can split it on a shell: - while read type key name; do echo $type $key $name > $name.pub; done < authorized_keys + grep -E '^ssh-rsa' authorized_keys | while read type key name; do echo $type $key $name > $name.pub; done --- [◀ Go back to main README](../README.md) From 9a0321d40d495b78fd613557260895a0e95e7734 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Dec 2021 16:30:29 +0100 Subject: [PATCH 0891/2612] doc/ssh-keys-import: number keys, do not overwrite on same comment --- doc/ssh-keys-import.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ssh-keys-import.md b/doc/ssh-keys-import.md index e6ae96c..3dc8ccf 100644 --- a/doc/ssh-keys-import.md +++ b/doc/ssh-keys-import.md @@ -26,7 +26,7 @@ Then run the script: Starting with an `authorized_keys` file you can split it on a shell: - grep -E '^ssh-rsa' authorized_keys | while read type key name; do echo $type $key $name > $name.pub; done + grep -E '^ssh-rsa' authorized_keys | nl -nrz | while read num type key name; do echo $type $key $name > $num-$name.pub; done --- [◀ Go back to main README](../README.md) From b936970c19b960294b4cbadfcfe1f917d7762d0d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Dec 2021 16:46:13 +0100 Subject: [PATCH 0892/2612] INITIAL-COMMANDS: adopt changes, no need to run global-config-overlay --- INITIAL-COMMANDS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index c88b709..46e1c8b 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -17,8 +17,8 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); }; - / system script { run global-config; run global-config-overlay; run global-functions; }; - / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }"; + / system script { run global-config; run global-functions; }; + / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-functions; }"; :global CertificateNameByCN; $CertificateNameByCN "R3"; $CertificateNameByCN "ISRG Root X1"; From ee57ddf595851d0068730bea2ef1b55752b6d7bc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Dec 2021 11:48:25 +0100 Subject: [PATCH 0893/2612] log-forward: fix forwarding first message Pulling the power cable results in log message on next boot: dec/16 18:28:28 system,error,critical router rebooted without proper shutdown, probably power outage This was not forwarded as it had the numeric id 0, which is not greater than the zero we initialized with. Now initialized with -1 when no log has been forwarded to fix this. --- log-forward | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log-forward b/log-forward index e0cb3aa..03b408d 100644 --- a/log-forward +++ b/log-forward @@ -44,7 +44,7 @@ $WaitFullyConnected; :local Count 0; :local Duplicates false; -:local Last [ $HexToNum $LogForwardLast ]; +:local Last [ $IfThenElse ([ :len $LogForwardLast ] > 0) [ $HexToNum $LogForwardLast ] -1 ]; :local Messages ""; :local MessageVal; :local MessageDups [ :toarray "" ]; From 500d0679ed5989ae0bb6fbd71ebf7e9e7b1ef86e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 20 Dec 2021 15:31:34 +0100 Subject: [PATCH 0894/2612] global-functions: $RequiredRouterOS: fix warning Passing a boolean does not work... Handle as string. --- global-functions | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/global-functions b/global-functions index 4ff2a7a..e89587f 100644 --- a/global-functions +++ b/global-functions @@ -632,16 +632,15 @@ # check for required RouterOS version :set RequiredRouterOS do={ - :local Caller [ :tostr $1 ]; - :local Required [ :tostr $2 ]; - :local Warn [ :tobool $3 ]; + :local Caller [ :tostr $1 ]; + :local Required [ :tostr $2 ]; + :local Warn [ :tostr $3 ]; :global IfThenElse; :global LogPrintExit2; :global VersionToNum; - :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" ] . \ " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!") false; } From 9348bd5039971b04e71de58ae64d6d14312a2a36 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 30 Dec 2021 23:45:57 +0100 Subject: [PATCH 0895/2612] README: add a qr code to join Telegram group --- README.d/telegram-group.png | Bin 0 -> 314 bytes README.md | 3 +++ 2 files changed, 3 insertions(+) create mode 100644 README.d/telegram-group.png diff --git a/README.d/telegram-group.png b/README.d/telegram-group.png new file mode 100644 index 0000000000000000000000000000000000000000..9208da20d01026db73df5d751de550bfc59662d5 GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^fgsGt3?wHw-Y5l9oCO|{#S9GGLLkg|>2BR0pded- zPlzj!{{R2~(wp<|0$H~_T^vIyZuMT?n0v%PfaQR&gvMm=1nKD;Rd+Ia-)Fcw$!J^Q z0W*bE9*(um$A1gU-WT`XvHJk$ef4?1OMIomIrkmxaz5-^r}nXs%q8>4!^Ohq*Hnl^a@E>@zJ1`qZ~6LP+!NW{wG>0_Vt~G6@O1Ta JS?83{1OQxDfFA$= literal 0 HcmV?d00001 diff --git a/README.md b/README.md index ec6b863..5fee7cd 100644 --- a/README.md +++ b/README.md @@ -237,6 +237,9 @@ Contact ------- We have a Telegram Group [RouterOS-Scripts](https://t.me/routeros_scripts)! + +![RouterOS Scripts Telegram Group](README.d/telegram-group.png) + Get help, give feedback or just chat - but do not expect free professional support! From 2e183da47fa911a752e16b955a64469e316e1fea Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 30 Dec 2021 23:46:33 +0100 Subject: [PATCH 0896/2612] README: add Telegram icon in qr code --- README.d/telegram-group.png | Bin 314 -> 20995 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/README.d/telegram-group.png b/README.d/telegram-group.png index 9208da20d01026db73df5d751de550bfc59662d5..4217477b40e8ef95cbfc73ade6fed2cb04b8958a 100644 GIT binary patch literal 20995 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 Date: Sat, 1 Jan 2022 21:38:15 +0100 Subject: [PATCH 0897/2612] update copyright for 2022 --- accesslist-duplicates.capsman | 2 +- accesslist-duplicates.local | 2 +- accesslist-duplicates.template | 2 +- capsman-download-packages | 2 +- capsman-rolling-upgrade | 2 +- certificate-renew-issued | 2 +- check-certificates | 2 +- check-health | 2 +- check-lte-firmware-upgrade | 2 +- check-routeros-update | 2 +- cloud-backup | 2 +- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- daily-psk.capsman | 2 +- daily-psk.local | 2 +- daily-psk.template | 2 +- dhcp-lease-comment.capsman | 2 +- dhcp-lease-comment.local | 2 +- dhcp-lease-comment.template | 2 +- dhcp-to-dns | 2 +- email-backup | 2 +- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 2 +- global-functions | 2 +- global-wait | 2 +- gps-track | 2 +- hotspot-to-wpa | 2 +- hotspot-to-wpa-cleanup | 2 +- ip-addr-bridge | 2 +- ipsec-to-dns | 2 +- ipv6-update | 2 +- learn-mac-based-vlan | 2 +- lease-script | 2 +- leds-day-mode | 2 +- leds-night-mode | 2 +- leds-toggle-mode | 2 +- log-forward | 2 +- manage-umts | 2 +- mod/bridge-port-to | 2 +- mod/bridge-port-vlan | 2 +- mod/inspectvar | 2 +- mod/ipcalc | 2 +- mod/notification-matrix | 2 +- mod/notification-telegram | 2 +- mod/scriptrunonce | 2 +- mode-button | 2 +- netwatch-notify | 2 +- netwatch-syslog | 2 +- ospf-to-leds | 2 +- packages-update | 2 +- ppp-on-up | 2 +- rotate-ntp | 2 +- sms-action | 2 +- sms-forward | 2 +- ssh-keys-import | 2 +- super-mario-theme | 2 +- unattended-lte-firmware-upgrade | 2 +- update-gre-address | 2 +- update-tunnelbroker | 2 +- upload-backup | 2 +- 62 files changed, 62 insertions(+), 62 deletions(-) diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman index 3992991..6d2c896 100644 --- a/accesslist-duplicates.capsman +++ b/accesslist-duplicates.capsman @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.capsman -# Copyright (c) 2018-2021 Christian Hesse +# Copyright (c) 2018-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # print duplicate antries in wireless access list diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local index cb2e7c3..24c8e29 100644 --- a/accesslist-duplicates.local +++ b/accesslist-duplicates.local @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.local -# Copyright (c) 2018-2021 Christian Hesse +# Copyright (c) 2018-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # print duplicate antries in wireless access list diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template index 25923e1..f9f4494 100644 --- a/accesslist-duplicates.template +++ b/accesslist-duplicates.template @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates%TEMPL% -# Copyright (c) 2018-2021 Christian Hesse +# Copyright (c) 2018-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # print duplicate antries in wireless access list diff --git a/capsman-download-packages b/capsman-download-packages index 5b03bba..333f01b 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-download-packages -# Copyright (c) 2018-2021 Christian Hesse +# Copyright (c) 2018-2022 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index 4c3b1c7..2893915 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-rolling-upgrade -# Copyright (c) 2018-2021 Christian Hesse +# Copyright (c) 2018-2022 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/certificate-renew-issued b/certificate-renew-issued index c8ce4ae..72b723f 100644 --- a/certificate-renew-issued +++ b/certificate-renew-issued @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: certificate-renew-issued -# Copyright (c) 2019-2021 Christian Hesse +# Copyright (c) 2019-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # renew locally issued certificates diff --git a/check-certificates b/check-certificates index 9ddf0e7..1f40496 100644 --- a/check-certificates +++ b/check-certificates @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-certificates -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for certificate validity diff --git a/check-health b/check-health index 56413c1..28de93e 100644 --- a/check-health +++ b/check-health @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-health -# Copyright (c) 2019-2021 Christian Hesse +# Copyright (c) 2019-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for RouterOS health state diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index c05c436..aef27fe 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-lte-firmware-upgrade -# Copyright (c) 2018-2021 Christian Hesse +# Copyright (c) 2018-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for LTE firmware upgrade, send notification diff --git a/check-routeros-update b/check-routeros-update index b82df24..0f687a5 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-routeros-update -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for RouterOS update, send notification and/or install diff --git a/cloud-backup b/cloud-backup index 3fa0e41..ab2cf7c 100644 --- a/cloud-backup +++ b/cloud-backup @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: cloud-backup -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 34e022d..326aa14 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.capsman -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # collect wireless mac adresses in access list diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 2149dd6..3f9fddb 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.local -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # collect wireless mac adresses in access list diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 7bb84dd..b3c1c04 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac%TEMPL% -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # collect wireless mac adresses in access list diff --git a/daily-psk.capsman b/daily-psk.capsman index ca95fb8..944d52c 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk.capsman -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/daily-psk.local b/daily-psk.local index bddf2c9..022b4a3 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk.local -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/daily-psk.template b/daily-psk.template index 967b51a..5f7a832 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk%TEMPL% -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index 83a9d79..c4844bf 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.capsman -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index eb4b915..55a2e3c 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.local -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index 2f070b4..fea0c14 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment%TEMPL% -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-to-dns b/dhcp-to-dns index 3d01ff8..eb73ca3 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-to-dns -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=20 diff --git a/email-backup b/email-backup index a819a4a..1d4099c 100644 --- a/email-backup +++ b/email-backup @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: email-backup -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script diff --git a/global-config b/global-config index 1622ef5..7196eb2 100644 --- a/global-config +++ b/global-config @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-config -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global configuration diff --git a/global-config-overlay b/global-config-overlay index ec0955a..f16a6a9 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -1,5 +1,5 @@ # Overlay for global configuration by RouterOS Scripts -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global configuration, custom overlay diff --git a/global-config.changes b/global-config.changes index 4c31080..9a702a2 100644 --- a/global-config.changes +++ b/global-config.changes @@ -1,5 +1,5 @@ # News, changes and migration by RouterOS Scripts -# Copyright (c) 2019-2021 Christian Hesse +# Copyright (c) 2019-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # Changes for global-config to be added to notification on script updates diff --git a/global-functions b/global-functions index e89587f..30463f1 100644 --- a/global-functions +++ b/global-functions @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-functions -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/global-wait b/global-wait index c601f69..9f3d438 100644 --- a/global-wait +++ b/global-wait @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-wait -# Copyright (c) 2020-2021 Christian Hesse +# Copyright (c) 2020-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script diff --git a/gps-track b/gps-track index 3fc3807..7c582e2 100644 --- a/gps-track +++ b/gps-track @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: gps-track -# Copyright (c) 2018-2021 Christian Hesse +# Copyright (c) 2018-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # track gps data by sending json data to http server diff --git a/hotspot-to-wpa b/hotspot-to-wpa index dbb1f49..b573b3f 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa -# Copyright (c) 2019-2021 Christian Hesse +# Copyright (c) 2019-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # add private WPA passphrase after hotspot login diff --git a/hotspot-to-wpa-cleanup b/hotspot-to-wpa-cleanup index d9bd3ec..f54edc6 100644 --- a/hotspot-to-wpa-cleanup +++ b/hotspot-to-wpa-cleanup @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa-cleanup -# Copyright (c) 2021 Christian Hesse +# Copyright (c) 2021-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 diff --git a/ip-addr-bridge b/ip-addr-bridge index 762c74e..783ff2f 100644 --- a/ip-addr-bridge +++ b/ip-addr-bridge @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ip-addr-bridge -# Copyright (c) 2018-2021 Christian Hesse +# Copyright (c) 2018-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # enable or disable ip addresses based on bridge port state diff --git a/ipsec-to-dns b/ipsec-to-dns index bfdc807..0131f62 100644 --- a/ipsec-to-dns +++ b/ipsec-to-dns @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ipsec-to-dns -# Copyright (c) 2021 Christian Hesse +# Copyright (c) 2021-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # and add/remove/update DNS entries from IPSec mode-config diff --git a/ipv6-update b/ipv6-update index 260b03b..742a7cf 100644 --- a/ipv6-update +++ b/ipv6-update @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ipv6-update -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update firewall and dns settings on IPv6 prefix change diff --git a/learn-mac-based-vlan b/learn-mac-based-vlan index e301a47..e05fb7e 100644 --- a/learn-mac-based-vlan +++ b/learn-mac-based-vlan @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: learn-mac-based-vlan -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # learn MAC address for MAC-based-VLAN diff --git a/lease-script b/lease-script index ab35ee5..2b873c8 100644 --- a/lease-script +++ b/lease-script @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: lease-script -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run scripts on DHCP lease diff --git a/leds-day-mode b/leds-day-mode index 4d77469..ed6f68d 100644 --- a/leds-day-mode +++ b/leds-day-mode @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-day-mode -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # enable LEDs diff --git a/leds-night-mode b/leds-night-mode index 89ac834..af2388c 100644 --- a/leds-night-mode +++ b/leds-night-mode @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-night-mode -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # disable LEDs diff --git a/leds-toggle-mode b/leds-toggle-mode index 6ee81c8..8ec66e3 100644 --- a/leds-toggle-mode +++ b/leds-toggle-mode @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-toggle-mode -# Copyright (c) 2018-2021 Christian Hesse +# Copyright (c) 2018-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # toggle LEDs mode diff --git a/log-forward b/log-forward index 03b408d..3cd83d5 100644 --- a/log-forward +++ b/log-forward @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: log-forward -# Copyright (c) 2020-2021 Christian Hesse +# Copyright (c) 2020-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # forward log messages via notification diff --git a/manage-umts b/manage-umts index b8426bd..8f782ec 100644 --- a/manage-umts +++ b/manage-umts @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: manage-umts -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # manage UMTS interface based on ethernet and wireless status diff --git a/mod/bridge-port-to b/mod/bridge-port-to index 40b216c..d88b1cd 100644 --- a/mod/bridge-port-to +++ b/mod/bridge-port-to @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/bridge-port-to -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # reset bridge ports to default bridge diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan index bfe00e9..db9cbfd 100644 --- a/mod/bridge-port-vlan +++ b/mod/bridge-port-vlan @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/bridge-port-vlan -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # manage VLANs on bridge ports diff --git a/mod/inspectvar b/mod/inspectvar index c78b3f0..2130bb1 100644 --- a/mod/inspectvar +++ b/mod/inspectvar @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/inspectvar -# Copyright (c) 2020-2021 Christian Hesse +# Copyright (c) 2020-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global InspectVar; diff --git a/mod/ipcalc b/mod/ipcalc index bbb9577..a3e1e00 100644 --- a/mod/ipcalc +++ b/mod/ipcalc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/ipcalc -# Copyright (c) 2020-2021 Christian Hesse +# Copyright (c) 2020-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global IPCalc; diff --git a/mod/notification-matrix b/mod/notification-matrix index a78539f..4ec5f6c 100644 --- a/mod/notification-matrix +++ b/mod/notification-matrix @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/notification-matrix -# Copyright (c) 2013-2021 Michael Gisbers +# Copyright (c) 2013-2022 Michael Gisbers # Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/mod/notification-telegram b/mod/notification-telegram index d575103..d42d459 100644 --- a/mod/notification-telegram +++ b/mod/notification-telegram @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/notification-telegram -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global FlushTelegramQueue; diff --git a/mod/scriptrunonce b/mod/scriptrunonce index 0b519c3..3e02236 100644 --- a/mod/scriptrunonce +++ b/mod/scriptrunonce @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/scriptrunonece -# Copyright (c) 2020-2021 Christian Hesse +# Copyright (c) 2020-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global ScriptRunOnce; diff --git a/mode-button b/mode-button index e2da374..e1b2a23 100644 --- a/mode-button +++ b/mode-button @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mode-button -# Copyright (c) 2018-2021 Christian Hesse +# Copyright (c) 2018-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # act on multiple mode and reset button presses diff --git a/netwatch-notify b/netwatch-notify index 7fdf5b5..9ebcc1f 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: netwatch-notify -# Copyright (c) 2020-2021 Christian Hesse +# Copyright (c) 2020-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # monitor netwatch and send notifications diff --git a/netwatch-syslog b/netwatch-syslog index f274c18..42e5c52 100644 --- a/netwatch-syslog +++ b/netwatch-syslog @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: netwatch-syslog -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires: dont-require-permissions=yes diff --git a/ospf-to-leds b/ospf-to-leds index 40fbbb3..448cc6b 100644 --- a/ospf-to-leds +++ b/ospf-to-leds @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ospf-to-leds -# Copyright (c) 2020-2021 Christian Hesse +# Copyright (c) 2020-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # visualize ospf instance state via leds diff --git a/packages-update b/packages-update index 627a7c4..b6b0524 100644 --- a/packages-update +++ b/packages-update @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: packages-update -# Copyright (c) 2019-2021 Christian Hesse +# Copyright (c) 2019-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # download packages and reboot for installation diff --git a/ppp-on-up b/ppp-on-up index 70c5cd6..eebe81c 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ppp-on-up -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run scripts on ppp up diff --git a/rotate-ntp b/rotate-ntp index 24eb107..83bf90a 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: rotate-ntp -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # rotate the ntp servers diff --git a/sms-action b/sms-action index e48c632..a1fa4e9 100644 --- a/sms-action +++ b/sms-action @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: sms-action -# Copyright (c) 2018-2021 Christian Hesse +# Copyright (c) 2018-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run action on received SMS diff --git a/sms-forward b/sms-forward index 2eecc07..436985d 100644 --- a/sms-forward +++ b/sms-forward @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: sms-forward -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # forward SMS to e-mail diff --git a/ssh-keys-import b/ssh-keys-import index 1f158fd..abf0350 100644 --- a/ssh-keys-import +++ b/ssh-keys-import @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ssh-keys-import -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # import ssh keys from file diff --git a/super-mario-theme b/super-mario-theme index e13c934..ae52fd1 100644 --- a/super-mario-theme +++ b/super-mario-theme @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: super-mario-theme -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # play Super Mario theme diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index 0bac0a2..14b03e5 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: unattended-lte-firmware-upgrade -# Copyright (c) 2018-2021 Christian Hesse +# Copyright (c) 2018-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # schedule unattended lte firmware upgrade diff --git a/update-gre-address b/update-gre-address index af57d2d..475b30c 100644 --- a/update-gre-address +++ b/update-gre-address @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: update-gre-address -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update gre interface remote address with dynamic address from diff --git a/update-tunnelbroker b/update-tunnelbroker index 4924516..d454cd7 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: update-tunnelbroker -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/upload-backup b/upload-backup index cde847c..f243ef0 100644 --- a/upload-backup +++ b/upload-backup @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: upload-backup -# Copyright (c) 2013-2021 Christian Hesse +# Copyright (c) 2013-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script From 6eddaf9b87d88d61d116a972d0ebfce0e732c421 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 3 Jan 2022 09:42:37 +0100 Subject: [PATCH 0898/2612] README: convert Telegram group qr code to AVIF --- README.d/telegram-group.avif | Bin 0 -> 891 bytes README.d/telegram-group.png | Bin 20995 -> 0 bytes README.md | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 README.d/telegram-group.avif delete mode 100644 README.d/telegram-group.png diff --git a/README.d/telegram-group.avif b/README.d/telegram-group.avif new file mode 100644 index 0000000000000000000000000000000000000000..eb75d13ab07889b8b4232f8f8f5f296f1d355aa7 GIT binary patch literal 891 zcmZQzU{FXasVqn=%S>Yc0uY^>nP!-qnV9D5Xy^zO`jnemk_eIm0*#E6oFWL5fuSHX zxdg@r(K(q(Fk|=%GD~v7a*RMyE;A=T8N_p8U|GFKxrGY@PxSVjuS zNo4{l2C7LcGca_{&&dZ{nUz^kQ~(tB&MZjI2ht*$#RaJ#g+NdP#R3JH6`3FbW)2Px zAjOkdX6W3g0Aw*R2q)*~6y+u7Q~*upWngOn3W;YH09}=to03=} z#K6UAA-VT=A|o%`1fz>AE-4I&Z4v=H(tNKz*%5qA`h%ILf?YQ@Hx|S*Iz82-Ei-o{bjf0mYP$csxLoJI5h9Op>wY%Q^k&w4H>x`&RRLW`*->N zvJ#smjk;6C6Cxigy)25~UOMMk(uNKl?fPq$8J#wFN*Y2p{}9;vO>1sR#IEbY(wVE* z&06pNd|I*YM~4WlqxBW%a+fp2a&2Q-BR=m-JfD5gq#4F$cOHI~`?|ncgm0CASi-Ng zzKi0q7Aj%QFJx~Se@&dj%2pye_X3mV{S~J)`wI6>a8mWK4Ab@K&!5A1;M}|YoO8}C z+rEKU=X#`s_KB*_ga7uYm8TnP_^g-D6@4hxe!)o2*ev&m$h?eCKiRaEMq#)IQ_{qFl$v1~LtPeQoW@~z+&!=HZ zS(}lGhckIJ2wSF5Y0j+@eeQN}%P$b@M+?iZicS|9{fG1DiMfIwGm@ VIb$}f?~KP&!Z*x+urG1LEC6%5Sb_im literal 0 HcmV?d00001 diff --git a/README.d/telegram-group.png b/README.d/telegram-group.png deleted file mode 100644 index 4217477b40e8ef95cbfc73ade6fed2cb04b8958a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20995 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 Date: Mon, 3 Jan 2022 09:49:24 +0100 Subject: [PATCH 0899/2612] README: convert screenshots to AVIF --- README.d/01-download-certs.avif | Bin 0 -> 2115 bytes README.d/01-download-certs.png | Bin 4827 -> 0 bytes README.d/02-import-certs.avif | Bin 0 -> 2356 bytes README.d/02-import-certs.png | Bin 4824 -> 0 bytes README.d/03-check-certs.avif | Bin 0 -> 5059 bytes README.d/03-check-certs.png | Bin 8366 -> 0 bytes README.d/04-import-scripts.avif | Bin 0 -> 3810 bytes README.d/04-import-scripts.png | Bin 5446 -> 0 bytes README.d/05-edit-global-config-overlay.avif | Bin 0 -> 6600 bytes README.d/05-edit-global-config-overlay.png | Bin 12301 -> 0 bytes README.d/06-run-and-schedule-scripts.avif | Bin 0 -> 2994 bytes README.d/06-run-and-schedule-scripts.png | Bin 4526 -> 0 bytes README.d/07-schedule-update.avif | Bin 0 -> 2312 bytes README.d/07-schedule-update.png | Bin 3654 -> 0 bytes README.d/08-update-scripts.avif | Bin 0 -> 1917 bytes README.d/08-update-scripts.png | Bin 2985 -> 0 bytes README.d/09-install-scripts.avif | Bin 0 -> 2493 bytes README.d/09-install-scripts.png | Bin 4320 -> 0 bytes README.d/10-schedule-script.avif | Bin 0 -> 2009 bytes README.d/10-schedule-script.png | Bin 3292 -> 0 bytes README.d/11-setup-lease-script.avif | Bin 0 -> 3712 bytes README.d/11-setup-lease-script.png | Bin 7041 -> 0 bytes README.md | 22 ++++++++++---------- 23 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 README.d/01-download-certs.avif delete mode 100644 README.d/01-download-certs.png create mode 100644 README.d/02-import-certs.avif delete mode 100644 README.d/02-import-certs.png create mode 100644 README.d/03-check-certs.avif delete mode 100644 README.d/03-check-certs.png create mode 100644 README.d/04-import-scripts.avif delete mode 100644 README.d/04-import-scripts.png create mode 100644 README.d/05-edit-global-config-overlay.avif delete mode 100644 README.d/05-edit-global-config-overlay.png create mode 100644 README.d/06-run-and-schedule-scripts.avif delete mode 100644 README.d/06-run-and-schedule-scripts.png create mode 100644 README.d/07-schedule-update.avif delete mode 100644 README.d/07-schedule-update.png create mode 100644 README.d/08-update-scripts.avif delete mode 100644 README.d/08-update-scripts.png create mode 100644 README.d/09-install-scripts.avif delete mode 100644 README.d/09-install-scripts.png create mode 100644 README.d/10-schedule-script.avif delete mode 100644 README.d/10-schedule-script.png create mode 100644 README.d/11-setup-lease-script.avif delete mode 100644 README.d/11-setup-lease-script.png diff --git a/README.d/01-download-certs.avif b/README.d/01-download-certs.avif new file mode 100644 index 0000000000000000000000000000000000000000..41fa5caba52eb91d1144a9d21f2e7a1a00acc096 GIT binary patch literal 2115 zcmXv|2|UyP8{dXsu9zbY$uXm{WPY)cYsrycbBElF<;&O{!<^+Ney+qyuAI54xk^Gg zlPf8qOhuV15yF4^zkbi>^?ARa=ly5_<~KPx=}vLBhH{{xWmBo+$;{$%&V zMi7WimIX1a4nfDDn@fNoh?@(8SjVVBp~HYOjqi#ZWcs|W>h@nnJI-10p5^;#6F zDaC}%ZuzEVhkj~7;K9(;nfFdl;U=f#DZ5HmGd!{8irC|!`1=q|5sEP#LE%`1z9>p6 zZ2t226J_&GRs-8gaD33|{vD{<61ZJU8xu0?FmIjZv>g|>2@EbI-{BU*bBa~~!F240<3ya{ zw&m6awStlT^r6+kIYj+4dcMew2{wM>aeNK}P0*C3%>_Qy{r7^^--B0dBxM{?R!tQO z2b1^$EjwKQ)7`e9wbH=!2T|d_`~xU(PSmk!x1Z}H3gLoPkk_pY&d6CjNUy;Lj*wh~ ztAI5J^EZ@#ahx+M0T(iJ2Q3|QogJE0nWblk_lI;I&4#@{kqQ+kYO1M{T;#j*4zZC` z^*V4$mhD%Sa7x{9U&R8)r|TvOxf;OSXs1}C#U!6#!`oNS*(oB0ZrptqG;!d|N-Pbt zt$6jfXR_Kwnkjt~@vISr>`aprpR!bV&{HA@@poCzEfTjt>o7f1c~0*UOvZavCVSdR z1}a}L2L){EeO;f9syaX2lUB z_sI2EDCtNnNaDlR1H<{@x00qyu;QUGfyjN0WQF=iz84}lBPXRk8PyiA81g!b zG0k2}YwJf;&zd!i+%)q9E4_`19r5Si_VphAn7Wi^mJ{ou1v5xbacv{VKQ=brY2?lJ ze20daV;+xxdHjBkfzlt)8ddMp%=3nR*G@C)G*44Nsd(fGC1jk9I6suW0LDOY;g<(A z^RD`<8}6J~QOH0#*WlHzWhw$(yHDZzQEpV(|Gnb^OR zpBcuQ$6NS}BbArZyS0mpLk1iKZhu3|k{Rv5UZM^C#~aRa+qd7*Wuj?tE(t7{sp6#j zQ8wE7yeff8g%jxKL|(Nv+IA+RI)vC7%7*BCFX|x{QCcQ)Z)!!`d$!*7Wrd>?7cM__ zQrW8D8gh{Zlny(&es@offTeR zGi^vs@7fnAJ#QT|!ImZFw770lRV(_FM`N-T7xTOtUhtCK#fQARF(CMwV39ICMtfZ!EiO_M#3x%W zFjL0VOB^Pa{;gkkPl?b=)4p3G!5oPjw#Nq;&k(~!#b)NdO?^0tb%ul&8o3(lva25X zszah3liO)oEtQngFM?^!K2Yw!l1gqn;ED0}u8yS8#q zvqdH@Tt7!M>{eqnBxq`^kcl|POQ{Z`vw07m#P=uRNB#Sy?;speaDy1J#-6@bo{Q!r za zl(1JS^cPybpTsA_PEq3S#}e1{D%bD`q^y6UWdd?_NF{e`r&{ou%%Eo(C4|{Um4X6i bKJNc|9r68sehhLcHuObVc&1;T-lhKmP=>Wq literal 0 HcmV?d00001 diff --git a/README.d/01-download-certs.png b/README.d/01-download-certs.png deleted file mode 100644 index d33040b5f4132aea24198d8ae3677968a66fdb28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4827 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 B4nhC` diff --git a/README.d/02-import-certs.avif b/README.d/02-import-certs.avif new file mode 100644 index 0000000000000000000000000000000000000000..09fe58604b4e17f73b188e222eb458514693d5da GIT binary patch literal 2356 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 Hyp;Vv!&Gzy literal 0 HcmV?d00001 diff --git a/README.d/03-check-certs.png b/README.d/03-check-certs.png deleted file mode 100644 index 802967cf5c65a89ccb81d3920e3c8072b8207d99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8366 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 diff --git a/README.d/04-import-scripts.avif b/README.d/04-import-scripts.avif new file mode 100644 index 0000000000000000000000000000000000000000..c6a2a3c6a7f8d7623a83e759c460413977675c5d GIT binary patch literal 3810 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 F{{eYG64?L% literal 0 HcmV?d00001 diff --git a/README.d/04-import-scripts.png b/README.d/04-import-scripts.png deleted file mode 100644 index 0db8c4d13e03bdedd9665fab87cfb1163f4b1bee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5446 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 Y!J6*%I|tOnAeQFKx1ypCYkw&G4|w`=$N&HU literal 0 HcmV?d00001 diff --git a/README.d/06-run-and-schedule-scripts.png b/README.d/06-run-and-schedule-scripts.png deleted file mode 100644 index 23b4d7b8017ba2f19dd30db30b3ca09281a145b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4526 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 M07*qoM6N<$f;qyZD*ylh diff --git a/README.d/07-schedule-update.avif b/README.d/07-schedule-update.avif new file mode 100644 index 0000000000000000000000000000000000000000..cb43b48e0598a62d7974ea8ab3ada4ac6b3c36d9 GIT binary patch literal 2312 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 Or|G;^*=^^|=6?YzZyuWf literal 0 HcmV?d00001 diff --git a/README.d/07-schedule-update.png b/README.d/07-schedule-update.png deleted file mode 100644 index 5449e9158bc2469c45c9314b2775e662cdb53efd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3654 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 literal 0 HcmV?d00001 diff --git a/README.d/08-update-scripts.png b/README.d/08-update-scripts.png deleted file mode 100644 index 3f05355c1d86db446084f7f388e9daa0d340f936..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2985 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 diff --git a/README.d/09-install-scripts.avif b/README.d/09-install-scripts.avif new file mode 100644 index 0000000000000000000000000000000000000000..467b9e4b50387a6e74c2ab74a6c81b2a48d4869e GIT binary patch literal 2493 zcmXv|2Rzhq8~+I7lsIDy%1r@-Lb#dfE9g_C9gM3# z;>@Fjga;Ds`@a+ba3~l5|L13nMmhg~3^NYpkNM|OQBVMd#=4wUMgTxXd1nYvK>&cR zn37ANP~QJ`|8pRe!j<~0nbLy@lvgmsqOt#0dZKW?IEoHO;asp3=0y47T+bQ-fJT%8 zNXlo$p@LEW6goOO3Ns=C6%3<<&J=*d1&j9ec0mVICNlw`NQwkT;V_6Zj}nx_XsM`U zXen1!Vvq=bcHjcNn%EmHw2(0VvtkCDDUy0d+0gmhw~mrYyx_v-cdB7>v_fNw1&zaI zlpKEkC|!+pX4bzRzt|{9y-XGUr@`Si87mZMnFdBY4gDkGr+GpsWO30CTF) z=w)MU;p~_->yuKbdas?AF`<_W=9tNEPkSTIH!rQ!AU_)}OFaja@buO!4S!*Snm=V& z6m#&(f0nXCudHG_CY;NuStf=f)r#^S_|dY#Y#^Yc1Mx}up1*&2;DKSWD8m}+`S_!S zguLM+1a@8dDR5Xpw`_N4jy*Z%F{#!7+g;Muz#iGA553y72(YZv0)rbvT&%R! zX_xp*fi%Z9d4YV^=X8U;U)luQ4ArsM^M9^N=$}^y(X!>*dp%q6ImxJ+o3s#ZfIr@P z006nG(*33#X`b3OeFO_F&;fH}Zc%Yz(M_c*lg=3}G z-I)}gFNqA=pP=fhF*zN=T%UXj_(ggwwmG}{Q;GI>p`ZFd}Be1c|SpPxbwwgWGVLK>&@WXAp}e1hdJ-1?+=)sM+bcj zy(2SrP%0i)g%lHhC@qPWHMnRLo6+AaxnxJ4z_zX`<_w@YWivZBYn`giIOT~$z-)`d zac+J`d@&O8`{vy@UgcvEc)YslL9d>L)h)G}vZS8$AA4wUb}Nd^0spai%nL0vOOy+; zYX16XREPY|(x*lfRw^g#s!i8?!LY|Lk1)2%0N&>CvM07GM;12>1_Z>{H^cQ$h8p-9 zK6ks&4Jp@6>5>PXuMqDpE6Q{*4%Lc{`yG?2K8mj&NhB+aK&3FN-A9yo)t}jK*HLTNR z%aQy) zYwC5-Q5pl771P~fn67U#67$U1td?(q!M)BU1;tDU0>n*`vS-}pulV90oz~DU(iuJY z_<(z3neIcgwcEhTT7tps>=K?&YuqzlglA7y!Kk8(=CT~!yOtrrOn{GvG#KTZKwgpC ztXoP8(l~U{%|GgWaawI+IoGg%dTVAvXW^dG_%B$g_v55&%e)EVwc4FJB}j7qhUe%0 zk*AFflk-!hx<1jx3jWPD5e}VEF@DLrftDeh+Qdc3lGc2h!QFi_0(|?21#&A%7c`R2 z-kxI8R@ApuEx#p}6EYsBQ#5Mj?C?G#$m&U*0hGUpx71U6zst|L_DZFPgo4PpM(rya z8Z!N-J*z*zB-}LOTHcrmjRblV`6>j5!V`0={hT%lrN+)uo{VS~?A4u5Ru4;d?s%Smg8P85j z4WF{fsS?xG3(Vp(c<&lD`S`*5ER{l@RH&|{zCvefCh6(9-Y+LA=;8Y5;M8!H8@5j4 zoXOdhaP-wkZNiaB)r3&Y*RG~15wG0UyT#4v%`tZ_4aI*NYf{ zD;MTW#OdpH!oY+}-E%VPH$}1oo|kBWbPhushb`o^T~9)sGPj z^hl(>f!x&t4aezB=6VgSik&bAHowoD3CsZp%O+CtSF^lZzmpnxVNa62&Wm@yX$r#T zufS_AuG~*>kEHJ*4fMFG@eL$AlR@^q4_U7hyfK>p<`=Z#jpUJ*ovFm!6-)0&hb+;l zPp~$`@ZfoXyN^2Xx8uRP0*eNPZgcEtvb!7Y^J%O0k*(7ur+k@E`(;v^QsA(UhO}vB zlSM+5ArWz9&3I31of$CiTud1Z-K67`S9QPi5bUGe)1gmFq|q~gc&lsD_GMn}TW^+;em`tQu0KjPs4O{x zU}gsqcHHe-@ga}DXo6RZyk2}S;ogt&TayA+v7GQre41_%{h9Q*XgqN?uB z`?A_#tBw@vv%3K@N)2`&^HiPrz6mdb*>=Ig<7BV8zn%V(Eq{>5U8RTizUTJbCZGQ#^qu literal 0 HcmV?d00001 diff --git a/README.d/09-install-scripts.png b/README.d/09-install-scripts.png deleted file mode 100644 index 6adee16f5ec7ce9e228ac5d86c06336db1fa3d05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4320 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 W#X?u*9i*|kxZ~uYt)%GKYU95V0gdGV literal 0 HcmV?d00001 diff --git a/README.d/10-schedule-script.png b/README.d/10-schedule-script.png deleted file mode 100644 index 5e72960ce7610ec6c68c59fd3d1f9e51bafa2f90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3292 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

D&Geg6n)G}MsS~up@anUy?$lVc zz0v95LGPnL@y$~G6iguPcQhIC_YLKjunH#YM=hO!N^~B!p&RVBu6s~Nq|Abd0YArY zjND{x(;FWOg-qg@!4jvhuZE&_)*MK)b#lole2qhZFpbpouUN-w=J!D)W`@%FShaQV zpSG5*6Y*Qf^ue>rov76Fn!5w2;`<6F}sLser!@WxGYt;kV1U71HlJSFaAoDzutu!Vb zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3&uk}aujh5s`O4*?`VFdRS-;Td@N{*>p@-M2e# zIBZw->8je5I}@a(^`O%Ium61MKlrF6ORCLApS@>3>a0^1-;Dgn$Nl+r=KSLO%D?jS zwetI_lK%3GU*8oz|Ma@NpT8AeQNHSrAAdhj<3{?Y8};8`%Rjwd+P}Q6zaKAuS<&df zpDcfV-DZCI&mZHDfA9Ht>^a5Nb=6LN`p-@M+T!;e7j6op-`hH$#=pk*_I*x1M_&1) zQnTliH=n1>B1Q8nwRlvmSB$SBNA!DbsL7P0S&P=BRcm=-I@NWk=#i_+ ztMYp-<$Lb@9(T&%!Ctsh3O6gf+@efXe>9WToq*=Y;fiM;}*M>Kd`0gYqWA<<7@r#X7isnphP^ov6!NC zAorrJ^pZ`)N}-N}{w!85nyPGCP+Ajbl~PqZ%^4EU<~>%vYo*DLml+`%(X^}4nyHIk z)!J%L)#?C4t7)sPwcf0aHrwjjYj3@G>oJSV)T%Y>W;Sfv8anD|qYoQn%(2pxsmyAd zecBvz&b4^x;?9eAud#Sx%hp|Y+kM*}d+v3B -Ke(a1h&q^+?UcGsD^WoFiEf*-= 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 diff --git a/README.md b/README.md index 57c52ca..3c38b5b 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ certificate chain. / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem"; -![screenshot: download certs](README.d/01-download-certs.png) +![screenshot: download certs](README.d/01-download-certs.avif) Note that the commands above do *not* verify server certificate, so if you want to be safe download with your workstations's browser and transfer the @@ -65,7 +65,7 @@ Then we import the certificates. / certificate import file-name=letsencrypt-R3.pem passphrase=""; -![screenshot: import certs](README.d/02-import-certs.png) +![screenshot: import certs](README.d/02-import-certs.avif) For basic verification we rename the certificates and print their count. Make sure the certificate count is **two**. @@ -74,7 +74,7 @@ sure the certificate count is **two**. / certificate set name="ISRG-Root-X1" [ find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ]; / certificate print count-only where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6"; -![screenshot: check certs](README.d/03-check-certs.png) +![screenshot: check certs](README.d/03-check-certs.avif) Always make sure there are no certificates installed you do not know or want! @@ -86,7 +86,7 @@ Now let's download the main scripts and add them in configuration on the fly. :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); }; -![screenshot: import scripts](README.d/04-import-scripts.png) +![screenshot: import scripts](README.d/04-import-scripts.avif) The configuration needs to be tweaked for your needs. Edit `global-config-overlay`, copy configuration from @@ -95,21 +95,21 @@ Save changes and exit with `Ctrl-o`. / system script edit global-config-overlay source; -![screenshot: edit global-config-overlay](README.d/05-edit-global-config-overlay.png) +![screenshot: edit global-config-overlay](README.d/05-edit-global-config-overlay.avif) And finally load configuration and functions and add the scheduler. / system script { run global-config; run global-functions; }; / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-functions; }"; -![screenshot: run and schedule scripts](README.d/06-run-and-schedule-scripts.png) +![screenshot: run and schedule scripts](README.d/06-run-and-schedule-scripts.avif) The last step is optional: Add this scheduler **only** if you want the scripts to be updated automatically! / system scheduler add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; -![screenshot: schedule update](README.d/07-schedule-update.png) +![screenshot: schedule update](README.d/07-schedule-update.avif) ### Changes for RouterOS v6 @@ -145,7 +145,7 @@ everything is up-to-date it will not produce any output. $ScriptInstallUpdate; -![screenshot: update scripts](README.d/08-update-scripts.png) +![screenshot: update scripts](README.d/08-update-scripts.avif) Adding a script --------------- @@ -155,7 +155,7 @@ a comma separated list of script names. $ScriptInstallUpdate check-certificates,check-routeros-update; -![screenshot: install scripts](README.d/09-install-scripts.png) +![screenshot: install scripts](README.d/09-install-scripts.avif) Scheduler and events -------------------- @@ -167,7 +167,7 @@ miss an update. / system scheduler add name="check-routeros-update" interval=1h on-event="/ system script run check-routeros-update;"; -![screenshot: schedule script](README.d/10-schedule-script.png) +![screenshot: schedule script](README.d/10-schedule-script.avif) Some events can run a script. If you want your DHCP hostnames to be available in DNS use `dhcp-to-dns` with the events from dhcp server. For a regular @@ -177,7 +177,7 @@ cleanup add a scheduler entry. / ip dhcp-server set lease-script=lease-script [ find ]; / system scheduler add name="dhcp-to-dns" interval=5m on-event="/ system script run dhcp-to-dns;"; -![screenshot: setup lease script](README.d/11-setup-lease-script.png) +![screenshot: setup lease script](README.d/11-setup-lease-script.avif) There's much more to explore... Have fun! From 772b675001a577a763f7393c1437d0c6be8bbca9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 3 Jan 2022 09:50:39 +0100 Subject: [PATCH 0900/2612] doc/accesslist-duplicates: convert screenshot to AVIF --- doc/accesslist-duplicates.d/01-example.avif | Bin 0 -> 5172 bytes doc/accesslist-duplicates.d/01-example.png | Bin 13646 -> 0 bytes doc/accesslist-duplicates.md | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 doc/accesslist-duplicates.d/01-example.avif delete mode 100644 doc/accesslist-duplicates.d/01-example.png diff --git a/doc/accesslist-duplicates.d/01-example.avif b/doc/accesslist-duplicates.d/01-example.avif new file mode 100644 index 0000000000000000000000000000000000000000..9b26451f371110d1539602b9a7d5fe636be664bd GIT binary patch literal 5172 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 NB@wesCo5(;@qg2)t7!lL literal 0 HcmV?d00001 diff --git a/doc/accesslist-duplicates.d/01-example.png b/doc/accesslist-duplicates.d/01-example.png deleted file mode 100644 index 0922984c230e4a42b896749a14cc412ecd348dc3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13646 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 UaOZsXUm#XNR#m1}$}H@E0my`I-~a#s diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index 64a5fea..e052c20 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -33,7 +33,7 @@ Run this script from a terminal: / system script run accesslist-duplicates.local; -![screenshot: example](accesslist-duplicates.d/01-example.png) +![screenshot: example](accesslist-duplicates.d/01-example.avif) See also -------- From 45ffb7e5521ddf551147e3d992fe94f279862e88 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 3 Jan 2022 09:51:08 +0100 Subject: [PATCH 0901/2612] add AVIF logo --- logo.avif | Bin 0 -> 2607 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 logo.avif diff --git a/logo.avif b/logo.avif new file mode 100644 index 0000000000000000000000000000000000000000..d118cc314250c762a2a328d71f42e14b7d35e78e GIT binary patch literal 2607 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 literal 0 HcmV?d00001 From 7f0a8cdfcd4977ad4cd719d0e8b12bd1a8565a32 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 2 Jan 2022 20:47:12 +0100 Subject: [PATCH 0902/2612] netwatch-notify: better match notify-entries --- netwatch-notify | 157 ++++++++++++++++++++++++------------------------ 1 file changed, 80 insertions(+), 77 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 9ebcc1f..767168b 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -50,94 +50,97 @@ $ScriptLock $0; -:foreach Host in=[ / tool netwatch find where comment~"^notify," disabled=no ] do={ +:foreach Host in=[ / tool netwatch find where comment~"notify" disabled=no ] do={ :local HostVal [ / tool netwatch get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; - :local HostName ($HostInfo->"hostname"); - :local Metric { "count"=0; "notified"=false }; - :if ([ :typeof ($NetwatchNotify->$HostName) ] = "array") do={ - :set $Metric ($NetwatchNotify->$HostName); - } + :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ + :local HostName ($HostInfo->"hostname"); - :if ([ :typeof ($HostInfo->"resolve") ] = "str" && [ $DNSIsResolving ] = true) do={ - :do { - :local Resolve [ :resolve ($HostInfo->"resolve") ]; - :if ($Resolve != $HostVal->"host") do={ - $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ - $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . \ - "' resolves to different address " . $Resolve . ", updating.") false; - / tool netwatch set host=$Resolve $Host; - :set ($Metric->"resolve-failed") false; - } - } on-error={ - :if ($Metric->"resolve-failed" != true) do={ - $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ - $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . "' failed.") false; - :set ($Metric->"resolve-failed") true; + :local Metric { "count"=0; "notified"=false }; + :if ([ :typeof ($NetwatchNotify->$HostName) ] = "array") do={ + :set $Metric ($NetwatchNotify->$HostName); + } + + :if ([ :typeof ($HostInfo->"resolve") ] = "str" && [ $DNSIsResolving ] = true) do={ + :do { + :local Resolve [ :resolve ($HostInfo->"resolve") ]; + :if ($Resolve != $HostVal->"host") do={ + $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ + $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . \ + "' resolves to different address " . $Resolve . ", updating.") false; + / tool netwatch set host=$Resolve $Host; + :set ($Metric->"resolve-failed") false; + } + } on-error={ + :if ($Metric->"resolve-failed" != true) do={ + $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ + $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . "' failed.") false; + :set ($Metric->"resolve-failed") true; + } } } - } - :if ($HostVal->"status" = "up") do={ - :local Count ($Metric->"count"); - :if ($Count > 0) do={ - $LogPrintExit2 info $0 ("Host " . $HostName . " (" . $HostVal->"host" . ") is up.") false; - :set ($Metric->"count") 0; - } - :if ($Metric->"notified" = true) do={ - :local Message ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ - "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); - :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $HostName "up" ($HostInfo->"up-hook") ]); + :if ($HostVal->"status" = "up") do={ + :local Count ($Metric->"count"); + :if ($Count > 0) do={ + $LogPrintExit2 info $0 ("Host " . $HostName . " (" . $HostVal->"host" . ") is up.") false; + :set ($Metric->"count") 0; } - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $HostName . " up"); \ - message=$Message }); - } - :set ($Metric->"notified") false; - :set ($Metric->"parent") ($HostInfo->"parent"); - :set ($Metric->"since"); - } else={ - :set ($Metric->"count") ($Metric->"count" + 1); - :set ($Metric->"parent") ($HostInfo->"parent"); - :set ($Metric->"since") ($HostVal->"since"); - :local Count [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; - :local Parent ($HostInfo->"parent"); - :while ([ :len $Parent ] > 0) do={ - :set Count ($Count + 1); - :set Parent ($NetwatchNotify->$Parent->"parent"); - } - :set Parent ($HostInfo->"parent"); - :local ParentNotified false; - :while ($ParentNotified = false && [ :len $Parent ] > 0) do={ - :set ParentNotified [ $IfThenElse (($NetwatchNotify->$Parent->"notified") = true) true false ]; - :if ($ParentNotified = false) do={ + :if ($Metric->"notified" = true) do={ + :local Message ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ + "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); + :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $HostName "up" ($HostInfo->"up-hook") ]); + } + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $HostName . " up"); \ + message=$Message }); + } + :set ($Metric->"notified") false; + :set ($Metric->"parent") ($HostInfo->"parent"); + :set ($Metric->"since"); + } else={ + :set ($Metric->"count") ($Metric->"count" + 1); + :set ($Metric->"parent") ($HostInfo->"parent"); + :set ($Metric->"since") ($HostVal->"since"); + :local Count [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; + :local Parent ($HostInfo->"parent"); + :while ([ :len $Parent ] > 0) do={ + :set Count ($Count + 1); :set Parent ($NetwatchNotify->$Parent->"parent"); } - } - $LogPrintExit2 info $0 ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ - $Metric->"count" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ - ($Metric->"notified" = true) ("already notified.") ($Count - $Metric->"count" . " to go.") ] \ - ("parent host " . $Parent . " is down.") ]) false; - :if ((($Count * 2) - ($Metric->"count" * 3)) / 2 = 0 && [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ - $NetwatchNotifyHook $HostName "pre-down" ($HostInfo->"pre-down-hook"); - } - :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ - :local Message ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); - :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $HostName "down" ($HostInfo->"down-hook") ]); + :set Parent ($HostInfo->"parent"); + :local ParentNotified false; + :while ($ParentNotified = false && [ :len $Parent ] > 0) do={ + :set ParentNotified [ $IfThenElse (($NetwatchNotify->$Parent->"notified") = true) true false ]; + :if ($ParentNotified = false) do={ + :set Parent ($NetwatchNotify->$Parent->"parent"); + } + } + $LogPrintExit2 info $0 ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ + $Metric->"count" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ + ($Metric->"notified" = true) ("already notified.") ($Count - $Metric->"count" . " to go.") ] \ + ("parent host " . $Parent . " is down.") ]) false; + :if ((($Count * 2) - ($Metric->"count" * 3)) / 2 = 0 && [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ + $NetwatchNotifyHook $HostName "pre-down" ($HostInfo->"pre-down-hook"); + } + :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ + :local Message ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); + :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $HostName "down" ($HostInfo->"down-hook") ]); + } + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down"); \ + message=$Message }); + :set ($Metric->"notified") true; } - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down"); \ - message=$Message }); - :set ($Metric->"notified") true; } + :set ($NetwatchNotify->$HostName) { + "count"=($Metric->"count"); + "notified"=($Metric->"notified"); + "parent"=($Metric->"parent"); + "resolve-failed"=($Metric->"resolve-failed"); + "since"=($Metric->"since") }; } - :set ($NetwatchNotify->$HostName) { - "count"=($Metric->"count"); - "notified"=($Metric->"notified"); - "parent"=($Metric->"parent"); - "resolve-failed"=($Metric->"resolve-failed"); - "since"=($Metric->"since") }; } From 491ecdb81254c07840939d9fd21d7f888e6c8386 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 2 Jan 2022 21:40:40 +0100 Subject: [PATCH 0903/2612] netwatch-notify: initialize after lock --- netwatch-notify | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 767168b..da6c5ce 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -44,12 +44,12 @@ :return ("Ran hook:\n" . $Hook); } +$ScriptLock $0; + :if ([ :typeof $NetwatchNotify ] = "nothing") do={ :set NetwatchNotify [ :toarray "" ]; } -$ScriptLock $0; - :foreach Host in=[ / tool netwatch find where comment~"notify" disabled=no ] do={ :local HostVal [ / tool netwatch get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; From cd3fde59d767e9948cbaad6fea08deb6b9b7a181 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 2 Jan 2022 21:44:22 +0100 Subject: [PATCH 0904/2612] netwatch-notify: give netwatch some time to settle --- netwatch-notify | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netwatch-notify b/netwatch-notify index da6c5ce..ae89cfb 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -46,6 +46,10 @@ $ScriptLock $0; +:if ([ / system resource get uptime ] < 5m) do={ + $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; +} + :if ([ :typeof $NetwatchNotify ] = "nothing") do={ :set NetwatchNotify [ :toarray "" ]; } From 57c80dc2a42280c1a8d1f2c7de8d73a3e03190bc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 2 Jan 2022 22:21:20 +0100 Subject: [PATCH 0905/2612] introduce netwatch-dns --- README.md | 1 + doc/netwatch-dns.md | 71 ++++++++++++++++++++++++++++++++++++++ doc/netwatch-notify.md | 12 +++++++ global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- netwatch-dns | 78 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 doc/netwatch-dns.md create mode 100644 netwatch-dns diff --git a/README.md b/README.md index 3c38b5b..f55a14b 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,7 @@ Available scripts * [Manage LEDs dark mode](doc/leds-mode.md) * [Forward log messages via notification](doc/log-forward.md) * [Mode button with multiple presses](doc/mode-button.md) +* [Manage DNS and DoH servers from netwatch](doc/netwatch-dns.md) * [Notify on host up and down](doc/netwatch-notify.md) * [Manage remote logging](doc/netwatch-syslog.md) * [Visualize OSPF state via LEDs](doc/ospf-to-leds.md) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md new file mode 100644 index 0000000..96710a2 --- /dev/null +++ b/doc/netwatch-dns.md @@ -0,0 +1,71 @@ +Manage DNS and DoH servers from netwatch +======================================== + +[◀ Go back to main README](../README.md) + +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + +Description +----------- + +This script reads server state from netwatch and manages used DNS and +DoH (DNS over HTTPS) servers. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate netwatch-dns; + +Then add a scheduler to run it periodically: + + / system scheduler add interval=1m name=netwatch-dns on-event="/ system script run netwatch-dns;" start-time=startup; + +Configuration +------------- + +The DNS and DoH servers to be checked have to be added to netwatch with +specific comment: + + / tool netwatch add comment="doh, hostname=cloudflare-dns" host=1.1.1.1; + / tool netwatch add comment="dns, hostname=google-dns" host=8.8.8.8; + / tool netwatch add comment="doh, dns, hostname=quad-nine" host=9.9.9.10; + +This will configure *cloudflare-dns* for DoH (`https://1.1.1.1/dnsquery`), and +*google-dns* and *quad-nine* for regular DNS (`8.8.8.8,9.9.9.10`) if up. +If *cloudflare-dns* is down the script will fall back to *quad-nine* for DoH. + +Giving a specific query url for DoH is possible: + + / tool netwatch add comment="doh, hostname=nextdns, doh-url=https://dns.nextdns.io/dns-query" host=199.247.16.158; + +Note that using a name in DoH url may introduce a chicken-and-egg issue! + +Sometimes using just one specific (possibly internal) DNS server may be +desired, with fallback in case it fails. This is possible as well: + + / tool netwatch add comment="dns, hostname=pi-hole" host=10.0.0.10; + / tool netwatch add comment="dns-fallback, hostname=cloudflare-dns" host=1.1.1.1; + +Tips & Tricks +------------- + +### Use in combination with notifications + +Netwatch entries can be created to work with both - this script and +[netwatch-notify](netwatch-notify.md). Just give options for both: + + / tool netwatch add comment="doh, notify, hostname=cloudflare-dns" host=1.1.1.1; + +Also this allows to update host address, see option `resolve`. + +See also +-------- + +* [Notify on host up and down](netwatch-notify.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index ef6f37e..78a0eed 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -116,6 +116,18 @@ link failure this address is not available, so use something reliable but non-essential. In this example the address `1.0.0.1` is used, the same service (Cloudflare DNS) is available at `1.1.1.1`. +### Use in combination with DNS and DoH management + +Netwatch entries can be created to work with both - this script and +[netwatch-dns](netwatch-dns.md). Just give options for both: + + / tool netwatch add comment="doh, notify, hostname=cloudflare-dns" host=1.1.1.1; + +See also +-------- + +* [Manage DNS and DoH servers from netwatch](netwatch-dns.md) + --- [◀ Go back to main README](../README.md) [▲ Go back to top](#top) diff --git a/global-config b/global-config index 7196eb2..cd8ba58 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 71; +:global GlobalConfigVersion 72; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index f16a6a9..f94d082 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 71; +:global GlobalConfigVersion 72; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 9a702a2..00c31fc 100644 --- a/global-config.changes +++ b/global-config.changes @@ -75,6 +75,7 @@ 69="Support hard lower limit for voltage in 'check-health'."; 70="MikroTik started pushing RouterOS v7. Changes are required if you run it, see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v7"; 71="MikroTik is pushing RouterOS v7 even more, in parallel branches. If you want to keep RouterOS v6 for some time see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v6"; + 72="Introduced new script 'netwatch-dns' to manage DNS and DoH servers from netwatch."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 30463f1..de1aec6 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 71; +:global ExpectedConfigVersion 72; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/netwatch-dns b/netwatch-dns new file mode 100644 index 0000000..e731d95 --- /dev/null +++ b/netwatch-dns @@ -0,0 +1,78 @@ +#!rsc by RouterOS +# RouterOS script: netwatch-dns +# Copyright (c) 2022 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# monitor and manage dns/doh with netwatch +# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-dns.md + +:local 0 "netwatch-dns"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global EitherOr; +:global LogPrintExit2; +:global ParseKeyValueStore; +:global ScriptLock; + +$ScriptLock $0; + +:if ([ / system resource get uptime ] < 5m) do={ + $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; +} + +:local DnsServers [ :toarray "" ]; +:local DnsFallback [ :toarray "" ]; +:local DnsCurrent [ / ip dns get servers ]; + +:foreach Host in=[ / tool netwatch find where comment~"dns" disabled=no ] do={ + :local HostVal [ / tool netwatch get $Host ]; + :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; + + :if ($HostVal->"status" = "up" && $HostInfo->"disabled" != true) do={ + :if ($HostInfo->"dns" = true) do={ + :set DnsServers ($DnsServers, $HostVal->"host"); + } + :if ($HostInfo->"dns-fallback" = true) do={ + :set DnsFallback ($DnsFallback, $HostVal->"host"); + } + } +} + +:if ([ :len $DnsServers ] > 0) do={ + :if ($DnsServers != $DnsCurrent) do={ + $LogPrintExit2 info $0 ("Updating DNS servers: " . [ :tostr $DnsServers ]) false; + / ip dns set servers=$DnsServers; + } +} else={ + :if ([ :len $DnsFallback ] > 0) do={ + :if ($DnsFallback != $DnsCurrent) do={ + $LogPrintExit2 info $0 ("Updating DNS servers to fallback: " . [ :tostr $DnsFallback ]) false; + / ip dns set servers=$DnsFallback; + } + } +} + +:local DohServer ""; +:local DohCurrent [ / ip dns get use-doh-server ]; + +:foreach Host in=[ / tool netwatch find where comment~"doh" disabled=no ] do={ + :local HostVal [ / tool netwatch get $Host ]; + :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; + + :if ($HostVal->"status" = "up" && $HostInfo->"doh" = true && $HostInfo->"disabled" != true && $DohServer = "") do={ + :set DohServer [ $EitherOr ($HostInfo->"doh-url") ("https://" . $HostVal->"host" . "/dns-query") ]; + } +} + +:if ($DohServer != "") do={ + :if ($DohServer != $DohCurrent) do={ + $LogPrintExit2 info $0 ("Updating DoH server: " . $DohServer) false; + / ip dns set use-doh-server=$DohServer; + } +} else={ + :if ($DohCurrent != "") do={ + $LogPrintExit2 info $0 ("DoH server (" . $DohCurrent . ") is down, disabling.") false; + / ip dns set use-doh-server=""; + } +} From 8c39f41ffcf3af7fe6d8b4091db5791756f59879 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Jan 2022 22:36:49 +0100 Subject: [PATCH 0906/2612] rename script cloud-backup -> backup-cloud --- README.md | 2 +- backup-cloud | 58 +++++++++++++++++++ cloud-backup | 58 +------------------ .../notification.svg | 2 +- doc/backup-cloud.md | 54 +++++++++++++++++ doc/cloud-backup.md | 55 +----------------- doc/email-backup.md | 2 +- doc/log-forward.d/notification.svg | 2 +- doc/upload-backup.md | 2 +- 9 files changed, 119 insertions(+), 116 deletions(-) create mode 100644 backup-cloud rename doc/{cloud-backup.d => backup-cloud.d}/notification.svg (99%) create mode 100644 doc/backup-cloud.md diff --git a/README.md b/README.md index f55a14b..f14403d 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,7 @@ Available scripts ----------------- * [Find and remove access list duplicates](doc/accesslist-duplicates.md) +* [Upload backup to Mikrotik cloud](doc/backup-cloud.md) * [Download packages for CAP upgrade from CAPsMAN](doc/capsman-download-packages.md) * [Run rolling CAP upgrades from CAPsMAN](doc/capsman-rolling-upgrade.md) * [Renew locally issued certificates](doc/certificate-renew-issued.md) @@ -192,7 +193,6 @@ Available scripts * [Notify about health state](doc/check-health.md) * [Notify on LTE firmware upgrade](doc/check-lte-firmware-upgrade.md) * [Notify on RouterOS update](doc/check-routeros-update.md) -* [Upload backup to Mikrotik cloud](doc/cloud-backup.md) * [Collect MAC addresses in wireless access list](doc/collect-wireless-mac.md) * [Use wireless network with daily psk](doc/daily-psk.md) * [Comment DHCP leases with info from access list](doc/dhcp-lease-comment.md) diff --git a/backup-cloud b/backup-cloud new file mode 100644 index 0000000..d1d9f14 --- /dev/null +++ b/backup-cloud @@ -0,0 +1,58 @@ +#!rsc by RouterOS +# RouterOS script: backup-cloud +# Copyright (c) 2013-2022 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: backup-script +# +# upload backup to MikroTik cloud +# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md + +:local 0 "backup-cloud"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global BackupPassword; +:global BackupRandomDelay; +:global Identity; + +:global DeviceInfo; +:global LogPrintExit2; +:global RandomDelay; +:global ScriptFromTerminal; +:global SendNotification2; +:global SymbolForNotification; +:global WaitFullyConnected; + +$WaitFullyConnected; + +:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ + $RandomDelay $BackupRandomDelay; +} + +:do { + # we are not interested in output, but print is + # required to fetch information from cloud + / system backup cloud print as-value; + :if ([ :len [ / system backup cloud find ] ] > 0) do={ + / system backup cloud upload-file action=create-and-upload \ + password=$BackupPassword replace=[ get ([ find ]->0) name ]; + } else={ + / system backup cloud upload-file action=create-and-upload \ + password=$BackupPassword; + } + :local Cloud [ / system backup cloud get ([ find ]->0) ]; + + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "floppy-disk,cloud" ] . "Cloud backup"); \ + message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ + [ $DeviceInfo ] . "\n\n" . \ + "Name: " . $Cloud->"name" . "\n" . \ + "Size: " . $Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)\n" . \ + "Download key: " . $Cloud->"secret-download-key"); silent=true }); +} on-error={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "warning-sign" ] . "Cloud backup failed"); \ + message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); + $LogPrintExit2 error $0 ("Failed uploading backup for " . $Identity . " to cloud!") true; +} diff --git a/cloud-backup b/cloud-backup index ab2cf7c..2c48f07 100644 --- a/cloud-backup +++ b/cloud-backup @@ -1,58 +1,2 @@ #!rsc by RouterOS -# RouterOS script: cloud-backup -# Copyright (c) 2013-2022 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: backup-script -# -# upload backup to MikroTik cloud -# https://git.eworm.de/cgit/routeros-scripts/about/doc/cloud-backup.md - -:local 0 "cloud-backup"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global BackupPassword; -:global BackupRandomDelay; -:global Identity; - -:global DeviceInfo; -:global LogPrintExit2; -:global RandomDelay; -:global ScriptFromTerminal; -:global SendNotification2; -:global SymbolForNotification; -:global WaitFullyConnected; - -$WaitFullyConnected; - -:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ - $RandomDelay $BackupRandomDelay; -} - -:do { - # we are not interested in output, but print is - # required to fetch information from cloud - / system backup cloud print as-value; - :if ([ :len [ / system backup cloud find ] ] > 0) do={ - / system backup cloud upload-file action=create-and-upload \ - password=$BackupPassword replace=[ get ([ find ]->0) name ]; - } else={ - / system backup cloud upload-file action=create-and-upload \ - password=$BackupPassword; - } - :local Cloud [ / system backup cloud get ([ find ]->0) ]; - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "floppy-disk,cloud" ] . "Cloud backup"); \ - message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - "Name: " . $Cloud->"name" . "\n" . \ - "Size: " . $Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)\n" . \ - "Download key: " . $Cloud->"secret-download-key"); silent=true }); -} on-error={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "warning-sign" ] . "Cloud backup failed"); \ - message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); - $LogPrintExit2 error $0 ("Failed uploading backup for " . $Identity . " to cloud!") true; -} +# dummy for migration diff --git a/doc/cloud-backup.d/notification.svg b/doc/backup-cloud.d/notification.svg similarity index 99% rename from doc/cloud-backup.d/notification.svg rename to doc/backup-cloud.d/notification.svg index 8b84b8f..b023e50 100644 --- a/doc/cloud-backup.d/notification.svg +++ b/doc/backup-cloud.d/notification.svg @@ -6,7 +6,7 @@ version="1.1" id="svg8" inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)" - sodipodi:docname="cloud-backup.svg" + sodipodi:docname="backup-cloud.svg" inkscape:export-filename="logo.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md new file mode 100644 index 0000000..18b9ec1 --- /dev/null +++ b/doc/backup-cloud.md @@ -0,0 +1,54 @@ +Upload backup to Mikrotik cloud +=============================== + +[◀ Go back to main README](../README.md) + +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + +Description +----------- + +This script uploads [binary backup to Mikrotik cloud](https://wiki.mikrotik.com/wiki/Manual:IP/Cloud#Backup). + +### Sample notification + +![backup-cloud notification](backup-cloud.d/notification.svg) + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate backup-cloud; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, these are the parameters: + +* `BackupPassword`: password to encrypt the backup with +* `BackupRandomDelay`: delay up to amount of seconds when run from scheduler + +Also notification settings are required for e-mail, matrix and/or telegram. + +Usage and invocation +-------------------- + +Just run the script: + + / system script run backup-cloud; + +Creating a scheduler may be an option: + + / system scheduler add interval=1w name=backup-cloud on-event="/ system script run backup-cloud;" start-time=09:20:00; + +See also +-------- + +* [Send backup via e-mail](email-backup.md) +* [Upload backup to server](upload-backup.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/cloud-backup.md b/doc/cloud-backup.md index 7522bc1..e161cfa 100644 --- a/doc/cloud-backup.md +++ b/doc/cloud-backup.md @@ -1,54 +1 @@ -Upload backup to Mikrotik cloud -=============================== - -[◀ Go back to main README](../README.md) - -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. - -Description ------------ - -This script uploads [binary backup to Mikrotik cloud](https://wiki.mikrotik.com/wiki/Manual:IP/Cloud#Backup). - -### Sample notification - -![cloud-backup notification](cloud-backup.d/notification.svg) - -Requirements and installation ------------------------------ - -Just install the script: - - $ScriptInstallUpdate cloud-backup; - -Configuration -------------- - -The configuration goes to `global-config-overlay`, these are the parameters: - -* `BackupPassword`: password to encrypt the backup with -* `BackupRandomDelay`: delay up to amount of seconds when run from scheduler - -Also notification settings are required for e-mail, matrix and/or telegram. - -Usage and invocation --------------------- - -Just run the script: - - / system script run cloud-backup; - -Creating a scheduler may be an option: - - / system scheduler add interval=1w name=cloud-backup on-event="/ system script run cloud-backup;" start-time=09:20:00; - -See also --------- - -* [Send backup via e-mail](email-backup.md) -* [Upload backup to server](upload-backup.md) - ---- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +This script has been renamed. Please see [backup-cloud](backup-cloud.md). diff --git a/doc/email-backup.md b/doc/email-backup.md index 85d50bd..bb48e9d 100644 --- a/doc/email-backup.md +++ b/doc/email-backup.md @@ -46,7 +46,7 @@ Creating a scheduler may be an option: See also -------- -* [Upload backup to Mikrotik cloud](cloud-backup.md) +* [Upload backup to Mikrotik cloud](backup-cloud.md) * [Upload backup to server](upload-backup.md) --- diff --git a/doc/log-forward.d/notification.svg b/doc/log-forward.d/notification.svg index b3389fe..373144b 100644 --- a/doc/log-forward.d/notification.svg +++ b/doc/log-forward.d/notification.svg @@ -170,7 +170,7 @@ ● 13:24:02 script;error cloud-backup: Failed uploading backup ● 13:24:02 script;error backup-cloud: Failed uploading backup for MikroTik to cloud! diff --git a/doc/upload-backup.md b/doc/upload-backup.md index 9566853..203f7f6 100644 --- a/doc/upload-backup.md +++ b/doc/upload-backup.md @@ -63,7 +63,7 @@ See also -------- * [Send backup via e-mail](email-backup.md) -* [Upload backup to Mikrotik cloud](cloud-backup.md) +* [Upload backup to Mikrotik cloud](backup-cloud.md) --- [◀ Go back to main README](../README.md) From 95b17ab9a17b7ad11df7c467813a061aead1c835 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Jan 2022 22:37:35 +0100 Subject: [PATCH 0907/2612] rename script email-backup -> backup-email --- README.md | 2 +- backup-email | 80 ++++++++++++++++++++++++++++++++++++++++++ doc/backup-cloud.md | 2 +- doc/backup-email.md | 54 ++++++++++++++++++++++++++++ doc/email-backup.md | 55 +---------------------------- doc/packages-update.md | 4 +-- doc/upload-backup.md | 2 +- email-backup | 80 +----------------------------------------- global-config | 2 +- 9 files changed, 142 insertions(+), 139 deletions(-) create mode 100644 backup-email create mode 100644 doc/backup-email.md diff --git a/README.md b/README.md index f14403d..1aca7ef 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,7 @@ Available scripts * [Find and remove access list duplicates](doc/accesslist-duplicates.md) * [Upload backup to Mikrotik cloud](doc/backup-cloud.md) +* [Send backup via e-mail](doc/backup-email.md) * [Download packages for CAP upgrade from CAPsMAN](doc/capsman-download-packages.md) * [Run rolling CAP upgrades from CAPsMAN](doc/capsman-rolling-upgrade.md) * [Renew locally issued certificates](doc/certificate-renew-issued.md) @@ -197,7 +198,6 @@ Available scripts * [Use wireless network with daily psk](doc/daily-psk.md) * [Comment DHCP leases with info from access list](doc/dhcp-lease-comment.md) * [Create DNS records for DHCP leases](doc/dhcp-to-dns.md) -* [Send backup via e-mail](doc/email-backup.md) * [Wait for global functions und modules](doc/global-wait.md) * [Send GPS position to server](doc/gps-track.md) * [Use WPA2 network with hotspot credentials](doc/hotspot-to-wpa.md) diff --git a/backup-email b/backup-email new file mode 100644 index 0000000..bda9215 --- /dev/null +++ b/backup-email @@ -0,0 +1,80 @@ +#!rsc by RouterOS +# RouterOS script: backup-email +# Copyright (c) 2013-2022 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: backup-script +# +# create and email backup and config file +# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md + +:local 0 "backup-email"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global BackupPassword; +:global BackupRandomDelay; +:global BackupSendBinary; +:global BackupSendExport; +:global Domain; +:global Identity; + +:global CharacterReplace; +:global DeviceInfo; +:global LogPrintExit2; +:global MkDir; +:global RandomDelay; +:global ScriptFromTerminal; +:global SendEMail2; +:global SymbolForNotification; +:global WaitForFile; +:global WaitFullyConnected; + +:if ($BackupSendBinary != true && \ + $BackupSendExport != true) do={ + $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; +} + +$WaitFullyConnected; + +:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ + $RandomDelay $BackupRandomDelay; +} + +:if ([ $MkDir $0 ] = false) do={ + $LogPrintExit2 error $0 ("Failed creating directory!") true; +} + +# filename based on identity +:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; +:local FilePath ($0 . "/" . $FileName); +:local BackupFile "none"; +:local ConfigFile "none"; +:local Attach [ :toarray "" ]; + +# 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 file=$FilePath; + $WaitForFile ($FilePath . ".rsc"); + :set ConfigFile ($FileName . ".rsc"); + :set Attach ($Attach, ($FilePath . ".rsc")); +} + +# send email with status and files +$SendEMail2 ({ origin=$0; \ + subject=([ $SymbolForNotification "floppy-disk,incoming-envelope" ] . \ + "Backup & Config"); \ + message=("See attached files for backup and config export for " . \ + $Identity . ".\n\n" . \ + [ $DeviceInfo ] . "\n\n" . \ + "Backup file: " . $BackupFile . "\n" . \ + "Config file: " . $ConfigFile); \ + attach=$Attach; remove-attach=true }); diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index 18b9ec1..a31a736 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -46,7 +46,7 @@ Creating a scheduler may be an option: See also -------- -* [Send backup via e-mail](email-backup.md) +* [Send backup via e-mail](backup-email.md) * [Upload backup to server](upload-backup.md) --- diff --git a/doc/backup-email.md b/doc/backup-email.md new file mode 100644 index 0000000..7361b44 --- /dev/null +++ b/doc/backup-email.md @@ -0,0 +1,54 @@ +Send backup via e-mail +====================== + +[◀ Go back to main README](../README.md) + +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + +Description +----------- + +This script sends binary backup (`/ system backup save`) and complete +configuration export (`/ export terse`) via e-mail. + + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate backup-email; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, these are the parameters: + +* `BackupSendBinary`: whether to send binary backup +* `BackupSendExport`: whether to send configuration export +* `BackupPassword`: password to encrypt the backup with +* `BackupRandomDelay`: delay up to amount of seconds when run from scheduler + +Also valid e-mail settings are required to send mails. + +Usage and invocation +-------------------- + +Just run the script: + + / system script run backup-email; + +Creating a scheduler may be an option: + + / system scheduler add interval=1w name=backup-email on-event="/ system script run backup-email;" start-time=09:15:00; + +See also +-------- + +* [Upload backup to Mikrotik cloud](backup-cloud.md) +* [Upload backup to server](upload-backup.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/email-backup.md b/doc/email-backup.md index bb48e9d..d674743 100644 --- a/doc/email-backup.md +++ b/doc/email-backup.md @@ -1,54 +1 @@ -Send backup via e-mail -====================== - -[◀ Go back to main README](../README.md) - -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. - -Description ------------ - -This script sends binary backup (`/ system backup save`) and complete -configuration export (`/ export terse`) via e-mail. - - -Requirements and installation ------------------------------ - -Just install the script: - - $ScriptInstallUpdate email-backup; - -Configuration -------------- - -The configuration goes to `global-config-overlay`, these are the parameters: - -* `BackupSendBinary`: whether to send binary backup -* `BackupSendExport`: whether to send configuration export -* `BackupPassword`: password to encrypt the backup with -* `BackupRandomDelay`: delay up to amount of seconds when run from scheduler - -Also valid e-mail settings are required to send mails. - -Usage and invocation --------------------- - -Just run the script: - - / system script run email-backup; - -Creating a scheduler may be an option: - - / system scheduler add interval=1w name=email-backup on-event="/ system script run email-backup;" start-time=09:15:00; - -See also --------- - -* [Upload backup to Mikrotik cloud](backup-cloud.md) -* [Upload backup to server](upload-backup.md) - ---- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +This script has been renamed. Please see [backup-email](backup-email.md). \ No newline at end of file diff --git a/doc/packages-update.md b/doc/packages-update.md index cc4a29b..8502a36 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -16,7 +16,7 @@ verification. But it provides some extra functionality: -* send backup via e-mail if [email-backup](email-backup.md) is installed +* send backup via e-mail if [backup-email](backup-email.md) is installed * upload backup if [upload-backup](upload-backup.md) is installed * schedule reboot at night @@ -41,7 +41,7 @@ See also -------- * [Notify on RouterOS update](check-routeros-update.md) -* [Send backup via e-mail](email-backup.md) +* [Send backup via e-mail](backup-email.md) * [Upload backup to server](upload-backup.md) --- diff --git a/doc/upload-backup.md b/doc/upload-backup.md index 203f7f6..33022f4 100644 --- a/doc/upload-backup.md +++ b/doc/upload-backup.md @@ -62,7 +62,7 @@ Creating a scheduler may be an option: See also -------- -* [Send backup via e-mail](email-backup.md) +* [Send backup via e-mail](backup-email.md) * [Upload backup to Mikrotik cloud](backup-cloud.md) --- diff --git a/email-backup b/email-backup index 1d4099c..2c48f07 100644 --- a/email-backup +++ b/email-backup @@ -1,80 +1,2 @@ #!rsc by RouterOS -# RouterOS script: email-backup -# Copyright (c) 2013-2022 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: backup-script -# -# create and email backup and config file -# https://git.eworm.de/cgit/routeros-scripts/about/doc/email-backup.md - -:local 0 "email-backup"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global BackupPassword; -:global BackupRandomDelay; -:global BackupSendBinary; -:global BackupSendExport; -:global Domain; -:global Identity; - -:global CharacterReplace; -:global DeviceInfo; -:global LogPrintExit2; -:global MkDir; -:global RandomDelay; -:global ScriptFromTerminal; -:global SendEMail2; -:global SymbolForNotification; -:global WaitForFile; -:global WaitFullyConnected; - -:if ($BackupSendBinary != true && \ - $BackupSendExport != true) do={ - $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; -} - -$WaitFullyConnected; - -:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ - $RandomDelay $BackupRandomDelay; -} - -:if ([ $MkDir $0 ] = false) do={ - $LogPrintExit2 error $0 ("Failed creating directory!") true; -} - -# filename based on identity -:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; -:local FilePath ($0 . "/" . $FileName); -:local BackupFile "none"; -:local ConfigFile "none"; -:local Attach [ :toarray "" ]; - -# 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 file=$FilePath; - $WaitForFile ($FilePath . ".rsc"); - :set ConfigFile ($FileName . ".rsc"); - :set Attach ($Attach, ($FilePath . ".rsc")); -} - -# send email with status and files -$SendEMail2 ({ origin=$0; \ - subject=([ $SymbolForNotification "floppy-disk,incoming-envelope" ] . \ - "Backup & Config"); \ - message=("See attached files for backup and config export for " . \ - $Identity . ".\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - "Backup file: " . $BackupFile . "\n" . \ - "Config file: " . $ConfigFile); \ - attach=$Attach; remove-attach=true }); +# dummy for migration diff --git a/global-config b/global-config index cd8ba58..1250818 100644 --- a/global-config +++ b/global-config @@ -49,7 +49,7 @@ # variable name, like this: #:global EmailGeneralToOverride { # "check-certificates"="override@example.com"; -# "email-backup"="backup@example.com"; +# "backup-email"="backup@example.com"; #} # Toggle this to disable symbols in notifications. From e77b39e933a87bf509c176ee5a964c0772e0c54d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Jan 2022 22:37:55 +0100 Subject: [PATCH 0908/2612] rename script upload-backup -> backup-upload --- README.md | 2 +- backup-upload | 106 ++++++++++++++++++ doc/backup-cloud.md | 2 +- doc/backup-email.md | 2 +- .../notification.svg | 2 +- doc/backup-upload.md | 70 ++++++++++++ doc/packages-update.md | 4 +- doc/upload-backup.md | 71 +----------- upload-backup | 106 +----------------- 9 files changed, 184 insertions(+), 181 deletions(-) create mode 100644 backup-upload rename doc/{upload-backup.d => backup-upload.d}/notification.svg (99%) create mode 100644 doc/backup-upload.md diff --git a/README.md b/README.md index 1aca7ef..d65ea0a 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,7 @@ Available scripts * [Find and remove access list duplicates](doc/accesslist-duplicates.md) * [Upload backup to Mikrotik cloud](doc/backup-cloud.md) * [Send backup via e-mail](doc/backup-email.md) +* [Upload backup to server](doc/backup-upload.md) * [Download packages for CAP upgrade from CAPsMAN](doc/capsman-download-packages.md) * [Run rolling CAP upgrades from CAPsMAN](doc/capsman-rolling-upgrade.md) * [Renew locally issued certificates](doc/certificate-renew-issued.md) @@ -222,7 +223,6 @@ Available scripts * [Install LTE firmware upgrade](doc/unattended-lte-firmware-upgrade.md) * [Update GRE configuration with dynamic addresses](doc/update-gre-address.md) * [Update tunnelbroker configuration](doc/update-tunnelbroker.md) -* [Upload backup to server](doc/upload-backup.md) [comment]: # (TODO: currently undocumented) [comment]: # (* learn-mac-based-vlan) diff --git a/backup-upload b/backup-upload new file mode 100644 index 0000000..6aba3e7 --- /dev/null +++ b/backup-upload @@ -0,0 +1,106 @@ +#!rsc by RouterOS +# RouterOS script: backup-upload +# Copyright (c) 2013-2022 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: backup-script +# +# create and upload backup and config file +# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md + +:local 0 "backup-upload"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global BackupPassword; +:global BackupRandomDelay; +:global BackupSendBinary; +:global BackupSendExport; +:global BackupUploadPass; +:global BackupUploadUrl; +:global BackupUploadUser; +:global Domain; +:global Identity; + +:global CharacterReplace; +:global DeviceInfo; +:global IfThenElse; +:global LogPrintExit2; +:global MkDir; +:global RandomDelay; +:global ScriptFromTerminal; +:global SendNotification2; +:global SymbolForNotification; +:global WaitForFile; +:global WaitFullyConnected; + +:if ($BackupSendBinary != true && \ + $BackupSendExport != true) do={ + $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; +} + +$WaitFullyConnected; + +:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ + $RandomDelay $BackupRandomDelay; +} + +:if ([ $MkDir $0 ] = false) do={ + $LogPrintExit2 error $0 ("Failed creating directory!") true; +} + +# filename based on identity +:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; +:local FilePath ($0 . "/" . $FileName); +:local BackupFile "none"; +:local ConfigFile "none"; +:local Failed 0; + +# binary backup +:if ($BackupSendBinary = true) do={ + / system backup save encryption=aes-sha256 name=$FilePath password=$BackupPassword; + $WaitForFile ($FilePath . ".backup"); + + :do { + / tool fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \ + user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".backup"); + :set BackupFile ($FileName . ".backup"); + } on-error={ + $LogPrintExit2 error $0 ("Uploading backup file failed!") false; + :set BackupFile "failed"; + :set Failed 1; + } + + / file remove ($FilePath . ".backup"); +} + +# create configuration export +:if ($BackupSendExport = true) do={ + / export terse file=$FilePath; + $WaitForFile ($FilePath . ".rsc"); + + :do { + / tool fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \ + user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".rsc"); + :set ConfigFile ($FileName . ".rsc"); + } on-error={ + $LogPrintExit2 error $0 ("Uploading configuration export failed!") false; + :set ConfigFile "failed"; + :set Failed 1; + } + + / file remove ($FilePath . ".rsc"); +} + +$SendNotification2 ({ origin=$0; \ + subject=[ $IfThenElse ($Failed > 0) \ + ([ $SymbolForNotification "warning-sign" ] . "Backup & Config upload with failure") \ + ([ $SymbolForNotification "floppy-disk,up-arrow" ] . "Backup & Config upload") ]; \ + message=("Backup and config export upload for " . $Identity . ".\n\n" . \ + [ $DeviceInfo ] . "\n\n" . \ + "Backup file: " . $BackupFile . "\n" . \ + "Config file: " . $ConfigFile); silent=true }); + +:if ($Failed = 1) do={ + :error "An error occured!"; +} diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index a31a736..117e4c7 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -47,7 +47,7 @@ See also -------- * [Send backup via e-mail](backup-email.md) -* [Upload backup to server](upload-backup.md) +* [Upload backup to server](backup-upload.md) --- [◀ Go back to main README](../README.md) diff --git a/doc/backup-email.md b/doc/backup-email.md index 7361b44..be36cb4 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -47,7 +47,7 @@ See also -------- * [Upload backup to Mikrotik cloud](backup-cloud.md) -* [Upload backup to server](upload-backup.md) +* [Upload backup to server](backup-upload.md) --- [◀ Go back to main README](../README.md) diff --git a/doc/upload-backup.d/notification.svg b/doc/backup-upload.d/notification.svg similarity index 99% rename from doc/upload-backup.d/notification.svg rename to doc/backup-upload.d/notification.svg index a85bd5c..90573ab 100644 --- a/doc/upload-backup.d/notification.svg +++ b/doc/backup-upload.d/notification.svg @@ -6,7 +6,7 @@ version="1.1" id="svg8" inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)" - sodipodi:docname="upload-backup.svg" + sodipodi:docname="backup-upload.svg" inkscape:export-filename="logo.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" diff --git a/doc/backup-upload.md b/doc/backup-upload.md new file mode 100644 index 0000000..212b16c --- /dev/null +++ b/doc/backup-upload.md @@ -0,0 +1,70 @@ +Upload backup to server +======================= + +[◀ Go back to main README](../README.md) + +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + +Description +----------- + +This script uploads binary backup (`/ system backup save`) and complete +configuration export (`/ export terse`) to external server. + +### Sample notification + +![backup-upload notification](backup-upload.d/notification.svg) + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate backup-upload; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, these are the parameters: + +* `BackupSendBinary`: whether to send binary backup +* `BackupSendExport`: whether to send configuration export +* `BackupPassword`: password to encrypt the backup with +* `BackupRandomDelay`: delay up to amount of seconds when run from scheduler +* `BackupUploadUrl`: url to upload to +* `BackupUploadUser`: username for server authentication +* `BackupUploadPass`: password for server authentication + +Also notification settings are required for e-mail, matrix and/or telegram. + +### Issues with SFTP client + +The RouterOS SFTP client is picky if it comes to authentication methods. +I had to disable all but password authentication on server side. For openssh +edit `/etc/ssh/sshd_config` and add a directive like this, changed for your +needs: + + Match User mikrotik + AuthenticationMethods password + +Usage and invocation +-------------------- + +Just run the script: + + / system script run backup-upload; + +Creating a scheduler may be an option: + + / system scheduler add interval=1w name=backup-upload on-event="/ system script run backup-upload;" start-time=09:25:00; + +See also +-------- + +* [Send backup via e-mail](backup-email.md) +* [Upload backup to Mikrotik cloud](backup-cloud.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/packages-update.md b/doc/packages-update.md index 8502a36..ac69301 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -17,7 +17,7 @@ verification. But it provides some extra functionality: * send backup via e-mail if [backup-email](backup-email.md) is installed -* upload backup if [upload-backup](upload-backup.md) is installed +* upload backup if [backup-upload](backup-upload.md) is installed * schedule reboot at night Requirements and installation @@ -42,7 +42,7 @@ See also * [Notify on RouterOS update](check-routeros-update.md) * [Send backup via e-mail](backup-email.md) -* [Upload backup to server](upload-backup.md) +* [Upload backup to server](backup-upload.md) --- [◀ Go back to main README](../README.md) diff --git a/doc/upload-backup.md b/doc/upload-backup.md index 33022f4..83c9991 100644 --- a/doc/upload-backup.md +++ b/doc/upload-backup.md @@ -1,70 +1 @@ -Upload backup to server -======================= - -[◀ Go back to main README](../README.md) - -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. - -Description ------------ - -This script uploads binary backup (`/ system backup save`) and complete -configuration export (`/ export terse`) to external server. - -### Sample notification - -![upload-backup notification](upload-backup.d/notification.svg) - -Requirements and installation ------------------------------ - -Just install the script: - - $ScriptInstallUpdate upload-backup; - -Configuration -------------- - -The configuration goes to `global-config-overlay`, these are the parameters: - -* `BackupSendBinary`: whether to send binary backup -* `BackupSendExport`: whether to send configuration export -* `BackupPassword`: password to encrypt the backup with -* `BackupRandomDelay`: delay up to amount of seconds when run from scheduler -* `BackupUploadUrl`: url to upload to -* `BackupUploadUser`: username for server authentication -* `BackupUploadPass`: password for server authentication - -Also notification settings are required for e-mail, matrix and/or telegram. - -### Issues with SFTP client - -The RouterOS SFTP client is picky if it comes to authentication methods. -I had to disable all but password authentication on server side. For openssh -edit `/etc/ssh/sshd_config` and add a directive like this, changed for your -needs: - - Match User mikrotik - AuthenticationMethods password - -Usage and invocation --------------------- - -Just run the script: - - / system script run upload-backup; - -Creating a scheduler may be an option: - - / system scheduler add interval=1w name=upload-backup on-event="/ system script run upload-backup;" start-time=09:25:00; - -See also --------- - -* [Send backup via e-mail](backup-email.md) -* [Upload backup to Mikrotik cloud](backup-cloud.md) - ---- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +This script has been renamed. Please see [backup-upload](backup-upload.md). diff --git a/upload-backup b/upload-backup index f243ef0..2c48f07 100644 --- a/upload-backup +++ b/upload-backup @@ -1,106 +1,2 @@ #!rsc by RouterOS -# RouterOS script: upload-backup -# Copyright (c) 2013-2022 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: backup-script -# -# create and upload backup and config file -# https://git.eworm.de/cgit/routeros-scripts/about/doc/upload-backup.md - -:local 0 "upload-backup"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global BackupPassword; -:global BackupRandomDelay; -:global BackupSendBinary; -:global BackupSendExport; -:global BackupUploadPass; -:global BackupUploadUrl; -:global BackupUploadUser; -:global Domain; -:global Identity; - -:global CharacterReplace; -:global DeviceInfo; -:global IfThenElse; -:global LogPrintExit2; -:global MkDir; -:global RandomDelay; -:global ScriptFromTerminal; -:global SendNotification2; -:global SymbolForNotification; -:global WaitForFile; -:global WaitFullyConnected; - -:if ($BackupSendBinary != true && \ - $BackupSendExport != true) do={ - $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; -} - -$WaitFullyConnected; - -:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ - $RandomDelay $BackupRandomDelay; -} - -:if ([ $MkDir $0 ] = false) do={ - $LogPrintExit2 error $0 ("Failed creating directory!") true; -} - -# filename based on identity -:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; -:local FilePath ($0 . "/" . $FileName); -:local BackupFile "none"; -:local ConfigFile "none"; -:local Failed 0; - -# binary backup -:if ($BackupSendBinary = true) do={ - / system backup save encryption=aes-sha256 name=$FilePath password=$BackupPassword; - $WaitForFile ($FilePath . ".backup"); - - :do { - / tool fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \ - user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".backup"); - :set BackupFile ($FileName . ".backup"); - } on-error={ - $LogPrintExit2 error $0 ("Uploading backup file failed!") false; - :set BackupFile "failed"; - :set Failed 1; - } - - / file remove ($FilePath . ".backup"); -} - -# create configuration export -:if ($BackupSendExport = true) do={ - / export terse file=$FilePath; - $WaitForFile ($FilePath . ".rsc"); - - :do { - / tool fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \ - user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".rsc"); - :set ConfigFile ($FileName . ".rsc"); - } on-error={ - $LogPrintExit2 error $0 ("Uploading configuration export failed!") false; - :set ConfigFile "failed"; - :set Failed 1; - } - - / file remove ($FilePath . ".rsc"); -} - -$SendNotification2 ({ origin=$0; \ - subject=[ $IfThenElse ($Failed > 0) \ - ([ $SymbolForNotification "warning-sign" ] . "Backup & Config upload with failure") \ - ([ $SymbolForNotification "floppy-disk,up-arrow" ] . "Backup & Config upload") ]; \ - message=("Backup and config export upload for " . $Identity . ".\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - "Backup file: " . $BackupFile . "\n" . \ - "Config file: " . $ConfigFile); silent=true }); - -:if ($Failed = 1) do={ - :error "An error occured!"; -} +# dummy for migration From ed0135c613b92ce59bda832f0e4a789a8268223f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Jan 2022 23:03:09 +0100 Subject: [PATCH 0909/2612] Migrate configuration and send notification on renames --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 2 ++ global-functions | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 1250818..feccf55 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 72; +:global GlobalConfigVersion 73; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index f94d082..89b74e4 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 72; +:global GlobalConfigVersion 73; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 00c31fc..0325ac5 100644 --- a/global-config.changes +++ b/global-config.changes @@ -76,6 +76,7 @@ 70="MikroTik started pushing RouterOS v7. Changes are required if you run it, see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v7"; 71="MikroTik is pushing RouterOS v7 even more, in parallel branches. If you want to keep RouterOS v6 for some time see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v6"; 72="Introduced new script 'netwatch-dns' to manage DNS and DoH servers from netwatch."; + 73="Renamed backup scripts ('cloud-backup' -> 'backup-cloud', 'email-backup' -> 'backup-email', 'upload-backup' -> 'backup-upload')."; }; # Migration steps to be applied on script updates @@ -87,4 +88,5 @@ 61="/ system script remove [ find where name~\"^(early-errors|mode-button-(event|scheduler)|script-updates)\\\$\" source~\"^#!rsc by RouterOS\\n\" ];"; 66=":global ScriptInstallUpdate; :if ([ :len [ / system script find where name=\"bridge-port-to-default\" ] ] > 0) do={ / system script remove [ find where name~\"^bridge-port-to(-default|ggle)\\\$\" ]; \$ScriptInstallUpdate mod/bridge-port-to; }"; 67=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Script in=[ / system script find where name~\"^global-functions.d/\" ] do={ / system script set name=[ \$CharacterReplace [ / system script get \$Script name ] \"global-functions.d/\" \"mod/\" ] \$Script; }; \$ScriptInstallUpdate;"; + 73=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Old,New in={ \"cloud-backup\"=\"backup-cloud\"; \"email-backup\"=\"backup-email\"; \"upload-backup\"=\"backup-upload\" } do={ / system script set name=\$New [ find where name=\$Old ]; :foreach Scheduler in=[ / system scheduler find where on-event~\$Old ] do={ / system scheduler set \$Scheduler name=[ \$CharacterReplace [ get \$Scheduler name ] \$Old \$New ] on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Old \$New ]; }; }; \$ScriptInstallUpdate;"; }; diff --git a/global-functions b/global-functions index de1aec6..a6f31c8 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 72; +:global ExpectedConfigVersion 73; # global variables not to be changed by user :global GlobalFunctionsReady false; From 491f53a8ce4a4a76fcaa4b1b99ec85e5f00b2ee5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Dec 2021 13:15:35 +0100 Subject: [PATCH 0910/2612] hotspot-to-wpa: support settings from template --- doc/hotspot-to-wpa.md | 24 +++++++++++++++++++++--- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- hotspot-to-wpa | 33 +++++++++++++++++++++++++++++++-- 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index 13f307a..f3dccdb 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -49,14 +49,32 @@ On first run a disabled access list entry acting as marker (with comment "`--- hotspot-to-wpa above ---`") is added. Move this entry to define where new entries are to be added. -Usage and invocation --------------------- - Create hotspot login credentials: / ip hotspot user add add comment="Test User 1" name=user1 password=v3ry; / ip hotspot user add add comment="Test User 2" name=user2 password=s3cr3t; +Additionally templates can be created to give more options for access list: + +* `private-passphrase`: do **not** use passphrase from hotspot's user + credentials, but given one - or unset (use default passphrase) with + special word `ignore` +* `ssid-regexp`: set a different SSID regular expression to match +* `vlan-id`: connect device to specific VLAN +* `vlan-mode`: set the VLAN mode for device + +For a hotspot called `example` the template could look like this: + + / caps-man access-list add comment="hotspot-to-wpa template example" disabled=yes private-passphrase="ignore" ssid-regexp="^example\$" vlan-id=10 vlan-mode=use-tag; + +The same settings are available in hotspot user's comment and take precedence +over the template settings: + + / ip hotspot user add comment="private-passphrase=ignore, ssid-regexp=^example\\\$, vlan-id=10, vlan-mode=use-tag" name=user password=v3ry-s3cr3t; + +Usage and invocation +-------------------- + Now let the users connect and login to the hotspot. After that the devices (identified by MAC address) can connect to the WPA2 network, using the passphrase from hotspot credentials. diff --git a/global-config b/global-config index feccf55..024e52f 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 73; +:global GlobalConfigVersion 74; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 89b74e4..37f78cf 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 73; +:global GlobalConfigVersion 74; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 0325ac5..a070ecd 100644 --- a/global-config.changes +++ b/global-config.changes @@ -77,6 +77,7 @@ 71="MikroTik is pushing RouterOS v7 even more, in parallel branches. If you want to keep RouterOS v6 for some time see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v6"; 72="Introduced new script 'netwatch-dns' to manage DNS and DoH servers from netwatch."; 73="Renamed backup scripts ('cloud-backup' -> 'backup-cloud', 'email-backup' -> 'backup-email', 'upload-backup' -> 'backup-upload')."; + 74="Extended 'hotspot-to-wpa', it can now read additional configuration from templates and hotspot users."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index a6f31c8..625bbe4 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 73; +:global ExpectedConfigVersion 74; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/hotspot-to-wpa b/hotspot-to-wpa index b573b3f..c40e08a 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -10,12 +10,15 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:global EitherOr; :global LogPrintExit2; +:global ParseKeyValueStore; :local MacAddress $"mac-address"; :local UserName $username; :local Date [ / system clock get date ]; -:local PassWord [ / ip hotspot user get [ find where name=$UserName ] password ]; +:local Hotspot [ / ip hotspot host get [ find where mac-address=$MacAddress authorized ] server ]; +:local UserVal [ / ip hotspot user get [ find where name=$UserName ] ]; :if ([ :len [ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ / caps-man access-list add comment="--- hotspot-to-wpa above ---" disabled=yes; @@ -28,4 +31,30 @@ $LogPrintExit2 info $0 ("Adding/updating accesslist entry for mac address " . $M / caps-man access-list remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; / caps-man access-list add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - mac-address=$MacAddress private-passphrase=$PassWord ssid-regexp="-wpa\$" place-before=$PlaceBefore; + mac-address=$MacAddress private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" place-before=$PlaceBefore; + +:local Template [ / caps-man access-list get ([ find where comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; +:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; +:local Entry [ / caps-man access-list find where mac-address=$MacAddress \ + comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; + +:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; +:if ([ :len $PrivatePassphrase ] > 0) do={ + :if ($PrivatePassphrase = "ignore") do={ + / caps-man access-list set $Entry !private-passphrase; + } else={ + / caps-man access-list set $Entry private-passphrase=$PrivatePassphrase; + } +} +:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; +:if ([ :len $SsidRegexp ] > 0) do={ + / caps-man access-list set $Entry ssid-regexp=$SsidRegexp; +} +:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; +:if ([ :len $VlanId ] > 0) do={ + / caps-man access-list set $Entry vlan-id=$VlanId; +} +:local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; +:if ([ :len $VlanMode] > 0) do={ + / caps-man access-list set $Entry vlan-mode=$VlanMode; +} From 31653a84ca161b8929ebb67118f688a7a6c3254e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 14 Jan 2022 07:48:08 +0100 Subject: [PATCH 0911/2612] INITIAL-COMMANDS: silence the certificate download --- INITIAL-COMMANDS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 46e1c8b..843a3a0 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -7,7 +7,7 @@ These command are inteneded for initial setup. If you are not aware of the procedure please follow [the long way in detail](README.md#the-long-way-in-detail). { - / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem"; + / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem" as-value; :delay 1s; / certificate import file-name=letsencrypt-R3.pem passphrase=""; :if ([ :len [ / certificate find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ] ] != 2) do={ From 1089b7e7f9a6638c7783538f464916d16b3a6e87 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 14 Jan 2022 07:46:43 +0100 Subject: [PATCH 0912/2612] README: install correct global-config-overlay for RouterOS v6 --- INITIAL-COMMANDS.md | 9 ++++++++- README.d/04-import-scripts.avif | Bin 3810 -> 4599 bytes README.md | 9 +++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 843a3a0..9a8a129 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -6,7 +6,14 @@ Initial commands These command are inteneded for initial setup. If you are not aware of the procedure please follow [the long way in detail](README.md#the-long-way-in-detail). +One extra step is required if you run RouterOS v6: + + :global ScriptUpdatesUrlSuffix "\?h=routeros-v6"; + +Then run the complete base installation: + { + :global ScriptUpdatesUrlSuffix; / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem" as-value; :delay 1s; / certificate import file-name=letsencrypt-R3.pem passphrase=""; @@ -15,7 +22,7 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai }; / file remove "letsencrypt-R3.pem"; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ - / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); + / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . $ScriptUpdatesUrlSuffix) output=user as-value]->"data"); }; / system script { run global-config; run global-functions; }; / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-functions; }"; diff --git a/README.d/04-import-scripts.avif b/README.d/04-import-scripts.avif index c6a2a3c6a7f8d7623a83e759c460413977675c5d..c86a5c8ac6161a17d181165b83e0447f1178c67a 100644 GIT binary patch delta 4349 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 diff --git a/README.md b/README.md index d65ea0a..990aef9 100644 --- a/README.md +++ b/README.md @@ -82,9 +82,14 @@ All following commands will verify the server certificate. For validity the certificate's lifetime is checked with local time, so make sure the device's date and time is set correctly! +One extra step is required if you run RouterOS v6: + + :global ScriptUpdatesUrlSuffix "\?h=routeros-v6"; + Now let's download the main scripts and add them in configuration on the fly. - :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); }; + :global ScriptUpdatesUrlSuffix; + :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . $ScriptUpdatesUrlSuffix) output=user as-value]->"data"); }; ![screenshot: import scripts](README.d/04-import-scripts.avif) @@ -116,7 +121,7 @@ to be updated automatically! RouterOS v6 will become deprecated at some time in the future, but to date it is still the default for these scripts (in branch `main`). This will change however, so if you want to stay with RouterOS v6 for some time add -these lines to your `global-config-overlay`: +these lines to your `global-config-overlay`, if missing: # Use branch routeros-v6 with RouterOS v6: :global ScriptUpdatesUrlSuffix "\?h=routeros-v6"; From d03b6d9374b4f4884bfd90bfc04b1d26802d6666 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Sep 2021 08:59:09 +0200 Subject: [PATCH 0913/2612] global-functions: bump the required version for RouterOS 7.x ... but keep a warning when running RouterOS v6. --- global-functions | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/global-functions b/global-functions index 625bbe4..388d24e 100644 --- a/global-functions +++ b/global-functions @@ -1257,12 +1257,11 @@ } # check for required RouterOS version -$RequiredRouterOS "global-functions" "6.47" true; - -# ... and give a hint on RouterOS v7. :if ([ $RequiredRouterOS "global-functions" "7.0" false ] = true) do={ - $LogPrintExit2 warning $0 ("RouterOS v7 brings some incompatible changes. Please switch to branch " . \ - "'routeros-v7', see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v7") false; + $RequiredRouterOS "global-functions" "7.1" true; +} else={ + $LogPrintExit2 warning $0 ("Still running RouterOS v6, please switch to branch " . \ + "'routeros-v6', see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v6") false; } # signal we are ready From cdd607037eba0571dd137e9efa507353d88a81c8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Dec 2021 16:44:01 +0100 Subject: [PATCH 0914/2612] README: drop hint on branch 'routeros-v7' --- README.md | 21 +++------------------ global-config | 5 +---- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 990aef9..02cb009 100644 --- a/README.md +++ b/README.md @@ -118,30 +118,15 @@ to be updated automatically! ### Changes for RouterOS v6 -RouterOS v6 will become deprecated at some time in the future, but to date -it is still the default for these scripts (in branch `main`). This will -change however, so if you want to stay with RouterOS v6 for some time add -these lines to your `global-config-overlay`, if missing: +RouterOS v7 is the way to go, let's consider RouterOS v6 deprecated. +If you want to stay with RouterOS v6 for some time add these lines +to your `global-config-overlay`, if missing: # Use branch routeros-v6 with RouterOS v6: :global ScriptUpdatesUrlSuffix "\?h=routeros-v6"; Then reload the configuration. -### Changes for RouterOS v7 - -RouterOS v7 is developed in paralled to RouterOS v6. The former brings some -shiny new features, the latter provides proven stability. - -The changes require incompatible changes to scripts, so these changes go to -a separate branch. If you decide to run RouterOS v7 please switch to branch -`routeros-v7` by adding these lines to your `global-config-overlay`: - - # Use branch routeros-v7 with RouterOS v7: - :global ScriptUpdatesUrlSuffix "\?h=routeros-v7"; - -Then reload the configuration and continue below to update scripts. - Updating scripts ---------------- diff --git a/global-config b/global-config index 024e52f..02d99b4 100644 --- a/global-config +++ b/global-config @@ -159,14 +159,11 @@ # alternative urls - main: stable code - next: currently in development #:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/main/"; #:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/next/"; -#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/routeros-v7/"; #:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/main/"; #:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/next/"; -#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/routeros-v7/"; :global ScriptUpdatesUrlSuffix ""; -# use next or routeros-v7 branch with default url (git.eworm.de) +# use next branch with default url (git.eworm.de) #:global ScriptUpdatesUrlSuffix "\?h=next"; -#:global ScriptUpdatesUrlSuffix "\?h=routeros-v7"; # Use this for defaults with $ScriptRunOnce # Install module with: From 35d10f80f503a92ef7d7004ecac196267ee3946e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Sep 2021 20:38:14 +0200 Subject: [PATCH 0915/2612] backup-email: export with show-sensitive This is available (and required) with RouterOS 7.1rc1. --- backup-email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backup-email b/backup-email index bda9215..ccbd4de 100644 --- a/backup-email +++ b/backup-email @@ -62,7 +62,7 @@ $WaitFullyConnected; # create configuration export :if ($BackupSendExport = true) do={ - / export terse file=$FilePath; + / export terse show-sensitive file=$FilePath; $WaitForFile ($FilePath . ".rsc"); :set ConfigFile ($FileName . ".rsc"); :set Attach ($Attach, ($FilePath . ".rsc")); From 768afd84c6f0644f899db450691a050e01c2a272 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Sep 2021 20:40:07 +0200 Subject: [PATCH 0916/2612] backup-upload: export with show-sensitive This is available (and required) with RouterOS 7.1rc1. --- backup-upload | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backup-upload b/backup-upload index 6aba3e7..c482b42 100644 --- a/backup-upload +++ b/backup-upload @@ -76,7 +76,7 @@ $WaitFullyConnected; # create configuration export :if ($BackupSendExport = true) do={ - / export terse file=$FilePath; + / export terse show-sensitive file=$FilePath; $WaitForFile ($FilePath . ".rsc"); :do { From 7e5652e0c5f45f6c606a60be5eabd57df785d50d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Sep 2021 15:12:46 +0200 Subject: [PATCH 0917/2612] ospf-to-leds: get state from count of neighbors The state property is gone in RouterOS v7... --- ospf-to-leds | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/ospf-to-leds b/ospf-to-leds index 448cc6b..39501c9 100644 --- a/ospf-to-leds +++ b/ospf-to-leds @@ -18,12 +18,18 @@ :local LED ([ $ParseKeyValueStore ($InstanceVal->"comment") ]->"leds"); :local LEDType [ / system leds get [ find where leds=$LED ] type ]; - :if ($InstanceVal->"state" = "running" && $LEDType = "off") do={ - $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " is running, led on!") false; + :local NeighborCount 0; + :foreach Area in=[ / routing ospf area find where instance=($InstanceVal->"name") ] do={ + :local AreaName [ / routing ospf area get $Area name ]; + :set NeighborCount ($NeighborCount + [ :len [ / routing ospf neighbor find where area=$AreaName ] ]); + } + + :if ($NeighborCount > 0 && $LEDType = "off") do={ + $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " has " . $NeighborCount . " neighbors, led on!") false; / system leds set type=on [ find where leds=$LED ]; } - :if ($InstanceVal->"state" = "down" && $LEDType = "on") do={ - $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " is down, led off!") false; + :if ($NeighborCount = 0 && $LEDType = "on") do={ + $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " has no neighbors, led off!") false; / system leds set type=off [ find where leds=$LED ]; } } From 0ecabfecf7739d368849190e47af1ab1c51a79f0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 30 Sep 2021 12:10:57 +0200 Subject: [PATCH 0918/2612] rotate-ntp: syntax for ROS 7.x The property name changed in RouterOS v7... --- rotate-ntp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rotate-ntp b/rotate-ntp index 83bf90a..dd3483a 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -29,4 +29,4 @@ } $LogPrintExit2 info $0 ("Updating NTP servers to " . $Ntp1 . " and " . $Ntp2) false; -/ system ntp client set primary-ntp=$Ntp1 secondary-ntp=$Ntp2; +/ system ntp client set servers=($Ntp1, $Ntp2); From 93770d40a8c51dd3128ebc1a6b1edcdf0ceb7be6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Nov 2021 13:49:14 +0100 Subject: [PATCH 0919/2612] check-health: adopt new data structure for ROS 7.x The PSU state has an empty string for type... Thus matching on name. --- check-health | 88 +++++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/check-health b/check-health index 28de93e..ca379c4 100644 --- a/check-health +++ b/check-health @@ -24,98 +24,108 @@ :global SendNotification2; :global SymbolForNotification; -:local FormatVoltage do={ - :local Voltage [ :tonum $1 ]; - :return (($Voltage / 10) . "." . [ :pick $Voltage ([ :len $Voltage ] - 1) ] . "V"); +:local TempToNum do={ + :global CharacterReplace; + :local T [ :toarray [ $CharacterReplace $1 "." "," ] ]; + :return ($T->0 * 10 + $T->1); } -:local CheckHealthCurrent [ / system health get ]; - -:if ([ :len $CheckHealthCurrent ] = 0) do={ +:if ([ :len [ / system health find ] ] = 0) do={ $LogPrintExit2 error $0 ("Your device does not provide any health values.") true; } +:if ([ :typeof $CheckHealthLast ] != "array") do={ + :set CheckHealthLast [ :toarray "" ]; +} :if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ :set CheckHealthTemperatureNotified [ :toarray "" ]; } $ScriptLock $0; -:foreach Name,Voltage in=$CheckHealthCurrent do={ - :if ($Name ~ "(battery|voltage)" && \ - [ :typeof ($CheckHealthLast->$Name) ] = "num" && \ - [ :typeof $Voltage ] = "num") do={ - :if ($CheckHealthLast->$Name * (100 + $CheckHealthVoltagePercent) < $Voltage * 100 || \ - $CheckHealthLast->$Name * 100 > $Voltage * (100 + $CheckHealthVoltagePercent)) do={ +:foreach Voltage in=[ / system health find where type="V" ] do={ + :local Name [ / system health get $Voltage name ]; + :local Value [ / system health get $Voltage value ]; + + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ + :local NumCurr [ $TempToNum $Value ]; + :local NumLast [ $TempToNum ($CheckHealthLast->$Name) ]; + + :if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \ + $NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={ $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($CheckHealthLast->$Name < \ - $Voltage) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ + subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \ + $NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ - "old value: " . [ $FormatVoltage ($CheckHealthLast->$Name) ] . "\n" . \ - "new value: " . [ $FormatVoltage $Voltage ]) }); + "old value: " . ($CheckHealthLast->$Name) . " V\n" . \ + "new value: " . $Value . " V") }); } else={ - :if ($Voltage <= $CheckHealthVoltageLow && $CheckHealthLast->$Name > $CheckHealthVoltageLow) do={ + :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \ - message=("The " . $Name . " on " . $Identity . " dropped to " . [ $FormatVoltage $Voltage ] . " below hard limit.") }); + message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") }); } - :if ($Voltage > $CheckHealthVoltageLow && $CheckHealthLast->$Name <= $CheckHealthVoltageLow) do={ + :if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={ $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ - message=("The " . $Name . " on " . $Identity . " recovered to " . [ $FormatVoltage $Voltage ] . " above hard limit.") }); + message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") }); } } } + :set ($CheckHealthLast->$Name) $Value; } -:foreach Name,PSU in=$CheckHealthCurrent do={ - :if ($Name ~ "psu.*-state" && \ - [ :typeof ($CheckHealthLast->$Name) ] = "str" && \ - [ :typeof $PSU ] = "str") do={ +:foreach PSU in=[ / system health find where name~"^psu.*-state\$" ] do={ + :local Name [ / system health get $PSU name ]; + :local Value [ / system health get $PSU value ]; + + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ :if ($CheckHealthLast->$Name = "ok" && \ - $PSU != "ok") do={ + $Value != "ok") do={ $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ message=("The power supply unit '" . $Name . "' on " . $Identity . " failed!") }); } :if ($CheckHealthLast->$Name != "ok" && \ - $PSU = "ok") do={ + $Value = "ok") do={ $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ message=("The power supply unit '" . $Name . "' on " . $Identity . " recovered!") }); } } + :set ($CheckHealthLast->$Name) $Value; } -:foreach Name,Temperature in=$CheckHealthCurrent do={ - :if ($Name ~ "temperature" && \ - [ :typeof $Temperature ] = "num") do={ +:foreach Temperature in=[ / system health find where type="C" ] do={ + :local Name [ / system health get $Temperature name ]; + :local Value [ / system health get $Temperature value ]; + + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ $LogPrintExit2 info $0 ("No threshold given for " . $Name . ", assuming 50C.") false; :set ($CheckHealthTemperature->$Name) 50; } - :local Validate [ / system health get $Name ]; - :while ($Temperature != $Validate) do={ - :set Temperature $Validate; - :set Validate [ / system health get $Name ]; + :local Validate [ / system health get [ find where name=$Name ] value ]; + :while ($Value != $Validate) do={ + :set Value $Validate; + :set Validate [ / system health get [ find where name=$Name ] value ]; } - :if ($Temperature > $CheckHealthTemperature->$Name && \ + :if ($Value > $CheckHealthTemperature->$Name && \ $CheckHealthTemperatureNotified->$Name != true) do={ $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ message=("The " . $Name . " on " . $Identity . " is above threshold: " . \ - $Temperature . "\C2\B0" . "C") }); + $Value . "\C2\B0" . "C") }); :set ($CheckHealthTemperatureNotified->$Name) true; } - :if ($Temperature <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ + :if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ $CheckHealthTemperatureNotified->$Name = true) do={ $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ - $Temperature . "\C2\B0" . "C") }); + $Value . "\C2\B0" . "C") }); :set ($CheckHealthTemperatureNotified->$Name) false; } } + :set ($CheckHealthLast->$Name) $Value; } - -:set CheckHealthLast $CheckHealthCurrent; From 25704812b21a9e24bff83f5406c94b2b54684be3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 13 Dec 2021 21:00:11 +0100 Subject: [PATCH 0920/2612] doc/capsman-download-packages: only bundle is available now --- doc/capsman-download-packages.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index cdbd72b..a27ca1e 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -32,11 +32,9 @@ place the required packages to CAPsMAN package path (see function `$DownloadPackage`, use something like this to download latest packages to directory `routeros`: - $DownloadPackage system "" arm routeros; - $DownloadPackage security "" arm routeros; - [...] - $DownloadPackage system "" mipsbe routeros; - $DownloadPackage security "" mipsbe routeros; + $DownloadPackage routeros "" arm routeros; + $DownloadPackage routeros "" arm64 routeros; + $DownloadPackage routeros "" mipsbe routeros; [...] Usage and invocation From 5135a413329ed401ae62ef6b4d05fe09fc0df2f7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 14 Jan 2022 08:35:47 +0100 Subject: [PATCH 0921/2612] global: notify about merging 'routeros-v7' into 'main' --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 8 +++++++- global-functions | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/global-config b/global-config index 02d99b4..454e5bf 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 74; +:global GlobalConfigVersion 75; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 37f78cf..562d7b5 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 74; +:global GlobalConfigVersion 75; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index a070ecd..d1058e4 100644 --- a/global-config.changes +++ b/global-config.changes @@ -2,6 +2,9 @@ # Copyright (c) 2019-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +:global IfThenElse; +:global RequiredRouterOS; + # Changes for global-config to be added to notification on script updates :global GlobalConfigChanges { 1="Moved variables from 'global-config' to 'global-functions' for independence"; @@ -73,11 +76,14 @@ 67="Moved modules to directory with shorter name."; 68="Reintroduced 'global-wait' for functions in scheduler."; 69="Support hard lower limit for voltage in 'check-health'."; - 70="MikroTik started pushing RouterOS v7. Changes are required if you run it, see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v7"; + 70="MikroTik started pushing RouterOS v7. Changes are no longer required."; 71="MikroTik is pushing RouterOS v7 even more, in parallel branches. If you want to keep RouterOS v6 for some time see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v6"; 72="Introduced new script 'netwatch-dns' to manage DNS and DoH servers from netwatch."; 73="Renamed backup scripts ('cloud-backup' -> 'backup-cloud', 'email-backup' -> 'backup-email', 'upload-backup' -> 'backup-upload')."; 74="Extended 'hotspot-to-wpa', it can now read additional configuration from templates and hotspot users."; + 75=("Finally merged the RouterOS v7 code into the main branch. " . [ $IfThenElse ([ $RequiredRouterOS "global-config.changes" "7.0" false ] = true) \ + ("You may now drop '\$ScriptUpdatesUrlSuffix' from 'global-config-overlay'.") \ + ("Still running RouterOS v6, so last reminder to see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v6") ]); }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 388d24e..1e402d9 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 74; +:global ExpectedConfigVersion 75; # global variables not to be changed by user :global GlobalFunctionsReady false; From 51cd11c80380eac0bfde4649cb30747c198881b7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 17 Jan 2022 20:15:24 +0100 Subject: [PATCH 0922/2612] global-functions: $DownloadPackage: give url in debug output --- global-functions | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 1e402d9..17aa56d 100644 --- a/global-functions +++ b/global-functions @@ -278,13 +278,13 @@ $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; } + :local Url ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile); $LogPrintExit2 info $0 ("Downloading package file '" . $PkgName . "'...") false; + $LogPrintExit2 debug $0 ("... from url: " . $Url) false; :local Retry 3; :while ($Retry > 0) do={ :do { - / tool fetch check-certificate=yes-without-crl \ - ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile) \ - dst-path=$PkgDest; + / tool fetch check-certificate=yes-without-crl $Url dst-path=$PkgDest; $WaitForFile $PkgDest; :if ([ / file get [ find where name=$PkgDest ] type ] = "package") do={ From 1e6931c8e34d5035cb07baa98b57eccbcd4278ab Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 17 Jan 2022 20:50:52 +0100 Subject: [PATCH 0923/2612] global-functions: $DownloadPackage: handle special case with name For RouterOS 6.x bundled package version and architecture are swapped. Closes: #21 --- global-functions | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/global-functions b/global-functions index 17aa56d..7646aea 100644 --- a/global-functions +++ b/global-functions @@ -252,6 +252,7 @@ :global CleanFilePath; :global LogPrintExit2; :global MkDir; + :global VersionToNum; :global WaitForFile; :if ([ :len $PkgName ] = 0) do={ :return false; } @@ -259,6 +260,9 @@ :if ([ :len $PkgArch ] = 0) do={ :set PkgArch [ / system resource get architecture-name ]; } :local PkgFile ($PkgName . "-" . $PkgVer . "-" . $PkgArch . ".npk"); + :if ([ $VersionToNum $PkgVer ] < [ $VersionToNum "7.0" ] && $PkgName = "routeros") do={ + :set PkgFile ($PkgName . "-" . $PkgArch . "-" . $PkgVer . ".npk"); + } :if ($PkgArch = "x86_64" || $PkgName ~ "^routeros-") do={ :set PkgFile ($PkgName . "-" . $PkgVer . ".npk"); } From b4a5d824a268fae9f06ccf61fff4f67c760773ed Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jan 2022 22:05:05 +0100 Subject: [PATCH 0924/2612] global-functions: $ScriptInstallUpdate: give final url in debug output --- global-functions | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/global-functions b/global-functions index 7646aea..16704c6 100644 --- a/global-functions +++ b/global-functions @@ -731,15 +731,15 @@ :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ :local Comment [ $ParseKeyValueStore ($ScriptVal->"comment") ]; :if (!($Comment->"ignore" = true)) do={ - $LogPrintExit2 debug $0 ("Fetching script from url: " . $ScriptVal->"name") false; :do { :local BaseUrl $ScriptUpdatesBaseUrl; :local UrlSuffix $ScriptUpdatesUrlSuffix; :if ([ :typeof ($Comment->"base-url") ] = "str") do={ :set BaseUrl ($Comment->"base-url"); } :if ([ :typeof ($Comment->"url-suffix") ] = "str") do={ :set UrlSuffix ($Comment->"url-suffix"); } + :local Url ($BaseUrl . $ScriptVal->"name" . $UrlSuffix); - :local Result [ / tool fetch check-certificate=yes-without-crl \ - ($BaseUrl . $ScriptVal->"name" . $UrlSuffix) output=user as-value ]; + $LogPrintExit2 debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url) false; + :local Result [ / tool fetch check-certificate=yes-without-crl $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set SourceNew ($Result->"data"); } @@ -804,11 +804,10 @@ :global GlobalConfigMigration; :local ChangeLogCode; - $LogPrintExit2 debug $0 ("Fetching news, changes and migration.") false; :do { - :local Result [ / tool fetch check-certificate=yes-without-crl \ - ($ScriptUpdatesBaseUrl . "global-config.changes" . $ScriptUpdatesUrlSuffix) \ - output=user as-value ]; + :local Url ($ScriptUpdatesBaseUrl . "global-config.changes" . $ScriptUpdatesUrlSuffix); + $LogPrintExit2 debug $0 ("Fetching news, changes and migration: " . $Url) false; + :local Result [ / tool fetch check-certificate=yes-without-crl $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set ChangeLogCode ($Result->"data"); } From 5e32105e7ea4bd357f9826d1ca24ca6e2c455bdc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jan 2022 22:11:30 +0100 Subject: [PATCH 0925/2612] global-functions: $ScriptInstallUpdate: quote names in log output --- global-functions | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/global-functions b/global-functions index 16704c6..a9b409b 100644 --- a/global-functions +++ b/global-functions @@ -723,8 +723,8 @@ :foreach Scheduler in=[ / system scheduler find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ :local SchedulerVal [ / system scheduler get $Scheduler ]; :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ - $LogPrintExit2 warning $0 ("Policies differ for script " . $ScriptVal->"name" . \ - " and its scheduler " . $SchedulerVal->"name" . "!") false; + $LogPrintExit2 warning $0 ("Policies differ for script '" . $ScriptVal->"name" . \ + "' and its scheduler '" . $SchedulerVal->"name" . "'!") false; } } @@ -744,7 +744,7 @@ :set SourceNew ($Result->"data"); } } on-error={ - $LogPrintExit2 warning $0 ("Failed fetching " . $ScriptVal->"name") false; + $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!") false; } } } @@ -765,18 +765,18 @@ :set ReloadGlobalFunctions true; } } else={ - $LogPrintExit2 warning $0 ("Syntax validation for script " . $ScriptVal->"name" . \ - " failed! Ignoring!") false; + $LogPrintExit2 warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . \ + "' failed! Ignoring!") false; } } else={ - $LogPrintExit2 warning $0 ("Looks like new script " . $ScriptVal->"name" . \ - " is not valid (missing shebang). Ignoring!") false; + $LogPrintExit2 warning $0 ("Looks like new script '" . $ScriptVal->"name" . \ + "' is not valid (missing shebang). Ignoring!") false; } } else={ - $LogPrintExit2 debug $0 ("Script " . $ScriptVal->"name" . " did not change.") false; + $LogPrintExit2 debug $0 ("Script '" . $ScriptVal->"name" . "' did not change.") false; } } else={ - $LogPrintExit2 debug $0 ("No update for script " . $ScriptVal->"name" . ".") false; + $LogPrintExit2 debug $0 ("No update for script '" . $ScriptVal->"name" . "'.") false; } } From dfe995be270f1ee9621454e7feada84c33168db0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 30 Jan 2022 22:05:58 +0100 Subject: [PATCH 0926/2612] check-routeros-update: use correct syntax --- check-routeros-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-routeros-update b/check-routeros-update index 0f687a5..8cad07a 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -108,7 +108,7 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; :if ([ $ScriptFromTerminal $0 ] = true) do={ :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); - :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ + :if (([ / terminal inkey timeout=60 ] % 32) = 25) do={ $DoUpdate; } else={ :put "Canceled..."; From 27a81bcbca52d513c5b9c10578474a1863bd08af Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 30 Jan 2022 22:06:37 +0100 Subject: [PATCH 0927/2612] packages-update: use correct syntax --- packages-update | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages-update b/packages-update index b6b0524..2e6d8be 100644 --- a/packages-update +++ b/packages-update @@ -35,7 +35,7 @@ $ScriptLock $0; :if ($NumInstalled > $NumLatest) do={ :if ([ $ScriptFromTerminal $0 ] = true) do={ :put "Latest version is older than installed one. Want to downgrade? [y/N]"; - :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ + :if (([ / terminal inkey timeout=60 ] % 32) = 25) do={ :set DoDowngrade true; } else={ :put "Canceled..."; @@ -61,7 +61,7 @@ $ScriptLock $0; $LogPrintExit2 warning $0 ("Running backup script " . $ScriptName . " before update failed!") false; :if ([ $ScriptFromTerminal $0 ] = true) do={ :put "Do you want to continue anyway? [y/N]"; - :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ + :if (([ / terminal inkey timeout=60 ] % 32) = 25) do={ $LogPrintExit2 info $0 ("User requested to continue anyway.") false; } else={ $LogPrintExit2 info $0 ("Canceled update...") true; @@ -80,7 +80,7 @@ $ScriptLock $0; :if ([ $ScriptFromTerminal $0 ] = true) do={ :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; - :if (([ :terminal inkey timeout=60 ] % 32) = 19) do={ + :if (([ / terminal inkey timeout=60 ] % 32) = 19) do={ / system scheduler add name="reboot-for-update" start-time=03:00:00 interval=1d \ on-event=(":global RandomDelay; \$RandomDelay 3600; " . \ "/ system scheduler remove reboot-for-update; / system reboot;"); From dd19aea3628471ce54fefa30913879322f20e63a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 3 Feb 2022 14:29:37 +0100 Subject: [PATCH 0928/2612] doc/packages-update: link backup-cloud --- doc/packages-update.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/packages-update.md b/doc/packages-update.md index ac69301..309a394 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -41,6 +41,7 @@ See also -------- * [Notify on RouterOS update](check-routeros-update.md) +* [Upload backup to Mikrotik cloud](backup-cloud.md) * [Send backup via e-mail](backup-email.md) * [Upload backup to server](backup-upload.md) From 42c203291a7db814be00f40caddb6980632358fa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 8 Feb 2022 17:39:53 +0100 Subject: [PATCH 0929/2612] doc/netwatch-notify: add sections --- doc/netwatch-notify.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 78a0eed..9b504f7 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -38,6 +38,8 @@ The hosts to be checked have to be added to netwatch with specific comment: / tool netwatch add comment="notify, hostname=example.com" host=[ :resolve "example.com" ]; +### Hooks + It is possible to run an up hook command (`up-hook`) or down hook command (`down-hook`) when a notification is triggered. This has to be added in comment, note that some characters need extra escaping: @@ -48,10 +50,14 @@ Also there is a `pre-down-hook` that fires at two thirds of failed checks required for the notification. The idea is to fix the issue before a notification is sent. +### Count threshould + The count threshould (default is 5 checks) is configurable as well: / tool netwatch add comment="notify, hostname=example.com, count=10" host=104.18.144.11; +### Parents & dependencies + If the host is behind another checked host add a dependency, this will suppress notification if the parent host is down: @@ -61,6 +67,8 @@ suppress notification if the parent host is down: Note that every configured parent in a chain increases the check count threshould by one. +### Update from DNS + The host address can be updated dynamically. Give extra parameter `resolve` with a resolvable name: From c6e581d4f90c9bea0adf405685aa634e264d1f3b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 3 Feb 2022 13:51:40 +0100 Subject: [PATCH 0930/2612] netwatch-notify: allow to suppress notification on host down --- doc/netwatch-notify.md | 10 ++++++++++ global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- netwatch-notify | 16 +++++++++------- 6 files changed, 23 insertions(+), 10 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 9b504f7..dc107f2 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -78,6 +78,16 @@ But be warned: Dynamic updates will probably cause issues if the name has more than one record in dns - a high rate of configuration changes (and flash writes) at least. +### No notification on host down + +Also suppressing the notification on host down is possible with parameter +`no-down-notification`. This may be desired for devices that are usually +powered off, but accessibility is of interest. + + / tool netwatch add comment="notify, hostname=printer, no-down-notification" host=10.0.0.30; + +Go and get your coffee â˜•ī¸ before sending the print job. + Also notification settings are required for e-mail, matrix and/or telegram. Tips & Tricks diff --git a/global-config b/global-config index 454e5bf..37a60e8 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 75; +:global GlobalConfigVersion 76; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 562d7b5..8e1a664 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 75; +:global GlobalConfigVersion 76; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index d1058e4..271d232 100644 --- a/global-config.changes +++ b/global-config.changes @@ -84,6 +84,7 @@ 75=("Finally merged the RouterOS v7 code into the main branch. " . [ $IfThenElse ([ $RequiredRouterOS "global-config.changes" "7.0" false ] = true) \ ("You may now drop '\$ScriptUpdatesUrlSuffix' from 'global-config-overlay'.") \ ("Still running RouterOS v6, so last reminder to see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v6") ]); + 76="Added an option to suppress notifications on host down with 'netwatch-notify'."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index a9b409b..0bdbb48 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 75; +:global ExpectedConfigVersion 76; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/netwatch-notify b/netwatch-notify index ae89cfb..e82cea6 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -122,10 +122,10 @@ $ScriptLock $0; :set Parent ($NetwatchNotify->$Parent->"parent"); } } - $LogPrintExit2 info $0 ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ - $Metric->"count" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ - ($Metric->"notified" = true) ("already notified.") ($Count - $Metric->"count" . " to go.") ] \ - ("parent host " . $Parent . " is down.") ]) false; + $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ + ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . $Metric->"count" . " checks, " . \ + [ $IfThenElse ($ParentNotified = false) [ $IfThenElse ($Metric->"notified" = true) ("already notified.") \ + ($Count - $Metric->"count" . " to go.") ] ("parent host " . $Parent . " is down.") ]) false; :if ((($Count * 2) - ($Metric->"count" * 3)) / 2 = 0 && [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ $NetwatchNotifyHook $HostName "pre-down" ($HostInfo->"pre-down-hook"); } @@ -134,9 +134,11 @@ $ScriptLock $0; :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $HostName "down" ($HostInfo->"down-hook") ]); } - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down"); \ - message=$Message }); + :if ($HostInfo->"no-down-notification" != true) do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down"); \ + message=$Message }); + } :set ($Metric->"notified") true; } } From 0b46c508dc8f76955dd528900882b54c07b62ef3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Feb 2022 21:46:10 +0100 Subject: [PATCH 0931/2612] netwatch-notify: nest conditions The logic here was right, but RouterOS runs the checks simultaneously. This caused delays even if no resolving was needed. Nesting the checks fixes this. --- netwatch-notify | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index e82cea6..34a9e8f 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -66,21 +66,23 @@ $ScriptLock $0; :set $Metric ($NetwatchNotify->$HostName); } - :if ([ :typeof ($HostInfo->"resolve") ] = "str" && [ $DNSIsResolving ] = true) do={ - :do { - :local Resolve [ :resolve ($HostInfo->"resolve") ]; - :if ($Resolve != $HostVal->"host") do={ - $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ - $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . \ - "' resolves to different address " . $Resolve . ", updating.") false; - / tool netwatch set host=$Resolve $Host; - :set ($Metric->"resolve-failed") false; - } - } on-error={ - :if ($Metric->"resolve-failed" != true) do={ - $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ - $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . "' failed.") false; - :set ($Metric->"resolve-failed") true; + :if ([ :typeof ($HostInfo->"resolve") ] = "str") do={ + :if ([ $DNSIsResolving ] = true) do={ + :do { + :local Resolve [ :resolve ($HostInfo->"resolve") ]; + :if ($Resolve != $HostVal->"host") do={ + $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ + $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . \ + "' resolves to different address " . $Resolve . ", updating.") false; + / tool netwatch set host=$Resolve $Host; + :set ($Metric->"resolve-failed") false; + } + } on-error={ + :if ($Metric->"resolve-failed" != true) do={ + $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ + $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . "' failed.") false; + :set ($Metric->"resolve-failed") true; + } } } } From a47f5723cc4cdd287d36aaffd7619c17494f9345 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Feb 2022 09:58:53 +0100 Subject: [PATCH 0932/2612] netwatch-dns: flush cache on configuration change --- netwatch-dns | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netwatch-dns b/netwatch-dns index e731d95..e2fcfa3 100644 --- a/netwatch-dns +++ b/netwatch-dns @@ -43,12 +43,14 @@ $ScriptLock $0; :if ($DnsServers != $DnsCurrent) do={ $LogPrintExit2 info $0 ("Updating DNS servers: " . [ :tostr $DnsServers ]) false; / ip dns set servers=$DnsServers; + / ip dns cache flush; } } else={ :if ([ :len $DnsFallback ] > 0) do={ :if ($DnsFallback != $DnsCurrent) do={ $LogPrintExit2 info $0 ("Updating DNS servers to fallback: " . [ :tostr $DnsFallback ]) false; / ip dns set servers=$DnsFallback; + / ip dns cache flush; } } } @@ -69,10 +71,12 @@ $ScriptLock $0; :if ($DohServer != $DohCurrent) do={ $LogPrintExit2 info $0 ("Updating DoH server: " . $DohServer) false; / ip dns set use-doh-server=$DohServer; + / ip dns cache flush; } } else={ :if ($DohCurrent != "") do={ $LogPrintExit2 info $0 ("DoH server (" . $DohCurrent . ") is down, disabling.") false; / ip dns set use-doh-server=""; + / ip dns cache flush; } } From 3c358980cb416c61419a0aaa384ab1db1dab8d29 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 2 Feb 2022 21:10:10 +0100 Subject: [PATCH 0933/2612] introduce firmware-upgrade-reboot --- README.md | 1 + doc/check-routeros-update.md | 1 + doc/firmware-upgrade-reboot.md | 36 ++++++++++++++++++++++++++++++++++ doc/packages-update.md | 1 + firmware-upgrade-reboot | 32 ++++++++++++++++++++++++++++++ global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 9 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 doc/firmware-upgrade-reboot.md create mode 100644 firmware-upgrade-reboot diff --git a/README.md b/README.md index 02cb009..43b8c58 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,7 @@ Available scripts * [Use wireless network with daily psk](doc/daily-psk.md) * [Comment DHCP leases with info from access list](doc/dhcp-lease-comment.md) * [Create DNS records for DHCP leases](doc/dhcp-to-dns.md) +* [Automatically upgrade firmware and reboot](doc/firmware-upgrade-reboot.md) * [Wait for global functions und modules](doc/global-wait.md) * [Send GPS position to server](doc/gps-track.md) * [Use WPA2 network with hotspot credentials](doc/hotspot-to-wpa.md) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 9385341..d55fa08 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -61,6 +61,7 @@ Installing script [packages-update](packages-update.md) gives extra options. See also -------- +* [Automatically upgrade firmware and reboot](firmware-upgrade-reboot.md) * [Manage system update](packages-update.md) --- diff --git a/doc/firmware-upgrade-reboot.md b/doc/firmware-upgrade-reboot.md new file mode 100644 index 0000000..6afc40e --- /dev/null +++ b/doc/firmware-upgrade-reboot.md @@ -0,0 +1,36 @@ +Automatically upgrade firmware and reboot +========================================= + +[◀ Go back to main README](../README.md) + +🛈 This script can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + +Description +----------- + +RouterOS and firmware are upgraded separately, activating the latter +requires an extra reboot. This script handles upgrade and reboot. + +âš ī¸ **Warning**: This *should* be bullet proof, but I can not guarantee. In +worst case it has potential to cause a boot loop, so handle with care! + +Requirements and installation +----------------------------- + +Just install the script and create a scheduler: + + $ScriptInstallUpdate firmware-upgrade-reboot; + / system scheduler add name=firmware-upgrade-reboot on-event="/ system script run firmware-upgrade-reboot;" start-time=startup; + +Enjoy firmware being up to date and in sync with RouterOS. + +See also +-------- + +* [Notify on RouterOS update](check-routeros-update.md) +* [Manage system update](packages-update.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/packages-update.md b/doc/packages-update.md index 309a394..a56f68e 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -44,6 +44,7 @@ See also * [Upload backup to Mikrotik cloud](backup-cloud.md) * [Send backup via e-mail](backup-email.md) * [Upload backup to server](backup-upload.md) +* [Automatically upgrade firmware and reboot](firmware-upgrade-reboot.md) --- [◀ Go back to main README](../README.md) diff --git a/firmware-upgrade-reboot b/firmware-upgrade-reboot new file mode 100644 index 0000000..b3cb621 --- /dev/null +++ b/firmware-upgrade-reboot @@ -0,0 +1,32 @@ +#!rsc by RouterOS +# RouterOS script: firmware-upgrade-reboot +# Copyright (c) 2022 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# install firmware upgrade, and reboot +# https://git.eworm.de/cgit/routeros-scripts/about/doc/firmware-upgrade-reboot.md + +:local 0 "firmware-upgrade-reboot"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global LogPrintExit2; + +:local RouterBoard [ / system routerboard get ]; +:if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ + $LogPrintExit2 info $0 ("Firmware is already up to date.") true; +} + +:if ([ / system routerboard settings get auto-upgrade ] = false) do={ + $LogPrintExit2 info $0 ("Firmware version " . $RouterBoard->"upgrade-firmware" . \ + " is available, upgrading.") false; + / system routerboard upgrade; +} + +:while ([ :len [ / log find where topics=({"system";"info";"critical"}) \ + message="Firmware upgraded successfully, please reboot for changes to take effect!" ] ] = 0) do={ + :delay 1s; +} + +$LogPrintExit2 info $0 ("Firmware upgrade successful, rebooting.") false; +/ system reboot; diff --git a/global-config b/global-config index 37a60e8..50e7f54 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 76; +:global GlobalConfigVersion 77; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 8e1a664..d8c2e0a 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 76; +:global GlobalConfigVersion 77; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 271d232..727b259 100644 --- a/global-config.changes +++ b/global-config.changes @@ -85,6 +85,7 @@ ("You may now drop '\$ScriptUpdatesUrlSuffix' from 'global-config-overlay'.") \ ("Still running RouterOS v6, so last reminder to see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v6") ]); 76="Added an option to suppress notifications on host down with 'netwatch-notify'."; + 77="Introduced new script 'firmware-upgrade-reboot'. Handle with care!"; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 0bdbb48..4d1d1a1 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 76; +:global ExpectedConfigVersion 77; # global variables not to be changed by user :global GlobalFunctionsReady false; From a50d9d30e3fbf6b4236f99cb40df656206492f8f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Feb 2022 14:28:09 +0100 Subject: [PATCH 0934/2612] update list of contributors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks a lot and please enjoy firmware-upgrade-reboot! 😊 --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 33f82f9..ba4dfed 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -22,6 +22,7 @@ Add yourself to the list, * Abdul Mannan Abbasi * Andrew Cox * Christoph Boss (@Kampfwurst) +* Devin Dean (@dd2594gh) * Klaus Michael RÃŧbsam * Linux-Schmie.de Michael Gisbers * Manuel Kuhn From 7b48b25c271111570d27708ceac437e24f05e6fe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 10 Feb 2022 11:05:21 +0100 Subject: [PATCH 0935/2612] global-functions: $MkDir: do not act without directory --- global-functions | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/global-functions b/global-functions index 4d1d1a1..acf3546 100644 --- a/global-functions +++ b/global-functions @@ -510,6 +510,10 @@ :set Dir [ $CleanFilePath $Dir ]; + :if ($Dir = "") do={ + :return true; + } + :if ([ :len [ / file find where name=$Dir type="directory" ] ] = 1) do={ :return true; } From 4d26dd07c32d5220c880e719df4f86ad34af6382 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 10 Feb 2022 11:58:08 +0100 Subject: [PATCH 0936/2612] capsman-download-packages: wireless package does no longer exist This is a RouterOS v7 only change! --- capsman-download-packages | 3 --- 1 file changed, 3 deletions(-) diff --git a/capsman-download-packages b/capsman-download-packages index 333f01b..6f4642c 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -44,9 +44,6 @@ $WaitFullyConnected; :if ($File->"package-architecture" = "mips") do={ :set ($File->"package-architecture") "mipsbe"; } - :if ($File->"package-name" = "wireless@") do={ - :set ($File->"package-name") "wireless"; - } :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion ($File->"package-architecture") $PackagePath ] = true) do={ :set Updated true; / file remove $Package; From 674398b3428448a7177873ca4c875c2695f88da8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 10 Feb 2022 12:20:24 +0100 Subject: [PATCH 0937/2612] global-functions: $DownloadPackage: handle special cases This is a RouterOS v7 only change! * Revert commit 1e6931c8e34d5035cb07baa98b57eccbcd4278ab (but keep the cherry-picked one in branch routeros-v6). * Drop special case 'routeros-$arch', which no longer exists. * Update package name 'system' to 'routeros'. This should be the correct name, and is expected by CAPsMAN. No idea why package-name property for the file is different... --- global-functions | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/global-functions b/global-functions index acf3546..3323f36 100644 --- a/global-functions +++ b/global-functions @@ -252,20 +252,16 @@ :global CleanFilePath; :global LogPrintExit2; :global MkDir; - :global VersionToNum; :global WaitForFile; :if ([ :len $PkgName ] = 0) do={ :return false; } :if ([ :len $PkgVer ] = 0) do={ :set PkgVer [ / system package update get installed-version ]; } :if ([ :len $PkgArch ] = 0) do={ :set PkgArch [ / system resource get architecture-name ]; } + :if ($PkgName = "system") do={ :set PkgName "routeros"; } + :local PkgFile ($PkgName . "-" . $PkgVer . "-" . $PkgArch . ".npk"); - :if ([ $VersionToNum $PkgVer ] < [ $VersionToNum "7.0" ] && $PkgName = "routeros") do={ - :set PkgFile ($PkgName . "-" . $PkgArch . "-" . $PkgVer . ".npk"); - } - :if ($PkgArch = "x86_64" || $PkgName ~ "^routeros-") do={ - :set PkgFile ($PkgName . "-" . $PkgVer . ".npk"); - } + :if ($PkgArch = "x86_64") do={ :set PkgFile ($PkgName . "-" . $PkgVer . ".npk"); } :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; :if ([ $MkDir $PkgDir ] = false) do={ From 3f8e835233d8d9ac6f31572a1a115eb73c46ff92 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 11 Feb 2022 00:19:41 +0100 Subject: [PATCH 0938/2612] firmware-upgrade-reboot: add a delay before reboot Looks like my timing was too good... Upgrade and reboot happened too fast, so device reported: system;error;critical router was rebooted without proper shutdown Let's try something smart... Delay the reboot by the amount of uptime, and hope all devices - slow and powerful - are happy. --- firmware-upgrade-reboot | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/firmware-upgrade-reboot b/firmware-upgrade-reboot index b3cb621..a3a25db 100644 --- a/firmware-upgrade-reboot +++ b/firmware-upgrade-reboot @@ -28,5 +28,10 @@ :delay 1s; } +:local Uptime [ / system resource get uptime ]; +:if ($Uptime < 1m) do={ + :delay $Uptime; +} + $LogPrintExit2 info $0 ("Firmware upgrade successful, rebooting.") false; / system reboot; From a5e421faebe8ac82c1ade73f8c1ea26ef728030b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 11 Feb 2022 23:35:02 +0100 Subject: [PATCH 0939/2612] README: put hint into block quote --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 43b8c58..9d4d858 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,8 @@ RouterOS script distribution](https://www.youtube.com/watch?v=B9neG3oAhcY) including demonstation recorded live at [MUM Europe 2019](https://mum.mikrotik.com/2019/EU/) in Vienna. -*Be warned!* Some details changed. So see the presentation, then follow -the steps below for up-to-date commands. +> âš ī¸ **Warning**: Some details changed. So see the presentation, then follow +> the steps below for up-to-date commands. ### The long way in detail From 4b16dc06c4b1bcd7c7ec5e3849736765799e32e6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 11 Feb 2022 23:37:29 +0100 Subject: [PATCH 0940/2612] INITIAL-COMMANDS: put hint into block quote --- INITIAL-COMMANDS.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 9a8a129..2cea9a9 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -3,8 +3,9 @@ Initial commands [◀ Go back to main README](README.md) -These command are inteneded for initial setup. If you are not aware of the -procedure please follow [the long way in detail](README.md#the-long-way-in-detail). +> âš ī¸ **Warning**: These command are inteneded for initial setup. If you are +> not aware of the procedure please follow +> [the long way in detail](README.md#the-long-way-in-detail). One extra step is required if you run RouterOS v6: From 9e91ed56aaed77c6776ef95ebed791c40d7f21d2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 11 Feb 2022 23:34:39 +0100 Subject: [PATCH 0941/2612] doc: put hints into block quote --- doc/accesslist-duplicates.md | 4 ++-- doc/backup-cloud.md | 4 ++-- doc/backup-email.md | 5 ++--- doc/backup-upload.md | 4 ++-- doc/capsman-download-packages.md | 4 ++-- doc/capsman-rolling-upgrade.md | 4 ++-- doc/certificate-renew-issued.md | 4 ++-- doc/check-certificates.md | 4 ++-- doc/check-health.md | 4 ++-- doc/check-lte-firmware-upgrade.md | 4 ++-- doc/check-routeros-update.md | 4 ++-- doc/collect-wireless-mac.md | 4 ++-- doc/daily-psk.md | 4 ++-- doc/dhcp-lease-comment.md | 4 ++-- doc/dhcp-to-dns.md | 4 ++-- doc/firmware-upgrade-reboot.md | 8 ++++---- doc/global-wait.md | 4 ++-- doc/gps-track.md | 4 ++-- doc/hotspot-to-wpa.md | 4 ++-- doc/ipsec-to-dns.md | 4 ++-- doc/ipv6-update.md | 4 ++-- doc/lease-script.md | 4 ++-- doc/log-forward.md | 4 ++-- doc/mode-button.md | 4 ++-- doc/netwatch-dns.md | 4 ++-- doc/netwatch-notify.md | 4 ++-- doc/ospf-to-leds.md | 4 ++-- doc/packages-update.md | 4 ++-- doc/ppp-on-up.md | 4 ++-- doc/rotate-ntp.md | 4 ++-- doc/sms-action.md | 4 ++-- doc/sms-forward.md | 4 ++-- doc/update-gre-address.md | 4 ++-- doc/update-tunnelbroker.md | 4 ++-- 34 files changed, 70 insertions(+), 71 deletions(-) diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index e052c20..dcf2044 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -3,8 +3,8 @@ Find and remove access list duplicates [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index 117e4c7..92bf2f7 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -3,8 +3,8 @@ Upload backup to Mikrotik cloud [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/backup-email.md b/doc/backup-email.md index be36cb4..51ac9a4 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -3,8 +3,8 @@ Send backup via e-mail [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- @@ -12,7 +12,6 @@ Description This script sends binary backup (`/ system backup save`) and complete configuration export (`/ export terse`) via e-mail. - Requirements and installation ----------------------------- diff --git a/doc/backup-upload.md b/doc/backup-upload.md index 212b16c..d54b9bd 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -3,8 +3,8 @@ Upload backup to server [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index a27ca1e..cbd4a04 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -3,8 +3,8 @@ Download packages for CAP upgrade from CAPsMAN [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index 92eafa6..fd89260 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -3,8 +3,8 @@ Run rolling CAP upgrades from CAPsMAN [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/certificate-renew-issued.md b/doc/certificate-renew-issued.md index 63d6408..c7c4635 100644 --- a/doc/certificate-renew-issued.md +++ b/doc/certificate-renew-issued.md @@ -3,8 +3,8 @@ Renew locally issued certificates [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 44bee7a..2869b25 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -3,8 +3,8 @@ Renew certificates and notify on expiration [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/check-health.md b/doc/check-health.md index 8e271d6..358cc08 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -3,8 +3,8 @@ Notify about health state [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index ef68bcb..9729aa1 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -3,8 +3,8 @@ Notify on LTE firmware upgrade [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index d55fa08..ccf9bf2 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -3,8 +3,8 @@ Notify on RouterOS update [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 380c89f..94b53b8 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -3,8 +3,8 @@ Collect MAC addresses in wireless access list [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 105737a..c1a09e4 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -3,8 +3,8 @@ Use wireless network with daily psk [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/dhcp-lease-comment.md b/doc/dhcp-lease-comment.md index 0b8ceb2..3d19bdf 100644 --- a/doc/dhcp-lease-comment.md +++ b/doc/dhcp-lease-comment.md @@ -3,8 +3,8 @@ Comment DHCP leases with info from access list [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 60eb29d..1982fa3 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -3,8 +3,8 @@ Create DNS records for DHCP leases [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/firmware-upgrade-reboot.md b/doc/firmware-upgrade-reboot.md index 6afc40e..7ca98fa 100644 --- a/doc/firmware-upgrade-reboot.md +++ b/doc/firmware-upgrade-reboot.md @@ -3,8 +3,8 @@ Automatically upgrade firmware and reboot [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- @@ -12,8 +12,8 @@ Description RouterOS and firmware are upgraded separately, activating the latter requires an extra reboot. This script handles upgrade and reboot. -âš ī¸ **Warning**: This *should* be bullet proof, but I can not guarantee. In -worst case it has potential to cause a boot loop, so handle with care! +> âš ī¸ **Warning**: This *should* be bullet proof, but I can not guarantee. In +> worst case it has potential to cause a boot loop, so handle with care! Requirements and installation ----------------------------- diff --git a/doc/global-wait.md b/doc/global-wait.md index 2d9dad3..15b11f6 100644 --- a/doc/global-wait.md +++ b/doc/global-wait.md @@ -3,8 +3,8 @@ Wait for global functions and modules [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/gps-track.md b/doc/gps-track.md index e4e553c..d6ebe51 100644 --- a/doc/gps-track.md +++ b/doc/gps-track.md @@ -3,8 +3,8 @@ Send GPS position to server [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index f3dccdb..a29232d 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -3,8 +3,8 @@ Use WPA2 network with hotspot credentials [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/ipsec-to-dns.md b/doc/ipsec-to-dns.md index 9a0f486..d293b2c 100644 --- a/doc/ipsec-to-dns.md +++ b/doc/ipsec-to-dns.md @@ -3,8 +3,8 @@ Create DNS records for IPSec peers [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md index 994ea23..8290e9d 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -3,8 +3,8 @@ Update configuration on IPv6 prefix change [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/lease-script.md b/doc/lease-script.md index 3d8a29b..78aeb36 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -3,8 +3,8 @@ Run other scripts on DHCP lease [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/log-forward.md b/doc/log-forward.md index e3603b5..b7ca016 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -3,8 +3,8 @@ Forward log messages via notification [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/mode-button.md b/doc/mode-button.md index 3cea720..49a40bc 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -3,8 +3,8 @@ Mode button with multiple presses [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 96710a2..adb35ac 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -3,8 +3,8 @@ Manage DNS and DoH servers from netwatch [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index dc107f2..b111d59 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -3,8 +3,8 @@ Notify on host up and down [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/ospf-to-leds.md b/doc/ospf-to-leds.md index 908fb56..06c3b4b 100644 --- a/doc/ospf-to-leds.md +++ b/doc/ospf-to-leds.md @@ -3,8 +3,8 @@ Visualize OSPF state via LEDs [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/packages-update.md b/doc/packages-update.md index a56f68e..33f7b99 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -3,8 +3,8 @@ Manage system update [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/ppp-on-up.md b/doc/ppp-on-up.md index 7514f82..c0f7aee 100644 --- a/doc/ppp-on-up.md +++ b/doc/ppp-on-up.md @@ -3,8 +3,8 @@ Run scripts on ppp connection [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/rotate-ntp.md b/doc/rotate-ntp.md index c151db2..49231dd 100644 --- a/doc/rotate-ntp.md +++ b/doc/rotate-ntp.md @@ -3,8 +3,8 @@ Rotate NTP servers [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/sms-action.md b/doc/sms-action.md index e36d384..d83fa80 100644 --- a/doc/sms-action.md +++ b/doc/sms-action.md @@ -3,8 +3,8 @@ Act on received SMS [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 873ccac..04c62a8 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -3,8 +3,8 @@ Forward received SMS [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/update-gre-address.md b/doc/update-gre-address.md index e45e17a..acd8f97 100644 --- a/doc/update-gre-address.md +++ b/doc/update-gre-address.md @@ -3,8 +3,8 @@ Update GRE configuration with dynamic addresses [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- diff --git a/doc/update-tunnelbroker.md b/doc/update-tunnelbroker.md index caff9ff..15d888f 100644 --- a/doc/update-tunnelbroker.md +++ b/doc/update-tunnelbroker.md @@ -3,8 +3,8 @@ Update tunnelbroker configuration [◀ Go back to main README](../README.md) -🛈 This script can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> 🛈 **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. Description ----------- From f0b0951968bc865877c1f5b6607935490ba68033 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 11 Feb 2022 23:50:56 +0100 Subject: [PATCH 0942/2612] doc/early-errors: no site structure, hint only --- doc/early-errors.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/doc/early-errors.md b/doc/early-errors.md index a16da7d..b3c6800 100644 --- a/doc/early-errors.md +++ b/doc/early-errors.md @@ -1,11 +1,2 @@ -Send notification with early errors -=================================== - -[◀ Go back to main README](../README.md) - -This script has been replace. Please migrate to +This script has been replaced. Please migrate to [Forward log messages via notification](log-forward.md). - ---- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) From cd2a7dcf8ce3324179768b48a785f24f0d53aa19 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 12 Feb 2022 13:05:56 +0100 Subject: [PATCH 0943/2612] =?UTF-8?q?doc:=20use=20another=20info=20icon:?= =?UTF-8?q?=20=F0=9F=9B=88=20->=20=E2=84=B9=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/accesslist-duplicates.md | 2 +- doc/backup-cloud.md | 2 +- doc/backup-email.md | 2 +- doc/backup-upload.md | 2 +- doc/capsman-download-packages.md | 2 +- doc/capsman-rolling-upgrade.md | 2 +- doc/certificate-renew-issued.md | 2 +- doc/check-certificates.md | 2 +- doc/check-health.md | 2 +- doc/check-lte-firmware-upgrade.md | 2 +- doc/check-routeros-update.md | 2 +- doc/collect-wireless-mac.md | 2 +- doc/daily-psk.md | 2 +- doc/dhcp-lease-comment.md | 2 +- doc/dhcp-to-dns.md | 2 +- doc/firmware-upgrade-reboot.md | 2 +- doc/global-wait.md | 2 +- doc/gps-track.md | 2 +- doc/hotspot-to-wpa.md | 2 +- doc/ipsec-to-dns.md | 2 +- doc/ipv6-update.md | 2 +- doc/lease-script.md | 2 +- doc/log-forward.md | 2 +- doc/mode-button.md | 2 +- doc/netwatch-dns.md | 2 +- doc/netwatch-notify.md | 2 +- doc/ospf-to-leds.md | 2 +- doc/packages-update.md | 2 +- doc/ppp-on-up.md | 2 +- doc/rotate-ntp.md | 2 +- doc/sms-action.md | 2 +- doc/sms-forward.md | 2 +- doc/update-gre-address.md | 2 +- doc/update-tunnelbroker.md | 2 +- 34 files changed, 34 insertions(+), 34 deletions(-) diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index dcf2044..db1e00a 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -3,7 +3,7 @@ Find and remove access list duplicates [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index 92bf2f7..4df14fd 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -3,7 +3,7 @@ Upload backup to Mikrotik cloud [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/backup-email.md b/doc/backup-email.md index 51ac9a4..e6bed51 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -3,7 +3,7 @@ Send backup via e-mail [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/backup-upload.md b/doc/backup-upload.md index d54b9bd..1e17d62 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -3,7 +3,7 @@ Upload backup to server [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index cbd4a04..d3e08ad 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -3,7 +3,7 @@ Download packages for CAP upgrade from CAPsMAN [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index fd89260..34e3c91 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -3,7 +3,7 @@ Run rolling CAP upgrades from CAPsMAN [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/certificate-renew-issued.md b/doc/certificate-renew-issued.md index c7c4635..d7c4676 100644 --- a/doc/certificate-renew-issued.md +++ b/doc/certificate-renew-issued.md @@ -3,7 +3,7 @@ Renew locally issued certificates [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 2869b25..f6a4d22 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -3,7 +3,7 @@ Renew certificates and notify on expiration [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/check-health.md b/doc/check-health.md index 358cc08..778c080 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -3,7 +3,7 @@ Notify about health state [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index 9729aa1..a9da4a2 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -3,7 +3,7 @@ Notify on LTE firmware upgrade [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index ccf9bf2..766c258 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -3,7 +3,7 @@ Notify on RouterOS update [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 94b53b8..3120749 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -3,7 +3,7 @@ Collect MAC addresses in wireless access list [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/daily-psk.md b/doc/daily-psk.md index c1a09e4..28baac0 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -3,7 +3,7 @@ Use wireless network with daily psk [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/dhcp-lease-comment.md b/doc/dhcp-lease-comment.md index 3d19bdf..8679bfa 100644 --- a/doc/dhcp-lease-comment.md +++ b/doc/dhcp-lease-comment.md @@ -3,7 +3,7 @@ Comment DHCP leases with info from access list [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 1982fa3..245b457 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -3,7 +3,7 @@ Create DNS records for DHCP leases [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/firmware-upgrade-reboot.md b/doc/firmware-upgrade-reboot.md index 7ca98fa..c913d8e 100644 --- a/doc/firmware-upgrade-reboot.md +++ b/doc/firmware-upgrade-reboot.md @@ -3,7 +3,7 @@ Automatically upgrade firmware and reboot [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/global-wait.md b/doc/global-wait.md index 15b11f6..2a7fbfa 100644 --- a/doc/global-wait.md +++ b/doc/global-wait.md @@ -3,7 +3,7 @@ Wait for global functions and modules [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/gps-track.md b/doc/gps-track.md index d6ebe51..3b9c94f 100644 --- a/doc/gps-track.md +++ b/doc/gps-track.md @@ -3,7 +3,7 @@ Send GPS position to server [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index a29232d..b410979 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -3,7 +3,7 @@ Use WPA2 network with hotspot credentials [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/ipsec-to-dns.md b/doc/ipsec-to-dns.md index d293b2c..349ae63 100644 --- a/doc/ipsec-to-dns.md +++ b/doc/ipsec-to-dns.md @@ -3,7 +3,7 @@ Create DNS records for IPSec peers [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md index 8290e9d..ae4eb6a 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -3,7 +3,7 @@ Update configuration on IPv6 prefix change [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/lease-script.md b/doc/lease-script.md index 78aeb36..0ad67fb 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -3,7 +3,7 @@ Run other scripts on DHCP lease [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/log-forward.md b/doc/log-forward.md index b7ca016..3a0f3be 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -3,7 +3,7 @@ Forward log messages via notification [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/mode-button.md b/doc/mode-button.md index 49a40bc..c1c059e 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -3,7 +3,7 @@ Mode button with multiple presses [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index adb35ac..4fbfc2b 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -3,7 +3,7 @@ Manage DNS and DoH servers from netwatch [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index b111d59..c9917cb 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -3,7 +3,7 @@ Notify on host up and down [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/ospf-to-leds.md b/doc/ospf-to-leds.md index 06c3b4b..2fba33e 100644 --- a/doc/ospf-to-leds.md +++ b/doc/ospf-to-leds.md @@ -3,7 +3,7 @@ Visualize OSPF state via LEDs [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/packages-update.md b/doc/packages-update.md index 33f7b99..0007acc 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -3,7 +3,7 @@ Manage system update [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/ppp-on-up.md b/doc/ppp-on-up.md index c0f7aee..ae58da5 100644 --- a/doc/ppp-on-up.md +++ b/doc/ppp-on-up.md @@ -3,7 +3,7 @@ Run scripts on ppp connection [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/rotate-ntp.md b/doc/rotate-ntp.md index 49231dd..775b977 100644 --- a/doc/rotate-ntp.md +++ b/doc/rotate-ntp.md @@ -3,7 +3,7 @@ Rotate NTP servers [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/sms-action.md b/doc/sms-action.md index d83fa80..8442774 100644 --- a/doc/sms-action.md +++ b/doc/sms-action.md @@ -3,7 +3,7 @@ Act on received SMS [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 04c62a8..417f462 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -3,7 +3,7 @@ Forward received SMS [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/update-gre-address.md b/doc/update-gre-address.md index acd8f97..c19e138 100644 --- a/doc/update-gre-address.md +++ b/doc/update-gre-address.md @@ -3,7 +3,7 @@ Update GRE configuration with dynamic addresses [◀ 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 > installation. See [main README](../README.md) for details. Description diff --git a/doc/update-tunnelbroker.md b/doc/update-tunnelbroker.md index 15d888f..9dd7f19 100644 --- a/doc/update-tunnelbroker.md +++ b/doc/update-tunnelbroker.md @@ -3,7 +3,7 @@ Update tunnelbroker configuration [◀ 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 > installation. See [main README](../README.md) for details. Description From fd36241be649989e7b26348db31a3d3461888a1c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 12 Feb 2022 13:15:33 +0100 Subject: [PATCH 0944/2612] doc/mod: put hints into block quote, update info icon, fix links --- doc/mod/bridge-port-to.md | 8 ++++---- doc/mod/bridge-port-vlan.md | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/mod/bridge-port-to.md b/doc/mod/bridge-port-to.md index 5b2817b..02d1e8d 100644 --- a/doc/mod/bridge-port-to.md +++ b/doc/mod/bridge-port-to.md @@ -1,10 +1,10 @@ Manage ports in bridge ====================== -[◀ Go back to main README](../README.md) +[◀ Go back to main README](../../README.md) -🛈 This module can not be used on its own but requires the base installation. -See [main README](../README.md) for details. +> â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base +> installation. See [main README](../../README.md) for details. Description ----------- @@ -77,5 +77,5 @@ See also * [Manage VLANs on bridge ports](bridge-port-vlan.md) --- -[◀ Go back to main README](../README.md) +[◀ Go back to main README](../../README.md) [▲ Go back to top](#top) diff --git a/doc/mod/bridge-port-vlan.md b/doc/mod/bridge-port-vlan.md index 67dd04d..290826e 100644 --- a/doc/mod/bridge-port-vlan.md +++ b/doc/mod/bridge-port-vlan.md @@ -3,8 +3,8 @@ Manage VLANs on bridge ports [◀ Go back to main README](../../README.md) -🛈 This module can not be used on its own but requires the base installation. -See [main README](../../README.md) for details. +> â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base +> installation. See [main README](../../README.md) for details. Description ----------- From 6f27553f15787540a7b4bc353d89aa4d3d268830 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 20 Feb 2022 23:34:35 +0100 Subject: [PATCH 0945/2612] doc/check-routeros-update: mention e-mail, matrix and telegram --- doc/check-routeros-update.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 766c258..da74639 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -47,6 +47,8 @@ safe versions from a web server. The configuration goes to * `SafeUpdateUrl`: url to check for safe update, the channel (`long-term`, `stable` or `testing`) is appended +Also notification settings are required for e-mail, matrix and/or telegram. + Usage and invocation -------------------- From 886cd67edba86906fea4c0d753b13b7c68c5e78b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 19 Feb 2022 14:13:23 +0100 Subject: [PATCH 0946/2612] Makefile: match all *.md files, incl. doc/mod/ --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b07d27d..9f21255 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ TEMPLATE = $(wildcard *.template) CAPSMAN = $(TEMPLATE:.template=.capsman) LOCAL = $(TEMPLATE:.template=.local) -MARKDOWN = $(wildcard *.md) $(wildcard doc/*.md) +MARKDOWN = $(wildcard *.md doc/*.md doc/mod/*.md) HTML = $(MARKDOWN:.md=.html) all: $(CAPSMAN) $(LOCAL) $(HTML) From e6a686187c3d3c981b7ab86b4cbce46fc6466da4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Nov 2021 16:03:43 +0100 Subject: [PATCH 0947/2612] add doc/mod/notification-telegram --- README.md | 1 + doc/backup-cloud.md | 3 +- doc/backup-upload.md | 3 +- doc/check-certificates.md | 2 +- doc/check-health.md | 3 +- doc/check-lte-firmware-upgrade.md | 3 +- doc/check-routeros-update.md | 3 +- doc/collect-wireless-mac.md | 3 +- doc/daily-psk.md | 3 +- doc/log-forward.md | 3 +- doc/mod/notification-telegram.d/newbot.avif | Bin 0 -> 35870 bytes doc/mod/notification-telegram.md | 58 ++++++++++++++++++++ doc/netwatch-notify.md | 3 +- doc/sms-forward.md | 5 +- 14 files changed, 81 insertions(+), 12 deletions(-) create mode 100644 doc/mod/notification-telegram.d/newbot.avif create mode 100644 doc/mod/notification-telegram.md diff --git a/README.md b/README.md index 9d4d858..69461a9 100644 --- a/README.md +++ b/README.md @@ -224,6 +224,7 @@ Available modules * [Manage ports in bridge](doc/mod/bridge-port-to.md) * [Manage VLANs on bridge ports](doc/mod/bridge-port-vlan.md) +* [Send notifications via Telegram](doc/mod/notification-telegram.md) Contact ------- diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index 4df14fd..c768be1 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -30,7 +30,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupPassword`: password to encrypt the backup with * `BackupRandomDelay`: delay up to amount of seconds when run from scheduler -Also notification settings are required for e-mail, matrix and/or telegram. +Also notification settings are required for e-mail, matrix and/or +[telegram](mod/notification-telegram.md). Usage and invocation -------------------- diff --git a/doc/backup-upload.md b/doc/backup-upload.md index 1e17d62..cbda74e 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -36,7 +36,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupUploadUser`: username for server authentication * `BackupUploadPass`: password for server authentication -Also notification settings are required for e-mail, matrix and/or telegram. +Also notification settings are required for e-mail, matrix and/or +[telegram](mod/notification-telegram.md). ### Issues with SFTP client diff --git a/doc/check-certificates.md b/doc/check-certificates.md index f6a4d22..bddcd5a 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -27,7 +27,7 @@ Configuration ------------- The expiry notifications just require notification settings for e-mail, -matrix and/or telegram. +matrix and/or [telegram](mod/notification-telegram.md). For automatic download and renewal of certificates you need configuration in `global-config-overlay`, these are the parameters: diff --git a/doc/check-health.md b/doc/check-health.md index 778c080..81a9f75 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -56,7 +56,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `CheckHealthVoltageLow`: value (in volt*10) giving a hard lower limit * `CheckHealthVoltagePercent`: percentage value to trigger voltage jumps -Also notification settings are required for e-mail, matrix and/or telegram. +Also notification settings are required for e-mail, matrix and/or +[telegram](mod/notification-telegram.md). --- [◀ Go back to main README](../README.md) diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index a9da4a2..e5027a8 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -35,7 +35,8 @@ Just install the script: Configuration ------------- -Notification setting are required for e-mail, matrix and/or telegram. +Notification setting are required for e-mail, matrix and/or +[telegram](mod/notification-telegram.md). See also -------- diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index da74639..b8f6183 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -47,7 +47,8 @@ safe versions from a web server. The configuration goes to * `SafeUpdateUrl`: url to check for safe update, the channel (`long-term`, `stable` or `testing`) is appended -Also notification settings are required for e-mail, matrix and/or telegram. +Also notification settings are required for e-mail, matrix and/or +[telegram](mod/notification-telegram.md). Usage and invocation -------------------- diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 3120749..4e629a5 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -40,7 +40,8 @@ On first run a disabled access list entry acting as marker (with comment "`--- collected above ---`") is added. Move this entry to define where new entries are to be added. -Also notification settings are required for e-mail, matrix and/or telegram. +Also notification settings are required for e-mail, matrix and/or +[telegram](mod/notification-telegram.md). Usage and invocation -------------------- diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 28baac0..0d6ddef 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -51,7 +51,8 @@ Then add an access list entry: / interface wireless access-list add comment="Daily PSK" interface=wl-daily private-pre-shared-key="ToBeChangedDaily"; -Also notification settings are required for e-mail, matrix and/or telegram. +Also notification settings are required for e-mail, matrix and/or +[telegram](mod/notification-telegram.md). --- [◀ Go back to main README](../README.md) diff --git a/doc/log-forward.md b/doc/log-forward.md index 3a0f3be..6ff652f 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -46,7 +46,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `LogForwardIncludeMessage`: define message text to be forwarded (even if filter matches) -Also notification settings are required for e-mail, matrix and/or telegram. +Also notification settings are required for e-mail, matrix and/or +[telegram](mod/notification-telegram.md)m. --- [◀ Go back to main README](../README.md) diff --git a/doc/mod/notification-telegram.d/newbot.avif b/doc/mod/notification-telegram.d/newbot.avif new file mode 100644 index 0000000000000000000000000000000000000000..1fc7355fd56c8102d7f754be052dada52ce71790 GIT binary patch literal 35870 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

  • l2TqEyGXkjU07P(tN^G z&+W_^aq&M;2fPEolDkST&x2op&y0<^;jOcfJ=dj2pBat=-wYg A-rx&EC=im^R%;V3CQ9<{9@Z=CcT= zUo&TGklBZC=)QUFJT4Ch#(nTV+wu=x7yBjEk2!%-o0Qk>GK$@-puu-H)^yAvh<>%1L7}}`#3WlpL(rMtQ-dJ;Is9}m zX|0?)a|IhOb+m&vL!PGk%e0aH=vf=rR@23bbuUg*_CijW#Y4#5`5>$`Q^Acjt~f!E zap>9)m-r)ytyX9l>%pTd8v8m>PE(X`kauoobfPCj3`sx!q0}rkB|EuS>t?OcKd-HY zjnGBPMsL^Q*GpCtB^l#(#dx7nbgO-S06p~1cvhM9Db4QS?H3w;pD!-yE1?64&oE|r zOm8fltyMGjV(+TO+HP+!@msT-?u?Y;9PV=u>-$9lr!^!g9{NB$3=5@XwFPaTid*t@ z5eN6G$U^ZiqdJkjFhiH$0NEo@D#_kYPJ^?>SwSShp7oi}PMJHz`I?CDt9CFMli}#m zvBck;{FROlhf-9y^H2k}8ZE4zOFi@)4~jbAG2hiSUJzB}l(++5@XTf$WuB>n(c071 zld1;X*i5e)@T0IK@{DrM(P?_QC(fQ4ULyu(p$yge4YejMUZ2B?;F7qz9l=C7Yc`zw zHE^B*g^vQ8R9f+WqhI{s6~%AkR&g;%8~%{9tf77#{U;!R@S&M8KL;Tdc}tQI%e146 zG3jZL^txwzaLCG6E)exCvvlwY%O2S@Xr5WcifW@Xbdx5o!g|2Cu5wt{pOfmw1e&7g zBQ;M1& literal 0 HcmV?d00001 diff --git a/doc/netwatch-notify.d/notification-02-up.svg b/doc/netwatch-notify.d/notification-02-up.svg deleted file mode 100644 index 32dfbcc..0000000 --- a/doc/netwatch-notify.d/notification-02-up.svg +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] ✅ Netwatch Notify: example.com up - -The host 'example.com' (93.184.216.34) is up -since jun/08/2021 07:01:00. -It was down for 6 checks since jun/08/2021 06:55:03. - - diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 032106a..b0214e4 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -17,8 +17,8 @@ optional parent host is not down to avoid false alerts. ### Sample notifications -![netwatch-notify notification down](netwatch-notify.d/notification-01-down.svg) -![netwatch-notify notification up](netwatch-notify.d/notification-02-up.svg) +![netwatch-notify notification down](netwatch-notify.d/notification-01-down.avif) +![netwatch-notify notification up](netwatch-notify.d/notification-02-up.avif) Requirements and installation ----------------------------- From aef88e313bce339df0a46ab9873ea5e2ed4ecee5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Oct 2022 10:58:48 +0200 Subject: [PATCH 1241/2612] doc/sms-forward: update notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- âœ‚ī¸ ---- 📨 SMS Forwarding from 7277 Received this message by MikroTik from 7277: On oct/17/2022 13:44:10 GMT -0 type class-0: Welcome to our network! ---- âœ‚ī¸ ---- --- doc/sms-forward.d/notification.avif | Bin 0 -> 4751 bytes doc/sms-forward.d/notification.svg | 36 ---------------------------- doc/sms-forward.md | 2 +- 3 files changed, 1 insertion(+), 37 deletions(-) create mode 100644 doc/sms-forward.d/notification.avif delete mode 100644 doc/sms-forward.d/notification.svg diff --git a/doc/sms-forward.d/notification.avif b/doc/sms-forward.d/notification.avif new file mode 100644 index 0000000000000000000000000000000000000000..e76f04c4a7b6184efdaddb2ae3083874d3ff098c GIT binary patch literal 4751 zcmXw5WmFVg*BxRcr5mK1A*GvPkd&6Lp=78TX#|EEN*WQ6MnI4bX&AagT2d4V0qGJX zK779Qp1baez4toj{JQG`003r3FMkBo2j&QPuz%4F<|yn2gE~G}5>|SEPTU;4p#QiB z<94!l_4xl306@U(y#AN}i>@%+|Ft1Pz`Wf4<1ijPBg_?U_pgEg02mMFp9f&j0RW`l z4>>ms=KkO8{}{T5!U6N2_(22p5fWC0yTbn)=?p`7ARcf{7{U(z5Gi1u2#0?{008r! z0QGQ55HLU3KLiUG7xy6$LVbjlLzy2k0D#;M?&{%g=j!*+`7z*8$OA+TL%2czaS!&e z7&ZoGIQGL@`$1qb~Q}u{<-{ z#7;FizH^DjSqjrl&eMqzXEGulKk*S#JBNkz%H}qO+Q15%cYjE}g5B};DDQ+U%`hz6 zx;Esn+R9$@vNy`?11p_%tg;ERfN#dj6w0B!|8 z|7KO@#7AK`dv!oB556Iwo%+t}tt?XyE`7lhpGkc;qL7x3ZFHRz;(;BjjZ7?=(bJtP z*I*h3*IL`%-$8y-PEF2AwFp@qf`U)&4&MTb&kDd?0ZYKOcWA|$a$xTI*4r`W&aFY- zkVgN^?*+d)sO_8%dtN?T?xt=yJl*-Vj$!U$kg_19=zT#J9W1(*P+yWSY14UWP_nmme2I9xi8SivAEiv!&`a-zR<=nhg5kwx{T@x;bW%ULNMGS>2 z^f+lv(X>^ZsBL&k7HxcAVK=xgM)hgQ{0KWe$3hg`%B8~IMx9C-0Xx;c5hPPO*{yzD z0ph22mLu8c!5r@k%BS!Q2!k&irzZ@rInm6yx8P$r_UhCo1(A9pq$JU+6Mkjw^vEq1 zuaLUunhXranOUGpkI7LnE=nSxu+3kwMP4da8^f~6nJ^%c@#zP0F1k)ow*bQPjx8+G z?E8dHc8Tp7kW~L~C$*$?3)B_a@SSwRRD(f=6E+%BJnHjhMFZTC;Z8jt9wU z_155aMGmW}JRdJ}cmC6qF5hC21*&N$7 z{d6brhqZ&g#{(#Gd^VoSRfC*PaM0eJ@GRdRlIs@f6M;aHo{GVe zYmwxq#4K`1FSZ)u-&egRWw*jYDUbP*_Q!M%L_S&?;0iw8&=~YsV@Gbqf7{afcCM*iHw(oa!b{h^|^PF#2IU$eCa34bJLVM5(Z-gl2R z5CR16yk|ZS3JxtxSx-@$R%KY*Qj}G4O}JIxHnp0;qv$7ON?Lo>CVg;5jMr~ji#JXr z=&YFPXsxiq-e$?an3sd5-)?H&nlIXJslxR?XI8M+!;sIZMw*iOTagTOpe+=(f%ey)FcsQ`&3mUV)wM{_>Ppwe&C)POnQL$-r+4wU zq4iAX8kDhTf!451j78RPr9yxuNNF_5WBOyuhdOH&=Cv@II)(|KsBg*FD00+p8X|W& z!DvKJ`+jCFmXfYMp*+ZDai-}IOw?*5i;Fhxn(^H*=uE>h^VvmmKX!)an*gTRV3Q`4g+U`!X;OsilFP;u#QKK%~e;a&_I>W5@QI z?X01((H>ZkkKag1M)C82wsGY%{xf zCBe9?k0|v7B{Mv@CC|u#S>Mvf=C;BJftw>>MsXjZth}iYTkcG)4F)pjzkQ@0Z*m(a z@jY6)S9qFPS!$-XTvd3j7pXIbdRrJRE#8yi+lwfO)b0xifuKU(_9w+9rn~4W{=n83 z|1p(vshn$kIyIG9891;NYdz+o?cz$z8J;SE4<(0;Dy3zztH@UX1@XUi)kN_{V20lL znzyD&l)qxs%D0_Mrx_sBn2iu=$``DzU?v~uVc3gYJhqGd=so1ufcoS}@a(;$;f{GK zywb(24SW~yz2=B>o)QrUIKTHMdFeSGK3%{{&KQw*r12tK;xnWJmHR|AmvaC1Bgi~@ z(R~ys#9m<#Sun~?Lu6_ynvb)q974QnY4j4{{fhhb=HB;jU2Bb^1J+v z)0~8DFPA>IIe5S~ftGDZ;-un&N?m|l?iEIrl&^x$emltGk3+%ips{#Le+4s%?j4dK z%Idm}CguBS;VL!{o;o7EcG2}PtXuGKy>s6yP{RsUFyi>(1a?0T+`nhI!0s=xGcrA= zvcRNgI&M%A^|)!Ori`Aprt^t0nWR{5=~{SrN9vNp_Ce;Fj+@`g9peA+z3m+?j}DVg zU@0Z1LPe>8J*QWxx~XIj6&nJmoJZF&ape1HezvRoof7AVIieDFjzov<;(^m~qE=W; zI#H@tPRjhlMSnK<^xz3L*E#5g%?x5tHPl4y?j~$?&dsH5h&O4*@spFTn}40Vl4r0U z`_$YpW8LP%mxvm9yQJ0-R}O8&r*G_gN*&s1BY|s4EW+^34S#edasp+Z%3?;y@hiHQ zM=zkTbjR6p%Eu=$`RUBEDPQk*lDE57Wh1t36OUD@s2EuS$CE0i{Em+kLEEALd^t)p3`L4a%MR zY`Sd<=)HgQSLd_4ZTD+Uw?2b&qNCcIxV;IORIt~AT}o8q3;ZrhtIvT6&1NFW6k4WD zP*OaZNH{a8HBp4#;iC6G3nNZ|f@mb7@n>86Th#pyvsZFcy!)4J;-o)k!JxwHPNq;w ziy(r?ths%NZKY@p^5fvf;T`Q4%j1&rRpfG4do+T-oGw|2;In)waS4ygB{NsW*Bmw@ zmBwn59BTT|FXjSuES!<`xAFW@zZ>}P@eI(cWAIOB*UTzc@YaRjnCpL;G@Uo+_Ds@w zh%dKnhdKSlxeY)w<}P_(@!Ag)sb`7Q$7FlZUkDtIwuAp6|-QA@b zN6``zzHOd>EP9pIhNOKt1gsbA&bjb;)z+GubKw{y;5&%OLB2kykT zHe9hYjv^H3BSp(k+10^Vq<#UG*lp>4$H>RIB~05rWEdx^BSxXyn*38bT(|%))I~Ib z@8grOalDouhUUe1Bg;Eq8~fN3AFj*eR;pGqD3z6?VS;jqq4o}`oMaNp0ucKO2ld{vVj&EK{buV_HGz-g_lC0Ct zS#LW;mT(bj^>m-CrM`axI|K!d7cqaDjsfJ)FOM%~JFVnxNU{$o-2oWiPvx#UTnk{# z6OHu8cMBxX>0-Ypm{J4&eX`U7SOEAK~lj@83Msk-@X3x7I)7+!ppPC2>R_4iKZRM~Jy zfC5u$WFTctqU_`2N8u*HOx?eq(C>dxlM5$7aZR+@Pv8(1C{fKdfep zgk{^3tnY57B*1d~FIF;-yu`xeZse&zK$VOJ{TfbL@CRvA?2!0;PS|NadAjHusu!wn zS$_w?Vegyorn+WZ9G**=n^}}BCK;3l^}Y5?Ry?$gf8>tJpyN%q2>_9@1Ddrnhn!>= z*Qv^4)g{=Z2!%pH3}R;QGe+aJkEzw?HIz3qD!fR6s+BoX!e-(h{NGdlJtrJxP7qbS zUQ)P>!#pf%w67}>)6g5t$^d($)`=CYT?Up`xR?C({xO&94t66qhUSdvv_8ki0mb^i z^xeC~@Xa-s+0AN+JOd03c^%hhDX#ByDw5iFWsg1@H|)eWd`S?1CVE=J&{50ftbzGFD$|rg(iMUybacckBYdo4?SV&uc8S;09XWMn10TZC(z_Kn;{@Hym0R39Y9&T1ixf0%g`dF~3pO@QIy|2j}Y?m6Eyd(yCF5r}(nvQ|;1Z$OQ z7NfLD=LQpOWDzk4ndlgWB%7L+k>0-fWH z&2v_nNNvmm^ukgFmNI9h@)9X8Sk9=}_x;{VqdtKaP^yf~suQhz<4l_it4wK(V{pk*c?cEO z>k)rUkF&wv!PDbcIL90up&k9$1@~7aQMG|>_q)_q9j&=)#$)cOxMal?8b$9G9f z=jj)FFFAjAneWDh+g2XYd~@d~|MgKK6T&3GUjwenBxn?1rVunR@lR~M=I@$BC_0LJ PSYu(xMSwMxR}}vbaPi{y literal 0 HcmV?d00001 diff --git a/doc/sms-forward.d/notification.svg b/doc/sms-forward.d/notification.svg deleted file mode 100644 index 4b94850..0000000 --- a/doc/sms-forward.d/notification.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] 📨 SMS Forwarding from 7277 - -Received this message by MikroTik from 7277: - -On Jun/12/2021 13:44:10 GMT -0 type class-0: -Welcome to our network! - - diff --git a/doc/sms-forward.md b/doc/sms-forward.md index f75b78f..09dd36a 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -15,7 +15,7 @@ A broadband interface with SMS support is required. ### Sample notification -![sms-forward notification](sms-forward.d/notification.svg) +![sms-forward notification](sms-forward.d/notification.avif) Requirements and installation ----------------------------- From c3da4ed69604bfcc2ec01c8c735a2e9820d1a4af Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Oct 2022 15:28:25 +0200 Subject: [PATCH 1242/2612] netwatch-notify: stop flooding the log after down notification This will now log all messages before notification, and every two hours (or scheduler interval * 120) after. --- netwatch-notify | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 27e0759..76b3f2b 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -143,11 +143,13 @@ $ScriptLock $0; :set Parent ($NetwatchNotify->$Parent->"parent"); } } - $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ - ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is down for " . \ - $Metric->"count-down" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ - ($Metric->"notified" = true) ("already notified.") ($CountDown - $Metric->"count-down" . \ - " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]) false; + :if ($Metric->"notified" = false || $Metric->"count-down" % 120 = 0) do={ + $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ + ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is down for " . \ + $Metric->"count-down" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ + ($Metric->"notified" = true) ("already notified.") ($CountDown - $Metric->"count-down" . \ + " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]) false; + } :if ((($CountDown * 2) - ($Metric->"count-down" * 3)) / 2 = 0 && \ [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ $NetwatchNotifyHook $Name $Type "pre-down" ($HostInfo->"pre-down-hook"); From a0163aa487df214d3f86428c7f93266a88ed3ab8 Mon Sep 17 00:00:00 2001 From: Michael Gisbers Date: Fri, 21 Oct 2022 09:00:42 +0200 Subject: [PATCH 1243/2612] netwatch-notify: always show messages when run from terminal Co-authored-by: Christian Hesse --- netwatch-notify | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index 76b3f2b..e37fc36 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -17,6 +17,7 @@ :global IsDNSResolving; :global LogPrintExit2; :global ParseKeyValueStore; +:global ScriptFromTerminal; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -143,7 +144,8 @@ $ScriptLock $0; :set Parent ($NetwatchNotify->$Parent->"parent"); } } - :if ($Metric->"notified" = false || $Metric->"count-down" % 120 = 0) do={ + :if ($Metric->"notified" = false || $Metric->"count-down" % 120 = 0 || \ + [ $ScriptFromTerminal $0 ] = true) do={ $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is down for " . \ $Metric->"count-down" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ From 6822e715646833efc3a0018ffe0e840dc8371715 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 21 Oct 2022 09:07:50 +0200 Subject: [PATCH 1244/2612] netwatch-notify: cache the result MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If this script runs from terminal this will not change... 😜 So cache the result. Co-authored-by: Michael Gisbers --- netwatch-notify | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index e37fc36..7a0766c 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -52,6 +52,8 @@ $ScriptLock $0; +:local ScriptFromTerminalCached [ $ScriptFromTerminal $0 ]; + :if ([ /system/resource/get uptime ] < 5m) do={ $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; } @@ -145,7 +147,7 @@ $ScriptLock $0; } } :if ($Metric->"notified" = false || $Metric->"count-down" % 120 = 0 || \ - [ $ScriptFromTerminal $0 ] = true) do={ + $ScriptFromTerminalCached = true) do={ $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is down for " . \ $Metric->"count-down" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ From 7594345da81ef0cb9b6842a069a8cb90085fa9f5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 31 Oct 2022 21:45:36 +0100 Subject: [PATCH 1245/2612] README: copy *relevant* configuration only --- README.d/05-edit-global-config-overlay.avif | Bin 5124 -> 5103 bytes README.md | 2 +- global-config-overlay | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.d/05-edit-global-config-overlay.avif b/README.d/05-edit-global-config-overlay.avif index f2f0f2d88aa5534ce9ffed56b2e2b95dd7ce8539..f87fda88e60281d3b0c4a2cb301025832c2bf8de 100644 GIT binary patch delta 4875 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 delta 4897 zcmV++6W;9aCxj@Fe*x-|fR%spZDe6|5&#MbIA!ubHV_cdX)@X+Ok@JxG*?BMc||c` ze^=CaexdDFC}14*OoYu9FflEalN9!Tu=piP1*xu$<(e4Xa@5?_X+1{W2Bb%2>Vrnm zyspk;bomh@+vfwhwV~^V z>`AfFE$vTP?u1zw6OO;1wc%eF0Jbl;`%zAshO@>&V4G23zFlNdiCNjWs_%h!ju?sF zFxT00>ba|yv@BPv?ZmI?V#>_lPI9WEM~G7Gf>7)0IZ`14XFWs#SqO#xepaY?yB z>~~Z8tq0C>al}_a2y}k}v8e3%vaHz9Bn2KrBLH$uGWr|eB%?5jIT*@+=TWQHrUg=^grB7XHsrU`x_O$9-M%2Q$zDsXtOJ^KzQ2 z1-gd5nhoR{h&`PCvIXbJrt@(&f_Dqg)#Gb!v}8Ij_bz|l$4)IC%0DfnX)Y%{i9i)k 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 T+?rdUD0KZurt5w{MFAE@Mf8OM diff --git a/README.md b/README.md index a664c06..36a24ca 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Now let's download the main scripts and add them in configuration on the fly. ![screenshot: import scripts](README.d/04-import-scripts.avif) The configuration needs to be tweaked for your needs. Edit -`global-config-overlay`, copy configuration from +`global-config-overlay`, copy relevant configuration from [`global-config`](global-config) (the one without `-overlay`). Save changes and exit with `Ctrl-o`. diff --git a/global-config-overlay b/global-config-overlay index 70d8570..500a579 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -5,7 +5,7 @@ # global configuration, custom overlay # https://git.eworm.de/cgit/routeros-scripts/about/ -# Copy configuration from global-config, paste and modify it here. +# Copy relevant configuration from global-config, paste and modify it here. # End of global-config-overlay From 9f02f0433422ce8f51e235aa73d6028542cd2e9c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 17 Nov 2022 22:10:52 +0100 Subject: [PATCH 1246/2612] mod/notification-email: fix typo --- mod/notification-email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-email b/mod/notification-email index 0c07beb..bcf0cc6 100644 --- a/mod/notification-email +++ b/mod/notification-email @@ -21,7 +21,7 @@ :local QueueLen [ :len $EmailQueue ]; :if ([ /tool/e-mail/get last-status ] = "in-progress") do={ - $LogPrintExit2 debug $0 ("Sending mail in currently in progress, not flushing.") false; + $LogPrintExit2 debug $0 ("Sending mail is currently in progress, not flushing.") false; :return false; } From 71d1f2a781ad74d2a0d442c4f833dc19ff54ff3d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 17 Nov 2022 22:13:02 +0100 Subject: [PATCH 1247/2612] mod/notification-email: convert to array earlier --- mod/notification-email | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/notification-email b/mod/notification-email index bcf0cc6..023c4db 100644 --- a/mod/notification-email +++ b/mod/notification-email @@ -43,7 +43,7 @@ :foreach Id,Message in=$EmailQueue do={ :if ([ :typeof $Message ] = "array" ) do={ - :local Attach [ $EitherOr ($Message->"attach") "" ]; + :local Attach [ :toarray [ $EitherOr ($Message->"attach") "" ] ]; :while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; } /tool/e-mail/send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \ body=($Message->"body") file=$Attach; @@ -55,7 +55,7 @@ :set ($EmailQueue->$Id); :set Wait false; :if (($Message->"remove-attach") = true) do={ - :foreach File in=[ :toarray $Attach ] do={ + :foreach File in=$Attach do={ /file/remove $File; } } From b517b26517d13299fe020670288e441e4000cf8f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 17 Nov 2022 22:18:16 +0100 Subject: [PATCH 1248/2612] mod/notification-email: check that attachment exists --- mod/notification-email | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mod/notification-email b/mod/notification-email index 023c4db..81ca563 100644 --- a/mod/notification-email +++ b/mod/notification-email @@ -43,8 +43,15 @@ :foreach Id,Message in=$EmailQueue do={ :if ([ :typeof $Message ] = "array" ) do={ - :local Attach [ :toarray [ $EitherOr ($Message->"attach") "" ] ]; + :local Attach ({}); :while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; } + :foreach File in=[ :toarray [ $EitherOr ($Message->"attach") "" ] ] do={ + :if ([ :len [ /file/find where name=$File ] ] = 1) do={ + :set Attach ($Attach, $File); + } else={ + $LogPrintExit2 warning $0 ("File '" . $File . "' does not exist, can not attach.") false; + } + } /tool/e-mail/send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \ body=($Message->"body") file=$Attach; :local Wait true; From 6f79eb996a3ddc2c6b7306841d7f101d059fd65d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 17 Nov 2022 22:34:08 +0100 Subject: [PATCH 1249/2612] mod/notification-email: make sure the scheduler interval is never zero --- mod/notification-email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-email b/mod/notification-email index 81ca563..264a154 100644 --- a/mod/notification-email +++ b/mod/notification-email @@ -39,7 +39,7 @@ $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; } - /system/scheduler/set interval=($QueueLen . "m") [ find where name=$0 ]; + /system/scheduler/set interval=([ $EitherOr $QueueLen 1 ] . "m") [ find where name=$0 ]; :foreach Id,Message in=$EmailQueue do={ :if ([ :typeof $Message ] = "array" ) do={ From 514d241969eae6afd0476d47d0f83cd6cafb3c19 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 17 Nov 2022 23:02:02 +0100 Subject: [PATCH 1250/2612] README: link to Github pull requests --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 36a24ca..a6978ac 100644 --- a/README.md +++ b/README.md @@ -271,7 +271,9 @@ Thanks a lot for [past contributions](CONTRIBUTIONS.md)! â¤ī¸ ### Patches, issues and whishlist Feel free to contact me via e-mail or open an -[issue at github](https://github.com/eworm-de/routeros-scripts/issues). +[issue](https://github.com/eworm-de/routeros-scripts/issues) or +[pull request](https://github.com/eworm-de/routeros-scripts/pulls) +at github. ### Donate From 3c4595e82b0200e3c213e78c673a65ed26f7e18b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Nov 2022 19:01:07 +0100 Subject: [PATCH 1251/2612] global-functions: $MkDir: use shorter random string ... but with all characters from alphabet with $GetRandom20CharAlNum. --- global-functions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index f4c47d7..3814176 100644 --- a/global-functions +++ b/global-functions @@ -506,7 +506,7 @@ :local Dir [ :tostr $1 ]; :global CleanFilePath; - :global GetRandom20CharHex; + :global GetRandom20CharAlNum; :global LogPrintExit2; :global WaitForFile; @@ -521,7 +521,7 @@ } :local Return true; - :local Name ($Dir . "-" . [ $GetRandom20CharHex ]); + :local Name ($Dir . "-" . [ $GetRandom20CharAlNum 6 ]); :do { /ip/smb/share/add disabled=yes directory=$Dir name=$Name; $WaitForFile $Dir; From c2a29da9f2fe48ad1cf028efaa02b4bfdae8504b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Nov 2022 19:01:19 +0100 Subject: [PATCH 1252/2612] global-functions: $ScriptLock: use shorter random string ... but with all characters from alphabet with $GetRandom20CharAlNum. --- global-functions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 3814176..3d04bcb 100644 --- a/global-functions +++ b/global-functions @@ -876,7 +876,7 @@ :local DoReturn $2; :local WaitMax ([ :tonum $3 ] * 10); - :global GetRandom20CharHex; + :global GetRandom20CharAlNum; :global IfThenElse; :global LogPrintExit2; @@ -977,7 +977,7 @@ /system/script/job/remove [ find where script=$Script ]; } - :local MyTicket [ $GetRandom20CharHex ]; + :local MyTicket [ $GetRandom20CharAlNum 6 ]; $AddTicket $Script $MyTicket; :local WaitCount 0; From ab3047ee8210831bd26dfc36df8ed00368c540c0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Nov 2022 21:09:27 +0100 Subject: [PATCH 1253/2612] mod/notification-email: reference scheduler from variable --- mod/notification-email | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mod/notification-email b/mod/notification-email index 264a154..ea2c40b 100644 --- a/mod/notification-email +++ b/mod/notification-email @@ -19,6 +19,7 @@ :local AllDone true; :local QueueLen [ :len $EmailQueue ]; + :local Scheduler [ /system/scheduler/find where name=$0 ]; :if ([ /tool/e-mail/get last-status ] = "in-progress") do={ $LogPrintExit2 debug $0 ("Sending mail is currently in progress, not flushing.") false; @@ -35,11 +36,11 @@ :return false; } - :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ + :if ([ :len $Scheduler ] > 0 && $QueueLen = 0) do={ $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; } - /system/scheduler/set interval=([ $EitherOr $QueueLen 1 ] . "m") [ find where name=$0 ]; + /system/scheduler/set interval=([ $EitherOr $QueueLen 1 ] . "m") $Scheduler; :foreach Id,Message in=$EmailQueue do={ :if ([ :typeof $Message ] = "array" ) do={ @@ -76,10 +77,10 @@ } :if ($AllDone = true && $QueueLen = [ :len $EmailQueue ]) do={ - /system/scheduler/remove [ find where name=$0 ]; + /system/scheduler/remove $Scheduler; :set EmailQueue; } else={ - /system/scheduler/set interval=1m [ find where name=$0 ]; + /system/scheduler/set interval=1m $Scheduler; } } From 03d19270670ae1b4b647ffca37177f92a5db0072 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Nov 2022 21:11:50 +0100 Subject: [PATCH 1254/2612] mod/notification-email: set scheduler interval earlier ... to make sure the checks are not re-run every second. --- mod/notification-email | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mod/notification-email b/mod/notification-email index ea2c40b..3cff322 100644 --- a/mod/notification-email +++ b/mod/notification-email @@ -20,6 +20,10 @@ :local AllDone true; :local QueueLen [ :len $EmailQueue ]; :local Scheduler [ /system/scheduler/find where name=$0 ]; + + :if ([ :len $Scheduler ] > 0 && [ /system/scheduler/get $Scheduler interval ] < 1m) do={ + /system/scheduler/set interval=1m $Scheduler; + } :if ([ /tool/e-mail/get last-status ] = "in-progress") do={ $LogPrintExit2 debug $0 ("Sending mail is currently in progress, not flushing.") false; From 89c0fde4659df9d1b3468a144540c19179a872d9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Nov 2022 21:16:06 +0100 Subject: [PATCH 1255/2612] mod/notification-email: put status in scheduler comment --- mod/notification-email | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mod/notification-email b/mod/notification-email index 3cff322..799c4ef 100644 --- a/mod/notification-email +++ b/mod/notification-email @@ -22,7 +22,7 @@ :local Scheduler [ /system/scheduler/find where name=$0 ]; :if ([ :len $Scheduler ] > 0 && [ /system/scheduler/get $Scheduler interval ] < 1m) do={ - /system/scheduler/set interval=1m $Scheduler; + /system/scheduler/set interval=1m comment="Doing initial checks..." $Scheduler; } :if ([ /tool/e-mail/get last-status ] = "in-progress") do={ @@ -44,7 +44,7 @@ $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; } - /system/scheduler/set interval=([ $EitherOr $QueueLen 1 ] . "m") $Scheduler; + /system/scheduler/set interval=([ $EitherOr $QueueLen 1 ] . "m") comment="Sending..." $Scheduler; :foreach Id,Message in=$EmailQueue do={ :if ([ :typeof $Message ] = "array" ) do={ @@ -84,7 +84,7 @@ /system/scheduler/remove $Scheduler; :set EmailQueue; } else={ - /system/scheduler/set interval=1m $Scheduler; + /system/scheduler/set interval=1m comment="Waiting for retry..." $Scheduler; } } @@ -124,7 +124,7 @@ attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") }; :if ([ :len [ /system/scheduler/find where name="\$FlushEmailQueue" ] ] = 0) do={ /system/scheduler/add name="\$FlushEmailQueue" interval=1s start-time=startup \ - on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); + comment="Queuing new mail..." on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); } } From a7bdebbfb0df6b847690f8df2e66d43729eb9f2b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Nov 2022 21:48:29 +0100 Subject: [PATCH 1256/2612] doc/mod/notification-email: mention correct time --- doc/mod/notification-email.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/mod/notification-email.md b/doc/mod/notification-email.md index 4e0ba04..144c48a 100644 --- a/doc/mod/notification-email.md +++ b/doc/mod/notification-email.md @@ -26,6 +26,8 @@ Configuration Set up your device's [e-mail settings](https://wiki.mikrotik.com/wiki/Manual:Tools/email). +Also make sure the device has correct time configured, best is to set up +the ntp client. Then edit `global-config-overlay`, add `EmailGeneralTo` with a valid recipient address. Finally reload the configuration. From ef7360453ff6b011e236e0adf3948719873c7040 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Nov 2022 21:59:21 +0100 Subject: [PATCH 1257/2612] global-functions: $IsTimeSync: no cloud with CHR free license --- global-functions | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/global-functions b/global-functions index 3d04bcb..52ecbed 100644 --- a/global-functions +++ b/global-functions @@ -445,6 +445,11 @@ :return false; } + :if ([ /system/license/get ]->"level" = "free") do={ + $LogPrintExit2 debug $0 ("No ntp client configured, relying on RTC for CHR free license.") false; + :return true; + } + :if ([ /ip/cloud/get update-time ] = true) do={ :if ([ :typeof [ /ip/cloud/get public-address ] ] = "ip") do={ :set IsTimeSyncCached true; From ad85f22540f3216224efc4fd36d1ffbf54a1486e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Nov 2022 22:02:18 +0100 Subject: [PATCH 1258/2612] global-functions: $IsTimeSync: no cloud on x86 --- global-functions | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 52ecbed..aa20e4e 100644 --- a/global-functions +++ b/global-functions @@ -445,8 +445,9 @@ :return false; } - :if ([ /system/license/get ]->"level" = "free") do={ - $LogPrintExit2 debug $0 ("No ntp client configured, relying on RTC for CHR free license.") false; + :if ([ /system/license/get ]->"level" = "free" || \ + [ /system/resource/get ]->"board-name" = "x86") do={ + $LogPrintExit2 debug $0 ("No ntp client configured, relying on RTC for CHR free license and x86.") false; :return true; } From 0ad94b042de8dac6939f330c2b4270701c5da6d1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 25 Nov 2022 08:39:07 +0100 Subject: [PATCH 1259/2612] netwatch-notify: support type https-get ... which was introduced in RouterOS 7.7beta8. --- netwatch-notify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index 7a0766c..7ee2026 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -64,7 +64,7 @@ $ScriptLock $0; :foreach Host in=[ /tool/netwatch/find where comment~"notify" !disabled ] do={ :local HostVal [ /tool/netwatch/get $Host ]; - :local Type [ $IfThenElse ($HostVal->"type" ~ "^(http-get|tcp-conn)\$") "service" "host" ]; + :local Type [ $IfThenElse ($HostVal->"type" ~ "^(https?-get|tcp-conn)\$") "service" "host" ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; :local HostDetails ($HostVal->"host" . \ [ $IfThenElse ([ :len ($HostInfo->"resolve") ] > 0) (", " . $HostInfo->"resolve") ]); From 8854d03ea216dbbce38c804d4296feabfb26a978 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 29 Nov 2022 17:06:04 +0100 Subject: [PATCH 1260/2612] global-functions: introduce $IsMacLocallyAdministered... ... and use it in $GetMacVendor. --- global-functions | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index aa20e4e..75e9796 100644 --- a/global-functions +++ b/global-functions @@ -35,6 +35,7 @@ :global IsDefaultRouteReachable; :global IsDNSResolving; :global IsFullyConnected; +:global IsMacLocallyAdministered; :global IsTimeSync; :global LogPrintExit2; :global MkDir; @@ -320,9 +321,10 @@ :local Mac [ :tostr $1 ]; :global CertificateAvailable; + :global IsMacLocallyAdministered; :global LogPrintExit2; - :if ([ :tonum ("0x" . [ :pick $Mac 0 [ :find $Mac ":" ] ]) ] & 2 = 2) do={ + :if ([ $IsMacLocallyAdministered $Mac ] = true) do={ :return "locally administered"; } @@ -427,6 +429,14 @@ :return true; } +# check if mac address is locally administered +:set IsMacLocallyAdministered do={ + :if ([ :tonum ("0x" . [ :pick $1 0 [ :find $1 ":" ] ]) ] & 2 = 2) do={ + :return true; + } + :return false; +} + # check if system time is sync :set IsTimeSync do={ :global IsTimeSyncCached; From 7f7c3a7a700f97f291d1749c10b155ab8384052e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 6 Dec 2022 16:41:14 +0100 Subject: [PATCH 1261/2612] global-functions: $SymbolByUnicodeName: append variation selector-16... ... to specify that the preceding character should be displayed with emoji presentation. https://unicode-table.com/en/FE0F/ --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 75e9796..260a7d4 100644 --- a/global-functions +++ b/global-functions @@ -1060,7 +1060,7 @@ "white-heavy-check-mark"="\E2\9C\85" } - :return ($Symbols->$1); + :return (($Symbols->$1) . "\EF\B8\8F"); } # return symbol for notification From 9c42263988e6c1615d348832a92c091c3414aa08 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 12 Dec 2022 15:16:36 +0100 Subject: [PATCH 1262/2612] global-functions: check RouterOS version before loading modules --- global-functions | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 260a7d4..75a7dda 100644 --- a/global-functions +++ b/global-functions @@ -1203,6 +1203,9 @@ } } +# check for required RouterOS version +$RequiredRouterOS $0 "7.1" true; + # load modules :foreach Script in=[ /system/script/find where name ~ "^mod/." ] do={ :local ScriptVal [ /system/script/get $Script ]; @@ -1217,8 +1220,5 @@ } } -# check for required RouterOS version -$RequiredRouterOS $0 "7.1" true; - # signal we are ready :set GlobalFunctionsReady true; From 446d5c89fcc4f1fba7f8339e0ead23ba5720be5e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Dec 2022 10:31:41 +0100 Subject: [PATCH 1263/2612] global-functions: $MkDir: fail if non-directory path exists --- global-functions | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/global-functions b/global-functions index 75a7dda..71d711b 100644 --- a/global-functions +++ b/global-functions @@ -536,6 +536,11 @@ :return true; } + :if ([ :len [ /file/find where name=$Dir ] ] = 1) do={ + $LogPrintExit2 warning $0 ("The path '" . $Dir . "' exists, but is not a directory.") false; + :return false; + } + :local Return true; :local Name ($Dir . "-" . [ $GetRandom20CharAlNum 6 ]); :do { From 58f769ac0016025533248aba5cd63436b00fc3db Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Dec 2022 10:37:56 +0100 Subject: [PATCH 1264/2612] global-functions: $MkDir: rename internal variable --- global-functions | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/global-functions b/global-functions index 71d711b..f0048dd 100644 --- a/global-functions +++ b/global-functions @@ -519,35 +519,35 @@ # create directory :set MkDir do={ - :local Dir [ :tostr $1 ]; + :local Path [ :tostr $1 ]; :global CleanFilePath; :global GetRandom20CharAlNum; :global LogPrintExit2; :global WaitForFile; - :set Dir [ $CleanFilePath $Dir ]; + :set Path [ $CleanFilePath $Path ]; - :if ($Dir = "") do={ + :if ($Path = "") do={ :return true; } - :if ([ :len [ /file/find where name=$Dir type="directory" ] ] = 1) do={ + :if ([ :len [ /file/find where name=$Path type="directory" ] ] = 1) do={ :return true; } - :if ([ :len [ /file/find where name=$Dir ] ] = 1) do={ - $LogPrintExit2 warning $0 ("The path '" . $Dir . "' exists, but is not a directory.") false; + :if ([ :len [ /file/find where name=$Path ] ] = 1) do={ + $LogPrintExit2 warning $0 ("The path '" . $Path . "' exists, but is not a directory.") false; :return false; } :local Return true; - :local Name ($Dir . "-" . [ $GetRandom20CharAlNum 6 ]); + :local Name ($Path . "-" . [ $GetRandom20CharAlNum 6 ]); :do { - /ip/smb/share/add disabled=yes directory=$Dir name=$Name; - $WaitForFile $Dir; + /ip/smb/share/add disabled=yes directory=$Path name=$Name; + $WaitForFile $Path; } on-error={ - $LogPrintExit2 warning $0 ("Making directory '" . $Dir . "' failed!") false; + $LogPrintExit2 warning $0 ("Making directory '" . $Path . "' failed!") false; :set Return false; } /ip/smb/share/remove [ find where name=$Name ]; From 1579330864c98f4526cf5e0f0ea7204ad25f87a3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Dec 2022 15:30:24 +0100 Subject: [PATCH 1265/2612] global-functions: $MkDir: create directories recursively --- global-functions | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/global-functions b/global-functions index f0048dd..9ff6bd5 100644 --- a/global-functions +++ b/global-functions @@ -521,6 +521,7 @@ :set MkDir do={ :local Path [ :tostr $1 ]; + :global CharacterReplace; :global CleanFilePath; :global GetRandom20CharAlNum; :global LogPrintExit2; @@ -536,22 +537,37 @@ :return true; } - :if ([ :len [ /file/find where name=$Path ] ] = 1) do={ - $LogPrintExit2 warning $0 ("The path '" . $Path . "' exists, but is not a directory.") false; - :return false; - } + :local Error false; + :local PathNext ""; + :foreach Dir in=[ :toarray [ $CharacterReplace $Path "/" "," ] ] do={ + :local Continue false; + :set PathNext [ $CleanFilePath ($PathNext . "/" . $Dir) ]; - :local Return true; - :local Name ($Path . "-" . [ $GetRandom20CharAlNum 6 ]); - :do { - /ip/smb/share/add disabled=yes directory=$Path name=$Name; - $WaitForFile $Path; - } on-error={ - $LogPrintExit2 warning $0 ("Making directory '" . $Path . "' failed!") false; - :set Return false; + :if ([ :len [ /file/find where name=$PathNext type="directory" ] ] = 1) do={ + :set Continue true; + } + + :if ($Continue = false && [ :len [ /file/find where name=$PathNext ] ] = 1) do={ + $LogPrintExit2 warning $0 ("The path '" . $PathNext . "' exists, but is not a directory.") false; + :return false; + } + + :if ($Continue = false) do={ + :local Name ($PathNext . "-" . [ $GetRandom20CharAlNum 6 ]); + :do { + /ip/smb/share/add disabled=yes directory=$PathNext name=$Name; + $WaitForFile $PathNext; + } on-error={ + $LogPrintExit2 warning $0 ("Making directory '" . $PathNext . "' failed!") false; + :set Error true; + } + /ip/smb/share/remove [ find where name=$Name ]; + :if ($Error = true) do={ + :return false; + } + } } - /ip/smb/share/remove [ find where name=$Name ]; - :return $Return; + :return true; } # prepare NotificationFunctions array From 16bfe4de7ebc651854fd66939a84c6af8ee81af2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Dec 2022 15:42:45 +0100 Subject: [PATCH 1266/2612] global-functions: $MkDir: create a tmpfs (RAM disk)... ... if the path starts with "tmpfs/". This helps to mitigate flash wear. --- global-functions | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/global-functions b/global-functions index 9ff6bd5..a9c1c93 100644 --- a/global-functions +++ b/global-functions @@ -525,6 +525,7 @@ :global CleanFilePath; :global GetRandom20CharAlNum; :global LogPrintExit2; + :global RequiredRouterOS; :global WaitForFile; :set Path [ $CleanFilePath $Path ]; @@ -547,6 +548,15 @@ :set Continue true; } + :if ($Continue = false && $PathNext = "tmpfs" && [ $RequiredRouterOS $0 "7.7rc1" false ] = true) do={ + :if ([ :len [ /disk/find where slot=tmpfs type=tmpfs ] ] = 0) do={ + $LogPrintExit2 info $0 ("Creating disk of type tmpfs.") false; + /file/remove [ find where name="tmpfs" type="directory" ]; + [ :parse "/disk/add slot=tmpfs type=tmpfs;" ]; + } + :set Continue true; + } + :if ($Continue = false && [ :len [ /file/find where name=$PathNext ] ] = 1) do={ $LogPrintExit2 warning $0 ("The path '" . $PathNext . "' exists, but is not a directory.") false; :return false; From 8b2571dc4943c290fc6af0da75e5228c2b61d46c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 12 Dec 2022 15:24:42 +0100 Subject: [PATCH 1267/2612] backup-email: create directory later --- backup-email | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backup-email b/backup-email index 34e15e1..70db237 100644 --- a/backup-email +++ b/backup-email @@ -45,10 +45,6 @@ $WaitFullyConnected; $RandomDelay $BackupRandomDelay; } -:if ([ $MkDir $0 ] = false) do={ - $LogPrintExit2 error $0 ("Failed creating directory!") true; -} - # filename based on identity :local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; :local FilePath ($0 . "/" . $FileName); @@ -56,6 +52,10 @@ $WaitFullyConnected; :local ConfigFile "none"; :local Attach ({}); +:if ([ $MkDir $0 ] = 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; From f8258b90a7ea23b81c8e05cae4cfdaa325996e6d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 12 Dec 2022 15:25:35 +0100 Subject: [PATCH 1268/2612] backup-upload: create directory later --- backup-upload | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backup-upload b/backup-upload index 8ed4149..110ef25 100644 --- a/backup-upload +++ b/backup-upload @@ -45,10 +45,6 @@ $WaitFullyConnected; $RandomDelay $BackupRandomDelay; } -:if ([ $MkDir $0 ] = false) do={ - $LogPrintExit2 error $0 ("Failed creating directory!") true; -} - # filename based on identity :local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; :local FilePath ($0 . "/" . $FileName); @@ -56,6 +52,10 @@ $WaitFullyConnected; :local ConfigFile "none"; :local Failed 0; +:if ([ $MkDir $0 ] = 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; From d3351bcf1839757ac677924c6c161c914db467ad Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 12 Dec 2022 15:27:00 +0100 Subject: [PATCH 1269/2612] backup-email: switch path to tmpfs --- backup-email | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backup-email b/backup-email index 70db237..339c5a4 100644 --- a/backup-email +++ b/backup-email @@ -46,13 +46,14 @@ $WaitFullyConnected; } # filename based on identity +:local DirName ("tmpfs/" . $0); :local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; -:local FilePath ($0 . "/" . $FileName); +:local FilePath ($DirName . "/" . $FileName); :local BackupFile "none"; :local ConfigFile "none"; :local Attach ({}); -:if ([ $MkDir $0 ] = false) do={ +:if ([ $MkDir $DirName ] = false) do={ $LogPrintExit2 error $0 ("Failed creating directory!") true; } From a3e2822a0a6fd16678159c066fd0f1c8fb69303d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 12 Dec 2022 15:32:54 +0100 Subject: [PATCH 1270/2612] backup-upload: switch path to tmpfs --- backup-upload | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backup-upload b/backup-upload index 110ef25..338db3f 100644 --- a/backup-upload +++ b/backup-upload @@ -46,13 +46,14 @@ $WaitFullyConnected; } # filename based on identity +:local DirName ("tmpfs/" . $0); :local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; -:local FilePath ($0 . "/" . $FileName); +:local FilePath ($DirName . "/" . $FileName); :local BackupFile "none"; :local ConfigFile "none"; :local Failed 0; -:if ([ $MkDir $0 ] = false) do={ +:if ([ $MkDir $DirName ] = false) do={ $LogPrintExit2 error $0 ("Failed creating directory!") true; } From 9983a69188992f341fffaca15f5c434b15d23a80 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 19 Dec 2022 09:49:45 +0100 Subject: [PATCH 1271/2612] README: RouterOS v7 path syntax Missed one in b6ddc5968e7a3393bb6e9b0c0ccf96379efc62b4... --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a6978ac..3908184 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ The configuration needs to be tweaked for your needs. Edit [`global-config`](global-config) (the one without `-overlay`). Save changes and exit with `Ctrl-o`. - /system/script edit global-config-overlay source; + /system/script/edit global-config-overlay source; ![screenshot: edit global-config-overlay](README.d/05-edit-global-config-overlay.avif) From 2f774f723d6e1a29ab1eac46a4362e42c4ef8ac5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jan 2023 23:33:49 +0100 Subject: [PATCH 1272/2612] update copyright for 2023 --- accesslist-duplicates.capsman | 2 +- accesslist-duplicates.local | 2 +- accesslist-duplicates.template | 2 +- backup-cloud | 2 +- backup-email | 2 +- backup-partition | 2 +- backup-upload | 2 +- capsman-download-packages | 2 +- capsman-rolling-upgrade | 2 +- certificate-renew-issued | 2 +- check-certificates | 2 +- check-health | 2 +- check-lte-firmware-upgrade | 2 +- check-routeros-update | 2 +- collect-wireless-mac.capsman | 2 +- collect-wireless-mac.local | 2 +- collect-wireless-mac.template | 2 +- daily-psk.capsman | 2 +- daily-psk.local | 2 +- daily-psk.template | 2 +- dhcp-lease-comment.capsman | 2 +- dhcp-lease-comment.local | 2 +- dhcp-lease-comment.template | 2 +- dhcp-to-dns | 2 +- firmware-upgrade-reboot | 2 +- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 2 +- global-functions | 2 +- global-wait | 2 +- gps-track | 2 +- hotspot-to-wpa | 2 +- hotspot-to-wpa-cleanup | 2 +- ip-addr-bridge | 2 +- ipsec-to-dns | 2 +- ipv6-update | 2 +- lease-script | 2 +- leds-day-mode | 2 +- leds-night-mode | 2 +- leds-toggle-mode | 2 +- log-forward | 2 +- mod/bridge-port-to | 2 +- mod/bridge-port-vlan | 2 +- mod/inspectvar | 2 +- mod/ipcalc | 2 +- mod/notification-email | 2 +- mod/notification-matrix | 2 +- mod/notification-telegram | 2 +- mod/scriptrunonce | 2 +- mode-button | 2 +- netwatch-dns | 2 +- netwatch-notify | 2 +- ospf-to-leds | 2 +- packages-update | 2 +- ppp-on-up | 2 +- sms-action | 2 +- sms-forward | 2 +- ssh-keys-import | 2 +- super-mario-theme | 2 +- unattended-lte-firmware-upgrade | 2 +- update-gre-address | 2 +- update-tunnelbroker | 2 +- 62 files changed, 62 insertions(+), 62 deletions(-) diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman index 848ca52..8831cc6 100644 --- a/accesslist-duplicates.capsman +++ b/accesslist-duplicates.capsman @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.capsman -# Copyright (c) 2018-2022 Christian Hesse +# Copyright (c) 2018-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # print duplicate antries in wireless access list diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local index 67f16f3..d4b8867 100644 --- a/accesslist-duplicates.local +++ b/accesslist-duplicates.local @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.local -# Copyright (c) 2018-2022 Christian Hesse +# Copyright (c) 2018-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # print duplicate antries in wireless access list diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template index 8676551..80c47a9 100644 --- a/accesslist-duplicates.template +++ b/accesslist-duplicates.template @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates%TEMPL% -# Copyright (c) 2018-2022 Christian Hesse +# Copyright (c) 2018-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # print duplicate antries in wireless access list diff --git a/backup-cloud b/backup-cloud index 38aed1f..3e55970 100644 --- a/backup-cloud +++ b/backup-cloud @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: backup-cloud -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script diff --git a/backup-email b/backup-email index 339c5a4..036c520 100644 --- a/backup-email +++ b/backup-email @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: backup-email -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script diff --git a/backup-partition b/backup-partition index a8aecac..824cb7e 100644 --- a/backup-partition +++ b/backup-partition @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: backup-partition -# Copyright (c) 2022 Christian Hesse +# Copyright (c) 2022-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script diff --git a/backup-upload b/backup-upload index 338db3f..a057f42 100644 --- a/backup-upload +++ b/backup-upload @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: backup-upload -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script diff --git a/capsman-download-packages b/capsman-download-packages index b745f14..08edd59 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-download-packages -# Copyright (c) 2018-2022 Christian Hesse +# Copyright (c) 2018-2023 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index e6b1c51..1f4a51c 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-rolling-upgrade -# Copyright (c) 2018-2022 Christian Hesse +# Copyright (c) 2018-2023 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/certificate-renew-issued b/certificate-renew-issued index 29aaa93..c297b15 100644 --- a/certificate-renew-issued +++ b/certificate-renew-issued @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: certificate-renew-issued -# Copyright (c) 2019-2022 Christian Hesse +# Copyright (c) 2019-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # renew locally issued certificates diff --git a/check-certificates b/check-certificates index 99da7d5..9802cde 100644 --- a/check-certificates +++ b/check-certificates @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-certificates -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for certificate validity diff --git a/check-health b/check-health index 5da7d2a..e754d69 100644 --- a/check-health +++ b/check-health @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-health -# Copyright (c) 2019-2022 Christian Hesse +# Copyright (c) 2019-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for RouterOS health state diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 62943ee..02e864b 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-lte-firmware-upgrade -# Copyright (c) 2018-2022 Christian Hesse +# Copyright (c) 2018-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for LTE firmware upgrade, send notification diff --git a/check-routeros-update b/check-routeros-update index 9e1de8e..ccc0d79 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-routeros-update -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for RouterOS update, send notification and/or install diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 9e502e3..e814fa9 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.capsman -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # collect wireless mac adresses in access list diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index a6dbd24..ee07f54 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.local -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # collect wireless mac adresses in access list diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index 42a3d0a..c315385 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac%TEMPL% -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # collect wireless mac adresses in access list diff --git a/daily-psk.capsman b/daily-psk.capsman index 6e89ff2..46e4e1d 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk.capsman -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/daily-psk.local b/daily-psk.local index 3876430..2af2414 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk.local -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/daily-psk.template b/daily-psk.template index af05cd7..373cc96 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk%TEMPL% -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index fa34539..55b76bf 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.capsman -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index 71e6d5e..3f4d6c5 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.local -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index a31812b..9de5f97 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment%TEMPL% -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-to-dns b/dhcp-to-dns index 368d68f..48f96b2 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-to-dns -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=20 diff --git a/firmware-upgrade-reboot b/firmware-upgrade-reboot index 7f27bea..cc45c38 100644 --- a/firmware-upgrade-reboot +++ b/firmware-upgrade-reboot @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: firmware-upgrade-reboot -# Copyright (c) 2022 Christian Hesse +# Copyright (c) 2022-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # install firmware upgrade, and reboot diff --git a/global-config b/global-config index 6ed2a45..d4ed298 100644 --- a/global-config +++ b/global-config @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-config -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global configuration diff --git a/global-config-overlay b/global-config-overlay index 500a579..a95f9cc 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -1,5 +1,5 @@ # Overlay for global configuration by RouterOS Scripts -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global configuration, custom overlay diff --git a/global-config.changes b/global-config.changes index 4bd302f..216cfc6 100644 --- a/global-config.changes +++ b/global-config.changes @@ -1,5 +1,5 @@ # News, changes and migration by RouterOS Scripts -# Copyright (c) 2019-2022 Christian Hesse +# Copyright (c) 2019-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global IfThenElse; diff --git a/global-functions b/global-functions index a9c1c93..d25d21d 100644 --- a/global-functions +++ b/global-functions @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-functions -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/global-wait b/global-wait index 43cc5cc..fe1928b 100644 --- a/global-wait +++ b/global-wait @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-wait -# Copyright (c) 2020-2022 Christian Hesse +# Copyright (c) 2020-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # wait for global-functions to finish diff --git a/gps-track b/gps-track index 56a26c5..d0d1232 100644 --- a/gps-track +++ b/gps-track @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: gps-track -# Copyright (c) 2018-2022 Christian Hesse +# Copyright (c) 2018-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # track gps data by sending json data to http server diff --git a/hotspot-to-wpa b/hotspot-to-wpa index add2893..dbce9ff 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa -# Copyright (c) 2019-2022 Christian Hesse +# Copyright (c) 2019-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # add private WPA passphrase after hotspot login diff --git a/hotspot-to-wpa-cleanup b/hotspot-to-wpa-cleanup index 26610ae..15f63f9 100644 --- a/hotspot-to-wpa-cleanup +++ b/hotspot-to-wpa-cleanup @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa-cleanup -# Copyright (c) 2021-2022 Christian Hesse +# Copyright (c) 2021-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 diff --git a/ip-addr-bridge b/ip-addr-bridge index 218eb2e..99fcba5 100644 --- a/ip-addr-bridge +++ b/ip-addr-bridge @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ip-addr-bridge -# Copyright (c) 2018-2022 Christian Hesse +# Copyright (c) 2018-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # enable or disable ip addresses based on bridge port state diff --git a/ipsec-to-dns b/ipsec-to-dns index 705b5e7..04ad4b8 100644 --- a/ipsec-to-dns +++ b/ipsec-to-dns @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ipsec-to-dns -# Copyright (c) 2021-2022 Christian Hesse +# Copyright (c) 2021-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # and add/remove/update DNS entries from IPSec mode-config diff --git a/ipv6-update b/ipv6-update index b81a0ec..fc42791 100644 --- a/ipv6-update +++ b/ipv6-update @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ipv6-update -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update firewall and dns settings on IPv6 prefix change diff --git a/lease-script b/lease-script index cc1b6e5..2ad8e66 100644 --- a/lease-script +++ b/lease-script @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: lease-script -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run scripts on DHCP lease diff --git a/leds-day-mode b/leds-day-mode index 78e1fae..ca2e8d8 100644 --- a/leds-day-mode +++ b/leds-day-mode @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-day-mode -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # enable LEDs diff --git a/leds-night-mode b/leds-night-mode index 112f9a1..cdd8127 100644 --- a/leds-night-mode +++ b/leds-night-mode @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-night-mode -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # disable LEDs diff --git a/leds-toggle-mode b/leds-toggle-mode index 225ceb2..da972b7 100644 --- a/leds-toggle-mode +++ b/leds-toggle-mode @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-toggle-mode -# Copyright (c) 2018-2022 Christian Hesse +# Copyright (c) 2018-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # toggle LEDs mode diff --git a/log-forward b/log-forward index 6ccad4f..df69008 100644 --- a/log-forward +++ b/log-forward @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: log-forward -# Copyright (c) 2020-2022 Christian Hesse +# Copyright (c) 2020-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # forward log messages via notification diff --git a/mod/bridge-port-to b/mod/bridge-port-to index 3f62e6f..f752d30 100644 --- a/mod/bridge-port-to +++ b/mod/bridge-port-to @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/bridge-port-to -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # reset bridge ports to default bridge diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan index 9a6e08a..8fb64e1 100644 --- a/mod/bridge-port-vlan +++ b/mod/bridge-port-vlan @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/bridge-port-vlan -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # manage VLANs on bridge ports diff --git a/mod/inspectvar b/mod/inspectvar index 2629b6e..8bb5c5f 100644 --- a/mod/inspectvar +++ b/mod/inspectvar @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/inspectvar -# Copyright (c) 2020-2022 Christian Hesse +# Copyright (c) 2020-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global InspectVar; diff --git a/mod/ipcalc b/mod/ipcalc index 14bb1ea..92e246f 100644 --- a/mod/ipcalc +++ b/mod/ipcalc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/ipcalc -# Copyright (c) 2020-2022 Christian Hesse +# Copyright (c) 2020-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global IPCalc; diff --git a/mod/notification-email b/mod/notification-email index 799c4ef..ea7d26a 100644 --- a/mod/notification-email +++ b/mod/notification-email @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/notification-email -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global FlushEmailQueue; diff --git a/mod/notification-matrix b/mod/notification-matrix index 5a5f8cf..c43514d 100644 --- a/mod/notification-matrix +++ b/mod/notification-matrix @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/notification-matrix -# Copyright (c) 2013-2022 Michael Gisbers +# Copyright (c) 2013-2023 Michael Gisbers # Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md diff --git a/mod/notification-telegram b/mod/notification-telegram index 471dc10..de8cdd8 100644 --- a/mod/notification-telegram +++ b/mod/notification-telegram @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/notification-telegram -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global FlushTelegramQueue; diff --git a/mod/scriptrunonce b/mod/scriptrunonce index 6cca175..7b87b4c 100644 --- a/mod/scriptrunonce +++ b/mod/scriptrunonce @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/scriptrunonece -# Copyright (c) 2020-2022 Christian Hesse +# Copyright (c) 2020-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global ScriptRunOnce; diff --git a/mode-button b/mode-button index e4d33cc..52ab00e 100644 --- a/mode-button +++ b/mode-button @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mode-button -# Copyright (c) 2018-2022 Christian Hesse +# Copyright (c) 2018-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # act on multiple mode and reset button presses diff --git a/netwatch-dns b/netwatch-dns index f828de0..4eb3285 100644 --- a/netwatch-dns +++ b/netwatch-dns @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: netwatch-dns -# Copyright (c) 2022 Christian Hesse +# Copyright (c) 2022-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # monitor and manage dns/doh with netwatch diff --git a/netwatch-notify b/netwatch-notify index 7ee2026..1d52b27 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: netwatch-notify -# Copyright (c) 2020-2022 Christian Hesse +# Copyright (c) 2020-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # monitor netwatch and send notifications diff --git a/ospf-to-leds b/ospf-to-leds index c4acb30..12ec820 100644 --- a/ospf-to-leds +++ b/ospf-to-leds @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ospf-to-leds -# Copyright (c) 2020-2022 Christian Hesse +# Copyright (c) 2020-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # visualize ospf instance state via leds diff --git a/packages-update b/packages-update index 2922759..9fa3b54 100644 --- a/packages-update +++ b/packages-update @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: packages-update -# Copyright (c) 2019-2022 Christian Hesse +# Copyright (c) 2019-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # download packages and reboot for installation diff --git a/ppp-on-up b/ppp-on-up index 0529352..ac01c97 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ppp-on-up -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run scripts on ppp up diff --git a/sms-action b/sms-action index a1fa4e9..f5de11f 100644 --- a/sms-action +++ b/sms-action @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: sms-action -# Copyright (c) 2018-2022 Christian Hesse +# Copyright (c) 2018-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run action on received SMS diff --git a/sms-forward b/sms-forward index aa2e71c..8dce464 100644 --- a/sms-forward +++ b/sms-forward @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: sms-forward -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # forward SMS to e-mail diff --git a/ssh-keys-import b/ssh-keys-import index 70ddf3d..b40a997 100644 --- a/ssh-keys-import +++ b/ssh-keys-import @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ssh-keys-import -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # import ssh keys from file diff --git a/super-mario-theme b/super-mario-theme index ae52fd1..7787a12 100644 --- a/super-mario-theme +++ b/super-mario-theme @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: super-mario-theme -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # play Super Mario theme diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index fafda62..eac65c3 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: unattended-lte-firmware-upgrade -# Copyright (c) 2018-2022 Christian Hesse +# Copyright (c) 2018-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # schedule unattended lte firmware upgrade diff --git a/update-gre-address b/update-gre-address index a94616a..2958055 100644 --- a/update-gre-address +++ b/update-gre-address @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: update-gre-address -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update gre interface remote address with dynamic address from diff --git a/update-tunnelbroker b/update-tunnelbroker index b936dcf..84d7430 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: update-tunnelbroker -# Copyright (c) 2013-2022 Christian Hesse +# Copyright (c) 2013-2023 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # From 4f931db1c39f1ef8a04aa4aab51a66a9ad4076cd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jan 2023 23:37:22 +0100 Subject: [PATCH 1273/2612] backup-cloud: keep floppy emoji for failure --- backup-cloud | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backup-cloud b/backup-cloud index 3e55970..b75d5cb 100644 --- a/backup-cloud +++ b/backup-cloud @@ -52,7 +52,7 @@ $WaitFullyConnected; "Download key: " . $Cloud->"secret-download-key"); silent=true }); } on-error={ $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "warning-sign" ] . "Cloud backup failed"); \ + subject=([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Cloud backup failed"); \ message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); $LogPrintExit2 error $0 ("Failed uploading backup for " . $Identity . " to cloud!") true; } From d1caf2bf106f701ebd9e7dd7eed2f2400450854a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jan 2023 23:37:57 +0100 Subject: [PATCH 1274/2612] backup-upload: keep floppy emoji for failure --- backup-upload | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backup-upload b/backup-upload index a057f42..ee7b867 100644 --- a/backup-upload +++ b/backup-upload @@ -95,7 +95,7 @@ $WaitFullyConnected; $SendNotification2 ({ origin=$0; \ subject=[ $IfThenElse ($Failed > 0) \ - ([ $SymbolForNotification "warning-sign" ] . "Backup & Config upload with failure") \ + ([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Backup & Config upload with failure") \ ([ $SymbolForNotification "floppy-disk,up-arrow" ] . "Backup & Config upload") ]; \ message=("Backup and config export upload for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ From b730264d80d880557cb64d3108ddafde2dd93fe4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 Dec 2022 23:22:17 +0100 Subject: [PATCH 1275/2612] .gitignore: add comments --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index f29d4e8..21c053c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ +# backup and temporary files *~ + +# patches *.patch + +# html files (as generated from markdown) *.html From 84be9123efdb58464b779fc5d0e963769c12a900 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 Dec 2022 23:23:24 +0100 Subject: [PATCH 1276/2612] .gitignore: ignore files created by patch command --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 21c053c..670fa4b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ # backup and temporary files *~ -# patches +# patches and related files +*.orig *.patch +*.rej # html files (as generated from markdown) *.html From 03ca9464df390ba1ce068f9405b59447fe24d6cb Mon Sep 17 00:00:00 2001 From: Anatoly Bubenkov Date: Fri, 30 Dec 2022 23:25:57 +0100 Subject: [PATCH 1277/2612] .gitignore: ignore folder settings file --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 670fa4b..cf89f87 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ # html files (as generated from markdown) *.html + +# Mac OS X folder settings file +.DS_Store From 88b34cfb39775560654d60d91da33681b9899251 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Jan 2023 15:35:57 +0100 Subject: [PATCH 1278/2612] doc/sms-forward: reorder configuration --- doc/sms-forward.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 09dd36a..3d9974d 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -31,13 +31,14 @@ Just install the script: Configuration ------------- +You have to enable receiving of SMS: + + /tool/sms/set receive-enabled=yes; + Notification settings are required for [e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). -Also you have to enable receiving of SMS: - - /tool/sms/set receive-enabled=yes; See also -------- From ea09a18d3f05b20ff7f1ec25aea74f32d68ca5e0 Mon Sep 17 00:00:00 2001 From: Anatoly Bubenkov Date: Thu, 3 Nov 2022 23:43:08 +0100 Subject: [PATCH 1279/2612] sms-forward: support hooks --- doc/sms-forward.md | 28 ++++++++++++++++++++++++++++ global-config | 8 ++++++++ global-config.changes | 1 + global-functions | 2 +- sms-forward | 22 ++++++++++++++++++++++ 5 files changed, 60 insertions(+), 1 deletion(-) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 3d9974d..73248eb 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -35,11 +35,39 @@ You have to enable receiving of SMS: /tool/sms/set receive-enabled=yes; +The configuration goes to `global-config-overlay`, this is the only parameter: + +* `SmsForwardHooks`: an array with pre-defined hooks, where each hook consists + of `match` (which is matched against the received message), `allowed-number` + (which is matched against the sending phone number or name) and `command`. + For `match` and `allowed-number` regular expressions are supported. + Notification settings are required for [e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). +Tips & Tricks +------------- + +### Order new volume + +Most broadband providers include a volume limit for their data plans. The +hook functionality can be used to order new volume automatically. + +Let's assume an imaginary provider **ABC** sends a message when the available +volume is about to deplete. The message is sent from `ABC` and the text +contains the string `80%`. New volume can be ordered by sending a SMS back to +the phone number `1234` with the text `data-plan`. + + :global SmsForwardHooks { + { match="80%"; + allowed-number="ABC"; + command="/tool/sms/send lte1 phone-number=1234 message=\"data-plan\";" }; + }; + +Adjust the values to your own needs. + See also -------- diff --git a/global-config b/global-config index d4ed298..fded46f 100644 --- a/global-config +++ b/global-config @@ -147,6 +147,14 @@ # add more here... }; +# Run commands by hooking into SMS forward. +:global SmsForwardHooks { + { match="magic string"; + allowed-number="12345678"; + command="/system/script/run ..." }; +# add more here... +}; + # This is the address used to send gps data to. :global GpsTrackUrl "https://example.com/index.php"; diff --git a/global-config.changes b/global-config.changes index 216cfc6..357dede 100644 --- a/global-config.changes +++ b/global-config.changes @@ -94,6 +94,7 @@ 83="Introduced new setting to disable news and change notifications, dropped version from configuration."; 84="Support for e-mail notifications moved to a module. It is installed automatically if required."; 85="Dropped 'netwatch-syslog', filtering in firewall is advised."; + 86="Added support for hooks in 'sms-forward'. This now provides similar functionality to 'sms-action', but is more flexible."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index d25d21d..0c584b7 100644 --- a/global-functions +++ b/global-functions @@ -10,7 +10,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 85; +:global ExpectedConfigVersion 86; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/sms-forward b/sms-forward index 8dce464..802da48 100644 --- a/sms-forward +++ b/sms-forward @@ -1,6 +1,7 @@ #!rsc by RouterOS # RouterOS script: sms-forward # Copyright (c) 2013-2023 Christian Hesse +# Anatoly Bubenkov # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # forward SMS to e-mail @@ -11,12 +12,14 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global Identity; +:global SmsForwardHooks; :global IfThenElse; :global LogPrintExit2; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; +:global ValidateSyntax; :global WaitFullyConnected; $ScriptLock $0; @@ -45,6 +48,25 @@ $WaitFullyConnected; } else={ :set Messages ($Messages . "\n\nOn " . $SmsVal->"timestamp" . \ " type " . $SmsVal->"type" . ":\n" . $SmsVal->"message"); + :foreach Hook in=$SmsForwardHooks do={ + :if ($Phone~($Hook->"allowed-number") && ($SmsVal->"message")~($Hook->"match")) do={ + :if ([ $ValidateSyntax ($Hook->"command") ] = true) do={ + $LogPrintExit2 info $0 ("Running hook '" . $Hook->"match" . "': " . \ + $Hook->"command") false; + :do { + [ :parse ($Hook->"command") ]; + :set Messages ($Messages . "\n\nRan hook '" . $Hook->"match" . "':\n" . \ + $Hook->"command"); + } on-error={ + $LogPrintExit2 warning $0 ("The code for hook '" . $Hook->"match" . \ + "' failed to run!") false; + } + } else={ + $LogPrintExit2 warning $0 ("The code for hook '" . $Hook->"match" . \ + "' failed syntax validation!") false; + } + } + } :set Delete ($Delete, $Sms); } } From 1ea613e8a01f214be576429f873bb5e157443198 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Jan 2023 15:44:02 +0100 Subject: [PATCH 1280/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 54b3228..51a2d49 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -10,6 +10,7 @@ Thanks a lot for your contributions! â¤ī¸ These persons contributed code or documentation. See the git history for details! +* [Anatoly Bubenkov](mailto:bubenkoff@gmail.com) (@bubenkoff) * [Ben Harris](mailto:mail@bharr.is) (@bharrisau) * [Daniel Ziegenberg](mailto:daniel@ziegenberg.at) (@ziegenberg) * [Michael Gisbers](mailto:michael@gisbers.de) (@mgisbers) From 80671e3803a91f0d868b60df11c400f8d09b157f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Jan 2023 16:22:18 +0100 Subject: [PATCH 1281/2612] doc/sms-forward: take care of harmful commands in hooks --- doc/sms-forward.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 73248eb..dc89d40 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -50,6 +50,13 @@ Notification settings are required for Tips & Tricks ------------- +### Take care of harmful commands! + +It is easy to fake the sending phone number! So make sure you do not rely on +that number for potentially harmful commands. Add a shared secret to match +into the text instead, for example: `reboot-53cr3t-5tr1n9` instead of just +`reboot`. + ### Order new volume Most broadband providers include a volume limit for their data plans. The From f211a8d099f3b86c9887d8800e717c2b0a4bbe77 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 17 Nov 2022 23:02:33 +0100 Subject: [PATCH 1282/2612] README: add linked custom scripts & modules --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 3908184..feb56e5 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,26 @@ without modification. Starting a script's name with `mod/` makes it a module and it is run automatically by `global-functions`. +### Linked custom scripts & modules + +> âš ī¸ **Warning**: These links are being provided for your convenience only; +> they do not constitute an endorsement or an approval by me. I bear no +> responsibility for the accuracy, legality or content of the external site +> or for that of subsequent links. Contact the external site for answers to +> questions regarding its content. + +* [Hello World](https://git.eworm.de/cgit/routeros-scripts-custom/about/doc/hello-world.md) + (This is a demo script to show how the linking to external documentation + will be done.) + +> â„šī¸ **Info**: You have your own set of scripts and/or modules and want these +> to be listed here? There should be a general info page that links here, +> and documentation for each script. You can start by cloning my +> [Custom RouterOS-Scripts](https://git.eworm.de/cgit/routeros-scripts-custom/) +> (or fork on [GitHub](https://github.com/eworm-de/routeros-scripts-custom) +> or [GitLab](https://gitlab.com/eworm-de/routeros-scripts-custom)) and make +> your changes. Then please [get in contact](#patches-issues-and-whishlist)... + Removing a script ----------------- From a38272e15e4070284d480bc0738aaccd05027e91 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Jan 2023 19:05:42 +0100 Subject: [PATCH 1283/2612] README: install custom script from routeros-scripts-custom --- README.d/12-install-custom-script.avif | Bin 2242 -> 4746 bytes README.md | 5 +---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/README.d/12-install-custom-script.avif b/README.d/12-install-custom-script.avif index c27408f112e83962a0dbed12ccb409874fbeeee4..df9f734218565e449d969005bb32c7515246ffef 100644 GIT binary patch literal 4746 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 Date: Tue, 10 Jan 2023 14:45:27 +0100 Subject: [PATCH 1284/2612] use arrows with emoji representation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We had... ◀ Go back to main README ▲ Go back to top ... and switch to... âŦ…ī¸ Go back to main README âŦ†ī¸ Go back to top --- CONTRIBUTIONS.md | 6 +++--- INITIAL-COMMANDS.md | 6 +++--- README.md | 2 +- doc/accesslist-duplicates.md | 6 +++--- doc/backup-cloud.md | 6 +++--- doc/backup-email.md | 6 +++--- doc/backup-partition.md | 6 +++--- doc/backup-upload.md | 6 +++--- doc/capsman-download-packages.md | 6 +++--- doc/capsman-rolling-upgrade.md | 6 +++--- doc/certificate-renew-issued.md | 6 +++--- doc/check-certificates.md | 6 +++--- doc/check-health.md | 6 +++--- doc/check-lte-firmware-upgrade.md | 6 +++--- doc/check-routeros-update.md | 6 +++--- doc/collect-wireless-mac.md | 6 +++--- doc/daily-psk.md | 6 +++--- doc/dhcp-lease-comment.md | 6 +++--- doc/dhcp-to-dns.md | 6 +++--- doc/firmware-upgrade-reboot.md | 6 +++--- doc/global-wait.md | 6 +++--- doc/gps-track.md | 6 +++--- doc/hotspot-to-wpa.md | 6 +++--- doc/ip-addr-bridge.md | 6 +++--- doc/ipsec-to-dns.md | 6 +++--- doc/ipv6-update.md | 6 +++--- doc/lease-script.md | 6 +++--- doc/leds-mode.md | 6 +++--- doc/log-forward.md | 6 +++--- doc/mod/bridge-port-to.md | 6 +++--- doc/mod/bridge-port-vlan.md | 6 +++--- doc/mod/inspectvar.md | 6 +++--- doc/mod/ipcalc.md | 6 +++--- doc/mod/notification-email.md | 6 +++--- doc/mod/notification-matrix.md | 6 +++--- doc/mod/notification-telegram.md | 6 +++--- doc/mod/scriptrunonce.md | 6 +++--- doc/mode-button.md | 6 +++--- doc/netwatch-dns.md | 6 +++--- doc/netwatch-notify.md | 6 +++--- doc/ospf-to-leds.md | 6 +++--- doc/packages-update.md | 6 +++--- doc/ppp-on-up.md | 6 +++--- doc/sms-action.md | 6 +++--- doc/sms-forward.md | 6 +++--- doc/ssh-keys-import.md | 6 +++--- doc/super-mario-theme.md | 6 +++--- doc/unattended-lte-firmware-upgrade.md | 6 +++--- doc/update-gre-address.md | 6 +++--- doc/update-tunnelbroker.md | 6 +++--- 50 files changed, 148 insertions(+), 148 deletions(-) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 51a2d49..e89f8f5 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -1,7 +1,7 @@ Past Contributions ================== -[◀ Go back to main README](README.md) +[âŦ…ī¸ Go back to main README](README.md) Thanks a lot for your contributions! â¤ī¸ @@ -41,5 +41,5 @@ Add yourself to the list, * Zac Kornilakis --- -[◀ Go back to main README](README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index e8be3e1..2300248 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -1,7 +1,7 @@ Initial commands ================ -[◀ Go back to main README](README.md) +[âŦ…ī¸ Go back to main README](README.md) > âš ī¸ **Warning**: These command are inteneded for initial setup. If you are > not aware of the procedure please follow @@ -33,5 +33,5 @@ Optional to update the scripts automatically: /system/scheduler/add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; --- -[◀ Go back to main README](README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/README.md b/README.md index fd74b3b..a5a2894 100644 --- a/README.md +++ b/README.md @@ -327,4 +327,4 @@ Mirror: [GitLab.com](https://gitlab.com/eworm-de/routeros-scripts#routeros-scripts) --- -[▲ Go back to top](#top) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index 50720b1..c59aebf 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -1,7 +1,7 @@ Find and remove access list duplicates ====================================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -41,5 +41,5 @@ See also * [Collect MAC addresses in wireless access list](collect-wireless-mac.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index 26f7db7..511fad3 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -1,7 +1,7 @@ Upload backup to Mikrotik cloud =============================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -60,5 +60,5 @@ See also * [Upload backup to server](backup-upload.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/backup-email.md b/doc/backup-email.md index ab2b9b5..c7de3e7 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -1,7 +1,7 @@ Send backup via e-mail ====================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -52,5 +52,5 @@ See also * [Upload backup to server](backup-upload.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/backup-partition.md b/doc/backup-partition.md index b502330..e95422c 100644 --- a/doc/backup-partition.md +++ b/doc/backup-partition.md @@ -1,7 +1,7 @@ Save configuration to fallback partition ======================================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -41,5 +41,5 @@ See also * [Upload backup to server](backup-upload.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/backup-upload.md b/doc/backup-upload.md index ab07862..3e4c7e8 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -1,7 +1,7 @@ Upload backup to server ======================= -[◀ 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 > installation. See [main README](../README.md) for details. @@ -75,5 +75,5 @@ See also * [Save configuration to fallback partition](doc/backup-partition.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index 0fdd6cb..58f84e8 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -1,7 +1,7 @@ Download packages for CAP upgrade from CAPsMAN ============================================= -[◀ 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 > installation. See [main README](../README.md) for details. @@ -49,5 +49,5 @@ See also * [Run rolling CAP upgrades from CAPsMAN](capsman-rolling-upgrade.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index 94a2a79..d146adf 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -1,7 +1,7 @@ Run rolling CAP upgrades from CAPsMAN ===================================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -41,5 +41,5 @@ See also * [Download packages for CAP upgrade from CAPsMAN](capsman-download-packages.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/certificate-renew-issued.md b/doc/certificate-renew-issued.md index d8201a7..72f7fc5 100644 --- a/doc/certificate-renew-issued.md +++ b/doc/certificate-renew-issued.md @@ -1,7 +1,7 @@ Renew locally issued certificates ================================= -[◀ 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 > installation. See [main README](../README.md) for details. @@ -46,5 +46,5 @@ See also * [Renew certificates and notify on expiration](check-certificates.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/check-certificates.md b/doc/check-certificates.md index e8c295a..6ce2ec7 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -1,7 +1,7 @@ Renew certificates and notify on expiration =========================================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -61,5 +61,5 @@ See also * [Renew locally issued certificates](certificate-renew-issued.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/check-health.md b/doc/check-health.md index d84693a..07151ff 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -1,7 +1,7 @@ Notify about health state ========================= -[◀ 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 > installation. See [main README](../README.md) for details. @@ -62,5 +62,5 @@ Also notification settings are required for [telegram](mod/notification-telegram.md). --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index 8443ea0..a81ca86 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -1,7 +1,7 @@ Notify on LTE firmware upgrade ============================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -47,5 +47,5 @@ See also * [Install LTE firmware upgrade](unattended-lte-firmware-upgrade.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 735fc5a..696abe6 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -1,7 +1,7 @@ Notify on RouterOS update ========================= -[◀ 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 > installation. See [main README](../README.md) for details. @@ -79,5 +79,5 @@ See also * [Manage system update](packages-update.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index f5c8a5c..dd3743f 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -1,7 +1,7 @@ Collect MAC addresses in wireless access list ============================================= -[◀ 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 > installation. See [main README](../README.md) for details. @@ -60,5 +60,5 @@ See also * [Run other scripts on DHCP lease](lease-script.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 67f0212..77928cd 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -1,7 +1,7 @@ Use wireless network with daily psk =================================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -57,5 +57,5 @@ Also notification settings are required for [telegram](mod/notification-telegram.md). --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/dhcp-lease-comment.md b/doc/dhcp-lease-comment.md index bb9222e..4add0b8 100644 --- a/doc/dhcp-lease-comment.md +++ b/doc/dhcp-lease-comment.md @@ -1,7 +1,7 @@ Comment DHCP leases with info from access list ============================================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -48,5 +48,5 @@ See also * [Run other scripts on DHCP lease](lease-script.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index bde7f12..531a75b 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -1,7 +1,7 @@ Create DNS records for DHCP leases ================================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -48,5 +48,5 @@ See also * [Run other scripts on DHCP lease](lease-script.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/firmware-upgrade-reboot.md b/doc/firmware-upgrade-reboot.md index 0215ce9..8bf4d19 100644 --- a/doc/firmware-upgrade-reboot.md +++ b/doc/firmware-upgrade-reboot.md @@ -1,7 +1,7 @@ Automatically upgrade firmware and reboot ========================================= -[◀ 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 > installation. See [main README](../README.md) for details. @@ -32,5 +32,5 @@ See also * [Manage system update](packages-update.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/global-wait.md b/doc/global-wait.md index ac3e5cc..39921db 100644 --- a/doc/global-wait.md +++ b/doc/global-wait.md @@ -1,7 +1,7 @@ Wait for global functions and modules ===================================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -36,5 +36,5 @@ See also * [Manage VLANs on bridge ports](mod/bridge-port-vlan.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/gps-track.md b/doc/gps-track.md index c7d28f6..f5d9901 100644 --- a/doc/gps-track.md +++ b/doc/gps-track.md @@ -1,7 +1,7 @@ Send GPS position to server =========================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -36,5 +36,5 @@ The configured coordinate format (see `/system/gps`) defines the format sent to the server. --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index 211d4fb..0abe18b 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -1,7 +1,7 @@ Use WPA2 network with hotspot credentials ========================================= -[◀ 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 > installation. See [main README](../README.md) for details. @@ -86,5 +86,5 @@ See also * [Run other scripts on DHCP lease](lease-script.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/ip-addr-bridge.md b/doc/ip-addr-bridge.md index f0b593e..a759829 100644 --- a/doc/ip-addr-bridge.md +++ b/doc/ip-addr-bridge.md @@ -1,7 +1,7 @@ Manage IP addresses with bridge status ====================================== -[◀ Go back to main README](../README.md) +[âŦ…ī¸ Go back to main README](../README.md) Description ----------- @@ -28,5 +28,5 @@ Note that IP addresses on bridges without a single port (acting as loopback interface) are ignored. --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/ipsec-to-dns.md b/doc/ipsec-to-dns.md index 87ad21a..5825def 100644 --- a/doc/ipsec-to-dns.md +++ b/doc/ipsec-to-dns.md @@ -1,7 +1,7 @@ Create DNS records for IPSec peers ================================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -42,5 +42,5 @@ See also * [Create DNS records for DHCP leases](dns-to-dhcp.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md index 7c5a943..49804f4 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -1,7 +1,7 @@ Update configuration on IPv6 prefix change ========================================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -64,5 +64,5 @@ See also * [Run scripts on ppp connection](ppp-on-up.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/lease-script.md b/doc/lease-script.md index a435d43..55928fc 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -1,7 +1,7 @@ Run other scripts on DHCP lease =============================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -43,5 +43,5 @@ See also * [Use WPA2 network with hotspot credentials](hotspot-to-wpa.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/leds-mode.md b/doc/leds-mode.md index 65f9f01..5710d85 100644 --- a/doc/leds-mode.md +++ b/doc/leds-mode.md @@ -1,7 +1,7 @@ Manage LEDs dark mode ===================== -[◀ Go back to main README](../README.md) +[âŦ…ī¸ Go back to main README](../README.md) Description ----------- @@ -46,5 +46,5 @@ See also * [Mode button with multiple presses](mode-button.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/log-forward.md b/doc/log-forward.md index 649298a..d3a1908 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -1,7 +1,7 @@ Forward log messages via notification ===================================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -52,5 +52,5 @@ Also notification settings are required for [telegram](mod/notification-telegram.md). --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/mod/bridge-port-to.md b/doc/mod/bridge-port-to.md index f86b21d..a956de4 100644 --- a/doc/mod/bridge-port-to.md +++ b/doc/mod/bridge-port-to.md @@ -1,7 +1,7 @@ Manage ports in bridge ====================== -[◀ 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 > installation. See [main README](../../README.md) for details. @@ -77,5 +77,5 @@ See also * [Manage VLANs on bridge ports](bridge-port-vlan.md) --- -[◀ Go back to main README](../../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/mod/bridge-port-vlan.md b/doc/mod/bridge-port-vlan.md index 0e6c28f..068f050 100644 --- a/doc/mod/bridge-port-vlan.md +++ b/doc/mod/bridge-port-vlan.md @@ -1,7 +1,7 @@ Manage VLANs on bridge ports ============================ -[◀ 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 > installation. See [main README](../../README.md) for details. @@ -81,5 +81,5 @@ See also * [Manage ports in bridge](bridge-port-to.md) --- -[◀ Go back to main README](../../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/mod/inspectvar.md b/doc/mod/inspectvar.md index 7782c8a..1cc49a2 100644 --- a/doc/mod/inspectvar.md +++ b/doc/mod/inspectvar.md @@ -1,7 +1,7 @@ Inspect variables ================= -[◀ 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 > installation. See [main README](../../README.md) for details. @@ -29,5 +29,5 @@ Call the function `$InspectVar` with a variable as parameter: ![InspectVar](inspectvar.d/inspectvar.avif) --- -[◀ Go back to main README](../../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/mod/ipcalc.md b/doc/mod/ipcalc.md index a3e7fc8..f2f1140 100644 --- a/doc/mod/ipcalc.md +++ b/doc/mod/ipcalc.md @@ -1,7 +1,7 @@ IP address calculation ====================== -[◀ 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 > installation. See [main README](../../README.md) for details. @@ -49,5 +49,5 @@ the information in a named array. ![IPCalcReturn](ipcalc.d/ipcalcreturn.avif) --- -[◀ Go back to main README](../../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/mod/notification-email.md b/doc/mod/notification-email.md index 144c48a..61798e6 100644 --- a/doc/mod/notification-email.md +++ b/doc/mod/notification-email.md @@ -1,7 +1,7 @@ Send notifications via e-mail ============================= -[◀ 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 > installation. See [main README](../../README.md) for details. @@ -61,5 +61,5 @@ See also * [Send notifications via Telegram](notification-telegram.md) --- -[◀ Go back to main README](../../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index b1f520e..6bb04b6 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -1,7 +1,7 @@ Send notifications via Matrix ============================= -[◀ 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 > installation. See [main README](../../README.md) for details. @@ -107,5 +107,5 @@ See also * [Send notifications via Telegram](notification-telegram.md) --- -[◀ Go back to main README](../../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index 2b1abe9..b55739a 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -1,7 +1,7 @@ Send notifications via Telegram =============================== -[◀ 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 > installation. See [main README](../../README.md) for details. @@ -70,5 +70,5 @@ See also * [Send notifications via Matrix](notification-matrix.md) --- -[◀ Go back to main README](../../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/mod/scriptrunonce.md b/doc/mod/scriptrunonce.md index 6efa1b7..5472bef 100644 --- a/doc/mod/scriptrunonce.md +++ b/doc/mod/scriptrunonce.md @@ -1,7 +1,7 @@ Download script and run it once =============================== -[◀ 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 > installation. See [main README](../../README.md) for details. @@ -44,5 +44,5 @@ The function `$ScriptRunOnce` expects an URL (or name if Giving multiple scripts is possible, separated by comma. --- -[◀ Go back to main README](../../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/mode-button.md b/doc/mode-button.md index ef7754c..50b1722 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -1,7 +1,7 @@ Mode button with multiple presses ================================= -[◀ 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 > installation. See [main README](../README.md) for details. @@ -60,5 +60,5 @@ Usage and invocation Press the mode button. 😜 --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 65d0488..a208d00 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -1,7 +1,7 @@ Manage DNS and DoH servers from netwatch ======================================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -74,5 +74,5 @@ See also * [Notify on host up and down](netwatch-notify.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index b0214e4..5bbd657 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -1,7 +1,7 @@ Notify on host up and down ========================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -151,5 +151,5 @@ See also * [Manage DNS and DoH servers from netwatch](netwatch-dns.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/ospf-to-leds.md b/doc/ospf-to-leds.md index 5ab5c75..ce7f9ff 100644 --- a/doc/ospf-to-leds.md +++ b/doc/ospf-to-leds.md @@ -1,7 +1,7 @@ Visualize OSPF state via LEDs ============================= -[◀ 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 > installation. See [main README](../README.md) for details. @@ -33,5 +33,5 @@ instance `default` via LED `user-led` set this: /routing/ospf/instance/set default comment="ospf-to-leds, leds=user-led"; --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/packages-update.md b/doc/packages-update.md index 57f02d9..4604bae 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -1,7 +1,7 @@ Manage system update ==================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -48,5 +48,5 @@ See also * [Automatically upgrade firmware and reboot](firmware-upgrade-reboot.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/ppp-on-up.md b/doc/ppp-on-up.md index 7545c5e..d5d0ae5 100644 --- a/doc/ppp-on-up.md +++ b/doc/ppp-on-up.md @@ -1,7 +1,7 @@ Run scripts on ppp connection ============================= -[◀ 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 > installation. See [main README](../README.md) for details. @@ -33,5 +33,5 @@ See also * [Update tunnelbroker configuration](update-tunnelbroker.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/sms-action.md b/doc/sms-action.md index d2e3252..e72aa11 100644 --- a/doc/sms-action.md +++ b/doc/sms-action.md @@ -1,7 +1,7 @@ Act on received SMS =================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -48,5 +48,5 @@ See also * [Forward received SMS](sms-forward.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index dc89d40..9dccaf3 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -1,7 +1,7 @@ Forward received SMS ==================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -81,5 +81,5 @@ See also * [Act on received SMS](sms-action.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/ssh-keys-import.md b/doc/ssh-keys-import.md index d83311f..2dd6c42 100644 --- a/doc/ssh-keys-import.md +++ b/doc/ssh-keys-import.md @@ -1,7 +1,7 @@ Import SSH keys =============== -[◀ Go back to main README](../README.md) +[âŦ…ī¸ Go back to main README](../README.md) Description ----------- @@ -29,5 +29,5 @@ Starting with an `authorized_keys` file you can split it on a shell: grep -E '^ssh-rsa' authorized_keys | nl -nrz | while read num type key name; do echo $type $key $name > $num-$name.pub; done --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/super-mario-theme.md b/doc/super-mario-theme.md index 8142cda..b3100e8 100644 --- a/doc/super-mario-theme.md +++ b/doc/super-mario-theme.md @@ -1,7 +1,7 @@ Play Super Mario theme ====================== -[◀ Go back to main README](../README.md) +[âŦ…ī¸ Go back to main README](../README.md) Description ----------- @@ -27,5 +27,5 @@ Just run the script to play: For extra fun use it for dhcp lease script. :) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/unattended-lte-firmware-upgrade.md b/doc/unattended-lte-firmware-upgrade.md index 63f2793..8bc9e71 100644 --- a/doc/unattended-lte-firmware-upgrade.md +++ b/doc/unattended-lte-firmware-upgrade.md @@ -1,7 +1,7 @@ Install LTE firmware upgrade ============================ -[◀ Go back to main README](../README.md) +[âŦ…ī¸ Go back to main README](../README.md) Description ----------- @@ -42,5 +42,5 @@ See also * [Notify on LTE firmware upgrade](check-lte-firmware-upgrade.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/update-gre-address.md b/doc/update-gre-address.md index 7e87743..5bf95bd 100644 --- a/doc/update-gre-address.md +++ b/doc/update-gre-address.md @@ -1,7 +1,7 @@ Update GRE configuration with dynamic addresses =============================================== -[◀ 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 > installation. See [main README](../README.md) for details. @@ -37,5 +37,5 @@ certificate CN into the comment: /interface/gre/set comment="ikev2-client1" gre-client1; --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/update-tunnelbroker.md b/doc/update-tunnelbroker.md index 3338e2b..4d6f1ba 100644 --- a/doc/update-tunnelbroker.md +++ b/doc/update-tunnelbroker.md @@ -1,7 +1,7 @@ Update tunnelbroker configuration ================================= -[◀ 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 > installation. See [main README](../README.md) for details. @@ -39,5 +39,5 @@ See also * [Run scripts on ppp connection](ppp-on-up.md) --- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) From 868557a24ae544f778531df71c4842fac72f308d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Jan 2023 09:21:13 +0100 Subject: [PATCH 1285/2612] log-forward: generate filter in mod/notification-email --- log-forward | 12 ++++-------- mod/notification-email | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/log-forward b/log-forward index df69008..642035c 100644 --- a/log-forward +++ b/log-forward @@ -19,11 +19,11 @@ :global LogForwardRateLimit; :global NotificationsWithSymbols; -:global EscapeForRegEx; +:global EitherOr; :global HexToNum; :global IfThenElse; +:global LogForwardFilterLogForwarding; :global LogPrintExit2; -:global QuotedPrintable; :global ScriptLock; :global SendNotification2; :global SymbolByUnicodeName; @@ -48,12 +48,8 @@ $ScriptLock $0; :local MessageVal; :local MessageDups ({}); -:local LogForwardFilterLogForwarding ("^Error sending e-mail <(" . \ - [ $EscapeForRegEx [ $QuotedPrintable ("[" . $Identity . "] " . \ - [ $SymbolForNotification "memo" ] . "Log Forwarding") ] ] . "|" . \ - [ $EscapeForRegEx [ $QuotedPrintable ("[" . $Identity . "] " . \ - [ $SymbolForNotification "warning-sign" ] . "Log Forwarding") ] ] . ")>:"); -:foreach Message in=[ /log/find where (!(message="") and !(message~$LogForwardFilterLogForwarding) and \ +:foreach Message in=[ /log/find where (!(message="") and \ + !(message~[ $EitherOr [ $LogForwardFilterLogForwarding ] ("\$^") ]) and \ !(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \ topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={ :set MessageVal [ /log/get $Message ]; diff --git a/mod/notification-email b/mod/notification-email index ea7d26a..8f624e9 100644 --- a/mod/notification-email +++ b/mod/notification-email @@ -4,6 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global FlushEmailQueue; +:global LogForwardFilterLogForwarding; :global NotificationFunctions; :global SendEMail; :global SendEMail2; @@ -88,6 +89,21 @@ } } +# generate filter for log-forward +:set LogForwardFilterLogForwarding do={ + :global Identity; + + :global EscapeForRegEx; + :global QuotedPrintable; + :global SymbolForNotification; + + :return ("^Error sending e-mail <(" . \ + [ $EscapeForRegEx [ $QuotedPrintable ("[" . $Identity . "] " . \ + [ $SymbolForNotification "memo" ] . "Log Forwarding") ] ] . "|" . \ + [ $EscapeForRegEx [ $QuotedPrintable ("[" . $Identity . "] " . \ + [ $SymbolForNotification "warning-sign" ] . "Log Forwarding") ] ] . ")>:"); +} + # send notification via e-mail - expects one array argument :set ($NotificationFunctions->"email") do={ :local Notification $1; From 329bef94df9a1d0a8592b81b63930dfe716f0582 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Jan 2023 09:26:13 +0100 Subject: [PATCH 1286/2612] log-forward: do not declare unused function --- log-forward | 1 - 1 file changed, 1 deletion(-) diff --git a/log-forward b/log-forward index 642035c..73620e8 100644 --- a/log-forward +++ b/log-forward @@ -26,7 +26,6 @@ :global LogPrintExit2; :global ScriptLock; :global SendNotification2; -:global SymbolByUnicodeName; :global SymbolForNotification; $ScriptLock $0; From a953a8fa59b110ce6016f5773a7b9b601651a291 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Jan 2023 10:06:31 +0100 Subject: [PATCH 1287/2612] mod/notification-email: move $QuotedPrintable (from global-functions) This is used for e-mail only... --- global-functions | 37 ------------------------------------- mod/notification-email | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/global-functions b/global-functions index 0c584b7..d070e39 100644 --- a/global-functions +++ b/global-functions @@ -42,7 +42,6 @@ :global NotificationFunctions; :global ParseKeyValueStore; :global PrettyPrint; -:global QuotedPrintable; :global RandomDelay; :global Read; :global RequiredRouterOS; @@ -612,42 +611,6 @@ :put [ $CharacterReplace $Input ("\n") ("\n\r") ]; } -# convert string to quoted-printable -:global QuotedPrintable do={ - :local Input [ :tostr $1 ]; - - :if ([ :len $Input ] = 0) do={ - :return $Input; - } - - :local Return ""; - :local Chars ("\80\81\82\83\84\85\86\87\88\89\8A\8B\8C\8D\8E\8F\90\91\92\93\94\95\96\97" . \ - "\98\99\9A\9B\9C\9D\9E\9F\A0\A1\A2\A3\A4\A5\A6\A7\A8\A9\AA\AB\AC\AD\AE\AF\B0\B1\B2\B3" . \ - "\B4\B5\B6\B7\B8\B9\BA\BB\BC\BD\BE\BF\C0\C1\C2\C3\C4\C5\C6\C7\C8\C9\CA\CB\CC\CD\CE\CF" . \ - "\D0\D1\D2\D3\D4\D5\D6\D7\D8\D9\DA\DB\DC\DD\DE\DF\E0\E1\E2\E3\E4\E5\E6\E7\E8\E9\EA\EB" . \ - "\EC\ED\EE\EF\F0\F1\F2\F3\F4\F5\F6\F7\F8\F9\FA\FB\FC\FD\FE\FF"); - :local Hex { "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"; "9"; "A"; "B"; "C"; "D"; "E"; "F" }; - - :for I from=0 to=([ :len $Input ] - 1) do={ - :local Char [ :pick $Input $I ]; - :local Replace [ :find $Chars $Char ]; - - :if ($Char = "=") do={ - :set Char "=3D"; - } - :if ([ :typeof $Replace ] = "num") do={ - :set Char ("=" . ($Hex->($Replace / 16 + 8)) . ($Hex->($Replace % 16))); - } - :set Return ($Return . $Char); - } - - :if ($Input = $Return) do={ - :return $Input; - } - - :return ("=\?utf-8\?Q\?" . $Return . "\?="); -} - # delay a random amount of seconds :set RandomDelay do={ :global EitherOr; diff --git a/mod/notification-email b/mod/notification-email index 8f624e9..5262ee5 100644 --- a/mod/notification-email +++ b/mod/notification-email @@ -6,6 +6,7 @@ :global FlushEmailQueue; :global LogForwardFilterLogForwarding; :global NotificationFunctions; +:global QuotedPrintable; :global SendEMail; :global SendEMail2; @@ -144,6 +145,42 @@ } } +# convert string to quoted-printable +:global QuotedPrintable do={ + :local Input [ :tostr $1 ]; + + :if ([ :len $Input ] = 0) do={ + :return $Input; + } + + :local Return ""; + :local Chars ("\80\81\82\83\84\85\86\87\88\89\8A\8B\8C\8D\8E\8F\90\91\92\93\94\95\96\97" . \ + "\98\99\9A\9B\9C\9D\9E\9F\A0\A1\A2\A3\A4\A5\A6\A7\A8\A9\AA\AB\AC\AD\AE\AF\B0\B1\B2\B3" . \ + "\B4\B5\B6\B7\B8\B9\BA\BB\BC\BD\BE\BF\C0\C1\C2\C3\C4\C5\C6\C7\C8\C9\CA\CB\CC\CD\CE\CF" . \ + "\D0\D1\D2\D3\D4\D5\D6\D7\D8\D9\DA\DB\DC\DD\DE\DF\E0\E1\E2\E3\E4\E5\E6\E7\E8\E9\EA\EB" . \ + "\EC\ED\EE\EF\F0\F1\F2\F3\F4\F5\F6\F7\F8\F9\FA\FB\FC\FD\FE\FF"); + :local Hex { "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"; "9"; "A"; "B"; "C"; "D"; "E"; "F" }; + + :for I from=0 to=([ :len $Input ] - 1) do={ + :local Char [ :pick $Input $I ]; + :local Replace [ :find $Chars $Char ]; + + :if ($Char = "=") do={ + :set Char "=3D"; + } + :if ([ :typeof $Replace ] = "num") do={ + :set Char ("=" . ($Hex->($Replace / 16 + 8)) . ($Hex->($Replace % 16))); + } + :set Return ($Return . $Char); + } + + :if ($Input = $Return) do={ + :return $Input; + } + + :return ("=\?utf-8\?Q\?" . $Return . "\?="); +} + # send notification via e-mail - expects at least two string arguments :set SendEMail do={ :global SendEMail2; From c8e22f33c25db61a3f8287aae812017f79e8cba1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Jan 2023 09:42:25 +0100 Subject: [PATCH 1288/2612] mod/notification-email: split off generation of subject --- mod/notification-email | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/mod/notification-email b/mod/notification-email index 5262ee5..8868941 100644 --- a/mod/notification-email +++ b/mod/notification-email @@ -5,6 +5,7 @@ :global FlushEmailQueue; :global LogForwardFilterLogForwarding; +:global NotificationEMailSubject; :global NotificationFunctions; :global QuotedPrintable; :global SendEMail; @@ -92,24 +93,30 @@ # generate filter for log-forward :set LogForwardFilterLogForwarding do={ - :global Identity; - :global EscapeForRegEx; - :global QuotedPrintable; + :global NotificationEMailSubject; :global SymbolForNotification; :return ("^Error sending e-mail <(" . \ - [ $EscapeForRegEx [ $QuotedPrintable ("[" . $Identity . "] " . \ - [ $SymbolForNotification "memo" ] . "Log Forwarding") ] ] . "|" . \ - [ $EscapeForRegEx [ $QuotedPrintable ("[" . $Identity . "] " . \ - [ $SymbolForNotification "warning-sign" ] . "Log Forwarding") ] ] . ")>:"); + [ $EscapeForRegEx [ $NotificationEMailSubject ([ $SymbolForNotification \ + "memo" ] . "Log Forwarding") ] ] . "|" . \ + [ $EscapeForRegEx [ $NotificationEMailSubject ([ $SymbolForNotification \ + "warning-sign" ] . "Log Forwarding") ] ] . ")>:"); +} + +# generate the e-mail subject +:set NotificationEMailSubject do={ + :global Identity; + + :global QuotedPrintable; + + :return [ $QuotedPrintable ("[" . $Identity . "] " . $1) ]; } # send notification via e-mail - expects one array argument :set ($NotificationFunctions->"email") do={ :local Notification $1; - :global Identity; :global EmailGeneralTo; :global EmailGeneralToOverride; :global EmailGeneralCc; @@ -118,7 +125,7 @@ :global EitherOr; :global IfThenElse; - :global QuotedPrintable; + :global NotificationEMailSubject; :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; @@ -134,7 +141,7 @@ :local Signature [ /system/note/get note ]; :set ($EmailQueue->[ :len $EmailQueue ]) { to=$To; cc=$Cc; - subject=[ $QuotedPrintable ("[" . $Identity . "] " . ($Notification->"subject")) ]; + subject=[ $NotificationEMailSubject ($Notification->"subject") ]; body=(($Notification->"message") . \ [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \ From 47a657d25c44910b548410dea84b092e5d5488dc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Jan 2023 00:31:49 +0100 Subject: [PATCH 1289/2612] =?UTF-8?q?mod/notification-*:=20support=20extra?= =?UTF-8?q?=20text=20(or=20emojis=20=F0=9F=9A=80)=20in=20notification=20ta?= =?UTF-8?q?gs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- global-config | 3 +++ global-config.changes | 1 + global-functions | 2 +- mod/notification-email | 3 ++- mod/notification-matrix | 10 ++++++---- mod/notification-telegram | 4 +++- 6 files changed, 16 insertions(+), 7 deletions(-) diff --git a/global-config b/global-config index fded46f..bd632a1 100644 --- a/global-config +++ b/global-config @@ -9,6 +9,9 @@ # Set this to 'true' to disable news and change notifications. :global NoNewsAndChangesNotification false; +# Add extra text (or emojis) in notification tags. +:global IdentityExtra ""; + # This is used for DNS and backup file. :global Domain "example.com"; :global HostNameInZone true; diff --git a/global-config.changes b/global-config.changes index 357dede..5dd7616 100644 --- a/global-config.changes +++ b/global-config.changes @@ -95,6 +95,7 @@ 84="Support for e-mail notifications moved to a module. It is installed automatically if required."; 85="Dropped 'netwatch-syslog', filtering in firewall is advised."; 86="Added support for hooks in 'sms-forward'. This now provides similar functionality to 'sms-action', but is more flexible."; + 87="Added support for extra text (or emojis \F0\9F\9A\80) in notification tags."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index d070e39..9e89670 100644 --- a/global-functions +++ b/global-functions @@ -10,7 +10,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 86; +:global ExpectedConfigVersion 87; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/mod/notification-email b/mod/notification-email index 8868941..b03e176 100644 --- a/mod/notification-email +++ b/mod/notification-email @@ -107,10 +107,11 @@ # generate the e-mail subject :set NotificationEMailSubject do={ :global Identity; + :global IdentityExtra; :global QuotedPrintable; - :return [ $QuotedPrintable ("[" . $Identity . "] " . $1) ]; + :return [ $QuotedPrintable ("[" . $IdentityExtra . $Identity . "] " . $1) ]; } # send notification via e-mail - expects one array argument diff --git a/mod/notification-matrix b/mod/notification-matrix index c43514d..6266b75 100644 --- a/mod/notification-matrix +++ b/mod/notification-matrix @@ -56,6 +56,7 @@ :local Notification $1; :global Identity; + :global IdentityExtra; :global MatrixAccessToken; :global MatrixAccessTokenOverride; :global MatrixHomeServer; @@ -106,10 +107,11 @@ :return false; } - :local Plain [ $PrepareText ("## [" . $Identity . "] " . ($Notification->"subject") . "\n```\n" . \ - ($Notification->"message") . "\n```") "plain" ]; - :local Formatted ("

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

    " . \ - "
    " . [ $PrepareText ($Notification->"message") "format" ] . "
    "); + :local Plain [ $PrepareText ("## [" . $IdentityExtra . $Identity . "] " . \ + ($Notification->"subject") . "\n```\n" . ($Notification->"message") . "\n```") "plain" ]; + :local Formatted ("

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

    " . "
    " . \
    +    [ $PrepareText ($Notification->"message") "format" ] . "
    "); :if ([ :len ($Notification->"link") ] > 0) do={ :set Plain ($Plain . "\\n" . [ $SymbolForNotification "link" ] . \ [ $PrepareText ("[" . $Notification->"link" . "](" . $Notification->"link" . ")") "plain" ]); diff --git a/mod/notification-telegram b/mod/notification-telegram index de8cdd8..03ccc3b 100644 --- a/mod/notification-telegram +++ b/mod/notification-telegram @@ -55,6 +55,7 @@ :local Notification $1; :global Identity; + :global IdentityExtra; :global TelegramChatId; :global TelegramChatIdOverride; :global TelegramFixedWidthFont; @@ -105,7 +106,8 @@ } :local Truncated false; - :local Text ("*__" . [ $EscapeMD ("[" . $Identity . "] " . ($Notification->"subject")) "plain" ] . "__*\n\n"); + :local Text ("*__" . [ $EscapeMD ("[" . $IdentityExtra . $Identity . "] " . \ + ($Notification->"subject")) "plain" ] . "__*\n\n"); :local LenSubject [ :len $Text ]; :local LenMessage [ :len ($Notification->"message") ]; :local LenLink [ :len ($Notification->"link") ]; From f67dc0218bcfb62be3e839a63a1dee042909a6c6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 12 Jan 2023 08:17:48 +0100 Subject: [PATCH 1290/2612] global-functions: $ScriptInstallUpdate: handle config version decrease... ... and log a warning. --- global-functions | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 9e89670..9ed6b4a 100644 --- a/global-functions +++ b/global-functions @@ -796,7 +796,13 @@ } } - :if ($ExpectedConfigVersionBefore != $ExpectedConfigVersion) do={ + :if ($ExpectedConfigVersionBefore > $ExpectedConfigVersion) do={ + $LogPrintExit2 warning $0 ("The configuration version decreased from " . \ + $ExpectedConfigVersionBefore . " to " . $ExpectedConfigVersion . \ + ". Installed an older version?") false; + } + + :if ($ExpectedConfigVersionBefore < $ExpectedConfigVersion) do={ :global GlobalConfigChanges; :global GlobalConfigMigration; :local ChangeLogCode; From ab306ad3c7bb4a5d0570ae4d047ab093ac1a2d35 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 12 Jan 2023 23:26:23 +0100 Subject: [PATCH 1291/2612] doc/daily-psk: add missing bits for CAPsMAN --- doc/daily-psk.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 77928cd..c9d7a99 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -22,18 +22,18 @@ Requirements and installation Just install this script. Depending on whether you use CAPsMAN (`/caps-man`) or local wireless -interface (`/interface/wireless`) you need to install a different script. +interface (`/interface/wireless`) you need to install a different script +and add schedulers to run the script: For CAPsMAN: $ScriptInstallUpdate daily-psk.capsman; + /system/scheduler/add interval=1d name=daily-psk-nightly on-event="/system/script/run daily-psk.capsman;" start-date=may/23/2018 start-time=03:00:00; + /system/scheduler/add name=daily-psk-startup on-event="/system/script/run daily-psk.capsman;" start-time=startup; For local interface: $ScriptInstallUpdate daily-psk.local; - -And add schedulers to run the script: - /system/scheduler/add interval=1d name=daily-psk-nightly on-event="/system/script/run daily-psk.local;" start-date=may/23/2018 start-time=03:00:00; /system/scheduler/add name=daily-psk-startup on-event="/system/script/run daily-psk.local;" start-time=startup; @@ -47,7 +47,11 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `DailyPskMatchComment`: pattern to match the wireless access list comment * `DailyPskSecrets`: an array with pseudo random strings -Then add an access list entry: +Then add an access list entry. For CAPsMAN: + + /caps-man/access-list/add comment="Daily PSK" ssid-regexp="-guest\$" private-passphrase="ToBeChangedDaily"; + +For local interface: /interface/wireless/access-list/add comment="Daily PSK" interface=wl-daily private-pre-shared-key="ToBeChangedDaily"; From aabc6b22fed1a6bae49c54373127413baa8e1fcb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 12 Jan 2023 23:28:37 +0100 Subject: [PATCH 1292/2612] doc/daily-psk: drop the start-date from scheduler --- doc/daily-psk.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/daily-psk.md b/doc/daily-psk.md index c9d7a99..0552f0d 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -28,13 +28,13 @@ and add schedulers to run the script: For CAPsMAN: $ScriptInstallUpdate daily-psk.capsman; - /system/scheduler/add interval=1d name=daily-psk-nightly on-event="/system/script/run daily-psk.capsman;" start-date=may/23/2018 start-time=03:00:00; + /system/scheduler/add interval=1d name=daily-psk-nightly on-event="/system/script/run daily-psk.capsman;" start-time=03:00:00; /system/scheduler/add name=daily-psk-startup on-event="/system/script/run daily-psk.capsman;" start-time=startup; For local interface: $ScriptInstallUpdate daily-psk.local; - /system/scheduler/add interval=1d name=daily-psk-nightly on-event="/system/script/run daily-psk.local;" start-date=may/23/2018 start-time=03:00:00; + /system/scheduler/add interval=1d name=daily-psk-nightly on-event="/system/script/run daily-psk.local;" start-time=03:00:00; /system/scheduler/add name=daily-psk-startup on-event="/system/script/run daily-psk.local;" start-time=startup; These will update the passphrase on boot and nightly at 3:00. From 23e5c01a429115a9c7590be10744debdb848782c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 12 Jan 2023 23:43:38 +0100 Subject: [PATCH 1293/2612] global-functions: $MkDir: no early continue for dir "tmpfs"... ... as we want a RAM disk. --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 9ed6b4a..cfd9091 100644 --- a/global-functions +++ b/global-functions @@ -543,7 +543,7 @@ :local Continue false; :set PathNext [ $CleanFilePath ($PathNext . "/" . $Dir) ]; - :if ([ :len [ /file/find where name=$PathNext type="directory" ] ] = 1) do={ + :if ([ :len [ /file/find where name=$PathNext !(name="tmpfs") type="directory" ] ] = 1) do={ :set Continue true; } From 03fb459ea4d1ec6e09d4d87b8c8e94b887f9ed89 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 17 Jan 2023 12:34:05 +0100 Subject: [PATCH 1294/2612] ipsec-to-dns: handle "CN=" from peer's id This was missing in commit bff6689b103287f44c573e3134b9b9a64c36c0a8 and cause the dns entry to be delete and re-created over and over again. --- ipsec-to-dns | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ipsec-to-dns b/ipsec-to-dns index 04ad4b8..530c714 100644 --- a/ipsec-to-dns +++ b/ipsec-to-dns @@ -16,8 +16,9 @@ :global PrefixInZone; :global CharacterReplace; -:global LogPrintExit2; +:global EscapeForRegEx; :global IfThenElse; +:global LogPrintExit2; :local Zone \ ([ $IfThenElse ($PrefixInZone = true) "ipsec." ] . \ @@ -35,7 +36,8 @@ :foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={ :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; :local PeerId [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; - :if ([ :len [ /ip/ipsec/active-peers/find where id=$PeerId dynamic-address=($DnsRecordVal->"address") ] ] > 0) do={ + :if ([ :len [ /ip/ipsec/active-peers/find where id~("^(CN=)?" . [ $EscapeForRegEx $PeerId ] . "\$") \ + dynamic-address=($DnsRecordVal->"address") ] ] > 0) do={ $LogPrintExit2 debug $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; } else={ :local Found false; From cfb31e840c9c0a44127f74602dac672e342a9401 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 18 Jan 2023 11:51:16 +0100 Subject: [PATCH 1295/2612] doc/log-forward: add some more details --- doc/log-forward.md | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/doc/log-forward.md b/doc/log-forward.md index d3a1908..250dbf9 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -9,16 +9,24 @@ Forward log messages via notification Description ----------- -RouterOS supports sending log messages via e-mail or to a syslog server. -This has some limitation, however: +RouterOS itself supports sending log messages via e-mail or to a syslog +server (see `/system/logging`). This has some limitation, however: * does not work early after boot if network connectivity is not - yet established + yet established, or breaks intermittently * lots of messages generate a flood of mails * Matrix and Telegram are not supported -The script is intended to be run periodically. It collects log messages -and forwards them via notification. +The script works around the limitations, for example it does: + +* read from `/log`, including messages from early boot +* skip multi-repeated messages +* rate-limit itself to mitigate flooding +* forward via notification (which includes *e-mail*, *Matrix* and *Telegram* + when installed and configured, see below) + +It is intended to be run periodically from scheduler, then collects new +log messages and forwards them via notification. ### Sample notification @@ -46,6 +54,13 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `LogForwardIncludeMessage`: define message text to be forwarded (even if filter matches) +These patterns are matched as +[regular expressions](https://wiki.mikrotik.com/wiki/Manual:Regular_Expressions). +To forward **all** (ignoring severity) log messages with topics `account` +(which includes user logins) and `dhcp` you need something like: + + :global LogForwardInclude "(account|dhcp)"; + Also notification settings are required for [e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or From 2294ac77a8a69b1962e06264ae0f4c250e5365ff Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Jan 2023 00:34:27 +0100 Subject: [PATCH 1296/2612] doc/log-forward: add tips and tricks --- doc/log-forward.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/log-forward.md b/doc/log-forward.md index 250dbf9..6faa27e 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -66,6 +66,18 @@ Also notification settings are required for [matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). +Tips & Tricks +------------- + +### Notification on reboot + +You want to receive a notification on every device (re-)boot? Quite easy, +just add: + + :global LogForwardIncludeMessage "(^router rebooted)"; + +This will match on every log message beginning with `router rebooted`. + --- [âŦ…ī¸ Go back to main README](../README.md) [âŦ†ī¸ Go back to top](#top) From 072d34947321fff4afa4e7df059874c3523eaccd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Jan 2023 11:15:55 +0100 Subject: [PATCH 1297/2612] log-forward: cache the result of $LogForwardFilterLogForwarding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks like the function is called for every message to match otherwise. đŸ˜ŗ --- log-forward | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-forward b/log-forward index 73620e8..96cb257 100644 --- a/log-forward +++ b/log-forward @@ -47,8 +47,9 @@ $ScriptLock $0; :local MessageVal; :local MessageDups ({}); +:local LogForwardFilterLogForwardingCached [ $EitherOr [ $LogForwardFilterLogForwarding ] ("\$^") ]; :foreach Message in=[ /log/find where (!(message="") and \ - !(message~[ $EitherOr [ $LogForwardFilterLogForwarding ] ("\$^") ]) and \ + !(message~$LogForwardFilterLogForwardingCached) and \ !(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \ topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={ :set MessageVal [ /log/get $Message ]; From b834517baac25495a9376b255cedb670545c74ad Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Jan 2023 08:54:22 +0100 Subject: [PATCH 1298/2612] global-functions: implement $Grep... ... that returns the first line that matches a pattern. --- global-functions | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/global-functions b/global-functions index cfd9091..ac5770b 100644 --- a/global-functions +++ b/global-functions @@ -30,6 +30,7 @@ :global GetRandom20CharAlNum; :global GetRandom20CharHex; :global GetRandomNumber; +:global Grep; :global HexToNum; :global IfThenElse; :global IsDefaultRouteReachable; @@ -367,6 +368,26 @@ :return [ :rndnum from=0 to=[ $EitherOr [ :tonum $1 ] 4294967295 ] ]; } +# return first line that matches a pattern +:set Grep do={ + :local Input ([ :tostr $1 ] . "\n"); + :local Pattern [ :tostr $2 ]; + + :if ([ :typeof [ :find $Input $Pattern ] ] = "nil") do={ + :return []; + } + + :do { + :local Line [ :pick $Input 0 [ :find $Input "\n" ] ]; + :if ([ :typeof [ :find $Line $Pattern ] ] = "num") do={ + :return $Line; + } + :set Input [ :pick $Input ([ :find $Input "\n" ] + 1) [ :len $Input ] ]; + } while=([ :len $Input ] > 0); + + :return []; +} + # convert from hex (string) to num :set HexToNum do={ :local Input [ :tostr $1 ]; From 9887ab084996cd8babd60c534edd5f7ff87e49f3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Jan 2023 08:58:46 +0100 Subject: [PATCH 1299/2612] lease-script: use $Grep --- lease-script | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lease-script b/lease-script index 2ad8e66..346d52b 100644 --- a/lease-script +++ b/lease-script @@ -10,6 +10,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:global Grep; :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; @@ -34,14 +35,10 @@ $ScriptLock $0 false 10; :local RunOrder ({}); :foreach Script in=[ /system/script/find where source~("\n# provides: lease-script, ") ] do={ - :local Name [ /system/script/get $Script name ]; - :local Store [ /system/script/get $Script source ]; + :local ScriptVal [ /system/script/get $Script ]; + :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") "# provides: lease-script, " ] ]; - :set Store [ :pick $Store ([ :find $Store "\n# provides: lease-script, " ] + 27) [ :len $Store ] ]; - :set Store [ :pick $Store 0 [ :find $Store "\n" ] ]; - :set Store [ $ParseKeyValueStore $Store ]; - - :set ($RunOrder->($Store->"order")) $Name; + :set ($RunOrder->($Store->"order")) ($ScriptVal->"name"); } :foreach Order,Script in=$RunOrder do={ From de9dde1b1418e6d5a93f16a027b6208ca89394bf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 19 Jan 2023 22:43:03 +0100 Subject: [PATCH 1300/2612] global-functions: $ScriptInstallUpdate: add a version check for scripts New RouterOS releases bring new features, and thus new syntax. Installing a new script on old RouterOS results in syntax errors. We want to give clear warning messages, so by adding an extra comment into the script... # requires RouterOS, version=7.8beta3 ... installing on unsupported RouterOS version is mitigated. --- global-functions | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/global-functions b/global-functions index ac5770b..78af95d 100644 --- a/global-functions +++ b/global-functions @@ -700,9 +700,12 @@ :global ScriptUpdatesUrlSuffix; :global CertificateAvailable; + :global EitherOr; + :global Grep; :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; + :global RequiredRouterOS; :global SendNotification2; :global SymbolForNotification; :global ValidateSyntax; @@ -773,18 +776,24 @@ :if ([ :len $SourceNew ] > 0) do={ :if ($SourceNew != $ScriptVal->"source") do={ :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ - :if ([ $ValidateSyntax $SourceNew ] = true) do={ - $LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; - /system/script/set owner=($ScriptVal->"name") source=$SourceNew $Script; - :if ($ScriptVal->"name" = "global-config") do={ - :set ReloadGlobalConfig true; - } - :if ($ScriptVal->"name" = "global-functions" || $ScriptVal->"name" ~ ("^mod/.")) do={ - :set ReloadGlobalFunctions true; + :local Required ([ $ParseKeyValueStore [ $Grep $SourceNew "# requires RouterOS, " ] ]->"version"); + :if ([ $RequiredRouterOS $0 [ $EitherOr $Required "0.0" ] false ] = true) do={ + :if ([ $ValidateSyntax $SourceNew ] = true) do={ + $LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; + /system/script/set owner=($ScriptVal->"name") source=$SourceNew $Script; + :if ($ScriptVal->"name" = "global-config") do={ + :set ReloadGlobalConfig true; + } + :if ($ScriptVal->"name" = "global-functions" || $ScriptVal->"name" ~ ("^mod/.")) do={ + :set ReloadGlobalFunctions true; + } + } else={ + $LogPrintExit2 warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . \ + "' failed! Ignoring!") false; } } else={ - $LogPrintExit2 warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . \ - "' failed! Ignoring!") false; + $LogPrintExit2 warning $0 ("The script '" . $ScriptVal->"name" . "' requires RouterOS " . \ + $Required . ", which is not met by your installation. Ignoring!") false; } } else={ $LogPrintExit2 warning $0 ("Looks like new script '" . $ScriptVal->"name" . \ From 9033e169210e620b1d2bef1c9ade2b70e82424e6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 19 Jan 2023 22:50:51 +0100 Subject: [PATCH 1301/2612] global-functions: use new functionality for version check --- global-functions | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 78af95d..da6e112 100644 --- a/global-functions +++ b/global-functions @@ -4,6 +4,8 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.1 +# # global functions # https://git.eworm.de/cgit/routeros-scripts/about/ @@ -1233,9 +1235,6 @@ } } -# check for required RouterOS version -$RequiredRouterOS $0 "7.1" true; - # load modules :foreach Script in=[ /system/script/find where name ~ "^mod/." ] do={ :local ScriptVal [ /system/script/get $Script ]; From 2694f8d2b1d15d16fa5f062612dd7fcf2d392ea8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Jan 2023 11:04:52 +0100 Subject: [PATCH 1302/2612] global-functions: $RequiredRouterOS: check for valid version string --- global-functions | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/global-functions b/global-functions index da6e112..bfb7b01 100644 --- a/global-functions +++ b/global-functions @@ -656,6 +656,12 @@ :global IfThenElse; :global LogPrintExit2; :global VersionToNum; + + :if (!($Required ~ "^\\d+\\.\\d+((beta|rc|\\.)\\d+|)\$")) do={ + $LogPrintExit2 error $0 ("No valid RouterOS version: " . $Required) false; + :return false; + } + :if ([ $VersionToNum $Required ] > [ $VersionToNum [ /system/package/update/get installed-version ] ]) do={ :if ($Warn = "true") do={ $LogPrintExit2 warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = ("\$")) "function" "script" ] . \ From 75bd14267e7a5507e0d58b9945dbb24e5d831af8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Jan 2023 14:24:20 +0100 Subject: [PATCH 1303/2612] check-health: monitor CPU load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- âœ‚ī¸ ---- đŸ§Žī¸đŸ“ˆī¸ Health warning: CPU load The average CPU load on MikroTik is at 76%! ---- âœ‚ī¸ ---- đŸ§Žī¸đŸ“‰ī¸ Health recovery: CPU load The average CPU load on MikroTik decreased to 64%. ---- âœ‚ī¸ ---- --- check-health | 16 ++++++++++++++ .../notification-01-cpu-load-high.avif | Bin 0 -> 6066 bytes .../notification-02-cpu-load-ok.avif | Bin 0 -> 6378 bytes ...tage.avif => notification-03-voltage.avif} | Bin ... => notification-04-temperature-high.avif} | Bin ...if => notification-05-temperature-ok.avif} | Bin ...ail.avif => notification-06-psu-fail.avif} | Bin ...su-ok.avif => notification-07-psu-ok.avif} | Bin doc/check-health.md | 20 ++++++++++++------ global-functions | 1 + 10 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 doc/check-health.d/notification-01-cpu-load-high.avif create mode 100644 doc/check-health.d/notification-02-cpu-load-ok.avif rename doc/check-health.d/{notification-01-voltage.avif => notification-03-voltage.avif} (100%) rename doc/check-health.d/{notification-02-temperature-high.avif => notification-04-temperature-high.avif} (100%) rename doc/check-health.d/{notification-03-temperature-ok.avif => notification-05-temperature-ok.avif} (100%) rename doc/check-health.d/{notification-04-psu-fail.avif => notification-06-psu-fail.avif} (100%) rename doc/check-health.d/{notification-05-psu-ok.avif => notification-07-psu-ok.avif} (100%) diff --git a/check-health b/check-health index e754d69..3957ad1 100644 --- a/check-health +++ b/check-health @@ -10,6 +10,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:global CheckHealthCPULoad; +:global CheckHealthCPULoadNotified; :global CheckHealthLast; :global CheckHealthTemperature; :global CheckHealthTemperatureDeviation; @@ -43,6 +45,20 @@ $ScriptLock $0; +:set CheckHealthCPULoad (($CheckHealthCPULoad * 4 + [ /system/resource/get cpu-load ] * 10) / 5); +:if ($CheckHealthCPULoad > 750 && $CheckHealthCPULoadNotified != true) do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "abacus,chart-increasing" ] . "Health warning: CPU load"); \ + message=("The average CPU load on " . $Identity . " is at " . ($CheckHealthCPULoad / 10) . "%!") }); + :set CheckHealthCPULoadNotified true; +} +:if ($CheckHealthCPULoad < 650 && $CheckHealthCPULoadNotified = true) do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "abacus,chart-decreasing" ] . "Health recovery: CPU load"); \ + message=("The average CPU load on " . $Identity . " decreased to " . ($CheckHealthCPULoad / 10) . "%.") }); + :set CheckHealthCPULoadNotified false; +} + :foreach Voltage in=[ /system/health/find where type="V" ] do={ :local Name [ /system/health/get $Voltage name ]; :local Value [ /system/health/get $Voltage value ]; diff --git a/doc/check-health.d/notification-01-cpu-load-high.avif b/doc/check-health.d/notification-01-cpu-load-high.avif new file mode 100644 index 0000000000000000000000000000000000000000..3c1a4685af3340f8bb446b4efd39b718f9198d19 GIT binary patch literal 6066 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 literal 0 HcmV?d00001 diff --git a/doc/check-health.d/notification-02-cpu-load-ok.avif b/doc/check-health.d/notification-02-cpu-load-ok.avif new file mode 100644 index 0000000000000000000000000000000000000000..4f12b700e27c3bfa533d6b1c38a8f00dd8be7899 GIT binary patch literal 6378 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 Date: Fri, 20 Jan 2023 14:34:18 +0100 Subject: [PATCH 1304/2612] check-health: monitor free RAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- âœ‚ī¸ ---- đŸ—ƒī¸đŸ“‰ī¸ Health warning: free RAM The available free RAM on MikroTik is at 18% (47MiB)! ---- âœ‚ī¸ ---- đŸ—ƒī¸đŸ“ˆī¸ Health recovery: free RAM The available free RAM on MikroTik increased to 65% (168MiB). ---- âœ‚ī¸ ---- --- check-health | 22 +++++++++++++++++- .../notification-03-free-ram-low.avif | Bin 0 -> 6426 bytes .../notification-04-free-ram-ok.avif | Bin 0 -> 6716 bytes ...tage.avif => notification-05-voltage.avif} | Bin ... => notification-06-temperature-high.avif} | Bin ...if => notification-07-temperature-ok.avif} | Bin ...ail.avif => notification-08-psu-fail.avif} | Bin ...su-ok.avif => notification-09-psu-ok.avif} | Bin doc/check-health.md | 21 +++++++++++------ global-functions | 1 + 10 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 doc/check-health.d/notification-03-free-ram-low.avif create mode 100644 doc/check-health.d/notification-04-free-ram-ok.avif rename doc/check-health.d/{notification-03-voltage.avif => notification-05-voltage.avif} (100%) rename doc/check-health.d/{notification-04-temperature-high.avif => notification-06-temperature-high.avif} (100%) rename doc/check-health.d/{notification-05-temperature-ok.avif => notification-07-temperature-ok.avif} (100%) rename doc/check-health.d/{notification-06-psu-fail.avif => notification-08-psu-fail.avif} (100%) rename doc/check-health.d/{notification-07-psu-ok.avif => notification-09-psu-ok.avif} (100%) diff --git a/check-health b/check-health index 3957ad1..55ad8ab 100644 --- a/check-health +++ b/check-health @@ -12,6 +12,7 @@ :global CheckHealthCPULoad; :global CheckHealthCPULoadNotified; +:global CheckHealthFreeRAMNotified; :global CheckHealthLast; :global CheckHealthTemperature; :global CheckHealthTemperatureDeviation; @@ -45,7 +46,9 @@ $ScriptLock $0; -:set CheckHealthCPULoad (($CheckHealthCPULoad * 4 + [ /system/resource/get cpu-load ] * 10) / 5); +:local Resource [ /system/resource/get ]; + +:set CheckHealthCPULoad (($CheckHealthCPULoad * 4 + ($Resource->"cpu-load") * 10) / 5); :if ($CheckHealthCPULoad > 750 && $CheckHealthCPULoadNotified != true) do={ $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "abacus,chart-increasing" ] . "Health warning: CPU load"); \ @@ -59,6 +62,23 @@ $ScriptLock $0; :set CheckHealthCPULoadNotified false; } +:local CheckHealthFreeRAM ($Resource->"free-memory" * 100 / $Resource->"total-memory"); +:if ($CheckHealthFreeRAM < 20 && $CheckHealthFreeRAMNotified != true) do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "card-file-box,chart-decreasing" ] . "Health warning: free RAM"); \ + message=("The available free RAM on " . $Identity . " is at " . $CheckHealthFreeRAM . "% (" . \ + ($Resource->"free-memory" / 1024 / 1024) . "MiB)!") }); + :set CheckHealthFreeRAMNotified true; +} +:if ($CheckHealthFreeRAM > 30 && $CheckHealthFreeRAMNotified = true) do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "card-file-box,chart-increasing" ] . "Health recovery: free RAM"); \ + message=("The available free RAM on " . $Identity . " increased to " . $CheckHealthFreeRAM . "% (" . \ + ($Resource->"free-memory" / 1024 / 1024) . "MiB).") }); + :set CheckHealthFreeRAMNotified false; +} + + :foreach Voltage in=[ /system/health/find where type="V" ] do={ :local Name [ /system/health/get $Voltage name ]; :local Value [ /system/health/get $Voltage value ]; diff --git a/doc/check-health.d/notification-03-free-ram-low.avif b/doc/check-health.d/notification-03-free-ram-low.avif new file mode 100644 index 0000000000000000000000000000000000000000..6f45fcf22a310e721bd245da45db20aa82c73324 GIT binary patch literal 6426 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 literal 0 HcmV?d00001 diff --git a/doc/check-health.d/notification-03-voltage.avif b/doc/check-health.d/notification-05-voltage.avif similarity index 100% rename from doc/check-health.d/notification-03-voltage.avif rename to doc/check-health.d/notification-05-voltage.avif diff --git a/doc/check-health.d/notification-04-temperature-high.avif b/doc/check-health.d/notification-06-temperature-high.avif similarity index 100% rename from doc/check-health.d/notification-04-temperature-high.avif rename to doc/check-health.d/notification-06-temperature-high.avif diff --git a/doc/check-health.d/notification-05-temperature-ok.avif b/doc/check-health.d/notification-07-temperature-ok.avif similarity index 100% rename from doc/check-health.d/notification-05-temperature-ok.avif rename to doc/check-health.d/notification-07-temperature-ok.avif diff --git a/doc/check-health.d/notification-06-psu-fail.avif b/doc/check-health.d/notification-08-psu-fail.avif similarity index 100% rename from doc/check-health.d/notification-06-psu-fail.avif rename to doc/check-health.d/notification-08-psu-fail.avif diff --git a/doc/check-health.d/notification-07-psu-ok.avif b/doc/check-health.d/notification-09-psu-ok.avif similarity index 100% rename from doc/check-health.d/notification-07-psu-ok.avif rename to doc/check-health.d/notification-09-psu-ok.avif diff --git a/doc/check-health.md b/doc/check-health.md index b498998..3b0c4ae 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -13,14 +13,16 @@ This script is run from scheduler periodically, sending notification on health related events: * high CPU load +* low available free RAM * voltage jumps up or down more than configured threshold or drops below limit * power supply failed or recovered * temperature is above or below threshold Note that bad initial state will not trigger an event. -Monitoring CPU load works on all devices. Other than that only sensors -available in hardware can be checked. See what your hardware supports: +Monitoring CPU load and available free RAM works on all devices. Other +than that only sensors available in hardware can be checked. See what your +hardware supports: /system/health/print; @@ -31,19 +33,24 @@ available in hardware can be checked. See what your hardware supports: ![check-health notification cpu load high](check-health.d/notification-01-cpu-load-high.avif) ![check-health notification cpu load ok](check-health.d/notification-02-cpu-load-ok.avif) +#### Available free RAM + +![check-health notification free ram low](check-health.d/notification-03-free-ram-low.avif) +![check-health notification free ram ok](check-health.d/notification-04-free-ram-ok.avif) + #### Voltage -![check-health notification voltage](check-health.d/notification-03-voltage.avif) +![check-health notification voltage](check-health.d/notification-05-voltage.avif) #### Temperature -![check-health notification temperature high](check-health.d/notification-04-temperature-high.avif) -![check-health notification temperature ok](check-health.d/notification-05-temperature-ok.avif) +![check-health notification temperature high](check-health.d/notification-06-temperature-high.avif) +![check-health notification temperature ok](check-health.d/notification-07-temperature-ok.avif) #### PSU state -![check-health notification psu fail](check-health.d/notification-06-psu-fail.avif) -![check-health notification psu ok](check-health.d/notification-07-psu-ok.avif) +![check-health notification psu fail](check-health.d/notification-08-psu-fail.avif) +![check-health notification psu ok](check-health.d/notification-09-psu-ok.avif) Requirements and installation ----------------------------- diff --git a/global-functions b/global-functions index 0e94dea..1ed5248 100644 --- a/global-functions +++ b/global-functions @@ -1078,6 +1078,7 @@ "abacus"="\F0\9F\A7\AE"; "alarm-clock"="\E2\8F\B0"; "calendar"="\F0\9F\93\85"; + "card-file-box"="\F0\9F\97\83"; "chart-decreasing"="\F0\9F\93\89"; "chart-increasing"="\F0\9F\93\88"; "cloud"="\E2\98\81"; From e9a426a7980d70ec9acfe79ed7b7aae53f8d594d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Jan 2023 14:37:50 +0100 Subject: [PATCH 1305/2612] check-health: silently exit without health readings... ... but after checking CPU load and free RAM. --- check-health | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/check-health b/check-health index 55ad8ab..a9a9dbf 100644 --- a/check-health +++ b/check-health @@ -33,17 +33,6 @@ :return ($T->0 * 10 + $T->1); } -:if ([ :len [ /system/health/find ] ] = 0) do={ - $LogPrintExit2 error $0 ("Your device does not provide any health values.") true; -} - -:if ([ :typeof $CheckHealthLast ] != "array") do={ - :set CheckHealthLast ({}); -} -:if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ - :set CheckHealthTemperatureNotified ({}); -} - $ScriptLock $0; :local Resource [ /system/resource/get ]; @@ -78,6 +67,17 @@ $ScriptLock $0; :set CheckHealthFreeRAMNotified false; } +:if ([ :len [ /system/health/find ] ] = 0) do={ + $LogPrintExit2 debug $0 ("Your device does not provide any health values.") true; +} + +:if ([ :typeof $CheckHealthLast ] != "array") do={ + :set CheckHealthLast ({}); +} +:if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ + :set CheckHealthTemperatureNotified ({}); +} + :foreach Voltage in=[ /system/health/find where type="V" ] do={ :local Name [ /system/health/get $Voltage name ]; From e6c256cd4b74599f3f539ca2c48adab91bd5ee8e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 Jan 2023 16:10:57 +0100 Subject: [PATCH 1306/2612] check-health: notify about new features --- global-config.changes | 1 + global-functions | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/global-config.changes b/global-config.changes index 5dd7616..dacb9a1 100644 --- a/global-config.changes +++ b/global-config.changes @@ -96,6 +96,7 @@ 85="Dropped 'netwatch-syslog', filtering in firewall is advised."; 86="Added support for hooks in 'sms-forward'. This now provides similar functionality to 'sms-action', but is more flexible."; 87="Added support for extra text (or emojis \F0\9F\9A\80) in notification tags."; + 88="Added support for monitoring CPU load and available free RAM in 'check-health'."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 1ed5248..d969653 100644 --- a/global-functions +++ b/global-functions @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 87; +:global ExpectedConfigVersion 88; # global variables not to be changed by user :global GlobalFunctionsReady false; From c7498c6397b706d191741d0a6634d4adfbd4c0db Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 22 Jan 2023 12:16:06 +0100 Subject: [PATCH 1307/2612] daily-psk: fixes for CAPsMAN --- daily-psk.capsman | 7 ++++--- daily-psk.template | 8 +++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/daily-psk.capsman b/daily-psk.capsman index 46e4e1d..81cb5a2 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -60,8 +60,9 @@ $WaitFullyConnected; :local NewPsk [ $GeneratePSK $Date ]; :foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ - :local Ssid [ /caps-man/access-list/get $AccList ssid-regexp ]; - :local Configuration [ /caps-man/configuration/get ([ find where ssid=$Ssid ]->0) name ]; + :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; + :local Configuration ([ /caps-man/configuration/find where ssid~$SsidRegExp ]->0); + :local Ssid [ /caps-man/configuration/get $Configuration ssid ]; :local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ]; :local Skip 0; @@ -69,7 +70,7 @@ $WaitFullyConnected; $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; /caps-man/access-list/set $AccList private-passphrase=$NewPsk; - :if ([ :len [ /caps-man/interface/find where configuration=$Configuration ] ] > 0) do={ + :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; diff --git a/daily-psk.template b/daily-psk.template index 373cc96..811f2f8 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -63,9 +63,11 @@ $WaitFullyConnected; :foreach AccList in=[ /%PATH%/access-list/find where comment~$DailyPskMatchComment ] do={ :local IntName [ /interface/wireless/access-list/get $AccList interface ]; :local Ssid [ /interface/wireless/get $IntName ssid ]; - :local Ssid [ /caps-man/access-list/get $AccList ssid-regexp ]; - :local Configuration [ /caps-man/configuration/get ([ find where ssid=$Ssid ]->0) name ]; :local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ]; + # /interface/wireless above - /caps-man below + :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; + :local Configuration ([ /caps-man/configuration/find where ssid~$SsidRegExp ]->0); + :local Ssid [ /caps-man/configuration/get $Configuration ssid ]; :local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ]; :local Skip 0; @@ -75,7 +77,7 @@ $WaitFullyConnected; /caps-man/access-list/set $AccList private-passphrase=$NewPsk; :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ - :if ([ :len [ /caps-man/interface/find where configuration=$Configuration ] ] > 0) do={ + :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; From c8dcd92e6b03af17b2585188629d3949aaf75601 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 22 Jan 2023 13:30:59 +0100 Subject: [PATCH 1308/2612] global-functions: $MkDir: create with reasonable tmpfs-max-size Giving no tmpfs-max-size breaks with RouterOS 7.8beta2, where a size limit is enforced. --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index d969653..e674d7d 100644 --- a/global-functions +++ b/global-functions @@ -574,7 +574,7 @@ :if ([ :len [ /disk/find where slot=tmpfs type=tmpfs ] ] = 0) do={ $LogPrintExit2 info $0 ("Creating disk of type tmpfs.") false; /file/remove [ find where name="tmpfs" type="directory" ]; - [ :parse "/disk/add slot=tmpfs type=tmpfs;" ]; + [ :parse "/disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/get total-memory ] / 3);" ]; } :set Continue true; } From f9839647d46f87a5ffef3a8410bca3ef0812c41d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 22 Jan 2023 13:44:57 +0100 Subject: [PATCH 1309/2612] global-functions: $MkDir: catch error on creating tmpfs --- global-functions | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index e674d7d..9654824 100644 --- a/global-functions +++ b/global-functions @@ -574,7 +574,13 @@ :if ([ :len [ /disk/find where slot=tmpfs type=tmpfs ] ] = 0) do={ $LogPrintExit2 info $0 ("Creating disk of type tmpfs.") false; /file/remove [ find where name="tmpfs" type="directory" ]; - [ :parse "/disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/get total-memory ] / 3);" ]; + :do { + [ :parse "/disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/get total-memory ] / 3);" ]; + $WaitForFile "tmpfs"; + } on-error={ + $LogPrintExit2 warning $0 ("Creating disk of type tmpfs failed!") false; + :set Error true; + } } :set Continue true; } From 36a8938dead84e97b6de67b2911e2186d12123a3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 23 Jan 2023 17:42:49 +0100 Subject: [PATCH 1310/2612] doc/check-certificates: document the renew time --- doc/check-certificates.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 6ce2ec7..76357ce 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -30,6 +30,7 @@ For automatic download and renewal of certificates you need configuration in `global-config-overlay`, these are the parameters: * `CertRenewPass`: an array of passphrases to try +* `CertRenewTime`: on what remaining time to try a renew * `CertRenewUrl`: the url to download certificates from Certificates on the web server should be named `CN.pem` (`PEM` format) or From 555d0e8bfc8d3773fa05302303b43ed43e5f27a1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 23 Jan 2023 17:27:34 +0100 Subject: [PATCH 1311/2612] check-certificates: make the warning time configurable --- check-certificates | 4 +++- doc/check-certificates.md | 1 + global-config | 1 + global-config.changes | 1 + global-functions | 2 +- 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/check-certificates b/check-certificates index 9802cde..2bf2443 100644 --- a/check-certificates +++ b/check-certificates @@ -13,6 +13,7 @@ :global CertRenewPass; :global CertRenewTime; :global CertRenewUrl; +:global CertWarnTime; :global Identity; :global CertificateAvailable @@ -103,7 +104,8 @@ $WaitFullyConnected; } } -:foreach Cert in=[ /certificate/find where !revoked !scep-url !(expires-after=[]) expires-after<2w !(fingerprint=[]) ] do={ +: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={ diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 76357ce..80f6aee 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -32,6 +32,7 @@ in `global-config-overlay`, these are the parameters: * `CertRenewPass`: an array of passphrases to try * `CertRenewTime`: on what remaining time to try a renew * `CertRenewUrl`: the url to download certificates from +* `CertWarnTime`: on what remaining time to warn via notification Certificates on the web server should be named `CN.pem` (`PEM` format) or `CN.p12` (`PKCS#12` format). diff --git a/global-config b/global-config index bd632a1..dcd7a09 100644 --- a/global-config +++ b/global-config @@ -194,6 +194,7 @@ "v3ry-s3cr3t"; "4n0th3r-s3cr3t"; } +:global CertWarnTime 2w; :global CertIssuedExportPass { "cert1-cn"="v3ry-s3cr3t"; "cert2-cn"="4n0th3r-s3cr3t"; diff --git a/global-config.changes b/global-config.changes index dacb9a1..2ae335e 100644 --- a/global-config.changes +++ b/global-config.changes @@ -97,6 +97,7 @@ 86="Added support for hooks in 'sms-forward'. This now provides similar functionality to 'sms-action', but is more flexible."; 87="Added support for extra text (or emojis \F0\9F\9A\80) in notification tags."; 88="Added support for monitoring CPU load and available free RAM in 'check-health'."; + 89="Made the warning time for 'check-certificates' configurable."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 9654824..58c025e 100644 --- a/global-functions +++ b/global-functions @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 88; +:global ExpectedConfigVersion 89; # global variables not to be changed by user :global GlobalFunctionsReady false; From 5c3585cd98dc18cee81b74a8040119bc7b5f031b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 24 Jan 2023 13:18:17 +0100 Subject: [PATCH 1312/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index e89f8f5..efa418c 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -28,6 +28,7 @@ Add yourself to the list, * Christoph Boss (@Kampfwurst) * Devin Dean (@dd2594gh) * Evaldo Gardenal +* Hugo BV * Klaus Michael RÃŧbsam * Linux-Schmie.de Michael Gisbers * Manuel Kuhn From b0d3e3d5f4775883554823ec26df36b00e4a5544 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Jan 2023 21:04:59 +0100 Subject: [PATCH 1313/2612] global-functions: $LogPrintExit2: always print the message... ... even on error. Not sure why and when this broke. --- global-functions | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/global-functions b/global-functions index 58c025e..dfb76f7 100644 --- a/global-functions +++ b/global-functions @@ -531,11 +531,11 @@ } :if ($Severity != "debug" || $Debug = true) do={ - :if ($Exit = "true") do={ - :error ([ $PrintSeverity $Severity ] . ": " . $Message); - } else={ - :put ([ $PrintSeverity $Severity ] . ": " . $Message); - } + :put ([ $PrintSeverity $Severity ] . ": " . $Message); + } + + :if ($Exit = "true") do={ + :error ("Hard error to exit."); } } From f62328ee8db1aee7efa199081f9d52bba0e61eb2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Jan 2023 21:20:10 +0100 Subject: [PATCH 1314/2612] check-certificates: handle decryption failures and warn If a download succeeds at least one of the given passphrases is expected to decrypt a key in the file. --- check-certificates | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/check-certificates b/check-certificates index 2bf2443..8a06f8b 100644 --- a/check-certificates +++ b/check-certificates @@ -49,11 +49,20 @@ $WaitFullyConnected; /tool/fetch check-certificate=yes-without-crl \ ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; $WaitForFile $CertFileName; + + :local DecryptionFailed true; :foreach PassPhrase in=$CertRenewPass do={ - /certificate/import file-name=$CertFileName passphrase=$PassPhrase as-value; + :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~("^" . $CertFileName . "_[0-9]+\$") common-name!=($CertVal->"common-name") ] do={ $CertificateNameByCN [ /certificate/get $CertInChain common-name ]; } From f666d2f8fffd7cefc4aa590533f47e7c7d14abd7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 31 Jan 2023 14:59:13 +0100 Subject: [PATCH 1315/2612] global-functions: $WaitForFile: allow to give iterations... ... to increase timeout. Every iteration is about 100ms. --- global-functions | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index dfb76f7..165ac9a 100644 --- a/global-functions +++ b/global-functions @@ -1213,14 +1213,16 @@ # wait for file to be available :set WaitForFile do={ :local FileName [ :tostr $1 ]; + :local Iter [ :tonum $2 ]; :global CleanFilePath; + :global EitherOr; :set FileName [ $CleanFilePath $FileName ]; :local I 0; :while ([ :len [ /file/find where name=$FileName ] ] = 0) do={ - :if ($I > 20) do={ + :if ($I > [ $EitherOr $Iter 20 ]) do={ :return false; } :delay 100ms; From 819c7294c62c84fbc59bbf16a7d9ce97b4957e57 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 30 Jan 2023 16:08:00 +0100 Subject: [PATCH 1316/2612] introduce telegram-chat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Druvis from Mikrotik produced a video "MikroTik Telegram bot - Chat with your Router?". He shows his script to chat with a Router via Telegram bot to send it commands: https://youtu.be/KLX6j3sLRIE This script is kind of limited and has several issues... đŸĨ´ Let's make it robust, usable, multi-device capable and just fun! 😁 (Sadly Mikrotik has a policy to not allow links in Youtube comments. Thus my comment with several hints was removed immediately. If anybody is in contact with Druvis... Please tell him about this script!) --- README.md | 1 + doc/mod/notification-telegram.md | 1 + doc/telegram-chat.d/01-chat-specific.avif | Bin 0 -> 31869 bytes doc/telegram-chat.d/02-chat-all.avif | Bin 0 -> 48099 bytes doc/telegram-chat.md | 89 ++++++++++++++++ global-config | 8 ++ global-config.changes | 1 + global-functions | 3 +- telegram-chat | 120 ++++++++++++++++++++++ 9 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 doc/telegram-chat.d/01-chat-specific.avif create mode 100644 doc/telegram-chat.d/02-chat-all.avif create mode 100644 doc/telegram-chat.md create mode 100644 telegram-chat diff --git a/README.md b/README.md index a5a2894..42f897b 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,7 @@ Available scripts * [Forward received SMS](doc/sms-forward.md) * [Import SSH keys](doc/ssh-keys-import.md) * [Play Super Mario theme](doc/super-mario-theme.md) +* [Chat with your router and send commands via Telegram bot](doc/telegram-chat.md) * [Install LTE firmware upgrade](doc/unattended-lte-firmware-upgrade.md) * [Update GRE configuration with dynamic addresses](doc/update-gre-address.md) * [Update tunnelbroker configuration](doc/update-tunnelbroker.md) diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index b55739a..5e6c1a0 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -66,6 +66,7 @@ methods: See also -------- +* [Chat with your router and send commands via Telegram bot](../telegram-chat.md) * [Send notifications via e-mail](notification-email.md) * [Send notifications via Matrix](notification-matrix.md) diff --git a/doc/telegram-chat.d/01-chat-specific.avif b/doc/telegram-chat.d/01-chat-specific.avif new file mode 100644 index 0000000000000000000000000000000000000000..387dc3aa207d4205622e44e403dec4449f522268 GIT binary patch literal 31869 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 literal 0 HcmV?d00001 diff --git a/doc/telegram-chat.d/02-chat-all.avif b/doc/telegram-chat.d/02-chat-all.avif new file mode 100644 index 0000000000000000000000000000000000000000..32fc1812428cc9ff06611468fc4fab7f102c6cde GIT binary patch literal 48099 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 â„šī¸ **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. + +Description +----------- + +This script makes your device poll a Telegram bot for new messages. With +these messages you can send commands to your device and make it run them. +The resulting output is send back to you. + +Requirements and installation +----------------------------- + +Just install the script and the module for notifications via Telegram: + + $ScriptInstallUpdate telegram-chat,mod/notification-telegram; + +Then create a schedule that runs the script periodically: + + /system/scheduler/add start-time=startup interval=30s name=telegram-chat on-event="/system/script/run telegram-chat;"; + +> âš ī¸ **Warning**: Make sure to keep the interval in sync when installing +> on several devices. Differing polling intervals will result in missed +> messages. + +Configuration +------------- + +Make sure to configure +[notifications via telegram](mod/notification-telegram.md) first. The +additional configuration goes to `global-config-overlay`, these are the +parameters: + +* `TelegramChatIdsTrusted`: an array with trusted chat ids or user names +* `TelegramChatGroups`: define the groups a device should belong to + +Usage and invocation +-------------------- + +This script is capable of chatting with multiple devices. By default a +device is passive and not acting on messages. To activate it send a message +containing `! identity` (exclamation mark, optional space and system's +identity). To query all dynamic ip addresses form a device named "*MikroTik*" +send `! MikroTik`, followed by `/ip/address/print where dynamic;`. + +![chat to specific device](telegram-chat.d/01-chat-specific.avif) + +Devices can be grouped to chat with them simultaneously. The default group +"*all*" can be activated by sending `! @all`, which will make all devices +act on your commands. + +![chat to all devices](telegram-chat.d/02-chat-all.avif) + +Send a single exclamation mark or non-existent identity to make all +devices passive again. + +Known limitations +----------------- + +### Do not use numeric ids! + +Numeric ids are valid within a session only. Usually you can use something +like this to print all ip addresses and remove the first one: + + /ip/address/print; + /ip/address/remove 0; + +This will fail when sent in separate messages. Instead you should use basic +scripting capabilities. Try to print what you want to act on... + + /ip/address/print where interface=eth; + +... verify and finally remove it. + + /ip/address/remove [ find where interface=eth ]; + +See also +-------- + +* [Send notifications via Telegram](mod/notification-telegram.md) + +--- +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/global-config b/global-config index dcd7a09..4b5338a 100644 --- a/global-config +++ b/global-config @@ -35,6 +35,14 @@ :global TelegramChatId ""; #:global TelegramTokenId "123456:ABCDEF-GHI"; #:global TelegramChatId "12345678"; +# Using telegram-chat you have to define trusted chat ids (not group ids!) +# or user names. Groups allow to chat with devices simultaneously. +#:global TelegramChatIdsTrusted { +# "12345678"; +# "example_user"; +#}; +:global TelegramChatGroups "(all)"; +#:global TelegramChatGroups "(all|home|office)"; # This is whether or not to send Telegram messages with fixed-width font. :global TelegramFixedWidthFont true; diff --git a/global-config.changes b/global-config.changes index 2ae335e..94da56c 100644 --- a/global-config.changes +++ b/global-config.changes @@ -98,6 +98,7 @@ 87="Added support for extra text (or emojis \F0\9F\9A\80) in notification tags."; 88="Added support for monitoring CPU load and available free RAM in 'check-health'."; 89="Made the warning time for 'check-certificates' configurable."; + 90="Chat with your router! Introduced 'telegram-chat' to chat via Telegram bot and send commands to your router."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 165ac9a..7fe3873 100644 --- a/global-functions +++ b/global-functions @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 89; +:global ExpectedConfigVersion 90; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -1101,6 +1101,7 @@ "pushpin"="\F0\9F\93\8C"; "scissors"="\E2\9C\82"; "sparkles"="\E2\9C\A8"; + "speech-balloon"="\F0\9F\92\AC"; "up-arrow"="\E2\AC\86"; "warning-sign"="\E2\9A\A0"; "white-heavy-check-mark"="\E2\9C\85" diff --git a/telegram-chat b/telegram-chat new file mode 100644 index 0000000..9c8261e --- /dev/null +++ b/telegram-chat @@ -0,0 +1,120 @@ +#!rsc by RouterOS +# RouterOS script: telegram-chat +# Copyright (c) 2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# use Telegram to chat with your Router and send commands +# https://git.eworm.de/cgit/routeros-scripts/about/doc/telegram-chat.md + +:local 0 "telegram-chat"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Identity; +:global TelegramChatActive; +:global TelegramChatGroups; +:global TelegramChatId; +:global TelegramChatIdsTrusted; +:global TelegramChatOffset; +:global TelegramTokenId; + +:global CertificateAvailable; +:global EscapeForRegEx; +:global GetRandom20CharAlNum; +:global IfThenElse; +:global LogPrintExit2; +:global MkDir; +:global ScriptLock; +:global SendTelegram2; +:global SymbolForNotification; +:global ValidateSyntax; +:global WaitForFile; +:global WaitFullyConnected; + +$ScriptLock $0; + +$WaitFullyConnected; + +:if ([ :typeof $TelegramChatOffset ] != "num") do={ + :set TelegramChatOffset 0; +} + +:if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; +} + +:local JsonGetKey do={ + :local Array [ :toarray $1 ]; + :local Key [ :tostr $2 ]; + + :for I from=0 to=([ :len $Array ] - 1) do={ + :if (($Array->$I) = $Key) do={ + :if ($Array->($I + 1) = ":") do={ + :return ($Array->($I + 2)); + } + :return [ :pick ($Array->($I + 1)) 1 [ :len ($Array->($I + 1)) ] ]; + } + } + + :return false; +} + +:local Data; +:do { + :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ + ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=" . \ + $TelegramChatOffset . "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); + :set Data [ :pick $Data ([ :find $Data "[" ] + 1) ([ :len $Data ] - 2) ]; +} on-error={ + $LogPrintExit2 info $0 ("Failed getting updates from Telegram.") true; +} + +:foreach Update in=[ :toarray $Data ] do={ + :local UpdateID [ $JsonGetKey $Update "update_id" ]; + :if ($UpdateID >= $TelegramChatOffset) do={ + :set TelegramChatOffset ($UpdateID + 1); + :local Trusted false; + :local Message [ $JsonGetKey $Update "message" ]; + :local From [ $JsonGetKey $Message "from" ]; + :local FromID [ $JsonGetKey $From "id" ]; + :local FromUserName [ $JsonGetKey $From "username" ]; + :foreach IdsTrusted in=($TelegramChatId, $TelegramChatIdsTrusted) do={ + :if ($FromID = $IdsTrusted || $FromUserName = $IdsTrusted) do={ + :set Trusted true; + } + } + + :if ($Trusted = true) do={ + :local Text [ $JsonGetKey $Message "text" ]; + :if ([ :pick $Text 0 1 ] = "!") do={ + :if ($Text ~ ("^! *(" . [ $EscapeForRegEx $Identity ] . "|@" . $TelegramChatGroups . ")\$")) do={ + :set TelegramChatActive true; + } else={ + :set TelegramChatActive false; + } + $LogPrintExit2 info $0 ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . "!") false; + } else={ + :if ($TelegramChatActive = true && [ :len $Text ] > 0) do={ + :if ([ $ValidateSyntax $Text ] = true) do={ + :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); + $MkDir "tmpfs/telegram-chat"; + $LogPrintExit2 info $0 ("Running command: " . $Text) false; + :exec script=($Text . "; :execute script=\":put\" file=" . $File . ".done") file=$File; + :if ([ $WaitForFile ($File . ".done.txt") 200 ] = false) do={ + $LogPrintExit2 warning $0 ("Command did not finish, possibly still running.") false; + } + :local Content [ /file/get ($File . ".txt") content ]; + $SendTelegram2 ({ origin=$0; silent=false; \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=("Command:\n" . $Text . "\n\nOutput:\n" . $Content) }); + /file/remove "tmpfs/telegram-chat"; + } else={ + $LogPrintExit2 warning $0 ("The command failed syntax validation: " . $Text) false; + } + } + } + } else={ + $LogPrintExit2 warning $0 ("Received a message from untrusted contact '" . $FromUserName . "' (ID " . $FromID . ")!") false; + } + } +} From cbc547332e511e1ae7a0658002e2cc595b3b1182 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 31 Jan 2023 12:35:19 +0100 Subject: [PATCH 1317/2612] check-routeros-update: drop check for cap This becomes complicated with legacy wireless and wifiwave2 package, old and new CAPsMAN. Let's just drop the check. --- check-routeros-update | 7 ------- doc/check-routeros-update.md | 1 - global-config | 2 -- global-config.changes | 1 + global-functions | 2 +- 5 files changed, 2 insertions(+), 11 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index ccc0d79..3e5a381 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -12,7 +12,6 @@ :global Identity; :global SafeUpdateNeighbor; -:global SafeUpdateOnCap; :global SafeUpdatePatch; :global SafeUpdateUrl; :global SentRouterosUpdateNotification; @@ -39,12 +38,6 @@ $ScriptLock $0; $WaitFullyConnected; -:if ([ /interface/wireless/cap/get enabled ] = true && \ - [ /caps-man/manager/get enabled ] = false && \ - $SafeUpdateOnCap != true) do={ - $LogPrintExit2 error $0 ("System is managed by CAPsMAN, not checking for RouterOS version.") true; -} - :if ([ :len [ /system/scheduler/find where name="reboot-for-update" ] ] > 0) do={ :error "A reboot for update is already scheduled."; } diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 696abe6..348acc6 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -51,7 +51,6 @@ safe versions from a web server. The configuration goes to `global-config-overlay`, this is the parameter: * `SafeUpdateNeighbor`: install updates automatically if seen in neighbor list -* `SafeUpdateOnCap`: check for updates even if device is managed by CAPsMAN * `SafeUpdatePatch`: install patch updates automatically * `SafeUpdateUrl`: url to check for safe update, the channel (`long-term`, `stable` or `testing`) is appended diff --git a/global-config b/global-config index 4b5338a..1e7a185 100644 --- a/global-config +++ b/global-config @@ -104,8 +104,6 @@ :global SafeUpdatePatch false; # Allow to install updates automatically if seen in neighbor list. :global SafeUpdateNeighbor false; -# Allow to install updates even if device is managed by CAPsMAN. -:global SafeUpdateOnCap false; # These thresholds control when to send health notification # on temperature and voltage. diff --git a/global-config.changes b/global-config.changes index 94da56c..3db2a28 100644 --- a/global-config.changes +++ b/global-config.changes @@ -99,6 +99,7 @@ 88="Added support for monitoring CPU load and available free RAM in 'check-health'."; 89="Made the warning time for 'check-certificates' configurable."; 90="Chat with your router! Introduced 'telegram-chat' to chat via Telegram bot and send commands to your router."; + 91="Dropped check for CAP in 'check-routeros-update' to solve issues with wifiwave2 package."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 7fe3873..8d865ba 100644 --- a/global-functions +++ b/global-functions @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 90; +:global ExpectedConfigVersion 91; # global variables not to be changed by user :global GlobalFunctionsReady false; From 63de875129cc3eafff517410d6f90cb78fe459d5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 31 Jan 2023 14:19:05 +0100 Subject: [PATCH 1318/2612] daily-psk: make qr-code url configurable --- daily-psk.capsman | 3 ++- daily-psk.local | 3 ++- daily-psk.template | 3 ++- global-config | 1 + global-config.changes | 1 + global-functions | 2 +- 6 files changed, 9 insertions(+), 4 deletions(-) diff --git a/daily-psk.capsman b/daily-psk.capsman index 81cb5a2..17a09e1 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -14,6 +14,7 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global DailyPskMatchComment; +:global DailyPskQrCodeUrl; :global Identity; :global LogPrintExit2; @@ -80,7 +81,7 @@ $WaitFullyConnected; :if ($Skip = 0) do={ :set Seen ($Seen, $Ssid); - :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ + :local Link ($DailyPskQrCodeUrl . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ diff --git a/daily-psk.local b/daily-psk.local index 2af2414..17a60f7 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -14,6 +14,7 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global DailyPskMatchComment; +:global DailyPskQrCodeUrl; :global Identity; :global LogPrintExit2; @@ -79,7 +80,7 @@ $WaitFullyConnected; :if ($Skip = 0) do={ :set Seen ($Seen, $Ssid); - :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ + :local Link ($DailyPskQrCodeUrl . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ diff --git a/daily-psk.template b/daily-psk.template index 811f2f8..7e41a1f 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -15,6 +15,7 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global DailyPskMatchComment; +:global DailyPskQrCodeUrl; :global Identity; :global LogPrintExit2; @@ -87,7 +88,7 @@ $WaitFullyConnected; :if ($Skip = 0) do={ :set Seen ($Seen, $Ssid); - :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ + :local Link ($DailyPskQrCodeUrl . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ diff --git a/global-config b/global-config index 1e7a185..6096f14 100644 --- a/global-config +++ b/global-config @@ -121,6 +121,7 @@ # Access-list entries matching this comment are updated # with daily pseudo-random PSK. :global DailyPskMatchComment "Daily PSK"; +:global DailyPskQrCodeUrl "https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi"; :global DailyPskSecrets { { "Abusive"; "Aggressive"; "Bored"; "Chemical"; "Cold"; "Cruel"; "Curved"; "Delightful"; "Discreet"; "Elite"; diff --git a/global-config.changes b/global-config.changes index 3db2a28..33a340e 100644 --- a/global-config.changes +++ b/global-config.changes @@ -100,6 +100,7 @@ 89="Made the warning time for 'check-certificates' configurable."; 90="Chat with your router! Introduced 'telegram-chat' to chat via Telegram bot and send commands to your router."; 91="Dropped check for CAP in 'check-routeros-update' to solve issues with wifiwave2 package."; + 92="Made qr-code url configurable for 'daily-psk'."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 8d865ba..2f57fae 100644 --- a/global-functions +++ b/global-functions @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 91; +:global ExpectedConfigVersion 92; # global variables not to be changed by user :global GlobalFunctionsReady false; From 8b488cb82fa47a4fb9a2e2a65e5e01d78abb2022 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 31 Jan 2023 18:11:22 +0100 Subject: [PATCH 1319/2612] doc/telegram-chat: allow bots to receive messages in a group --- doc/telegram-chat.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index b245efa..388aa35 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -79,6 +79,12 @@ scripting capabilities. Try to print what you want to act on... /ip/address/remove [ find where interface=eth ]; +### Sending commands to a group + +Adding a bot to a group allows it to send messages to that group. To allow +it to receive messages you have to make it an admin of that group! It is +fine to deny all permissions, though. + See also -------- From 8f47bc9836b42c1e25367732793dcb02123d886d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Feb 2023 09:55:29 +0100 Subject: [PATCH 1320/2612] doc/telegram-chat: warn about changing group id --- doc/telegram-chat.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index 388aa35..540cc88 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -85,6 +85,9 @@ Adding a bot to a group allows it to send messages to that group. To allow it to receive messages you have to make it an admin of that group! It is fine to deny all permissions, though. +Also adding an admin to a group can cause the group id to change, so check +that if things break suddenly. + See also -------- From 7e7987afec9e8bbbaecb9c84d267097568d7edc7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Feb 2023 10:39:34 +0100 Subject: [PATCH 1321/2612] doc/telegram-chat: add hint on command runtime --- doc/telegram-chat.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index 540cc88..0c1e157 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -79,6 +79,12 @@ scripting capabilities. Try to print what you want to act on... /ip/address/remove [ find where interface=eth ]; +### Mind command runtime + +The command is run in background while the script waits for it - about +20 seconds at maximum. A command exceeding that time continues to run in +background, but the output in the message is missing or truncated then. + ### Sending commands to a group Adding a bot to a group allows it to send messages to that group. To allow From 44c30efbcd77f85a92595d06e4531fca1461f101 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Feb 2023 11:01:59 +0100 Subject: [PATCH 1322/2612] telegram-chat: give a hint if command is still running --- telegram-chat | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/telegram-chat b/telegram-chat index 9c8261e..aeb4e6d 100644 --- a/telegram-chat +++ b/telegram-chat @@ -96,17 +96,18 @@ $WaitFullyConnected; } else={ :if ($TelegramChatActive = true && [ :len $Text ] > 0) do={ :if ([ $ValidateSyntax $Text ] = true) do={ + :local State ""; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); $MkDir "tmpfs/telegram-chat"; $LogPrintExit2 info $0 ("Running command: " . $Text) false; :exec script=($Text . "; :execute script=\":put\" file=" . $File . ".done") file=$File; :if ([ $WaitForFile ($File . ".done.txt") 200 ] = false) do={ - $LogPrintExit2 warning $0 ("Command did not finish, possibly still running.") false; + :set State "The command did not finish, still running in background.\n\n"; } :local Content [ /file/get ($File . ".txt") content ]; $SendTelegram2 ({ origin=$0; silent=false; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Command:\n" . $Text . "\n\nOutput:\n" . $Content) }); + message=("Command:\n" . $Text . "\n\n" . $State . "Output:\n" . $Content) }); /file/remove "tmpfs/telegram-chat"; } else={ $LogPrintExit2 warning $0 ("The command failed syntax validation: " . $Text) false; From c2cf05e9e59c60aa24e7d57d53b81c4b919b8495 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Feb 2023 10:55:28 +0100 Subject: [PATCH 1323/2612] telegram-chat: handle error in command... --- telegram-chat | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/telegram-chat b/telegram-chat index aeb4e6d..2f60a62 100644 --- a/telegram-chat +++ b/telegram-chat @@ -100,7 +100,8 @@ $WaitFullyConnected; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); $MkDir "tmpfs/telegram-chat"; $LogPrintExit2 info $0 ("Running command: " . $Text) false; - :exec script=($Text . "; :execute script=\":put\" file=" . $File . ".done") file=$File; + :exec script=(":do {\n" . $Text . "\n} on-error={};" . \ + ":execute script=\":put\" file=" . $File . ".done") file=$File; :if ([ $WaitForFile ($File . ".done.txt") 200 ] = false) do={ :set State "The command did not finish, still running in background.\n\n"; } From a07383566755a30fc03374f2bc83d78d3f6dad54 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Feb 2023 11:09:34 +0100 Subject: [PATCH 1324/2612] telegram-chat: ... and give a hint on failure --- telegram-chat | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/telegram-chat b/telegram-chat index 2f60a62..1c10fcd 100644 --- a/telegram-chat +++ b/telegram-chat @@ -100,11 +100,14 @@ $WaitFullyConnected; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); $MkDir "tmpfs/telegram-chat"; $LogPrintExit2 info $0 ("Running command: " . $Text) false; - :exec script=(":do {\n" . $Text . "\n} on-error={};" . \ + :exec script=(":do {\n" . $Text . "\n} on-error={ :execute script=\":put\" file=" . $File . ".failed };" . \ ":execute script=\":put\" file=" . $File . ".done") file=$File; :if ([ $WaitForFile ($File . ".done.txt") 200 ] = false) do={ :set State "The command did not finish, still running in background.\n\n"; } + :if ([ :len [ /file/find where name=($File . ".failed.txt") ] ] > 0) do={ + :set State "The command failed with an error!\n\n"; + } :local Content [ /file/get ($File . ".txt") content ]; $SendTelegram2 ({ origin=$0; silent=false; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ From b5399099c6bd01b46cb1e6d0074a0d8b0715d707 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Feb 2023 11:23:25 +0100 Subject: [PATCH 1325/2612] telegram-chat: also give a hint on failed syntax validation ... and drop the warning in log instead. --- telegram-chat | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/telegram-chat b/telegram-chat index 1c10fcd..da3f0e5 100644 --- a/telegram-chat +++ b/telegram-chat @@ -114,7 +114,9 @@ $WaitFullyConnected; message=("Command:\n" . $Text . "\n\n" . $State . "Output:\n" . $Content) }); /file/remove "tmpfs/telegram-chat"; } else={ - $LogPrintExit2 warning $0 ("The command failed syntax validation: " . $Text) false; + $SendTelegram2 ({ origin=$0; silent=false; \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=("Command:\n" . $Text . "\n\nThe command failed syntax validation!") }); } } } From 8dd53c80f53d504b9e2c9a8e20e98bdedb477824 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Feb 2023 14:25:13 +0100 Subject: [PATCH 1326/2612] telegram-chat: modify text if no output available --- telegram-chat | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/telegram-chat b/telegram-chat index da3f0e5..317f030 100644 --- a/telegram-chat +++ b/telegram-chat @@ -111,7 +111,8 @@ $WaitFullyConnected; :local Content [ /file/get ($File . ".txt") content ]; $SendTelegram2 ({ origin=$0; silent=false; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Command:\n" . $Text . "\n\n" . $State . "Output:\n" . $Content) }); + message=("Command:\n" . $Text . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ + ("Output:\n" . $Content) "No output available." ]) }); /file/remove "tmpfs/telegram-chat"; } else={ $SendTelegram2 ({ origin=$0; silent=false; \ From 049a029170ccb1206c556ea56a579110d80752d2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Feb 2023 14:29:16 +0100 Subject: [PATCH 1327/2612] doc/telegram-chat: add hint on output size --- doc/telegram-chat.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index 0c1e157..c3983d3 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -85,6 +85,12 @@ The command is run in background while the script waits for it - about 20 seconds at maximum. A command exceeding that time continues to run in background, but the output in the message is missing or truncated then. +### Output size + +RouterOS is limited in reading file content to a size of about four +kilobytes. Reading larger files does just fail, and that is also the limit +for command output. + ### Sending commands to a group Adding a bot to a group allows it to send messages to that group. To allow From bf1af61d2de5a6b2f5188c3b06b6a4c2c670465a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 1 Feb 2023 17:25:48 +0100 Subject: [PATCH 1328/2612] doc/telegram-chat: give an example on how to work around command runtime --- doc/telegram-chat.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index c3983d3..fe0d2d6 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -85,6 +85,13 @@ The command is run in background while the script waits for it - about 20 seconds at maximum. A command exceeding that time continues to run in background, but the output in the message is missing or truncated then. +If you still want a response you can work around this by making your code +send information on its own. Something like this should do the job: + + :global SendTelegram; + :delay 30s; + $SendTelegram "Command finished" "Your command finished..."; + ### Output size RouterOS is limited in reading file content to a size of about four From 2cb74f0269c7fbd342ee801b9478e4704448f349 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Feb 2023 09:11:34 +0100 Subject: [PATCH 1329/2612] mod/notification-telegram: support sending to specific chatid --- mod/notification-telegram | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mod/notification-telegram b/mod/notification-telegram index 03ccc3b..69c4801 100644 --- a/mod/notification-telegram +++ b/mod/notification-telegram @@ -98,7 +98,8 @@ :return $Return; } - :local ChatId [ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ]; + :local ChatId [ $EitherOr ($Notification->"chatid") \ + [ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ] ]; :local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ]; :if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={ From 08383daa5c03f0621a59010bf86b5cea1b032471 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Feb 2023 09:24:19 +0100 Subject: [PATCH 1330/2612] telegram-chat: always reply to origin chat --- doc/telegram-chat.md | 2 +- telegram-chat | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index fe0d2d6..c3ef7fc 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -105,7 +105,7 @@ it to receive messages you have to make it an admin of that group! It is fine to deny all permissions, though. Also adding an admin to a group can cause the group id to change, so check -that if things break suddenly. +that if notifications break suddenly. See also -------- diff --git a/telegram-chat b/telegram-chat index 317f030..f5b0f63 100644 --- a/telegram-chat +++ b/telegram-chat @@ -78,6 +78,7 @@ $WaitFullyConnected; :local From [ $JsonGetKey $Message "from" ]; :local FromID [ $JsonGetKey $From "id" ]; :local FromUserName [ $JsonGetKey $From "username" ]; + :local ChatID [ $JsonGetKey [ $JsonGetKey $Message "chat" ] "id" ]; :foreach IdsTrusted in=($TelegramChatId, $TelegramChatIdsTrusted) do={ :if ($FromID = $IdsTrusted || $FromUserName = $IdsTrusted) do={ :set Trusted true; @@ -109,13 +110,13 @@ $WaitFullyConnected; :set State "The command failed with an error!\n\n"; } :local Content [ /file/get ($File . ".txt") content ]; - $SendTelegram2 ({ origin=$0; silent=false; \ + $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Command:\n" . $Text . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ ("Output:\n" . $Content) "No output available." ]) }); /file/remove "tmpfs/telegram-chat"; } else={ - $SendTelegram2 ({ origin=$0; silent=false; \ + $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Command:\n" . $Text . "\n\nThe command failed syntax validation!") }); } From b794d98cbb513f7ef49ffd4e19101e4580e96949 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Feb 2023 09:48:43 +0100 Subject: [PATCH 1331/2612] telegram-chat: reply with a hint when untrusted... ... but only when activating via identity. --- telegram-chat | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/telegram-chat b/telegram-chat index f5b0f63..93d4294 100644 --- a/telegram-chat +++ b/telegram-chat @@ -79,6 +79,7 @@ $WaitFullyConnected; :local FromID [ $JsonGetKey $From "id" ]; :local FromUserName [ $JsonGetKey $From "username" ]; :local ChatID [ $JsonGetKey [ $JsonGetKey $Message "chat" ] "id" ]; + :local Text [ $JsonGetKey $Message "text" ]; :foreach IdsTrusted in=($TelegramChatId, $TelegramChatIdsTrusted) do={ :if ($FromID = $IdsTrusted || $FromUserName = $IdsTrusted) do={ :set Trusted true; @@ -86,7 +87,6 @@ $WaitFullyConnected; } :if ($Trusted = true) do={ - :local Text [ $JsonGetKey $Message "text" ]; :if ([ :pick $Text 0 1 ] = "!") do={ :if ($Text ~ ("^! *(" . [ $EscapeForRegEx $Identity ] . "|@" . $TelegramChatGroups . ")\$")) do={ :set TelegramChatActive true; @@ -124,6 +124,11 @@ $WaitFullyConnected; } } else={ $LogPrintExit2 warning $0 ("Received a message from untrusted contact '" . $FromUserName . "' (ID " . $FromID . ")!") false; + :if ($Text ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ + $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=("You are not trusted.") }); + } } } } From 978c03131a905c1a6892c9d2fbb049256af2c263 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Feb 2023 11:05:16 +0100 Subject: [PATCH 1332/2612] global-functions: $WaitForFile: use delay instead of iterations --- global-functions | 11 ++++++----- telegram-chat | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/global-functions b/global-functions index 2f57fae..d2f911e 100644 --- a/global-functions +++ b/global-functions @@ -1213,20 +1213,21 @@ # wait for file to be available :set WaitForFile do={ - :local FileName [ :tostr $1 ]; - :local Iter [ :tonum $2 ]; + :local FileName [ :tostr $1 ]; + :local WaitTime [ :totime $2 ]; :global CleanFilePath; :global EitherOr; :set FileName [ $CleanFilePath $FileName ]; - :local I 0; + :local I 1; + :local Delay ([ :totime [ $EitherOr $WaitTime 2s ] ] / 20); :while ([ :len [ /file/find where name=$FileName ] ] = 0) do={ - :if ($I > [ $EitherOr $Iter 20 ]) do={ + :if ($I >= 20) do={ :return false; } - :delay 100ms; + :delay $Delay; :set I ($I + 1); } :return true; diff --git a/telegram-chat b/telegram-chat index 93d4294..2d3cee6 100644 --- a/telegram-chat +++ b/telegram-chat @@ -103,7 +103,7 @@ $WaitFullyConnected; $LogPrintExit2 info $0 ("Running command: " . $Text) false; :exec script=(":do {\n" . $Text . "\n} on-error={ :execute script=\":put\" file=" . $File . ".failed };" . \ ":execute script=\":put\" file=" . $File . ".done") file=$File; - :if ([ $WaitForFile ($File . ".done.txt") 200 ] = false) do={ + :if ([ $WaitForFile ($File . ".done.txt") 20s ] = false) do={ :set State "The command did not finish, still running in background.\n\n"; } :if ([ :len [ /file/find where name=($File . ".failed.txt") ] ] > 0) do={ From 82003bc7d139b4fd68ba0fdf32e837852b42edbc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Feb 2023 11:08:43 +0100 Subject: [PATCH 1333/2612] telegram-chat: allow to modify the time to wait for command For now this is a hidden settings... Do we want this to be documented? --- telegram-chat | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/telegram-chat b/telegram-chat index 2d3cee6..4a78da4 100644 --- a/telegram-chat +++ b/telegram-chat @@ -16,9 +16,11 @@ :global TelegramChatId; :global TelegramChatIdsTrusted; :global TelegramChatOffset; +:global TelegramChatRunTime; :global TelegramTokenId; :global CertificateAvailable; +:global EitherOr; :global EscapeForRegEx; :global GetRandom20CharAlNum; :global IfThenElse; @@ -103,7 +105,7 @@ $WaitFullyConnected; $LogPrintExit2 info $0 ("Running command: " . $Text) false; :exec script=(":do {\n" . $Text . "\n} on-error={ :execute script=\":put\" file=" . $File . ".failed };" . \ ":execute script=\":put\" file=" . $File . ".done") file=$File; - :if ([ $WaitForFile ($File . ".done.txt") 20s ] = false) do={ + :if ([ $WaitForFile ($File . ".done.txt") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ :set State "The command did not finish, still running in background.\n\n"; } :if ([ :len [ /file/find where name=($File . ".failed.txt") ] ] > 0) do={ From c47c9a290605ce91dd6816702b27114784c05b97 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Feb 2023 11:30:49 +0100 Subject: [PATCH 1334/2612] telegram-chat: discard messages without text --- telegram-chat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram-chat b/telegram-chat index 4a78da4..dffded1 100644 --- a/telegram-chat +++ b/telegram-chat @@ -97,7 +97,7 @@ $WaitFullyConnected; } $LogPrintExit2 info $0 ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . "!") false; } else={ - :if ($TelegramChatActive = true && [ :len $Text ] > 0) do={ + :if ($TelegramChatActive = true && $Text != false && [ :len $Text ] > 0) do={ :if ([ $ValidateSyntax $Text ] = true) do={ :local State ""; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); From 490a738af12a0415da252441d50cbe29745a90ad Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Feb 2023 11:49:01 +0100 Subject: [PATCH 1335/2612] backup-email: wait for the mail to be sent --- backup-email | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/backup-email b/backup-email index 036c520..158e746 100644 --- a/backup-email +++ b/backup-email @@ -83,3 +83,13 @@ $SendEMail2 ({ origin=$0; \ "Backup file: " . $BackupFile . "\n" . \ "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); +} From 9d1cf8748923873da5e2c5df9d21a9976412a6b1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Feb 2023 09:53:49 +0100 Subject: [PATCH 1336/2612] telegram-chat: handle missing username --- telegram-chat | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/telegram-chat b/telegram-chat index dffded1..3d94221 100644 --- a/telegram-chat +++ b/telegram-chat @@ -125,7 +125,9 @@ $WaitFullyConnected; } } } else={ - $LogPrintExit2 warning $0 ("Received a message from untrusted contact '" . $FromUserName . "' (ID " . $FromID . ")!") false; + $LogPrintExit2 warning $0 ("Received a message from untrusted contact " . \ + [ $IfThenElse ($FromUserName = false) "without username" ("'" . $FromUserName . "'") ] . \ + " (ID " . $FromID . ")!") false; :if ($Text ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ From 4bc5b9cf5f705600bdaacf439fb36737fb33729e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Feb 2023 09:56:30 +0100 Subject: [PATCH 1337/2612] telegram-chat: log warning only when trying to activate --- telegram-chat | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/telegram-chat b/telegram-chat index 3d94221..d7b6f18 100644 --- a/telegram-chat +++ b/telegram-chat @@ -125,13 +125,16 @@ $WaitFullyConnected; } } } else={ - $LogPrintExit2 warning $0 ("Received a message from untrusted contact " . \ + :local Message ("Received a message from untrusted contact " . \ [ $IfThenElse ($FromUserName = false) "without username" ("'" . $FromUserName . "'") ] . \ - " (ID " . $FromID . ")!") false; + " (ID " . $FromID . ")!"); :if ($Text ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ + $LogPrintExit2 warning $0 $Message false; $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("You are not trusted.") }); + } else={ + $LogPrintExit2 info $0 $Message false; } } } From 8a900dce00bf08acc1347ff9befedd634ee76adb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Feb 2023 20:29:10 +0100 Subject: [PATCH 1338/2612] telegram-chat: delay confirmation of updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several devices can communicate with the same bot, and we want all of them to receive their updates. However this can be tricky, as... * ... sometimes internet connection can be unreliable or saturated. * ... device can be busy with long running command. * ... the Telegram bot api servers seem to implement what ever kind of rate limiting. Anybody can give details? So let's confirm the update id after third request only. 😁 This gives delayed devices some extra chances to catch up. --- telegram-chat | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/telegram-chat b/telegram-chat index d7b6f18..16b6e9e 100644 --- a/telegram-chat +++ b/telegram-chat @@ -37,8 +37,8 @@ $ScriptLock $0; $WaitFullyConnected; -:if ([ :typeof $TelegramChatOffset ] != "num") do={ - :set TelegramChatOffset 0; +:if ([ :typeof $TelegramChatOffset ] != "array") do={ + :set TelegramChatOffset { 0; 0; 0 }; } :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ @@ -65,16 +65,16 @@ $WaitFullyConnected; :do { :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=" . \ - $TelegramChatOffset . "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); + $TelegramChatOffset->0 . "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); :set Data [ :pick $Data ([ :find $Data "[" ] + 1) ([ :len $Data ] - 2) ]; } on-error={ $LogPrintExit2 info $0 ("Failed getting updates from Telegram.") true; } +:local UpdateID 0; :foreach Update in=[ :toarray $Data ] do={ - :local UpdateID [ $JsonGetKey $Update "update_id" ]; - :if ($UpdateID >= $TelegramChatOffset) do={ - :set TelegramChatOffset ($UpdateID + 1); + :set UpdateID [ $JsonGetKey $Update "update_id" ]; + :if ($UpdateID >= $TelegramChatOffset->2) do={ :local Trusted false; :local Message [ $JsonGetKey $Update "message" ]; :local From [ $JsonGetKey $Message "from" ]; @@ -139,3 +139,5 @@ $WaitFullyConnected; } } } +:set TelegramChatOffset ([ :pick $TelegramChatOffset 1 3 ], \ + [ $IfThenElse ($UpdateID > 0) ($UpdateID + 1) ($TelegramChatOffset->2) ]); From 04c26d3d2e0856cd96e202ce71ff748761b4520e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Feb 2023 21:16:25 +0100 Subject: [PATCH 1339/2612] telegram-chat: log with severity debug only... ... as failed request are quite common. --- telegram-chat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram-chat b/telegram-chat index 16b6e9e..9fcbc4f 100644 --- a/telegram-chat +++ b/telegram-chat @@ -68,7 +68,7 @@ $WaitFullyConnected; $TelegramChatOffset->0 . "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); :set Data [ :pick $Data ([ :find $Data "[" ] + 1) ([ :len $Data ] - 2) ]; } on-error={ - $LogPrintExit2 info $0 ("Failed getting updates from Telegram.") true; + $LogPrintExit2 debug $0 ("Failed getting updates from Telegram.") true; } :local UpdateID 0; From 600203797bdde92b606fa916d4066304c95bd58f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Feb 2023 22:30:08 +0100 Subject: [PATCH 1340/2612] telegram-chat: no need to :put ... ... a simple change to root dir is sufficient. --- telegram-chat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telegram-chat b/telegram-chat index 9fcbc4f..4c6ea21 100644 --- a/telegram-chat +++ b/telegram-chat @@ -103,8 +103,8 @@ $WaitFullyConnected; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); $MkDir "tmpfs/telegram-chat"; $LogPrintExit2 info $0 ("Running command: " . $Text) false; - :exec script=(":do {\n" . $Text . "\n} on-error={ :execute script=\":put\" file=" . $File . ".failed };" . \ - ":execute script=\":put\" file=" . $File . ".done") file=$File; + :exec script=(":do {\n" . $Text . "\n} on-error={ :execute script=\"/\" file=" . $File . ".failed };" . \ + ":execute script=\"/\" file=" . $File . ".done") file=$File; :if ([ $WaitForFile ($File . ".done.txt") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ :set State "The command did not finish, still running in background.\n\n"; } From 9c066599e8a57bfcf26eacb18fcca8f404938f15 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 4 Feb 2023 23:24:44 +0100 Subject: [PATCH 1341/2612] telegram-chat: handle exceeded file read size --- telegram-chat | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/telegram-chat b/telegram-chat index 4c6ea21..c6a4c3b 100644 --- a/telegram-chat +++ b/telegram-chat @@ -115,7 +115,8 @@ $WaitFullyConnected; $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Command:\n" . $Text . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ - ("Output:\n" . $Content) "No output available." ]) }); + ("Output:\n" . $Content) [ $IfThenElse ([ /file/get ($File . ".txt") size ] > 0) \ + ("Output exceeds file read size.") ("No output.") ] ]) }); /file/remove "tmpfs/telegram-chat"; } else={ $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; \ From 48bf54644aadf1f289080f83ecfd06ee936ead78 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Feb 2023 20:24:50 +0100 Subject: [PATCH 1342/2612] global-config: new option to backup global-config-overlay --- global-config | 1 + 1 file changed, 1 insertion(+) diff --git a/global-config b/global-config index 6096f14..c65e2f0 100644 --- a/global-config +++ b/global-config @@ -72,6 +72,7 @@ # This defines what backups to generate and what password to use. :global BackupSendBinary false; :global BackupSendExport true; +:global BackupSendGlobalConfig true; :global BackupPassword "v3ry-s3cr3t"; :global BackupRandomDelay 0; # These credentials are used to upload backup and config export files. From 0527503c8e357e7cff99231b3cce2c153c9d6132 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Feb 2023 20:29:13 +0100 Subject: [PATCH 1343/2612] backup-email: support sending global-config-overlay --- backup-email | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/backup-email b/backup-email index 158e746..50c5ce5 100644 --- a/backup-email +++ b/backup-email @@ -16,6 +16,7 @@ :global BackupRandomDelay; :global BackupSendBinary; :global BackupSendExport; +:global BackupSendGlobalConfig; :global Domain; :global Identity; @@ -50,6 +51,7 @@ $WaitFullyConnected; :local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; :local FilePath ($DirName . "/" . $FileName); :local BackupFile "none"; +:local ExportFile "none"; :local ConfigFile "none"; :local Attach ({}); @@ -69,10 +71,19 @@ $WaitFullyConnected; :if ($BackupSendExport = true) do={ /export terse show-sensitive file=$FilePath; $WaitForFile ($FilePath . ".rsc"); - :set ConfigFile ($FileName . ".rsc"); + :set ExportFile ($FileName . ".rsc"); :set Attach ($Attach, ($FilePath . ".rsc")); } +# global-config-overlay +:if ($BackupSendGlobalConfig = true) do={ + :execute script={ / } file=($FilePath . ".conf"); + $WaitForFile ($FilePath . ".conf.txt"); + /file/set ($FilePath . ".conf.txt") contents=[ /system/script/get global-config-overlay source ]; + :set ConfigFile ($FileName . ".conf.txt"); + :set Attach ($Attach, ($FilePath . ".conf.txt")); +} + # send email with status and files $SendEMail2 ({ origin=$0; \ subject=([ $SymbolForNotification "floppy-disk,incoming-envelope" ] . \ @@ -81,6 +92,7 @@ $SendEMail2 ({ origin=$0; \ $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ + "Export file: " . $ExportFile . "\n" . \ "Config file: " . $ConfigFile); \ attach=$Attach; remove-attach=true }); From 5d263ca11eac4305ba9ae8b70742e9bc66fb6bf0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Feb 2023 20:34:35 +0100 Subject: [PATCH 1344/2612] backup-upload: support uploading global-config-overlay --- backup-upload | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/backup-upload b/backup-upload index ee7b867..4fe9535 100644 --- a/backup-upload +++ b/backup-upload @@ -16,6 +16,7 @@ :global BackupRandomDelay; :global BackupSendBinary; :global BackupSendExport; +:global BackupSendGlobalConfig; :global BackupUploadPass; :global BackupUploadUrl; :global BackupUploadUser; @@ -50,6 +51,7 @@ $WaitFullyConnected; :local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; :local FilePath ($DirName . "/" . $FileName); :local BackupFile "none"; +:local ExportFile "none"; :local ConfigFile "none"; :local Failed 0; @@ -83,16 +85,35 @@ $WaitFullyConnected; :do { /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \ user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".rsc"); - :set ConfigFile ($FileName . ".rsc"); + :set ExportFile ($FileName . ".rsc"); } on-error={ $LogPrintExit2 error $0 ("Uploading configuration export failed!") false; - :set ConfigFile "failed"; + :set ExportFile "failed"; :set Failed 1; } /file/remove ($FilePath . ".rsc"); } +# global-config-overlay +:if ($BackupSendGlobalConfig = true) do={ + :execute script={ / } file=($FilePath . ".conf"); + $WaitForFile ($FilePath . ".conf.txt"); + /file/set ($FilePath . ".conf.txt") contents=[ /system/script/get global-config-overlay source ]; + + :do { + /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \ + user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf.txt"); + :set ConfigFile ($FileName . ".conf"); + } on-error={ + $LogPrintExit2 error $0 ("Uploading global-config-overlay failed!") false; + :set ConfigFile "failed"; + :set Failed 1; + } + + /file/remove ($FilePath . ".conf.txt"); +} + $SendNotification2 ({ origin=$0; \ subject=[ $IfThenElse ($Failed > 0) \ ([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Backup & Config upload with failure") \ @@ -100,6 +121,7 @@ $SendNotification2 ({ origin=$0; \ message=("Backup and config export upload for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ "Backup file: " . $BackupFile . "\n" . \ + "Export file: " . $ExportFile . "\n" . \ "Config file: " . $ConfigFile); silent=true }); :if ($Failed = 1) do={ From ba730708f57afa5343bd83d048b2b72d23f79ec1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Feb 2023 21:00:32 +0100 Subject: [PATCH 1345/2612] notify about backup for global-config-overlay --- global-config.changes | 1 + global-functions | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/global-config.changes b/global-config.changes index 33a340e..dd40f09 100644 --- a/global-config.changes +++ b/global-config.changes @@ -101,6 +101,7 @@ 90="Chat with your router! Introduced 'telegram-chat' to chat via Telegram bot and send commands to your router."; 91="Dropped check for CAP in 'check-routeros-update' to solve issues with wifiwave2 package."; 92="Made qr-code url configurable for 'daily-psk'."; + 93="Added support to backup global-config-overlay in 'backup-email' and 'backup-upload'."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index d2f911e..63ec636 100644 --- a/global-functions +++ b/global-functions @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 92; +:global ExpectedConfigVersion 93; # global variables not to be changed by user :global GlobalFunctionsReady false; From 58a6fac3d9b36c9b7350e8315115ee81d4ce6982 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Feb 2023 21:18:50 +0100 Subject: [PATCH 1346/2612] telegram-chat: use complete property name --- telegram-chat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram-chat b/telegram-chat index c6a4c3b..c861c5d 100644 --- a/telegram-chat +++ b/telegram-chat @@ -111,7 +111,7 @@ $WaitFullyConnected; :if ([ :len [ /file/find where name=($File . ".failed.txt") ] ] > 0) do={ :set State "The command failed with an error!\n\n"; } - :local Content [ /file/get ($File . ".txt") content ]; + :local Content [ /file/get ($File . ".txt") contents ]; $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Command:\n" . $Text . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ From d63db7ea9528271f242fb1845841a6fac14da771 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Feb 2023 21:20:49 +0100 Subject: [PATCH 1347/2612] global-functions: $ScriptInstallUpdate: use complete property name --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 63ec636..c179263 100644 --- a/global-functions +++ b/global-functions @@ -748,7 +748,7 @@ :local ScriptFile [ /file/find where name=("script-updates/" . $ScriptVal->"name") ]; :local SourceNew; :if ([ :len $ScriptFile ] > 0) do={ - :set SourceNew [ /file/get $ScriptFile content ]; + :set SourceNew [ /file/get $ScriptFile contents ]; /file/remove $ScriptFile; } From b9eaab8e77d906be7bc71d13a979d4f1b14ce038 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 Feb 2023 09:06:48 +0100 Subject: [PATCH 1348/2612] backup-email: use :use inside :execute for global-config-overlay This will add carriage return and line feed, but works around the limitation of reading just four kilobytes from file. --- backup-email | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backup-email b/backup-email index 50c5ce5..ba12494 100644 --- a/backup-email +++ b/backup-email @@ -77,9 +77,9 @@ $WaitFullyConnected; # global-config-overlay :if ($BackupSendGlobalConfig = true) do={ - :execute script={ / } file=($FilePath . ".conf"); + :execute script={ :put [ /system/script/get global-config-overlay source ]; } \ + file=($FilePath . ".conf"); $WaitForFile ($FilePath . ".conf.txt"); - /file/set ($FilePath . ".conf.txt") contents=[ /system/script/get global-config-overlay source ]; :set ConfigFile ($FileName . ".conf.txt"); :set Attach ($Attach, ($FilePath . ".conf.txt")); } From 818638d0f48e7e9cac275933a8cbb09ca119815b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 Feb 2023 09:11:34 +0100 Subject: [PATCH 1349/2612] backup-upload: use :use inside :execute for global-config-overlay --- backup-upload | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backup-upload b/backup-upload index 4fe9535..4c09d4a 100644 --- a/backup-upload +++ b/backup-upload @@ -97,9 +97,9 @@ $WaitFullyConnected; # global-config-overlay :if ($BackupSendGlobalConfig = true) do={ - :execute script={ / } file=($FilePath . ".conf"); + :execute script={ :put [ /system/script/get global-config-overlay source ]; } \ + file=($FilePath . ".conf"); $WaitForFile ($FilePath . ".conf.txt"); - /file/set ($FilePath . ".conf.txt") contents=[ /system/script/get global-config-overlay source ]; :do { /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \ From f2f7d66b2dc5f491030198dd425a94809267ba80 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 Feb 2023 09:44:21 +0100 Subject: [PATCH 1350/2612] doc/backup-email: new option $BackupSendGlobalConfig --- doc/backup-email.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/backup-email.md b/doc/backup-email.md index c7de3e7..a8ec760 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -29,6 +29,7 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupSendBinary`: whether to send binary backup * `BackupSendExport`: whether to send configuration export +* `BackupSendGlobalConfig`: whether to send `global-config-overlay` * `BackupPassword`: password to encrypt the backup with * `BackupRandomDelay`: delay up to amount of seconds when run from scheduler From 15fc0b91e9150e81920b54217aef47e04f74aa57 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 Feb 2023 09:44:52 +0100 Subject: [PATCH 1351/2612] doc/backup-upload: new option $BackupSendGlobalConfig --- doc/backup-upload.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/backup-upload.md b/doc/backup-upload.md index 3e4c7e8..f2bf4de 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -35,6 +35,7 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupSendBinary`: whether to send binary backup * `BackupSendExport`: whether to send configuration export +* `BackupSendGlobalConfig`: whether to send `global-config-overlay` * `BackupPassword`: password to encrypt the backup with * `BackupRandomDelay`: delay up to amount of seconds when run from scheduler * `BackupUploadUrl`: url to upload to From c6245b31250b59068da6675530167e042e012ac4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 Feb 2023 22:10:48 +0100 Subject: [PATCH 1352/2612] ipv6-update: use identical parameters to find address --- ipv6-update | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipv6-update b/ipv6-update index fc42791..34df5b3 100644 --- a/ipv6-update +++ b/ipv6-update @@ -38,7 +38,7 @@ :local ListEntryVal [ /ipv6/firewall/address-list/get $ListEntry ]; :local Comment [ $ParseKeyValueStore ($ListEntryVal->"comment") ]; - :local Address [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") ]; + :local Address [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; :if ([ :len $Address ] = 1) do={ :set Address [ /ipv6/address/get $Address address ]; $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $Address . \ @@ -51,7 +51,7 @@ :local RecordVal [ /ip/dns/static/get $Record ]; :local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ]; - :local Prefix [ /ipv6/address/get [ find where interface=($Comment->"interface") from-pool=$Pool global ] address ]; + :local Prefix [ /ipv6/address/get [ find where from-pool=$Pool interface=($Comment->"interface") global ] address ]; :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); From 769edbcf61a31e0664c43dcf7c8301ed89bed01a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 Feb 2023 22:13:16 +0100 Subject: [PATCH 1353/2612] ipv6-update: rename variable --- ipv6-update | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ipv6-update b/ipv6-update index 34df5b3..13660c4 100644 --- a/ipv6-update +++ b/ipv6-update @@ -38,12 +38,12 @@ :local ListEntryVal [ /ipv6/firewall/address-list/get $ListEntry ]; :local Comment [ $ParseKeyValueStore ($ListEntryVal->"comment") ]; - :local Address [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; - :if ([ :len $Address ] = 1) do={ - :set Address [ /ipv6/address/get $Address address ]; - $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $Address . \ + :local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; + :if ([ :len $Prefix ] = 1) do={ + :set Prefix [ /ipv6/address/get $Prefix address ]; + $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $Prefix . \ " from interface " . ($Comment->"interface")) false; - /ipv6/firewall/address-list/set address=$Address $ListEntry; + /ipv6/firewall/address-list/set address=$Prefix $ListEntry; } } From a34d5d71417d0720e9695b2bfa8657f3734de3b6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 Feb 2023 22:36:40 +0100 Subject: [PATCH 1354/2612] ipv6-update: accept a single prefix only --- ipv6-update | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ipv6-update b/ipv6-update index 13660c4..dd22538 100644 --- a/ipv6-update +++ b/ipv6-update @@ -51,12 +51,15 @@ :local RecordVal [ /ip/dns/static/get $Record ]; :local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ]; - :local Prefix [ /ipv6/address/get [ find where from-pool=$Pool interface=($Comment->"interface") global ] address ]; - :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); - :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); + :local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; + :if ([ :len $Prefix ] = 1) do={ + :set Prefix [ /ipv6/address/get $Prefix address ]; + :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); + :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); - $LogPrintExit2 info $0 ("Updating DNS record for " . ($RecordVal->"name") . \ - ($RecordVal->"regexp") . " to " . $Address) false; - /ip/dns/static/set address=$Address $Record; + $LogPrintExit2 info $0 ("Updating DNS record for " . ($RecordVal->"name") . \ + ($RecordVal->"regexp") . " to " . $Address) false; + /ip/dns/static/set address=$Address $Record; + } } } From 62707dc549855e1c4247a9d2df599afc48782902 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 Feb 2023 22:42:02 +0100 Subject: [PATCH 1355/2612] ipv6-update: support host addresses in address-list --- doc/ipv6-update.md | 7 ++++++- global-config.changes | 1 + global-functions | 2 +- ipv6-update | 17 ++++++++++++++--- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md index 49804f4..f49cfaa 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -11,7 +11,7 @@ Description With changing IPv6 prefix from ISP this script handles to update... -* ipv6 firewall address-list +* ipv6 firewall address-list (prefixes (`/64`) and host addresses (`/128`)) * dns records Requirements and installation @@ -52,6 +52,11 @@ has to be associated to an interface in comment: /ipv6/firewall/address-list/add address=2003:cf:2f0f:de01::/64 comment="ipv6-pool-isp, interface=br-local" list=local; +Updating address list entries with host addresses works as well, the new +prefix is combinded with given suffix then: + + /ipv6/firewall/address-list/add address=2003:cf:2f0f:de01:e3e0:f8fa:8cd6:dbe1/128 comment="ipv6-pool-isp, interface=br-local" list=hosts; + Static DNS records need a special comment to be updated. Again it has to start with "`ipv6-pool-`" and actual pool name, followed by a comma, "`interface=`" and the name of interface this address is connected to: diff --git a/global-config.changes b/global-config.changes index dd40f09..ad8e7a9 100644 --- a/global-config.changes +++ b/global-config.changes @@ -102,6 +102,7 @@ 91="Dropped check for CAP in 'check-routeros-update' to solve issues with wifiwave2 package."; 92="Made qr-code url configurable for 'daily-psk'."; 93="Added support to backup global-config-overlay in 'backup-email' and 'backup-upload'."; + 94="Added support for host addresses in address-list for 'ipv6-update'."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index c179263..89d2612 100644 --- a/global-functions +++ b/global-functions @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 93; +:global ExpectedConfigVersion 94; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/ipv6-update b/ipv6-update index dd22538..2838feb 100644 --- a/ipv6-update +++ b/ipv6-update @@ -41,9 +41,20 @@ :local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; :if ([ :len $Prefix ] = 1) do={ :set Prefix [ /ipv6/address/get $Prefix address ]; - $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $Prefix . \ - " from interface " . ($Comment->"interface")) false; - /ipv6/firewall/address-list/set address=$Prefix $ListEntry; + + :if ([ :typeof [ :find ($ListEntryVal->"address") "/128" ] ] = "num" ) do={ + :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); + :local Address ($ListEntryVal->"address"); + :local Address ($Prefix | ([ :toip6 [ :pick $Address 0 [ :find $Address "/128" ] ] ] & ::ffff:ffff:ffff:ffff)); + + $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 host address " . $Address . \ + " from interface " . ($Comment->"interface")) false; + /ipv6/firewall/address-list/set address=$Address $ListEntry; + } else={ + $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $Prefix . \ + " from interface " . ($Comment->"interface")) false; + /ipv6/firewall/address-list/set address=$Prefix $ListEntry; + } } } From 7d3c4738d07e040cbe3c293ef0b2be04631290eb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 13 Feb 2023 10:12:16 +0100 Subject: [PATCH 1356/2612] global-functions: introduce $Unix2Dos --- global-functions | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/global-functions b/global-functions index 89d2612..84c7ece 100644 --- a/global-functions +++ b/global-functions @@ -55,6 +55,7 @@ :global SendNotification2; :global SymbolByUnicodeName; :global SymbolForNotification; +:global Unix2Dos; :global UrlEncode; :global ValidateSyntax; :global VersionToNum; @@ -1125,6 +1126,16 @@ :return ($Return . " "); } +# convert line endings, UNIX -> DOS +:set Unix2Dos do={ + :local Input [ :tostr $1 ]; + + :global CharacterReplace; + + :return [ $CharacterReplace [ $CharacterReplace $Input \ + ("\n") ("\r\n") ] ("\r\r\n") ("\r\n") ]; +} + # url encoding :set UrlEncode do={ :local Input [ :tostr $1 ]; From d54c46ab98224c51675e74846362e80cb5f9102b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 13 Feb 2023 10:14:11 +0100 Subject: [PATCH 1357/2612] global-functions: introduce $Dos2Unix --- global-functions | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/global-functions b/global-functions index 84c7ece..d184650 100644 --- a/global-functions +++ b/global-functions @@ -25,6 +25,7 @@ :global CharacterReplace; :global CleanFilePath; :global DeviceInfo; +:global Dos2Unix; :global DownloadPackage; :global EitherOr; :global EscapeForRegEx; @@ -226,6 +227,15 @@ "\n Version: " . $ExpectedConfigVersion); } +# convert line endings, DOS -> UNIX +:set Dos2Unix do={ + :local Input [ :tostr $1 ]; + + :global CharacterReplace; + + :return [ $CharacterReplace $Input ("\r\n") ("\n") ]; +} + # download package from upgrade server :set DownloadPackage do={ :local PkgName [ :tostr $1 ]; From f5d872a99003a5d30983cbc6a90025cea3185d10 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 13 Feb 2023 10:15:23 +0100 Subject: [PATCH 1358/2612] global-functions: $PrettyPrint: use $Unix2Dos --- global-functions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index d184650..f15a7d1 100644 --- a/global-functions +++ b/global-functions @@ -646,9 +646,9 @@ :set PrettyPrint do={ :local Input [ :tostr $1 ]; - :global CharacterReplace; + :global Unix2Dos; - :put [ $CharacterReplace $Input ("\n") ("\n\r") ]; + :put [ $Unix2Dos $Input ]; } # delay a random amount of seconds From ad75d6e031ae47b66d30e47e422d04a41e591653 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 13 Feb 2023 10:26:09 +0100 Subject: [PATCH 1359/2612] README: give hint about converting line endings --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 42f897b..da0bb5e 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,11 @@ Save changes and exit with `Ctrl-o`. ![screenshot: edit global-config-overlay](README.d/05-edit-global-config-overlay.avif) +> â„šī¸ **Info**: It is recommended to edit the configuration using the command +> line interface. If using Winbox on Windows OS, the line endings may be +> missing. To fix this, use the below (to load global functions), then run: +> `/system/script/set source=[ $Unix2Dos [ get global-config-overlay source ] ] global-config-overlay;` + And finally load configuration and functions and add the scheduler. /system/script { run global-config; run global-functions; }; From b6d2cb44c10eb450f8464f0b0dda306adddad7e0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 13 Feb 2023 11:12:44 +0100 Subject: [PATCH 1360/2612] doc/check-health: add line break between screenshots --- doc/check-health.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/check-health.md b/doc/check-health.md index 3b0c4ae..644b6d3 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -30,12 +30,12 @@ hardware supports: #### CPU load -![check-health notification cpu load high](check-health.d/notification-01-cpu-load-high.avif) +![check-health notification cpu load high](check-health.d/notification-01-cpu-load-high.avif) ![check-health notification cpu load ok](check-health.d/notification-02-cpu-load-ok.avif) #### Available free RAM -![check-health notification free ram low](check-health.d/notification-03-free-ram-low.avif) +![check-health notification free ram low](check-health.d/notification-03-free-ram-low.avif) ![check-health notification free ram ok](check-health.d/notification-04-free-ram-ok.avif) #### Voltage From e50e25c6388aa4fea38e465fc053283719a79805 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 13 Feb 2023 11:15:06 +0100 Subject: [PATCH 1361/2612] doc/check-health: make the voltage limit a separate point --- doc/check-health.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/check-health.md b/doc/check-health.md index 644b6d3..850d61c 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -14,7 +14,8 @@ health related events: * high CPU load * low available free RAM -* voltage jumps up or down more than configured threshold or drops below limit +* voltage jumps up or down more than configured threshold +* voltage drops below hard lower limit * power supply failed or recovered * temperature is above or below threshold From c48509683c556aacde6b4fcbbdd53f2c77d38077 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Feb 2023 20:09:41 +0100 Subject: [PATCH 1362/2612] check-health: wording: load -> utilization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The load is defined as something different... https://en.wikipedia.org/wiki/Load_(computing) So let's update the wording and use 'utilization' instead. ---- âœ‚ī¸ ---- đŸ§Žī¸đŸ“ˆī¸ Health warning: CPU utilization The average CPU utilization on MikroTik is at 76%! ---- âœ‚ī¸ ---- đŸ§Žī¸đŸ“‰ī¸ Health recovery: CPU utilization The average CPU utilization on MikroTik decreased to 64%. ---- âœ‚ī¸ ---- --- check-health | 22 +++++++++--------- .../notification-01-cpu-load-high.avif | Bin 6066 -> 0 bytes .../notification-01-cpu-utilization-high.avif | Bin 0 -> 6453 bytes .../notification-02-cpu-load-ok.avif | Bin 6378 -> 0 bytes .../notification-02-cpu-utilization-ok.avif | Bin 0 -> 6717 bytes doc/check-health.md | 14 +++++------ global-config.changes | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) delete mode 100644 doc/check-health.d/notification-01-cpu-load-high.avif create mode 100644 doc/check-health.d/notification-01-cpu-utilization-high.avif delete mode 100644 doc/check-health.d/notification-02-cpu-load-ok.avif create mode 100644 doc/check-health.d/notification-02-cpu-utilization-ok.avif diff --git a/check-health b/check-health index a9a9dbf..e208bac 100644 --- a/check-health +++ b/check-health @@ -10,8 +10,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global CheckHealthCPULoad; -:global CheckHealthCPULoadNotified; +:global CheckHealthCPUUtilization; +:global CheckHealthCPUUtilizationNotified; :global CheckHealthFreeRAMNotified; :global CheckHealthLast; :global CheckHealthTemperature; @@ -37,18 +37,18 @@ $ScriptLock $0; :local Resource [ /system/resource/get ]; -:set CheckHealthCPULoad (($CheckHealthCPULoad * 4 + ($Resource->"cpu-load") * 10) / 5); -:if ($CheckHealthCPULoad > 750 && $CheckHealthCPULoadNotified != true) do={ +:set CheckHealthCPUUtilization (($CheckHealthCPUUtilization * 4 + ($Resource->"cpu-load") * 10) / 5); +:if ($CheckHealthCPUUtilization > 750 && $CheckHealthCPUUtilizationNotified != true) do={ $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "abacus,chart-increasing" ] . "Health warning: CPU load"); \ - message=("The average CPU load on " . $Identity . " is at " . ($CheckHealthCPULoad / 10) . "%!") }); - :set CheckHealthCPULoadNotified true; + subject=([ $SymbolForNotification "abacus,chart-increasing" ] . "Health warning: CPU utilization"); \ + message=("The average CPU utilization on " . $Identity . " is at " . ($CheckHealthCPUUtilization / 10) . "%!") }); + :set CheckHealthCPUUtilizationNotified true; } -:if ($CheckHealthCPULoad < 650 && $CheckHealthCPULoadNotified = true) do={ +:if ($CheckHealthCPUUtilization < 650 && $CheckHealthCPUUtilizationNotified = true) do={ $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "abacus,chart-decreasing" ] . "Health recovery: CPU load"); \ - message=("The average CPU load on " . $Identity . " decreased to " . ($CheckHealthCPULoad / 10) . "%.") }); - :set CheckHealthCPULoadNotified false; + subject=([ $SymbolForNotification "abacus,chart-decreasing" ] . "Health recovery: CPU utilization"); \ + message=("The average CPU utilization on " . $Identity . " decreased to " . ($CheckHealthCPUUtilization / 10) . "%.") }); + :set CheckHealthCPUUtilizationNotified false; } :local CheckHealthFreeRAM ($Resource->"free-memory" * 100 / $Resource->"total-memory"); diff --git a/doc/check-health.d/notification-01-cpu-load-high.avif b/doc/check-health.d/notification-01-cpu-load-high.avif deleted file mode 100644 index 3c1a4685af3340f8bb446b4efd39b718f9198d19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6066 zcmeHGWn5J2x8B15!_YB=Al(f^OLrrkDnmPTmy!x1A%e8X5CQ_CjHDpaf*_4_h=hPh zhafO_@SO9%=ls9i_;SD8wSQ}`=Xuw9*Snr~|26;sEYAKR-gbdVX8>!L(F5r$>VdR# z)>jr)1^|$lhm*hEWe#gRw;kPm|9}ACjdbw;3tvWer2SuQNWGE%9=~%S>{|fo?&WaF z)BpenxLmPb^kOB0Yak@;gJ1B~F(mmpkkNMMPD-+`WDeaOGba zY+5}S>3r#zh4e^Yr#~710I7qcpTqAXFAsG^di#1~qb}0h!3!HRgGf7A^@Or@N)O{bZ`&G4nqRqM`D*~k=`D5mpQC~01z$+ z=N>Kq(Aau7+Wo#7ZEZf_vJG|=tV4kd0QXYKZ^xGZ8L|9N%!bY3fWQD48zZp}#^TF* z{7e5Erv4LO)`4*T=o5>@IDg`0D3)N2;P-=>#C!qBbu_d!um}Af6aX+YfGR+Mj}O7e zBY;34P$&T*F^q(mh=}+KB^4Qrk)D}}k^bsc77ih97B&I)t5pdbL)Kv=PC01gEROaa1l0?gPs@j$=r z4=I;I!MJ$%5CSM65w@U~{PL#2IJjUuJY4LhgTkzJ6DnOj&|Svxp7 zIlJ6Oy88JC1O^3%gxZEWx8 z?E28%^RahibnNr^#N^cU;@73+mDO)+>l?d!`v-?d$3IU_FLhn&{LB7O_HVi{^<5IY|#Hh2^POeLiN-3DbBGv1-L_Z=pr;SgWs+`W|c zTiJh4SoHr&*}sJSr><#$7!1OGJTL{I2ps4`lt;G2Wg%hL=9Ys^Qyp-h#D8X@9?`vj zF;Gpa%o<3%n}`8KPe$Ldi4`K}$G@MINyxZVeZD&yV?6IDrg-{ZiHsrTShxM^X zqpmBEkMt<9O~05K6Q=Vt(0s2gA$7(cXvLlT?EbGbKGXAX^|KfnqV$6LovzMk>CH-O zl?y8)^4_|+*;5~5o5|q7?+RuyWo;}Mn*nr#`_vLG4+I50b5>~_)3anLlCvU}28XCl z#ug^)E{qZsn>aFVCd3Yi<;kq^${(m}%<1?}2759K_rIyRE*f9rz$}VOwyLhl!32wE zZ|=gCa~H*fw!@h{q#c3KhSqK2=|D|~!|2*Rp7=9*+SQS@CD zw>?1XDLUjcv?O8d1wjT8)j0}@bgat9wJ{Iwi(3j=-%}fUWoKnK`omgsfFRLt`Z)%; zAEbc+@||9v|Dp~YpY!k-hjB)K%aF^>9UHS0a*k-1Es7X|Ph6bGD=sn)x2#=p!vNu3 z$YJ&9RhKjNMyYeKV8r%h(FMgE!$nj^%kif9GuZ#_zI_Z3A4rqqi9(E<@6J^Bwk4{1 zYRFfNeeVw!iRh8i#{jST&&uRu>t#J~wJu^uO$N4jrBPJXSL~a9qJ{`#NH`i zC040ie+=M4EiqRAQHEx`U90m>Jq_5;W$RJsQj3A>4;Uyf)l~!W8s_@6Re(U|mT%~} z;nh{i&}H}f(n z@vP}p`TQOp9m!$M{KoM>vF!Zw(w>A*#^3uWA{%776&lVq8g(nQgWTTFs*~mDEx=Jv z9312@z#T80&xMg<-!hG9Nvo7%Sr+&yWf-7`7e{!U8ygW`QI%HVz2$eumIOjRi2bA= zE{ud1hS`2f6IXSR3%BCbHmVJB1W#@$qH6VG&zDKq(#!%GOv`4Qf)(?^_|9POEzPe2Eq!5Ll=dS%QP%_!k+s7wS(OFpms<9v2&NSrT zR>t$>*(#wnjy93QeqlV_FlLGpAcRVDmeRYku;!1zr)c#Y zab`RVkx!?JEOQiQ6tA(PUKkKMsYKb&DZNpTA<)f<&U4oIP~y9=`(w276fvBZ zdlahcas$*&e2)p%h5$kJoz_{$zhr9bd|UNuNgm%-vEw(ul(=+WEE@Am=DpX{D)^GE zO!%#C;$3|`(KvdetKsHiUrBH=Yq@Lo1Pc>=+5nA!ae)@ySm*AI5!*61;@4o#_Dqw} zm-y^SlEof|u=PN_jGh+4<7bt|T5Kzu=WbcT6WMQquSg=yj%g^(UZ7U`ZkB%dz^{uq zZ<*-YKII9>Y7JvU8Au-1KvWALcblux#O9_4#$eAH2F@!>Uwx5eiSXBDPOl$+@%E5a z5D$bM4*yt^<$aRD^5_7AO9YzChlw}xaSMc~IqkD&rs z*4onFl)r>W_;fcP=-FThH5kI&SR>q(f{E8+G|zThRMf1}%pmk{`J+LSVZrPL&P=n(Fuz??^HKF-#FyNIX;b!)rf68UXKa-0QJ5=LJ*7Nr zZ6JT4*Z#5R+x}MTbtgw0eIlA8ozy30T2#WlkN86w;7_gPzX>x$`gUYQ+&ZUXHow)~ zRoIRsbGgrTxaV`))8E8WXh1wFOicdK9(|j{@)boc*IZ^Tw>ATBdW;Y;vn_9CyCsjv zH2`u5y_aI#AkcZd)>)+~EkBzde(`+s^Y`&N4M8S{x&)S`JxOr{?p#+8;w7_UtBUm^ zA%o7R8w4L9&u2vu^KD1G?0StaIGDiIrGmjz%6Gzp!i&|Y-^7iHyneiOBjHiB%UD;^ zAgWg_NzGs4W?Fm{<$EJTNfu3G`I{0-UPA_tZgDTu?mZ}sTbcHEvz5B;mSizd6=d$v zGd8r=+xfX!1lJjncz7R@VvaY|d^R`Z*)vkJ?QuRJ+=Z(MeZUz28TbO%SC4?@r%sHA zLBPCWZ7FhD*PmxS5y-|p*ekNI(34y3>T!N2*6)!-pNDG32z2;#a$NyEHH&%H{Z*eu3*zXicOP?x!S}vPCf?f?P(t1q z)#S~5aI;a5jD>w-b37r$YGMaX>9h7V>6lG_Lpfx-NYct5?kk44))gQYWQ2FTLwbB` z(*9|m_LrQiu#*Ea8|AfSJ)5{Hsi8(Nw+El&bv?>;#p*Hg)kq1(74_cxIfAd_Hrm%j z*mm7{*Tj4*%Oq7}RMg#@25W^vEqN)WCTeqL0rczp&9Gze#9b6>xM|EKZ_>)zy zn^hRI=32w^%$}g2-a#39&u&H*;T6v@RV;J4&ECKtKd}yNH$0*z%IgoMHFKRADJFn@U{|dt43dodL)P*ISKWx0YnF*~PxsN>R=%vy7iGU&yiZ9YB8?Nj z^J9X$TDn&#d7j#~PU1=SGR(PwFLi#ChIhN;k*3tRG9w{rZxF#=E<;AVFCcT&JWx z|Mm-9lg`RHoT1F31a8erho6KaL7mB-0%8-C@hYj5%nuvMT70d&sNkdD= zgI=QdfOWX8{X<*aE^|Fw{q=lCaDzJ2eexY8rKP_+Er zGN@hMZ*p^C`Y0jI#%yZveG@Skm8J=^St)gYnFK+gRCngh(KdHc|LR-??~t#LO`e^R z6`UTR$Czr_{qzx1?XrsKn&-pnQxBtTKHU@&vCpj7po%QPD?B@{sXiK0bUk&lE>{?4 z&<*XNZ=B#^lc_o#Jkd=XDvf!!qWSYEHPPt3789QDbG7u%g$DL|i}4+luSpW;Ms~k( zv&t!=wvSCU{l;A%HiJ-~E#uSkdFtGa@byHYC+H4=Q3(v=DHQ*`!gh=FcSZk`P7|IK zo!p<_a&vmNbRYWh$iVmeBsR<3$DR5ZZ9fqoZX;Yj-4)&fHW_Uz0kUoBpyACSP5HOw zkr!H{V;94Nm?tlHpK{B@#&)M$^+WPVD;7sCS=QyoIgmzo4`H`^9ByBt7(Rf%|64=m6FU1q?c}%(ZQ0_ftDO#OH zQjg+h9i$22_*q}|1g0E_=%0WSuBRb0E3XG}bql3hJZ3I+D&Dc#1`({uP`y48nJoJ> zHZC^bJ$2hVrCQfxx@&6eg`8gn*T}-x8Cl5FH)4c=`f6M3b=OAM<}Kv*JPoo{8=LWX zIckz0^ANJ5HCwbxG@~5IG%BaUlL^Dc+ICHdi`ZLAZMR$76+C{SM2k$?98-Y;7pY7j= z=Sx!E((cdp(5O=rh9L*c`kKsm;Zvb(YtBkD5qyO6c=GRdg2Zb>2=r3AW}Et4Cs`L> zeVx6l;!P^|^(N~z@)m8^Tx%P(yUQS&hRrbfntL3wd&NB#Wdea>QMxuYq<9H3t%k)) zr7eCL+@oFw=jRn}M;;qrR528p>!IRmE3fuHnHn(6edGDL8Y$MVYPOWz(y?fEBiw~n z9DQnbOA52U(D(dKf#hvU>uxmt>m@esypFtG@gt5SpS!93W~=zjN#Sr$5OAB%H`Q>? z&iIaLt+;JKem9+!zi9=o!U1?ohxbJ7N9$8d;$G8n!4Iw=5o#hRqz|sRt>**k{4j02 zPP$({6v#ZwuMU68-&KS1k)x|Utd*mt2G>i@eVk&-+R~I)%@~rjFQA)JPw8BU9QnL} zB6axrkq!MY>ef{jZcq7!8nn$+s{|Yv66GL}=^2U<r7AB1}G~rq7?{cO=JHZ%>J$@~0U%9fW#?~T_odN^lFD3BHRA2(LV^#A|> diff --git a/doc/check-health.d/notification-01-cpu-utilization-high.avif b/doc/check-health.d/notification-01-cpu-utilization-high.avif new file mode 100644 index 0000000000000000000000000000000000000000..8aad87832594b52984424d63ad9eb6a423303f4f GIT binary patch literal 6453 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 WX^Y8_YCi?K==#dQvkrNFqW=I*mzJpj literal 0 HcmV?d00001 diff --git a/doc/check-health.d/notification-02-cpu-load-ok.avif b/doc/check-health.d/notification-02-cpu-load-ok.avif deleted file mode 100644 index 4f12b700e27c3bfa533d6b1c38a8f00dd8be7899..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6378 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 Date: Tue, 14 Feb 2023 21:28:15 +0100 Subject: [PATCH 1363/2612] telegram-chat: add updateid in log messages --- telegram-chat | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/telegram-chat b/telegram-chat index c861c5d..67183a7 100644 --- a/telegram-chat +++ b/telegram-chat @@ -95,14 +95,15 @@ $WaitFullyConnected; } else={ :set TelegramChatActive false; } - $LogPrintExit2 info $0 ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . "!") false; + $LogPrintExit2 info $0 ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . \ + " from update " . $UpdateID . "!") false; } else={ :if ($TelegramChatActive = true && $Text != false && [ :len $Text ] > 0) do={ :if ([ $ValidateSyntax $Text ] = true) do={ :local State ""; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); $MkDir "tmpfs/telegram-chat"; - $LogPrintExit2 info $0 ("Running command: " . $Text) false; + $LogPrintExit2 info $0 ("Running command from update " . $UpdateID . ": " . $Text) false; :exec script=(":do {\n" . $Text . "\n} on-error={ :execute script=\"/\" file=" . $File . ".failed };" . \ ":execute script=\"/\" file=" . $File . ".done") file=$File; :if ([ $WaitForFile ($File . ".done.txt") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ @@ -128,7 +129,7 @@ $WaitFullyConnected; } else={ :local Message ("Received a message from untrusted contact " . \ [ $IfThenElse ($FromUserName = false) "without username" ("'" . $FromUserName . "'") ] . \ - " (ID " . $FromID . ")!"); + " (ID " . $FromID . ") in update " . $UpdateID . "!"); :if ($Text ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ $LogPrintExit2 warning $0 $Message false; $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; \ From 77d26e02d46441958303f111ff846e159cb51714 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Feb 2023 21:33:34 +0100 Subject: [PATCH 1364/2612] telegram-chat: add debug message for handled updates --- telegram-chat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/telegram-chat b/telegram-chat index 67183a7..a3f1640 100644 --- a/telegram-chat +++ b/telegram-chat @@ -139,6 +139,8 @@ $WaitFullyConnected; $LogPrintExit2 info $0 $Message false; } } + } else={ + $LogPrintExit2 debug $0 ("Already handled update " . $UpdateID . ".") false; } } :set TelegramChatOffset ([ :pick $TelegramChatOffset 1 3 ], \ From f1ad240e59cb10936379ead4dd64437cfd95ff4e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Feb 2023 21:49:04 +0100 Subject: [PATCH 1365/2612] telegram-chat: never decrease the local offset --- telegram-chat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram-chat b/telegram-chat index a3f1640..51b3572 100644 --- a/telegram-chat +++ b/telegram-chat @@ -144,4 +144,4 @@ $WaitFullyConnected; } } :set TelegramChatOffset ([ :pick $TelegramChatOffset 1 3 ], \ - [ $IfThenElse ($UpdateID > 0) ($UpdateID + 1) ($TelegramChatOffset->2) ]); + [ $IfThenElse ($UpdateID >= $TelegramChatOffset->2) ($UpdateID + 1) ($TelegramChatOffset->2) ]); From 95b8a47b81b987b7004dd46bf3d07a6baf948469 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Feb 2023 22:01:49 +0100 Subject: [PATCH 1366/2612] telegram-chat: log command with failed syntax validation --- telegram-chat | 1 + 1 file changed, 1 insertion(+) diff --git a/telegram-chat b/telegram-chat index 51b3572..882ce55 100644 --- a/telegram-chat +++ b/telegram-chat @@ -120,6 +120,7 @@ $WaitFullyConnected; ("Output exceeds file read size.") ("No output.") ] ]) }); /file/remove "tmpfs/telegram-chat"; } else={ + $LogPrintExit2 info $0 ("The command from update " . $UpdateID . " failed syntax validation!") false; $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Command:\n" . $Text . "\n\nThe command failed syntax validation!") }); From 7c2ac135e308941311b4e7defaa503ec8db108c3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Feb 2023 11:06:25 +0100 Subject: [PATCH 1367/2612] packages-update: check version before reboot from scheduler Chances are that the device was rebooted manually... Do not reboot then. --- packages-update | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages-update b/packages-update index 9fa3b54..1c1fda8 100644 --- a/packages-update +++ b/packages-update @@ -82,8 +82,9 @@ $ScriptLock $0; :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; :if (([ /terminal/inkey timeout=60 ] % 32) = 19) do={ /system/scheduler/add name="reboot-for-update" start-time=03:00:00 interval=1d \ - on-event=(":global RandomDelay; \$RandomDelay 3600; " . \ - "/system/scheduler/remove reboot-for-update; /system/reboot;"); + on-event=("/system/scheduler/remove reboot-for-update; " . \ + ":if ([ /system/package/update/get installed-version ] != \"" . $Update->"latest-version" . "\") " . \ + "do={ :global RandomDelay; \$RandomDelay 3600; /system/reboot; }"); $LogPrintExit2 info $0 ("Scheduled reboot for update between 03:00 and 04:00.") true; } } From 49e89070a140a7c991d6e17f0ec1a4f1eb06fa88 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Feb 2023 12:03:46 +0100 Subject: [PATCH 1368/2612] packages-update: put reboot into a function Make the logic even simpler... Let's put the reboot code into a function. That is volatile, so device does not reboot if it is rebooted already. --- packages-update | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages-update b/packages-update index 1c1fda8..5162103 100644 --- a/packages-update +++ b/packages-update @@ -81,10 +81,14 @@ $ScriptLock $0; :if ([ $ScriptFromTerminal $0 ] = true) do={ :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; :if (([ /terminal/inkey timeout=60 ] % 32) = 19) do={ + :global RebootForUpdate do={ + :global RandomDelay; + $RandomDelay 3600; + /system/reboot; + } /system/scheduler/add name="reboot-for-update" start-time=03:00:00 interval=1d \ on-event=("/system/scheduler/remove reboot-for-update; " . \ - ":if ([ /system/package/update/get installed-version ] != \"" . $Update->"latest-version" . "\") " . \ - "do={ :global RandomDelay; \$RandomDelay 3600; /system/reboot; }"); + ":global RebootForUpdate; \$RebootForUpdate;"); $LogPrintExit2 info $0 ("Scheduled reboot for update between 03:00 and 04:00.") true; } } From c247fe5a9697bd297d0b1f7645a57f7a6550a58e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Feb 2023 07:57:10 +0100 Subject: [PATCH 1369/2612] README: move configuration down, make it a separate paragraph --- ....avif => 05-run-and-schedule-scripts.avif} | Bin ...le-update.avif => 06-schedule-update.avif} | Bin ...vif => 07-edit-global-config-overlay.avif} | Bin README.d/08-apply-configuration.avif | Bin 0 -> 2437 bytes ...te-scripts.avif => 09-update-scripts.avif} | Bin ...l-scripts.avif => 10-install-scripts.avif} | Bin ...le-script.avif => 11-schedule-script.avif} | Bin ...script.avif => 12-setup-lease-script.avif} | Bin ...ipt.avif => 13-install-custom-script.avif} | Bin ...move-script.avif => 14-remove-script.avif} | Bin README.md | 56 +++++++++++------- 11 files changed, 34 insertions(+), 22 deletions(-) rename README.d/{06-run-and-schedule-scripts.avif => 05-run-and-schedule-scripts.avif} (100%) rename README.d/{07-schedule-update.avif => 06-schedule-update.avif} (100%) rename README.d/{05-edit-global-config-overlay.avif => 07-edit-global-config-overlay.avif} (100%) create mode 100644 README.d/08-apply-configuration.avif rename README.d/{08-update-scripts.avif => 09-update-scripts.avif} (100%) rename README.d/{09-install-scripts.avif => 10-install-scripts.avif} (100%) rename README.d/{10-schedule-script.avif => 11-schedule-script.avif} (100%) rename README.d/{11-setup-lease-script.avif => 12-setup-lease-script.avif} (100%) rename README.d/{12-install-custom-script.avif => 13-install-custom-script.avif} (100%) rename README.d/{13-remove-script.avif => 14-remove-script.avif} (100%) diff --git a/README.d/06-run-and-schedule-scripts.avif b/README.d/05-run-and-schedule-scripts.avif similarity index 100% rename from README.d/06-run-and-schedule-scripts.avif rename to README.d/05-run-and-schedule-scripts.avif diff --git a/README.d/07-schedule-update.avif b/README.d/06-schedule-update.avif similarity index 100% rename from README.d/07-schedule-update.avif rename to README.d/06-schedule-update.avif diff --git a/README.d/05-edit-global-config-overlay.avif b/README.d/07-edit-global-config-overlay.avif similarity index 100% rename from README.d/05-edit-global-config-overlay.avif rename to README.d/07-edit-global-config-overlay.avif diff --git a/README.d/08-apply-configuration.avif b/README.d/08-apply-configuration.avif new file mode 100644 index 0000000000000000000000000000000000000000..b66af1a7ad18f9ee6b4958b1de8c5db463d58382 GIT binary patch literal 2437 zcmbW0d03M97RP_cA}DGoS|GTPmgX{oj9XcQYo^s`re!&W2#L8ME@@@rQaL(PX=+(o zS+;4plw_7#YA%&a<&tS?Zdlhg%fYls=6$K=-sk>tpL_4&Iq&(N-#MJ$`Mf*;0Q7iK zaRPP>p9dg=VC0TA#xQQtKjL-+yT$EXVU zQK9l00(zSAL&7<5<^+HOfKMRDT!oTeD3@o5EdZdsAkE_Q!{nRDD`Y6)!Y%MO*fAD# z$MBGF`2wWBD^S@vmd}G7ZY1-C+^+)wP~`+ha^zRSmj?3%LID)r`2tQj6p8#u0T+sp zAq}7h>Tu-Z27Bkb6W=BG0-ZISg>SkA+5$GL{3Gj?y#Nc=xVX7M7s(d|K-Lc&0TzQ%#GtW?ii$WK zRtZm3!7D4{N$MJEL@HTVhf1bU^bE|G>d{OWQz%B(#-9y@lYM02xxVEIt!!W$yTIA5E+RX1=z(7<#n1~kKY?u1_+aI zN?HpSk;sNimKqr^WBzDmZDVWa=;Z9;y4r2c2JekNzMD4taRRx#9YOry$f)R;U9oYy zlT-E|IGFltTISKL?3`oAb5EQ-S9t!y#Y>lqu3fJX->AG?BBQu5SIc9g+wXBTnL3-FgO8) z)~93CS)PjQ2n`w|5leK)C@8PPEw=P}uNfeGtfXbY95$SS(d1<1B^hgquE!lbox5ptMRFZ!G}%}G*73boH^pk7bGnkV?@pG-b@)k4xKbJ0XWyX{=3)@P4HoBZsp_YX+Ih5fZ#RdLN*Po2un zcBZ^uS*r8yU4kTRYcSc)J$FN7Ea4Up~H(PO6Qg> z?|WuWtWvwy+BlWV5NU2->DWx7-VO|?3O1pil=>Yz_;dZ!J`K11w2f)QUG#xEQh+PP zTL${c_zvnFDO1pwy5gFfVRgfjk#Ui!3qaoSeDu`P8TfViwUtV&u=hi2s>`0W4>VKV z-lP>f6M^S{c7*JiI#9yd7z%BAe{y6MGFs41EuaB!apw8{B|PT*M4U~c>TX_$(z8EO z&zkHd`uHw8y5?R9mZaPx6x`dp>8rIK^NzC3|NjZLp=+>x~V@*hwCA z=VcG5I+^u`ca?cw^0K>Qnx8tbbBKLl;LD8yR!0HnVRY_}%!~wO%}N~eo^;A)b&Jw; zvIF7w!zLd}GiD^~dP{CxuyUcK3uy<~hr?PO`@;M&y!3#wz|S$2=-U&Otb*9Q_nl7( zM#T21DCadyIc>iacJ^&~Q8^^7Y7roWWY1s0F_>m9|g$(=x; z(Vy#dPmqri+xJb<>l5;WE|M!2pHt(F;oCM(3h?|yVMXJKWS*AGyq#5+rS66Y1j)SD z3p>BHhTF=}Y44Z}@M_BL%BpB>u8)@eBdOQG>fJ|gsTwIYU0%L!d@eWs<=QtbQPsYe z?qq0vyzQM?^1899#B9nndt$FgkH|rK(X94lM3Q=b<$z_i>koMyA8GN;#qIeax#Hjk zNymt;y$RR6g1+}RTDtT3ZQV0(XSNC-3C3P)mgZ!|oSYK94p33N^y^UDE^(ypp#7{x z4*M9v{g*8so26kI>UqU)({48oS8hz&(%}>;b-@_harKTIBTz`r^MuD?)A`Ddf4b~w2$=eJh6X~ znzKVqL^MiNcKOyakD5dEddYv5n0TFZ*Ge5+;o;xK>Zl$oToRZ=y?~MJNlBBo1%Y?1 zRVznAO1(aZ5x2`+ds)8hV&hP!qi^rly0Z*j-5zO+kIs=}7HVr5c@+Kf%6vZ8ri!%Q zT#|<+B@Go+=bK-};LE4ZS(~{M&)+xb@-@`6x4V|E&YqTh+5Ks}`=^=0!<(Y`GfuJ5 YsSidUC(c4dfoaqY>zTcCgQ7Ek0U)B8WdHyG literal 0 HcmV?d00001 diff --git a/README.d/08-update-scripts.avif b/README.d/09-update-scripts.avif similarity index 100% rename from README.d/08-update-scripts.avif rename to README.d/09-update-scripts.avif diff --git a/README.d/09-install-scripts.avif b/README.d/10-install-scripts.avif similarity index 100% rename from README.d/09-install-scripts.avif rename to README.d/10-install-scripts.avif diff --git a/README.d/10-schedule-script.avif b/README.d/11-schedule-script.avif similarity index 100% rename from README.d/10-schedule-script.avif rename to README.d/11-schedule-script.avif diff --git a/README.d/11-setup-lease-script.avif b/README.d/12-setup-lease-script.avif similarity index 100% rename from README.d/11-setup-lease-script.avif rename to README.d/12-setup-lease-script.avif diff --git a/README.d/12-install-custom-script.avif b/README.d/13-install-custom-script.avif similarity index 100% rename from README.d/12-install-custom-script.avif rename to README.d/13-install-custom-script.avif diff --git a/README.d/13-remove-script.avif b/README.d/14-remove-script.avif similarity index 100% rename from README.d/13-remove-script.avif rename to README.d/14-remove-script.avif diff --git a/README.md b/README.md index da0bb5e..8bf4681 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,23 @@ Now let's download the main scripts and add them in configuration on the fly. ![screenshot: import scripts](README.d/04-import-scripts.avif) +And finally load configuration and functions and add the scheduler. + + /system/script { run global-config; run global-functions; }; + /system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }"; + +![screenshot: run and schedule scripts](README.d/05-run-and-schedule-scripts.avif) + +The last step is optional: Add this scheduler **only** if you want the scripts +to be updated automatically! + + /system/scheduler/add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; + +![screenshot: schedule update](README.d/06-schedule-update.avif) + +Editing configuration +--------------------- + The configuration needs to be tweaked for your needs. Edit `global-config-overlay`, copy relevant configuration from [`global-config`](global-config) (the one without `-overlay`). @@ -98,27 +115,22 @@ Save changes and exit with `Ctrl-o`. /system/script/edit global-config-overlay source; -![screenshot: edit global-config-overlay](README.d/05-edit-global-config-overlay.avif) +![screenshot: edit global-config-overlay](README.d/07-edit-global-config-overlay.avif) + +To apply your changes run `global-config`, which will automatically load +the overlay as well: + + /system/script/run global-config; + +![screenshot: apply configuration](README.d/08-apply-configuration.avif) + +This last step is required when ever you make changes to your configuration. > â„šī¸ **Info**: It is recommended to edit the configuration using the command > line interface. If using Winbox on Windows OS, the line endings may be -> missing. To fix this, use the below (to load global functions), then run: +> missing. To fix this run: > `/system/script/set source=[ $Unix2Dos [ get global-config-overlay source ] ] global-config-overlay;` -And finally load configuration and functions and add the scheduler. - - /system/script { run global-config; run global-functions; }; - /system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }"; - -![screenshot: run and schedule scripts](README.d/06-run-and-schedule-scripts.avif) - -The last step is optional: Add this scheduler **only** if you want the scripts -to be updated automatically! - - /system/scheduler/add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; - -![screenshot: schedule update](README.d/07-schedule-update.avif) - Updating scripts ---------------- @@ -127,7 +139,7 @@ everything is up-to-date it will not produce any output. $ScriptInstallUpdate; -![screenshot: update scripts](README.d/08-update-scripts.avif) +![screenshot: update scripts](README.d/09-update-scripts.avif) If the update includes news or requires configuration changes a notification is sent - in addition to terminal output and log messages. @@ -142,7 +154,7 @@ a comma separated list of script names. $ScriptInstallUpdate check-certificates,check-routeros-update; -![screenshot: install scripts](README.d/09-install-scripts.avif) +![screenshot: install scripts](README.d/10-install-scripts.avif) Scheduler and events -------------------- @@ -154,7 +166,7 @@ miss an update. /system/scheduler/add name="check-routeros-update" interval=1h on-event="/system/script/run check-routeros-update;"; -![screenshot: schedule script](README.d/10-schedule-script.avif) +![screenshot: schedule script](README.d/11-schedule-script.avif) Some events can run a script. If you want your DHCP hostnames to be available in DNS use `dhcp-to-dns` with the events from dhcp server. For a regular @@ -164,7 +176,7 @@ cleanup add a scheduler entry. /ip/dhcp-server/set lease-script=lease-script [ find ]; /system/scheduler/add name="dhcp-to-dns" interval=5m on-event="/system/script/run dhcp-to-dns;"; -![screenshot: setup lease script](README.d/11-setup-lease-script.avif) +![screenshot: setup lease script](README.d/12-setup-lease-script.avif) There's much more to explore... Have fun! @@ -235,7 +247,7 @@ This will fetch and install a script `hello-world.rsc` from the given url: $ScriptInstallUpdate hello-world.rsc "base-url=https://git.eworm.de/cgit/routeros-scripts-custom/plain/"; -![screenshot: install custom script](README.d/12-install-custom-script.avif) +![screenshot: install custom script](README.d/13-install-custom-script.avif) For a script to be considered valid it has to begin with a *magic token*. Have a look at [any script](README.d/hello-world.rsc) and copy the first line @@ -272,7 +284,7 @@ configuration... /system/script/remove to-be-removed; -![screenshot: remove script](README.d/13-remove-script.avif) +![screenshot: remove script](README.d/14-remove-script.avif) Possibly a scheduler and other configuration has to be removed as well. From da46c42d4ace3cf2d0400f04a6ee1aa7dd0065dc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Feb 2023 12:21:15 +0100 Subject: [PATCH 1370/2612] README: add a paragraph for scheduled automatic updates --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8bf4681..0813f2d 100644 --- a/README.md +++ b/README.md @@ -98,8 +98,10 @@ And finally load configuration and functions and add the scheduler. ![screenshot: run and schedule scripts](README.d/05-run-and-schedule-scripts.avif) -The last step is optional: Add this scheduler **only** if you want the scripts -to be updated automatically! +### Scheduled automatic updates + +The last step is optional: Add this scheduler **only** if you want the +scripts to be updated automatically! /system/scheduler/add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; From fe0460ef6daaee5f5cf0a77f694e3e4b4f00a300 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Feb 2023 12:26:24 +0100 Subject: [PATCH 1371/2612] INITIAL-COMMANDS: link to new paragraphs --- INITIAL-COMMANDS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 2300248..a31112a 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -28,9 +28,9 @@ Run the complete base installation: $CertificateNameByCN "ISRG Root X1"; }; -Optional to update the scripts automatically: - - /system/scheduler/add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; +Then continue setup with +[scheduled automatic updates](README.md#scheduled-automatic-updates) or +[editing configuration](README.md#editing-configuration). --- [âŦ…ī¸ Go back to main README](README.md) From 8213c5ed612459b4f69688377d8db914e63a39a2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 19 Feb 2023 14:45:18 +0100 Subject: [PATCH 1372/2612] netwatch-notify: support sending silent notifications --- netwatch-notify | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 1d52b27..d04d23f 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -116,7 +116,7 @@ $ScriptLock $0; :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "up" \ ($HostInfo->"up-hook") ]); } - $SendNotification2 ({ origin=$0; \ + $SendNotification2 ({ origin=$0; silent=($HostInfo->"silent"); \ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . \ $Name . " up"); \ message=$Message }); @@ -167,7 +167,7 @@ $ScriptLock $0; ($HostInfo->"down-hook") ]); } :if ($HostInfo->"no-down-notification" != true) do={ - $SendNotification2 ({ origin=$0; \ + $SendNotification2 ({ origin=$0; silent=($HostInfo->"silent"); \ subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . \ $Name . " down"); \ message=$Message }); From b96376187472fc5469f6f7c126a6dcb73667bf0a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 23 Feb 2023 22:05:08 +0100 Subject: [PATCH 1373/2612] mod/notification-telegram: support sending in reply --- mod/notification-telegram | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mod/notification-telegram b/mod/notification-telegram index 69c4801..c90e3f0 100644 --- a/mod/notification-telegram +++ b/mod/notification-telegram @@ -34,6 +34,7 @@ ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ http-data=("chat_id=" . ($Message->"chatid") . \ "&disable_notification=" . ($Message->"silent") . \ + "&reply_to_message_id=" . ($Notification->"replyto") . \ "&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \ "&text=" . ($Message->"text")) as-value; :set ($TelegramQueue->$Id); @@ -137,6 +138,7 @@ /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ + "&reply_to_message_id=" . ($Notification->"replyto") . \ "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; } on-error={ $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; @@ -148,7 +150,8 @@ [ $EscapeMD ("This message was queued since " . [ /system/clock/get date ] . \ " " . [ /system/clock/get time ] . " and may be obsolete.") "plain" ]) ]); :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; - parsemode=$ParseMode; text=$Text; silent=($Notification->"silent") }; + parsemode=$ParseMode; text=$Text; silent=($Notification->"silent"); + replyto=($Notification->"replyto") }; :if ([ :len [ /system/scheduler/find where name="\$FlushTelegramQueue" ] ] = 0) do={ /system/scheduler/add name="\$FlushTelegramQueue" interval=1m start-time=startup \ on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;"); From 5ea892662f94d817ff325abe21620665efde24fa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 23 Feb 2023 22:07:37 +0100 Subject: [PATCH 1374/2612] telegram-chat: send messages in reply --- telegram-chat | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/telegram-chat b/telegram-chat index 882ce55..8b7fa5f 100644 --- a/telegram-chat +++ b/telegram-chat @@ -77,6 +77,7 @@ $WaitFullyConnected; :if ($UpdateID >= $TelegramChatOffset->2) do={ :local Trusted false; :local Message [ $JsonGetKey $Update "message" ]; + :local MessageId [ $JsonGetKey $Message "message_id" ]; :local From [ $JsonGetKey $Message "from" ]; :local FromID [ $JsonGetKey $From "id" ]; :local FromUserName [ $JsonGetKey $From "username" ]; @@ -113,7 +114,7 @@ $WaitFullyConnected; :set State "The command failed with an error!\n\n"; } :local Content [ /file/get ($File . ".txt") contents ]; - $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; \ + $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; replyto=$MessageId; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Command:\n" . $Text . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ ("Output:\n" . $Content) [ $IfThenElse ([ /file/get ($File . ".txt") size ] > 0) \ @@ -121,7 +122,7 @@ $WaitFullyConnected; /file/remove "tmpfs/telegram-chat"; } else={ $LogPrintExit2 info $0 ("The command from update " . $UpdateID . " failed syntax validation!") false; - $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; \ + $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; replyto=$MessageId; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Command:\n" . $Text . "\n\nThe command failed syntax validation!") }); } @@ -133,7 +134,7 @@ $WaitFullyConnected; " (ID " . $FromID . ") in update " . $UpdateID . "!"); :if ($Text ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ $LogPrintExit2 warning $0 $Message false; - $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; \ + $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; replyto=$MessageId; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("You are not trusted.") }); } else={ From 02b447212d3b6aa238c719b34a8b245d63ca5deb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 23 Feb 2023 22:36:37 +0100 Subject: [PATCH 1375/2612] telegram-chat: ignore new messages after reboot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This script supports multiple devices, and sending offset to discard messages is delayed to third fetch to make sure all devices get the message. This can cause trouble, though: Sending a device a reboot command can make that device reboot multiple times đŸĨ´ or - even worse - make it enter an infinite boot loop đŸ˜ŗ if it is the only device. So let's ignore first messages after reboot. --- telegram-chat | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/telegram-chat b/telegram-chat index 8b7fa5f..e4bd783 100644 --- a/telegram-chat +++ b/telegram-chat @@ -74,7 +74,8 @@ $WaitFullyConnected; :local UpdateID 0; :foreach Update in=[ :toarray $Data ] do={ :set UpdateID [ $JsonGetKey $Update "update_id" ]; - :if ($UpdateID >= $TelegramChatOffset->2) do={ + :if (($TelegramChatOffset->0 > 0 || [ /system/resource/get uptime ] > 5m) && \ + $UpdateID >= $TelegramChatOffset->2) do={ :local Trusted false; :local Message [ $JsonGetKey $Update "message" ]; :local MessageId [ $JsonGetKey $Message "message_id" ]; From bfd1361f7122754dfd2d30004d4effc73f375796 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 26 Feb 2023 22:00:52 +0100 Subject: [PATCH 1376/2612] telegram-chat: get the uptime just once --- telegram-chat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telegram-chat b/telegram-chat index e4bd783..ba2a3ff 100644 --- a/telegram-chat +++ b/telegram-chat @@ -72,10 +72,10 @@ $WaitFullyConnected; } :local UpdateID 0; +:local Uptime [ /system/resource/get uptime ]; :foreach Update in=[ :toarray $Data ] do={ :set UpdateID [ $JsonGetKey $Update "update_id" ]; - :if (($TelegramChatOffset->0 > 0 || [ /system/resource/get uptime ] > 5m) && \ - $UpdateID >= $TelegramChatOffset->2) do={ + :if (($TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={ :local Trusted false; :local Message [ $JsonGetKey $Update "message" ]; :local MessageId [ $JsonGetKey $Message "message_id" ]; From b0595e53a5ebbbadd88e51ce6c0f70d93549f5f2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 12 Jan 2023 23:52:57 +0100 Subject: [PATCH 1377/2612] global-functions: $MkDir: drop the compatibility workaround If you are still running RouterOS 7.6 or older add this in your global-config-overlay: :global ScriptUpdatesUrlSuffix "\?h=routeros-7.7~1"; ... and remeber to revert that change once updated. --- global-functions | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index f15a7d1..996a6e1 100644 --- a/global-functions +++ b/global-functions @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.1 +# requires RouterOS, version=7.7 # # global functions # https://git.eworm.de/cgit/routeros-scripts/about/ @@ -581,12 +581,12 @@ :set Continue true; } - :if ($Continue = false && $PathNext = "tmpfs" && [ $RequiredRouterOS $0 "7.7rc1" false ] = true) do={ + :if ($Continue = false && $PathNext = "tmpfs") do={ :if ([ :len [ /disk/find where slot=tmpfs type=tmpfs ] ] = 0) do={ $LogPrintExit2 info $0 ("Creating disk of type tmpfs.") false; /file/remove [ find where name="tmpfs" type="directory" ]; :do { - [ :parse "/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"; } on-error={ $LogPrintExit2 warning $0 ("Creating disk of type tmpfs failed!") false; From a9741336b89a41a8cbf252c799ef3926b268b6e0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Mar 2023 14:08:48 +0100 Subject: [PATCH 1378/2612] doc/check-routeros-update: update wording and details --- doc/check-routeros-update.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 348acc6..8eec19b 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -46,14 +46,16 @@ And add a scheduler for automatic update notification: Configuration ------------- -Configuration is required only if you want to control update process with -safe versions from a web server. The configuration goes to -`global-config-overlay`, this is the parameter: +No extra configuration is required to receive notifications. Several +mechanisms are availalbe to enable automatic installation of updates. +The configuration goes to `global-config-overlay`, these are the parameters: -* `SafeUpdateNeighbor`: install updates automatically if seen in neighbor list -* `SafeUpdatePatch`: install patch updates automatically -* `SafeUpdateUrl`: url to check for safe update, the channel (`long-term`, -`stable` or `testing`) is appended +* `SafeUpdateNeighbor`: install updates automatically if at least one other + device is seen in neighbor list with new version +* `SafeUpdatePatch`: install patch updates (where just last digit changes) + automatically +* `SafeUpdateUrl`: url on webserver to check for safe update, the channel + (`long-term`, `stable` or `testing`) is appended Also notification settings are required for [e-mail](mod/notification-email.md), From d2d913ec19c0395fdc1090bb8baaf911d79dbab0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Mar 2023 14:15:24 +0100 Subject: [PATCH 1379/2612] check-routeros-update: allow to install all updates automatically... ... but with extra hurdle for more awareness of danger. Let's not send a new notification, intentionally. This feature is dangerous, and we should not advertise it. --- check-routeros-update | 11 +++++++++++ doc/check-routeros-update.md | 4 ++++ global-config | 3 +++ 3 files changed, 18 insertions(+) diff --git a/check-routeros-update b/check-routeros-update index 3e5a381..d1c82c5 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -11,6 +11,7 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global Identity; +:global SafeUpdateAll; :global SafeUpdateNeighbor; :global SafeUpdatePatch; :global SafeUpdateUrl; @@ -59,6 +60,16 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; } :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"); \ + 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={ $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; $SendNotification2 ({ origin=$0; \ diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 8eec19b..8e158e1 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -56,6 +56,10 @@ The configuration goes to `global-config-overlay`, these are the parameters: automatically * `SafeUpdateUrl`: url on webserver to check for safe update, the channel (`long-term`, `stable` or `testing`) is appended +* `SafeUpdateAll`: install **all** updates automatically + +> â„šī¸ **Info**: Installing **all** updates automatically requires extra +> confirmation. See `global-config` for details. Also notification settings are required for [e-mail](mod/notification-email.md), diff --git a/global-config b/global-config index c65e2f0..770efd0 100644 --- a/global-config +++ b/global-config @@ -105,6 +105,9 @@ :global SafeUpdatePatch false; # Allow to install updates automatically if seen in neighbor list. :global SafeUpdateNeighbor false; +# Install *ALL* updates automatically! +# Set to all upper-case "Yes, please!" to enable. +:global SafeUpdateAll "no"; # These thresholds control when to send health notification # on temperature and voltage. From 154a036c64a0dc5961ef4de0f0d931617ed95d4c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Mar 2023 17:18:23 +0100 Subject: [PATCH 1380/2612] use a new logo --- logo.avif | Bin 2607 -> 2001 bytes logo.png | Bin 3807 -> 4428 bytes logo.svg | 46 ++++++++++++++++++++++++++-------------------- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/logo.avif b/logo.avif index d118cc314250c762a2a328d71f42e14b7d35e78e..399a2f5ad184fabd7e8127b1e2f1bd994ac7a6b4 100644 GIT binary patch delta 1614 zcmV-U2C@0C6wwcmdK3eO000C_00IC2009610kr@C0nxFJApw5|ByD72bP@mx1{fKy z-(gTP!~;YC0NqNr!~%rchQ<7C_gm=G(E-~6%Iv7n{wQ^9`(%3tH$y{UL2-whDf+PTBdBt(eDqSo^hFgbp(q)#zr2WYWtTbv|w z_sz`3(xK`HZ^Wld@#0fDAk(E3KqjJVz@p4**S2B5Axq>5d?~(DcWcfn@0Gs-wjg(j zH~rSuRt;kgdOR8IFNG#knQ0V1TZ3~i{TlO|tkVnTj)H$$Qb#lavhGSviyk4IJ- zg^UwjH~xR7&7SpHW^fe`YmIBX?2Aqru8_1h^hG$GGy=y`3LIlI`rBGbwh2kd13ji1 z;2ei$0-%3QjMe@bt5xL|t${H^4RE-QpG%uN7Z!`MfEbi_9^@tGJyxq8x;(wr1VJtc z5nJr#OzwsX=}tN(;LpDRJjy5|ddREvd?KC`i%f&ZEB@53jF z>xS7PGIhwR^WsjIbz?1&6{mN7I%wfigPX1g(71lQB;%4*RNI;~C&6JF z{Wk$FfWSTViST#=W^jMK1qH+d%X{fNywEJi-hBe#3VqB?IaRFgtXETaT4F>mn|hx7 zw<7{-BQN1&3FFs0Kl@yHuR%Chw2Sca*zK>>B~)|(({<8GPwmuTHD=)!_S`$IDFeBgILNNy`?V3!{a z_-ZLE)ENN|;XrIa4+6KQuG@bpT72tU>`T>Q_&G*8wnOB3n$Vtk$O;>jnfpVk4uYJC z1`ybqCTwj9j%eokJd16-AAGyvf5>8(x}XHH0ojbEb>sG~+Qhk)u)7ZSbwFFzU%y+| z`0B!hVQwka$v43IL8jX}fc4q}mi;=R4D)fmS17@Gglpg(#QOaK4? delta 2225 zcmV;i2u}CW53dxEdK3np000A#00IC2009610kr@C1nIGkApw5~f^B4BbP@mx1{fKy z-(gTP+zAi>0NpDpp42!s3T7$W3Mnc>$yqhHt<;~yKk_(7-o8E)lo+ctkg0n|EcH3f zO?OA&&9#6?&&uibYf)EBUFz*XtXztOzjm{3qrCtL@#6OSJiYjnZ>`m*`ht%z0DV6$ zKytPrWg837MqB`Ou=B~t#|uKJ+-SO;DH&!Gvu>Lk2-dw5a@@Q)^A$*p*PRKBaTpJb zCQvbz`$B)K8B(w{v`N&HhOl4ClQ4nw9sY<`872jg6HuA6!>xt9IWF`pqE3OlYRqmg zNqkf{7mLHG?l=BC*9S-L$UL)QW>qNy^S%bp4l46*0z?CMkijX@cEda}SEKpM+!@TU z{YqUj6D5p|!?LZNSO`ca=IXt|e-`l&QdGm|lU#q7xxvQF(O(YiazJ5lX*ba-zw_fL zJRX(7LP2VREN%kJ(%nog7RQ+uJd-F9S< zf7X8>e5%3`h_?8Zq(0)@+53JM@Hoxe$sAuD{44(lYSyMlpBRVmrgIBlL`AXk;1L*j zgzXVYLY=!&II^=@f1nVx$LH}@Z7Ix=qG{w{tub!7dFVWz8Xa3CinZScry`lZB1U5J=u0)9M1Nl3T;8gMoy_`iV5DzmT#{aX497O|K7M-egFU5T3T9t|Nq=tegw1%2$IBSSf_?o z6|A=Vx(EIQDx@7$IcmRb%}FIU)eX)$?p!z|e1a>eXNEO3U;+ZwC-%lwd-TtiQ)X6A z@3sEN@>L}5@+J5Z0162>8LxleVF3*WkTQV>L}UPAh8R%WaTfj~Vv9Ey7P+;n%kA03 z7jR}Ye>(n2>g{edcJbRAaAc*58c)$;(3;OMiZ18R#-XTFf)sv9dD3xpkbYy~q11A0 z1PuK+FU#qI~p6TVt5MjB_BB*oj8fTNyx7B#_9@#a7JPCgagZj$O-lA)G z0r6a63OES(5<6FH!St$a%{nc**{{C1octF%0Mx1f`(4 zm}507JMlTGH9nH06z_{7v%k`3X3ElZl#craS^o)%a{n_ZdW)`?%wi7>*^_C#kYawH zTPML+x-SU@6II=aJw1QdHf(&kKWAENfHD%;w1lNH*3sVDs(t`m$1_33YZ&20vFEJ> z-fVJds>IZ)h0TCo-DSD(s&g&Pf@t*;=>C$SZ(xp9SEeIsG;`a+ZI}}#c@i&h3xC;z zPeGTGh#$#zfCZ5yG%3!R`Ff?f67|QbmZLP;M;tMhZ0(tt6bye%3LYr1BxvsQfCj0& zj2`W(U3c6U>)e;FvRmtvBK}8^)LGj5RqZTJ!siJF_Ro=iq4;3bPV$?JOgi^y-DN_* ztk^?bK?|tsHPBsAD%vVA1;4jsa(ccu-8(Vn-(EG?i7>c<+ij$vjLyokyx-_FUKRl+gR* z_$7hmQGT$t2GBqD2bGh4p;L$(9$W{ZwUna;=acoXvRNum)FS<_J)#9Toe=$Lt5tQ* z23c^}RuAv;hEp`~S-kWE(~NxcR;L4i-VUe7EYevC*sXtYAA?I^Ut0P-$_reKpzB(2 zH!7M18cHZ_cUrcXq}qi8At*0sQqbhx!Pyd9Q7h-*TL=3*Uh1}z2J(SV?R{&jPvD9VMeTPA7AuRk$zK`^58;lN(bZdVcCTOh?{B0B)9je#Ipr=B1KGu5`ng;dc z!!*B9V*dO}wxNnTWoyG-gk|JLhV@(5AL^aqb0n`GkelvYAT9fZXiVYK^G=E(^S5!h zJa6mx@Ya_BlEx2rmz)}Wc*zb1zh^ofap&J+EcX#Jn)sSG+pt9VAnEfhGyA3>2L3^b diff --git a/logo.png b/logo.png index 142e9186fb149f5508d2942e93aca9db90ee7276..d97b75dc7d39e2c9e6ff6339d47711e97d6be1f0 100644 GIT binary patch literal 4428 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 - - - - - image/svg+xml - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + From 4ca8f83a526c71ffa541be8f065e0fec6b768461 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Mar 2023 14:45:30 +0100 Subject: [PATCH 1381/2612] ... and update the logo in notifications --- README.d/news-and-changes-notification.avif | Bin 14720 -> 0 bytes README.d/notification-news-and-changes.avif | Bin 0 -> 14861 bytes README.md | 2 +- doc/backup-cloud.d/notification.avif | Bin 11615 -> 11629 bytes doc/backup-upload.d/notification.avif | Bin 11674 -> 11776 bytes doc/check-certificates.d/notification.avif | Bin 12960 -> 13088 bytes .../notification-01-cpu-utilization-high.avif | Bin 6453 -> 6481 bytes .../notification-02-cpu-utilization-ok.avif | Bin 6717 -> 6797 bytes .../notification-03-free-ram-low.avif | Bin 6426 -> 6457 bytes .../notification-04-free-ram-ok.avif | Bin 6716 -> 6772 bytes .../notification-05-voltage.avif | Bin 4053 -> 3829 bytes .../notification-06-temperature-high.avif | Bin 3615 -> 3519 bytes .../notification-07-temperature-ok.avif | Bin 3763 -> 3727 bytes .../notification-08-psu-fail.avif | Bin 3544 -> 3474 bytes .../notification-09-psu-ok.avif | Bin 3561 -> 3531 bytes .../notification.avif | Bin 5279 -> 5077 bytes doc/check-routeros-update.d/notification.avif | Bin 6850 -> 6392 bytes doc/collect-wireless-mac.d/notification.avif | Bin 13403 -> 13378 bytes doc/daily-psk.d/notification.avif | Bin 7485 -> 7040 bytes doc/log-forward.d/notification.avif | Bin 6326 -> 6178 bytes .../notification-01-down.avif | Bin 4340 -> 4193 bytes doc/netwatch-notify.d/notification-02-up.avif | Bin 4862 -> 4744 bytes doc/sms-forward.d/notification.avif | Bin 4751 -> 4619 bytes 23 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 README.d/news-and-changes-notification.avif create mode 100644 README.d/notification-news-and-changes.avif diff --git a/README.d/news-and-changes-notification.avif b/README.d/news-and-changes-notification.avif deleted file mode 100644 index 547c15cbc88b2f5a8a9ea5b80cf33a5005d3dfd7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14720 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%0D5C*Bw5JX{ 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 JnRTxUEue9S7N7tC diff --git a/doc/backup-upload.d/notification.avif b/doc/backup-upload.d/notification.avif index 277cab4d065268aa631dfcc2c4cb2e9a6b6c97c9..83cfb18aabeb4cf7725154fd08a50663458d7863 100644 GIT binary patch delta 11601 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 Q>cpLc*`c=GG~4R_F!1MF;s5{u diff --git a/doc/check-certificates.d/notification.avif b/doc/check-certificates.d/notification.avif index a458b7ccfb5b6e472e370e76742d45788ffb6389..d7e9e84e8e14d8a3b3a12642fd92d8bb746470a4 100644 GIT binary patch delta 12925 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 OKd7Vqh~B4*4cJMueG&Tr diff --git a/doc/check-health.d/notification-01-cpu-utilization-high.avif b/doc/check-health.d/notification-01-cpu-utilization-high.avif index 8aad87832594b52984424d63ad9eb6a423303f4f..326e7feddb23d52c83f43050e15bb75f29b6c6c5 100644 GIT binary patch delta 3405 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" . "
    " . \
         [ $PrepareText ($Notification->"message") ] . "
    "); :if ([ :len ($Notification->"link") ] > 0) do={ - :set Plain ($Plain . "\\n" . [ $SymbolForNotification "link" ] . \ + :set Plain ($Plain . "\n" . [ $SymbolForNotification "link" ] . \ "[" . $Notification->"link" . "](" . $Notification->"link" . ")"); :set Formatted ($Formatted . "
    " . [ $SymbolForNotification "link" ] . \ ""link") ] . "\">" . \ @@ -140,7 +140,7 @@ :local Text ([ $SymbolForNotification "alarm-clock" ] . \ "This message was queued since " . [ /system/clock/get date ] . \ " " . [ /system/clock/get time ] . " and may be obsolete."); - :set Plain ($Plain . "\\n" . $Text); + :set Plain ($Plain . "\n" . $Text); :set Formatted ($Formatted . "
    " . $Text); :set ($MatrixQueue->[ :len $MatrixQueue ]) { headers=$Headers; \ accesstoken=$AccessToken; homeserver=$HomeServer; room=$Room; \ From 6fd0becf64184184642e719e288bc537a0bee499 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 19 Apr 2024 08:59:51 +0200 Subject: [PATCH 2182/2612] global-functions: introduce $ProtocolStrip --- global-functions.rsc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 918ea9a..3b9f27c 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -58,6 +58,7 @@ :global ParseDate; :global ParseKeyValueStore; :global PrettyPrint; +:global ProtocolStrip; :global RandomDelay; :global RequiredRouterOS; :global ScriptFromTerminal; @@ -885,6 +886,17 @@ :put [ $Unix2Dos $Input ]; } +# strip protocol from from url string +:set ProtocolStrip do={ + :local Input [ :tostr $1 ]; + + :local Pos [ :find $Input "://" ]; + :if ([ :typeof $Pos ] = "nil") do={ + :return $Input; + } + :return [ :pick $Input ($Pos + 3) [ :len $Input ] ]; +} + # delay a random amount of seconds :set RandomDelay do={ :local Time [ :tonum $1 ]; From 8cd03167ca0bd47efd9b7c9b12aabebbe228b36c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 19 Apr 2024 09:04:08 +0200 Subject: [PATCH 2183/2612] mod/notification-matrix: string protocol for display --- mod/notification-matrix.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 7eae1b0..9442f54 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -76,6 +76,7 @@ :global EitherOr; :global FetchUserAgentStr; :global LogPrint; + :global ProtocolStrip; :global SymbolForNotification; :local PrepareText do={ @@ -117,11 +118,12 @@ ($Notification->"subject")) ] . "

    IQ!+wNBMPY)|FK>q}|P z>ibHD{OFSSwofRyL0<~MAf-`M4zsb4OGg*oXmxT}e<0exPS5`&~Dn?o0Hjt3%%#t|A?#CD11o;qj5URA>|A9;Ba zNz%`Pu=w}PC41k>IE7uB5`p$qwotQH_#SYTdmYfa50q| zG)E)>KA(bklM?&75f4UWD~>kpkKO6JSin5)ErL!a?>B$Bw@lPi94*0EB|OlO%%f~O z^ywpjS-#>c1JQ+L7_Q%ROEfGGK!A^jd**c>E{0rEd7|qU7XL`!XL#vhm5c6<2F)n* zm^3hvPtTd9o=4}USi|Y-6S7owK}{p;)4E5BSqL4RXA~-)CA|ah?P$5E7_#|7ty2q> zJQ6S+;<;g9_>imc|C-Bz;ogoZy&DAMqAY4! znzaDK1UT-`-o3f=F4z&;zh7^iAI^WU{a7Bc=2Iq|@s2l6kpXn@CPEB|@pO2{Pm7&n zqBVc>H4uQ`T_K9!IYss9r_;TV(kEW7^}VGP7D@mOzf2z5-LS8rXs2bmMDBcuEgjm{ z0%@gpHezg+JduX@O4V}_I+6vhuCvLLH?I7@Sv`j$x25%f zeN7>}_;LJh_I8^LU&!W8-fy)>q-=}$wk0^TywNN>~ckS14d>q3g1=FHrMWgx4>&t-X9oeU3*dBkW zb*jnci+g93Q*WYLCgQ1qKvD8T1GH^7Lr9xdjZB`M_@=2PXtC?v= z>@L<8O~eTLpVq6>zZj1w!mb@d})A5~b(SRfyzhjWSr8ZcopI(um1(TWm*iIVsU) znn-l$d&cyXqk~&iHybj!CqvT>buD9>DZxkXCCsyCpvrE?7Fv;B#)4R?0WN=dxwP18 zTd^PxH7OMImx%5FV60U3qNBj6dW}PL3@;Rm3JlRyg>Y!Ut#m;)`TOc0tLHYws8Pofp`#v? ztLSO_MxSRRWcj=9lbMyW{?YB6M2&OAPr~%YyuNo4HJ4tM|({=qILaSM|@f zZ;tU@Mx$o}45bNQ$uUZML0YQ2xp`zg{ohH)lo?6>ti zpKa1~`isDojdWfC1VxdOc>V<90<7m_y7|@i6#Y+vB$pEoxNCoew76m$_SWS2!RDXl zer6f|M;Q?b9omnZQpkweLgDhWX|@a=%ngj-kxvRrJ+Nig0S@oGP+`Q{jzkQkSxjSk=NvqB0GyH!?P=bta1Ts}mAFq6r!JF8W z>RqhjVOB~o+X#Dx0i|f`AwSFnZA|87cduXG^2m$-#=CQZbz`J&jxlX6us8;pk}JZT zD6$3)zGr^eWNowg(vzDj@+sJhwZ}x~=Q^5U(?A~<+WkqMYFCr*+_bnK--{bUrv~U+%{=Rw#@s5Op>wlvz?hPIJA1`k_&&1$;iqEw*YkyqHZDjz@-3Q zeUAC#mM!(7y8^#gst#uZkrnSy6v^zWDepw5@J4)$cYZ$HT zPBLH<^;nJOT8+(t4apY3HhwK5#~O#3t|g`OT!OP0~^ktlksn)L&##)nO&jZ KLt8fs8-l?9T7k#_ diff --git a/doc/check-health.d/notification-04-free-ram-ok.avif b/doc/check-health.d/notification-04-free-ram-ok.avif index 0b76baca81a23bab499490118e933af5c16b9c16..cadb1d01373f7624cc251ccda0a66ca0428eab93 100644 GIT binary patch delta 3596 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 delta 3540 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 diff --git a/doc/check-health.d/notification-06-temperature-high.avif b/doc/check-health.d/notification-06-temperature-high.avif index 1a93610d49c1e033adf38663f322830188e30348..60d38027a92d5bb8f1cd6467ae10b5a1dfd34001 100644 GIT binary patch delta 3281 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 delta 3378 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 I43>Yi5ZAABwEzGB diff --git a/doc/check-health.d/notification-07-temperature-ok.avif b/doc/check-health.d/notification-07-temperature-ok.avif index 3bb9c68c4786ca4400bdd8428442e597321daefc..4afed02da806b192859d23f3731281d50ca209a8 100644 GIT binary patch delta 3489 zcmV;S4PNrI9giK5e*txofR%rJZDe6|5&#MbI3=eVY#)vf#4a^&@q|b^IizA&+Cmc%vP)#?k1<~$1!}!Tna-O8 z?rh?#!^>!Z8w)J@f|q(WPy~5!H~mYmcdpf@apH&zX&a+c`_gV0TeU(7fDi-+asxMU zYAwEBwEWD)ri||aN$G#hN}eeB*NtY;f|FptJ%wsoUy4cyHd?Bs6K%`KJal>#HFIxD z)*7Nfio0AVL4uT>ZoIDfi2V|Gmw1mUfJ`H>%Oq4oU2#kVjEo$?A27*)r~4Cb*X%K^ z1+Si#s11*dul{}%+kDBG@{W1|U%n2`BQJMkEjJ<#mr)y%6P2@n4Q=yU_T^2d8LM5P47tH;igw$(zvs#^ zqpyfJ%Q6T11%rbQP=aaJMR9Tkw6?R8hP9bf*aN@3yTb=6o^q_g(#0Oar|5vZAMC2P zOZo8JT`@FP9+!W5*hgUX?weT7ll&ekY&xYd%~%>)B5ot1hq0vqTAi_f zGp0lD_AU-GiJYi+(0{Bs3XDiGynHY0kK3O_@d|q^HwAygM6XY7g~TQ@d7z`x8SyMT?*-g5a8>VbJr+(qr7zl z?h-u>9AbV!#QUZk+lrhulu^=OuN~b)!iLpDwJm)_a~Q8gu9{TWM2rLHPtM zs#v3Hxn#bQ+PQhTkChkjba4C?O7~zkR!FY2DN=vAG$mXE@n-XRUb~Aq=Kq~7^JTb6 zP75kQ_$MHc(;Qq7x+D_CQX1!NGhf;8n{aqLd$TVC06PxX1=CJBXBb!p5duGByFve~ zB*Q*Q2aBD4(}0y_CjVFg;S6z&1)tA!?nPh}BaVeAXTM1hb?Y|%V&+OE*hQQj`X4BQ zZBKtwS*e+VCYGp#+^J9&Wk=_ZdIM2eAj0})_Cz?9JrMViEF%__Ztg^&y($d3Z-d)t zuj|gVVFg<@&d|7rqhbA_2xLs-U_XyK6!&1xOL&o^B#C!CG$y=aA!&Y(s$G(w^y*V~ z@oH6TJl(+T8Ld|LB^4^5;yV_$Eui3pH_3k^(TMPqwj!+UP@&8nBEupT%t>F^gP-U- z6FB*k3B7hLp0E>aHG$g!$JDqvD>`E)K8D*o8`oprVyYPfyNX7sP`xlD#;QGVEL_G- z6?AF^0qha8cZNV6{5AMcGzW$Ft5KLqoaNUS_o5ut|p0^gmGCYC9dO zo5S;U4Vxgu>RCikC8L8FtmA)*LyC_kvC-j=UrjK+9c*Px|8pXA4?kOxz3)I2x4R4; z!ZB(4@SRc>Q#c{yeqDieBvn? zg7E`Byd3mFKg5UDo2~PL2&w}4pByqu5Jz~mP{iULAky8R0bB%ru7or*(bZFJgC(%N zag4ptA)sh&M;<(O$^WC=NSeOHHvZJNhLTzKGzgk^RX8fDj%J1MKmj%q}>pg zk;?HpxvU><^mbYXr#*iU2khAHO>%n{$WR&>9lNk*M0+unz$*SC8I|BSu~X(w`0@La zP{flAft@cxpVtX&Q|$<~&RrIp#poCTA{OmtspmpJvZAu}hm-#UhqWZnIf6$>XfCUi z4V1v<)W7*+t3)_lgd>BQts4ytV=hKlQvzKdB=RMmmO>5#h}(*JZ>f@l5WAObA!yLZ?Y6`Y!SI&Z zs=>WDWJvyQvuq)9OTlTbe0UgsGU)f}0xb~S#j>46g*|_1hKtGknziS%T|qZ;+c%i> zK}}G+WDupA@^y@G*lwsVcaHK2mp6S=hYcic07gYv4f|u4?~w250K$qY5d-_DH}fnz za8WA5Vpd~jCk4UcHC!M3D?2Au5xF77WQR^``YNlUI%qt*x4c}GkuuT;uqUeek<;*t*4 zP0?A)rT55kqQB3IqB(y55Vp=92hwWTx+<1RR#krm48S?! zYoznijv9kqU`*1F4K7n371(cKKuYZM-sUBHn4l-r`%(C8f%A#cGM4+_HUR0^gSN;Q zDBmbvVPPg<+Pn9sX)ms`+PBO|Cr7(IOnK%zjL6ul4DYc@JP86lRDIpzoJh`^D6?od za0`Ezw|+Xaqah}bCF#URBnM7WPFaMJwUzJtSdVszdO}!f(IdPG^TCQZoE_{43>Q?% z0k#y7p?lXNGw)t>z}Yr8SH4*dWhU}mFwO+yRhsN|10mH~sfhC_8Bc^b^I2iJyGLe? zXd?7=TijMr?r(mOZAu*%`_kq^To=$N#NdChwC`=5Wix`R@^IDJ*E5?@&lupHW(@1mf5^l6RSqw z3x-YVAKSPR@iu3o(+^xt;_ZO`n{0uY;;?qi;s$RlpatrIO|eRwJ}L%*kf1<1_2Y{B zR`F^yjdSXcsx)cy>-|VFGeR!{eJOt^_-7^1TU~(M(Om9|$L{ThZNeT~??tP?43cO= zbUV}tKpyiS1tS8+Nj2-6KQp$k044|0_xCKezrtZW(eCnX^eN1L-Wwp?(=-47-~EM3 z@)b`T@S?}A-=^bnlt1Qr@uD--nj5SdkMI7n5l(5MwoZz3%s@YfFp^BZ92Dh3Ip%M=zL|3B!M5)KgGS` zu`BFe1D;OWKqDN!+HSHs45h*|M5F3ClM?u*te)}^+OmB#{HaOVWOfw=bG$~j_IZl) PGTd(eM9>Y&CSX1gp$4vu delta 3525 zcmV;$4Lb6V9kU&fe*u}1fR%rtZDe6|5&#MbI3=eVY#UJJ#%Ot2hfF$3XcYUPMskU`C$E$7gJsYD(%QV ztR!Z7%PP)17|CgzU$KDiuU=$J_rrZ`+i62Ncp)Ti=~ju`MBkru@aE00zr9Gqrx@0A zjw^?YYzk~PB?abxP2PWAs%R?|RMh$I8$Lq(3mMViDs@9UvqGpnd=mjqV& zoq%!#i%x!zr_)hT)vHP$$wIMTWB>j{;}y}+)H%5@Uhgb_^JDLm0HySyLMMCL1>cpv zK(MO?p5o?{%pkw!$0~rfd79v%=)D(XXz#*j2HU|GweR!k=;D6?TXIv9*f~IT_7aGH zG~bT1r=U1szxPwJ@*%yYL{>b-@^XuO3W*w5>A|D6^$|M^l*oSXkYpi5o zNftwJY4c9}FA{%2^6IY*tSl`TYCRC`DFV&JeV`O`dxCG+@t2Ot-)I=sZn+8rX2Vah zkbMzza5*@>-OhNbyc>SzA#{MUO-mdcSDKqFt#Z)IH76Ag1uSa?F3c#N3TMLl+Ci(YE1Z33_|v zEr_1JtJ8p7bLV+G?WczxUEf+M7Us+oWQaawla)rojwy&rCUiYfi=e}g7(z_yaA~0i z*JY~GWCT_p<_Wr+=_B#S6B$w8Z)2oo-LzqM_+`_f&8a4z<55OzR>2lwutAiV`F<|& zM$wo*Syz7`;n4f*U}(+neBiEBTlOHMTf^%_2ENAA9o_zIa>I#x?uw{CgDL5JWD=4` z#{oVl>Bd!vsvFb@bKDWPH>7`rbo+>-I3j(M9lgrJmICL3z9r^PxgtHFP{;8{($Wt+Lp?|Fi%X=}kCtraqY9-~%ccQ8K< zi-s+;vEXK49$Avw&-uebG^q$!W=FyYc&mX?PI288Eb*mbOp70CQy7oRtT$0W<>qFA ze6)WGVFiH+smBqU5SZNT2uLIfXqpKkMc>YrMTjRjFl1z6q&Vx-b)w2vsI@q|rsVgh zltWsFWt@wPQU`2Sxd}8LfcSf_wb&M2SCZRz?nm@mrxuL2=b)1mnEA-O+nTcez&0Pq zEn1^gmxz6v(SM@nba_93=GT#R2Zpy5&5T+cP;0DuauEFEjT{Hw9T=lJ`t;BvH?wOQFVm-ETcGGcYXNk*BWLN5G zY6tUe07(;-W)0#^aF&kyOqG|8x>WhkgO4
    f;dRl{a5I6 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 delta 3304 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 DtR`)9 diff --git a/doc/check-lte-firmware-upgrade.d/notification.avif b/doc/check-lte-firmware-upgrade.d/notification.avif index 4e28c365aec3a8508af1336dcf09781d1fba3e42..c440da59460bd6de4e5958bc992c5e4d1fa45cb2 100644 GIT binary patch delta 4851 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 V7nN7?1G~uPdWLj`eF-?8WooIv&5!^9 diff --git a/doc/check-routeros-update.d/notification.avif b/doc/check-routeros-update.d/notification.avif index 517ebeb6c15759403a0b69ea9d9d3c978f8dadf1..50317cf7722e30986a49869f3e72f8983928e74e 100644 GIT binary patch delta 6177 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 delta 6638 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 diff --git a/doc/collect-wireless-mac.d/notification.avif b/doc/collect-wireless-mac.d/notification.avif index 33fa9cb059572dd44f6e3acc486e73fb55e47e73..a2833f095d53748fcf3e92cdd44e5469f83f177d 100644 GIT binary patch delta 13216 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 delta 13241 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 delta 7278 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 I-ZooOaO$-))Bpeg diff --git a/doc/log-forward.d/notification.avif b/doc/log-forward.d/notification.avif index d332ca56918b37679439aed55636e0083faf0da0..a0f9ab339175ae768e1e791bd701a2a91dd5bc57 100644 GIT binary patch delta 5959 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 delta 6108 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 diff --git a/doc/netwatch-notify.d/notification-01-down.avif b/doc/netwatch-notify.d/notification-01-down.avif index d050e607641451dbe3c39e4dfc7d14d17409d7e3..894fb23ff4c3fa227e797d8ec03801bb59a61bd2 100644 GIT binary patch delta 3958 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 diff --git a/doc/netwatch-notify.d/notification-02-up.avif b/doc/netwatch-notify.d/notification-02-up.avif index 8dcf26afb44afb637ce909b912f19c7fd7ced02b..9021a93b9c174db32c78586d4dc3bf0f40ef6a4f 100644 GIT binary patch delta 4514 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 AMF0Q* delta 4633 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 P0dwi7nrD74;!aJ_dJ6$m diff --git a/doc/sms-forward.d/notification.avif b/doc/sms-forward.d/notification.avif index e76f04c4a7b6184efdaddb2ae3083874d3ff098c..01eb7ba6713a1bff1b0e55e5c730050724a21477 100644 GIT binary patch delta 4390 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 delta 4523 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 Jg+fb1+(4vW%9H>A From 1e6e0646e256c4acb9f8470853d0699286af010e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Mar 2023 16:54:41 +0100 Subject: [PATCH 1382/2612] add the notification generator --- contrib/notification.d/style.css | 39 ++++++++++++++++++++++++++++++++ contrib/notification.html | 33 +++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 contrib/notification.d/style.css create mode 100644 contrib/notification.html diff --git a/contrib/notification.d/style.css b/contrib/notification.d/style.css new file mode 100644 index 0000000..c07de89 --- /dev/null +++ b/contrib/notification.d/style.css @@ -0,0 +1,39 @@ +body { + font-family: fira-sans, sans; + font-size: 10pt; + background-color: transparent; +} +div.notification { + position: relative; + float: right; + width: 600px; + border: 3px outset #6c5d53; + /* border-radius: 5px; */ + padding: 10px; + background-color: #e6e6e6; +} +div.content { + padding-left: 60px; +} +img.logo { + float: left; + border-radius: 50%; +} +p.heading { + margin: 0px; + font-weight: bold; + text-decoration: underline; +} +p.hint { + display: none; +} +pre { + font-family: fira-mono, mono; + white-space: pre-wrap; +} +span.link { + color: #863600; +} +tt { + background-color: #e6e6e6; +} diff --git a/contrib/notification.html b/contrib/notification.html new file mode 100644 index 0000000..56cb612 --- /dev/null +++ b/contrib/notification.html @@ -0,0 +1,33 @@ + + + + +RouterOS-Scripts Notification Generator + + + + +

    RouterOS-Scripts Notification Generator

    + +
    + +
    +

    [MikroTik] â„šī¸ Subject

    +
    Message
    + +

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

    +

    âœ‚ī¸ The message was too long and has been truncated, cut off 13%!

    +
    +
    + +

    Hostname:

    +

    Subject:

    +

    Message:

    +

    Show link:

    +

    Queued since

    +

    Cut-off with percent

    + +

    â„šī¸ Open the inspector, select the div element, right click and select "Screenshot Node"!

    + + + From a832fd04ef085ef7e85000843a8e8fa59ce36dfb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Mar 2023 10:57:42 +0100 Subject: [PATCH 1383/2612] rename scripts and add file extension ".rsc" No functional change for the user... The migration is done automatically. --- INITIAL-COMMANDS.md | 2 +- Makefile | 14 +- README.md | 6 +- accesslist-duplicates.capsman | 41 +- accesslist-duplicates.capsman.rsc | 42 + accesslist-duplicates.local | 41 +- accesslist-duplicates.local.rsc | 42 + ...late => accesslist-duplicates.template.rsc | 0 backup-cloud | 57 +- backup-cloud.rsc | 58 + backup-email | 106 +- backup-email.rsc | 107 ++ backup-partition | 35 +- backup-partition.rsc | 36 + backup-upload | 128 +- backup-upload.rsc | 129 ++ capsman-download-packages | 85 +- capsman-download-packages.rsc | 86 ++ capsman-rolling-upgrade | 35 +- capsman-rolling-upgrade.rsc | 36 + certificate-renew-issued | 37 +- certificate-renew-issued.rsc | 38 + check-certificates | 137 +- check-certificates.rsc | 138 ++ check-health | 166 +-- check-health.rsc | 167 +++ check-lte-firmware-upgrade | 81 +- check-lte-firmware-upgrade.rsc | 82 ++ check-routeros-update | 146 +- check-routeros-update.rsc | 147 ++ collect-wireless-mac.capsman | 84 +- collect-wireless-mac.capsman.rsc | 85 ++ collect-wireless-mac.local | 85 +- collect-wireless-mac.local.rsc | 86 ++ ...plate => collect-wireless-mac.template.rsc | 0 daily-psk.capsman | 95 +- daily-psk.capsman.rsc | 96 ++ daily-psk.local | 94 +- daily-psk.local.rsc | 95 ++ daily-psk.template => daily-psk.template.rsc | 0 dhcp-lease-comment.capsman | 29 +- dhcp-lease-comment.capsman.rsc | 30 + dhcp-lease-comment.local | 29 +- dhcp-lease-comment.local.rsc | 30 + ...emplate => dhcp-lease-comment.template.rsc | 0 dhcp-to-dns | 96 +- dhcp-to-dns.rsc | 97 ++ doc/mod/scriptrunonce.md | 4 +- firmware-upgrade-reboot | 41 +- firmware-upgrade-reboot.rsc | 42 + global-config | 219 +-- ...onfig-overlay => global-config-overlay.rsc | 0 global-config.changes | 2 + global-config.rsc | 220 +++ global-functions | 1059 +------------- global-functions.rsc | 1292 +++++++++++++++++ global-wait | 10 +- global-wait.rsc | 11 + gps-track | 33 +- gps-track.rsc | 34 + hotspot-to-wpa | 71 +- hotspot-to-wpa-cleanup | 50 +- hotspot-to-wpa-cleanup.rsc | 51 + hotspot-to-wpa.rsc | 72 + ip-addr-bridge | 17 +- ip-addr-bridge.rsc | 18 + ipsec-to-dns | 68 +- ipsec-to-dns.rsc | 69 + ipv6-update | 75 +- ipv6-update.rsc | 76 + lease-script | 50 +- lease-script.rsc | 51 + leds-day-mode | 8 +- leds-day-mode.rsc | 9 + leds-night-mode | 8 +- leds-night-mode.rsc | 9 + leds-toggle-mode | 12 +- leds-toggle-mode.rsc | 13 + log-forward | 89 +- log-forward.rsc | 90 ++ mod/bridge-port-to | 64 +- mod/bridge-port-to.rsc | 65 + mod/bridge-port-vlan | 72 +- mod/bridge-port-vlan.rsc | 73 + mod/inspectvar | 55 +- mod/inspectvar.rsc | 54 + mod/ipcalc | 47 +- mod/ipcalc.rsc | 46 + mod/notification-email | 207 +-- mod/notification-email.rsc | 206 +++ mod/notification-matrix | 166 +-- mod/notification-matrix.rsc | 165 +++ mod/notification-telegram | 177 +-- mod/notification-telegram.rsc | 176 +++ mod/scriptrunonce | 47 +- mod/scriptrunonce.rsc | 46 + mode-button | 75 +- mode-button.rsc | 76 + netwatch-dns | 93 +- netwatch-dns.rsc | 94 ++ netwatch-notify | 185 +-- netwatch-notify.rsc | 186 +++ news-and-changes.rsc | 16 + ospf-to-leds | 34 +- ospf-to-leds.rsc | 35 + packages-update | 97 +- packages-update.rsc | 98 ++ ppp-on-up | 33 +- ppp-on-up.rsc | 34 + sms-action | 30 +- sms-action.rsc | 31 + sms-forward | 83 +- sms-forward.rsc | 84 ++ ssh-keys-import | 10 +- ssh-keys-import.rsc | 11 + super-mario-theme | 68 +- super-mario-theme.rsc | 69 + telegram-chat | 149 +- telegram-chat.rsc | 150 ++ unattended-lte-firmware-upgrade | 44 +- unattended-lte-firmware-upgrade.rsc | 45 + update-gre-address | 31 +- update-gre-address.rsc | 32 + update-tunnelbroker | 54 +- update-tunnelbroker.rsc | 55 + 125 files changed, 5622 insertions(+), 5175 deletions(-) create mode 100644 accesslist-duplicates.capsman.rsc create mode 100644 accesslist-duplicates.local.rsc rename accesslist-duplicates.template => accesslist-duplicates.template.rsc (100%) create mode 100644 backup-cloud.rsc create mode 100644 backup-email.rsc create mode 100644 backup-partition.rsc create mode 100644 backup-upload.rsc create mode 100644 capsman-download-packages.rsc create mode 100644 capsman-rolling-upgrade.rsc create mode 100644 certificate-renew-issued.rsc create mode 100644 check-certificates.rsc create mode 100644 check-health.rsc create mode 100644 check-lte-firmware-upgrade.rsc create mode 100644 check-routeros-update.rsc create mode 100644 collect-wireless-mac.capsman.rsc create mode 100644 collect-wireless-mac.local.rsc rename collect-wireless-mac.template => collect-wireless-mac.template.rsc (100%) create mode 100644 daily-psk.capsman.rsc create mode 100644 daily-psk.local.rsc rename daily-psk.template => daily-psk.template.rsc (100%) create mode 100644 dhcp-lease-comment.capsman.rsc create mode 100644 dhcp-lease-comment.local.rsc rename dhcp-lease-comment.template => dhcp-lease-comment.template.rsc (100%) create mode 100644 dhcp-to-dns.rsc create mode 100644 firmware-upgrade-reboot.rsc rename global-config-overlay => global-config-overlay.rsc (100%) create mode 100644 global-config.rsc create mode 100644 global-functions.rsc create mode 100644 global-wait.rsc create mode 100644 gps-track.rsc create mode 100644 hotspot-to-wpa-cleanup.rsc create mode 100644 hotspot-to-wpa.rsc create mode 100644 ip-addr-bridge.rsc create mode 100644 ipsec-to-dns.rsc create mode 100644 ipv6-update.rsc create mode 100644 lease-script.rsc create mode 100644 leds-day-mode.rsc create mode 100644 leds-night-mode.rsc create mode 100644 leds-toggle-mode.rsc create mode 100644 log-forward.rsc create mode 100644 mod/bridge-port-to.rsc create mode 100644 mod/bridge-port-vlan.rsc create mode 100644 mod/inspectvar.rsc create mode 100644 mod/ipcalc.rsc create mode 100644 mod/notification-email.rsc create mode 100644 mod/notification-matrix.rsc create mode 100644 mod/notification-telegram.rsc create mode 100644 mod/scriptrunonce.rsc create mode 100644 mode-button.rsc create mode 100644 netwatch-dns.rsc create mode 100644 netwatch-notify.rsc create mode 100644 news-and-changes.rsc create mode 100644 ospf-to-leds.rsc create mode 100644 packages-update.rsc create mode 100644 ppp-on-up.rsc create mode 100644 sms-action.rsc create mode 100644 sms-forward.rsc create mode 100644 ssh-keys-import.rsc create mode 100644 super-mario-theme.rsc create mode 100644 telegram-chat.rsc create mode 100644 unattended-lte-firmware-upgrade.rsc create mode 100644 update-gre-address.rsc create mode 100644 update-tunnelbroker.rsc diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index a31112a..a53ae0f 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -19,7 +19,7 @@ Run the complete base installation: /file/remove "letsencrypt-R3.pem"; :delay 1s; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ - /system/script/add name=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); + /system/script/add name=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . ".rsc") output=user as-value]->"data"); }; /system/script { run global-config; run global-functions; }; /system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }"; diff --git a/Makefile b/Makefile index b0737ab..8c9bcf5 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,9 @@ # template scripts -> final scripts # markdown files -> html files -TEMPLATE = $(wildcard *.template) -CAPSMAN = $(TEMPLATE:.template=.capsman) -LOCAL = $(TEMPLATE:.template=.local) +TEMPLATE = $(wildcard *.template.rsc) +CAPSMAN = $(TEMPLATE:.template.rsc=.capsman.rsc) +LOCAL = $(TEMPLATE:.template.rsc=.local.rsc) MARKDOWN = $(wildcard *.md doc/*.md doc/mod/*.md) HTML = $(MARKDOWN:.md=.html) @@ -14,13 +14,13 @@ all: $(CAPSMAN) $(LOCAL) $(HTML) %.html: %.md Makefile markdown $< | sed 's/href="\([-_\./[:alnum:]]*\)\.md"/href="\1.html"/g' > $@ -%.local: %.template Makefile - sed -e '/\/caps-man/d' -e 's|%PATH%|interface\/wireless|' -e 's|%TEMPL%|$(suffix $@)|' \ +%.local.rsc: %.template.rsc Makefile + sed -e '/\/caps-man/d' -e 's|%PATH%|interface\/wireless|' -e 's|%TEMPL%|.local|' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ -%.capsman: %.template Makefile - sed -e '/\/interface\/wireless/d' -e 's/%PATH%/caps-man/' -e 's/%TEMPL%/$(suffix $@)/' \ +%.capsman.rsc: %.template.rsc Makefile + sed -e '/\/interface\/wireless/d' -e 's|%PATH%|caps-man|' -e 's|%TEMPL%|.capsman|' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ diff --git a/README.md b/README.md index 2a8405f..9c3f703 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ date and time is set correctly! Now let's download the main scripts and add them in configuration on the fly. - :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ /system/script/add name=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); }; + :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ /system/script/add name=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . ".rsc") output=user as-value]->"data"); }; ![screenshot: import scripts](README.d/04-import-scripts.avif) @@ -112,7 +112,7 @@ Editing configuration The configuration needs to be tweaked for your needs. Edit `global-config-overlay`, copy relevant configuration from -[`global-config`](global-config) (the one without `-overlay`). +[`global-config`](global-config.rsc) (the one without `-overlay`). Save changes and exit with `Ctrl-o`. /system/script/edit global-config-overlay source; @@ -247,7 +247,7 @@ still use my scripts to manage and deploy yours, by specifying `base-url` This will fetch and install a script `hello-world.rsc` from the given url: - $ScriptInstallUpdate hello-world.rsc "base-url=https://git.eworm.de/cgit/routeros-scripts-custom/plain/"; + $ScriptInstallUpdate hello-world "base-url=https://git.eworm.de/cgit/routeros-scripts-custom/plain/"; ![screenshot: install custom script](README.d/13-install-custom-script.avif) diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman index 8831cc6..2da00ca 100644 --- a/accesslist-duplicates.capsman +++ b/accesslist-duplicates.capsman @@ -1,42 +1,3 @@ #!rsc by RouterOS -# RouterOS script: accesslist-duplicates.capsman -# Copyright (c) 2018-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# print duplicate antries in wireless access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md -# -# !! Do not edit this file, it is generated from template! - -:local 0 "accesslist-duplicates.capsman"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Read; - -:local Seen ({}); -:local Shown ({}); - -:foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ - :local Mac [ /caps-man/access-list/get $AccList mac-address ]; - :foreach SeenMac in=$Seen do={ - :if ($SeenMac = $Mac) do={ - :local Skip 0; - :foreach ShownMac in=$Shown do={ - :if ($ShownMac = $Mac) do={ :set Skip 1; } - } - :if ($Skip = 0) do={ - /caps-man/access-list/print where mac-address=$Mac; - :set Shown ($Shown, $Mac); - - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /caps-man/access-list/remove $Remove; - } - } - } - } - :set Seen ($Seen, $Mac); -} +# dummy for migration diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc new file mode 100644 index 0000000..8831cc6 --- /dev/null +++ b/accesslist-duplicates.capsman.rsc @@ -0,0 +1,42 @@ +#!rsc by RouterOS +# RouterOS script: accesslist-duplicates.capsman +# Copyright (c) 2018-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# print duplicate antries in wireless access list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "accesslist-duplicates.capsman"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Read; + +:local Seen ({}); +:local Shown ({}); + +:foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ + :local Mac [ /caps-man/access-list/get $AccList mac-address ]; + :foreach SeenMac in=$Seen do={ + :if ($SeenMac = $Mac) do={ + :local Skip 0; + :foreach ShownMac in=$Shown do={ + :if ($ShownMac = $Mac) do={ :set Skip 1; } + } + :if ($Skip = 0) do={ + /caps-man/access-list/print where mac-address=$Mac; + :set Shown ($Shown, $Mac); + + :put "\nNumeric id to remove, any key to skip!"; + :local Remove [ :tonum [ $Read ] ]; + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /caps-man/access-list/remove $Remove; + } + } + } + } + :set Seen ($Seen, $Mac); +} diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local index d4b8867..2da00ca 100644 --- a/accesslist-duplicates.local +++ b/accesslist-duplicates.local @@ -1,42 +1,3 @@ #!rsc by RouterOS -# RouterOS script: accesslist-duplicates.local -# Copyright (c) 2018-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# print duplicate antries in wireless access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md -# -# !! Do not edit this file, it is generated from template! - -:local 0 "accesslist-duplicates.local"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Read; - -:local Seen ({}); -:local Shown ({}); - -:foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ - :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; - :foreach SeenMac in=$Seen do={ - :if ($SeenMac = $Mac) do={ - :local Skip 0; - :foreach ShownMac in=$Shown do={ - :if ($ShownMac = $Mac) do={ :set Skip 1; } - } - :if ($Skip = 0) do={ - /interface/wireless/access-list/print where mac-address=$Mac; - :set Shown ($Shown, $Mac); - - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /interface/wireless/access-list/remove $Remove; - } - } - } - } - :set Seen ($Seen, $Mac); -} +# dummy for migration diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc new file mode 100644 index 0000000..d4b8867 --- /dev/null +++ b/accesslist-duplicates.local.rsc @@ -0,0 +1,42 @@ +#!rsc by RouterOS +# RouterOS script: accesslist-duplicates.local +# Copyright (c) 2018-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# print duplicate antries in wireless access list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "accesslist-duplicates.local"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Read; + +:local Seen ({}); +:local Shown ({}); + +:foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ + :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; + :foreach SeenMac in=$Seen do={ + :if ($SeenMac = $Mac) do={ + :local Skip 0; + :foreach ShownMac in=$Shown do={ + :if ($ShownMac = $Mac) do={ :set Skip 1; } + } + :if ($Skip = 0) do={ + /interface/wireless/access-list/print where mac-address=$Mac; + :set Shown ($Shown, $Mac); + + :put "\nNumeric id to remove, any key to skip!"; + :local Remove [ :tonum [ $Read ] ]; + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /interface/wireless/access-list/remove $Remove; + } + } + } + } + :set Seen ($Seen, $Mac); +} diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template.rsc similarity index 100% rename from accesslist-duplicates.template rename to accesslist-duplicates.template.rsc diff --git a/backup-cloud b/backup-cloud index b75d5cb..2da00ca 100644 --- a/backup-cloud +++ b/backup-cloud @@ -1,58 +1,3 @@ #!rsc by RouterOS -# RouterOS script: backup-cloud -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: backup-script -# -# upload backup to MikroTik cloud -# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md - -:local 0 "backup-cloud"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global BackupPassword; -:global BackupRandomDelay; -:global Identity; - -:global DeviceInfo; -:global LogPrintExit2; -:global RandomDelay; -:global ScriptFromTerminal; -:global SendNotification2; -:global SymbolForNotification; -:global WaitFullyConnected; - -$WaitFullyConnected; - -:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ - $RandomDelay $BackupRandomDelay; -} - -:do { - # we are not interested in output, but print is - # required to fetch information from cloud - /system/backup/cloud/print as-value; - :if ([ :len [ /system/backup/cloud/find ] ] > 0) do={ - /system/backup/cloud/upload-file action=create-and-upload \ - password=$BackupPassword replace=[ get ([ find ]->0) name ]; - } else={ - /system/backup/cloud/upload-file action=create-and-upload \ - password=$BackupPassword; - } - :local Cloud [ /system/backup/cloud/get ([ find ]->0) ]; - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "floppy-disk,cloud" ] . "Cloud backup"); \ - message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - "Name: " . $Cloud->"name" . "\n" . \ - "Size: " . $Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)\n" . \ - "Download key: " . $Cloud->"secret-download-key"); silent=true }); -} on-error={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Cloud backup failed"); \ - message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); - $LogPrintExit2 error $0 ("Failed uploading backup for " . $Identity . " to cloud!") true; -} +# dummy for migration diff --git a/backup-cloud.rsc b/backup-cloud.rsc new file mode 100644 index 0000000..b75d5cb --- /dev/null +++ b/backup-cloud.rsc @@ -0,0 +1,58 @@ +#!rsc by RouterOS +# RouterOS script: backup-cloud +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: backup-script +# +# upload backup to MikroTik cloud +# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md + +:local 0 "backup-cloud"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global BackupPassword; +:global BackupRandomDelay; +:global Identity; + +:global DeviceInfo; +:global LogPrintExit2; +:global RandomDelay; +:global ScriptFromTerminal; +:global SendNotification2; +:global SymbolForNotification; +:global WaitFullyConnected; + +$WaitFullyConnected; + +:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ + $RandomDelay $BackupRandomDelay; +} + +:do { + # we are not interested in output, but print is + # required to fetch information from cloud + /system/backup/cloud/print as-value; + :if ([ :len [ /system/backup/cloud/find ] ] > 0) do={ + /system/backup/cloud/upload-file action=create-and-upload \ + password=$BackupPassword replace=[ get ([ find ]->0) name ]; + } else={ + /system/backup/cloud/upload-file action=create-and-upload \ + password=$BackupPassword; + } + :local Cloud [ /system/backup/cloud/get ([ find ]->0) ]; + + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "floppy-disk,cloud" ] . "Cloud backup"); \ + message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ + [ $DeviceInfo ] . "\n\n" . \ + "Name: " . $Cloud->"name" . "\n" . \ + "Size: " . $Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)\n" . \ + "Download key: " . $Cloud->"secret-download-key"); silent=true }); +} on-error={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Cloud backup failed"); \ + message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); + $LogPrintExit2 error $0 ("Failed uploading backup for " . $Identity . " to cloud!") true; +} diff --git a/backup-email b/backup-email index ba12494..2da00ca 100644 --- a/backup-email +++ b/backup-email @@ -1,107 +1,3 @@ #!rsc by RouterOS -# RouterOS script: backup-email -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: backup-script -# -# create and email backup and config file -# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md - -:local 0 "backup-email"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global BackupPassword; -:global BackupRandomDelay; -:global BackupSendBinary; -:global BackupSendExport; -:global BackupSendGlobalConfig; -:global Domain; -:global Identity; - -:global CharacterReplace; -:global DeviceInfo; -:global LogPrintExit2; -:global MkDir; -:global RandomDelay; -:global ScriptFromTerminal; -:global SendEMail2; -:global SymbolForNotification; -:global WaitForFile; -:global WaitFullyConnected; - -:if ([ :typeof $SendEMail2 ] = "nothing") do={ - $LogPrintExit2 error $0 ("The module for sending notifications via e-mail is not installed.") true; -} - -:if ($BackupSendBinary != true && \ - $BackupSendExport != true) do={ - $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; -} - -$WaitFullyConnected; - -:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ - $RandomDelay $BackupRandomDelay; -} - -# filename based on identity -:local DirName ("tmpfs/" . $0); -:local FileName [ $CharacterReplace ($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={ - :execute script={ :put [ /system/script/get global-config-overlay source ]; } \ - file=($FilePath . ".conf"); - $WaitForFile ($FilePath . ".conf.txt"); - :set ConfigFile ($FileName . ".conf.txt"); - :set Attach ($Attach, ($FilePath . ".conf.txt")); -} - -# send email with status and files -$SendEMail2 ({ origin=$0; \ - subject=([ $SymbolForNotification "floppy-disk,incoming-envelope" ] . \ - "Backup & Config"); \ - message=("See attached files for backup and config export for " . \ - $Identity . ".\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - "Backup file: " . $BackupFile . "\n" . \ - "Export file: " . $ExportFile . "\n" . \ - "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); -} +# dummy for migration diff --git a/backup-email.rsc b/backup-email.rsc new file mode 100644 index 0000000..ba12494 --- /dev/null +++ b/backup-email.rsc @@ -0,0 +1,107 @@ +#!rsc by RouterOS +# RouterOS script: backup-email +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: backup-script +# +# create and email backup and config file +# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md + +:local 0 "backup-email"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global BackupPassword; +:global BackupRandomDelay; +:global BackupSendBinary; +:global BackupSendExport; +:global BackupSendGlobalConfig; +:global Domain; +:global Identity; + +:global CharacterReplace; +:global DeviceInfo; +:global LogPrintExit2; +:global MkDir; +:global RandomDelay; +:global ScriptFromTerminal; +:global SendEMail2; +:global SymbolForNotification; +:global WaitForFile; +:global WaitFullyConnected; + +:if ([ :typeof $SendEMail2 ] = "nothing") do={ + $LogPrintExit2 error $0 ("The module for sending notifications via e-mail is not installed.") true; +} + +:if ($BackupSendBinary != true && \ + $BackupSendExport != true) do={ + $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; +} + +$WaitFullyConnected; + +:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ + $RandomDelay $BackupRandomDelay; +} + +# filename based on identity +:local DirName ("tmpfs/" . $0); +:local FileName [ $CharacterReplace ($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={ + :execute script={ :put [ /system/script/get global-config-overlay source ]; } \ + file=($FilePath . ".conf"); + $WaitForFile ($FilePath . ".conf.txt"); + :set ConfigFile ($FileName . ".conf.txt"); + :set Attach ($Attach, ($FilePath . ".conf.txt")); +} + +# send email with status and files +$SendEMail2 ({ origin=$0; \ + subject=([ $SymbolForNotification "floppy-disk,incoming-envelope" ] . \ + "Backup & Config"); \ + message=("See attached files for backup and config export for " . \ + $Identity . ".\n\n" . \ + [ $DeviceInfo ] . "\n\n" . \ + "Backup file: " . $BackupFile . "\n" . \ + "Export file: " . $ExportFile . "\n" . \ + "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); +} diff --git a/backup-partition b/backup-partition index 824cb7e..2da00ca 100644 --- a/backup-partition +++ b/backup-partition @@ -1,36 +1,3 @@ #!rsc by RouterOS -# RouterOS script: backup-partition -# Copyright (c) 2022-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: backup-script -# -# save configuration to fallback partition -# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md - -:local 0 "backup-partition"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; - -:if ([ :len [ /partitions/find ] ] < 2) do={ - $LogPrintExit2 error $0 ("Device does not have a fallback partition.") true; -} - -:local ActiveRunning [ /partitions/find where active running ]; - -:if ([ :len $ActiveRunning ] < 1) do={ - $LogPrintExit2 error $0 ("Device is not running from active partition.") true; -} - -:local ActiveRunningVar [ /partitions/get $ActiveRunning ]; - -:do { - /partitions/save-config-to ($ActiveRunningVar->"fallback-to"); - $LogPrintExit2 info $0 ("Saved configuration to partition '" . \ - ($ActiveRunningVar->"fallback-to") . "'.") false; -} on-error={ - $LogPrintExit2 error $0 ("Failed saving configuration to partition '" . \ - ($ActiveRunningVar->"fallback-to") . "'!") true; -} +# dummy for migration diff --git a/backup-partition.rsc b/backup-partition.rsc new file mode 100644 index 0000000..824cb7e --- /dev/null +++ b/backup-partition.rsc @@ -0,0 +1,36 @@ +#!rsc by RouterOS +# RouterOS script: backup-partition +# Copyright (c) 2022-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: backup-script +# +# save configuration to fallback partition +# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md + +:local 0 "backup-partition"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global LogPrintExit2; + +:if ([ :len [ /partitions/find ] ] < 2) do={ + $LogPrintExit2 error $0 ("Device does not have a fallback partition.") true; +} + +:local ActiveRunning [ /partitions/find where active running ]; + +:if ([ :len $ActiveRunning ] < 1) do={ + $LogPrintExit2 error $0 ("Device is not running from active partition.") true; +} + +:local ActiveRunningVar [ /partitions/get $ActiveRunning ]; + +:do { + /partitions/save-config-to ($ActiveRunningVar->"fallback-to"); + $LogPrintExit2 info $0 ("Saved configuration to partition '" . \ + ($ActiveRunningVar->"fallback-to") . "'.") false; +} on-error={ + $LogPrintExit2 error $0 ("Failed saving configuration to partition '" . \ + ($ActiveRunningVar->"fallback-to") . "'!") true; +} diff --git a/backup-upload b/backup-upload index 4c09d4a..2da00ca 100644 --- a/backup-upload +++ b/backup-upload @@ -1,129 +1,3 @@ #!rsc by RouterOS -# RouterOS script: backup-upload -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: backup-script -# -# create and upload backup and config file -# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md - -:local 0 "backup-upload"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global BackupPassword; -:global BackupRandomDelay; -:global BackupSendBinary; -:global BackupSendExport; -:global BackupSendGlobalConfig; -:global BackupUploadPass; -:global BackupUploadUrl; -:global BackupUploadUser; -:global Domain; -:global Identity; - -:global CharacterReplace; -:global DeviceInfo; -:global IfThenElse; -:global LogPrintExit2; -:global MkDir; -:global RandomDelay; -:global ScriptFromTerminal; -:global SendNotification2; -:global SymbolForNotification; -:global WaitForFile; -:global WaitFullyConnected; - -:if ($BackupSendBinary != true && \ - $BackupSendExport != true) do={ - $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; -} - -$WaitFullyConnected; - -:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ - $RandomDelay $BackupRandomDelay; -} - -# filename based on identity -:local DirName ("tmpfs/" . $0); -:local FileName [ $CharacterReplace ($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 ($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 ($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={ - :execute script={ :put [ /system/script/get global-config-overlay source ]; } \ - file=($FilePath . ".conf"); - $WaitForFile ($FilePath . ".conf.txt"); - - :do { - /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \ - user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf.txt"); - :set ConfigFile ($FileName . ".conf"); - } on-error={ - $LogPrintExit2 error $0 ("Uploading global-config-overlay failed!") false; - :set ConfigFile "failed"; - :set Failed 1; - } - - /file/remove ($FilePath . ".conf.txt"); -} - -$SendNotification2 ({ origin=$0; \ - subject=[ $IfThenElse ($Failed > 0) \ - ([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Backup & Config upload with failure") \ - ([ $SymbolForNotification "floppy-disk,up-arrow" ] . "Backup & Config upload") ]; \ - message=("Backup and config export upload for " . $Identity . ".\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - "Backup file: " . $BackupFile . "\n" . \ - "Export file: " . $ExportFile . "\n" . \ - "Config file: " . $ConfigFile); silent=true }); - -:if ($Failed = 1) do={ - :error "An error occured!"; -} +# dummy for migration diff --git a/backup-upload.rsc b/backup-upload.rsc new file mode 100644 index 0000000..4c09d4a --- /dev/null +++ b/backup-upload.rsc @@ -0,0 +1,129 @@ +#!rsc by RouterOS +# RouterOS script: backup-upload +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: backup-script +# +# create and upload backup and config file +# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md + +:local 0 "backup-upload"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global BackupPassword; +:global BackupRandomDelay; +:global BackupSendBinary; +:global BackupSendExport; +:global BackupSendGlobalConfig; +:global BackupUploadPass; +:global BackupUploadUrl; +:global BackupUploadUser; +:global Domain; +:global Identity; + +:global CharacterReplace; +:global DeviceInfo; +:global IfThenElse; +:global LogPrintExit2; +:global MkDir; +:global RandomDelay; +:global ScriptFromTerminal; +:global SendNotification2; +:global SymbolForNotification; +:global WaitForFile; +:global WaitFullyConnected; + +:if ($BackupSendBinary != true && \ + $BackupSendExport != true) do={ + $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; +} + +$WaitFullyConnected; + +:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ + $RandomDelay $BackupRandomDelay; +} + +# filename based on identity +:local DirName ("tmpfs/" . $0); +:local FileName [ $CharacterReplace ($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 ($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 ($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={ + :execute script={ :put [ /system/script/get global-config-overlay source ]; } \ + file=($FilePath . ".conf"); + $WaitForFile ($FilePath . ".conf.txt"); + + :do { + /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \ + user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf.txt"); + :set ConfigFile ($FileName . ".conf"); + } on-error={ + $LogPrintExit2 error $0 ("Uploading global-config-overlay failed!") false; + :set ConfigFile "failed"; + :set Failed 1; + } + + /file/remove ($FilePath . ".conf.txt"); +} + +$SendNotification2 ({ origin=$0; \ + subject=[ $IfThenElse ($Failed > 0) \ + ([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Backup & Config upload with failure") \ + ([ $SymbolForNotification "floppy-disk,up-arrow" ] . "Backup & Config upload") ]; \ + message=("Backup and config export upload for " . $Identity . ".\n\n" . \ + [ $DeviceInfo ] . "\n\n" . \ + "Backup file: " . $BackupFile . "\n" . \ + "Export file: " . $ExportFile . "\n" . \ + "Config file: " . $ConfigFile); silent=true }); + +:if ($Failed = 1) do={ + :error "An error occured!"; +} diff --git a/capsman-download-packages b/capsman-download-packages index 08edd59..2da00ca 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -1,86 +1,3 @@ #!rsc by RouterOS -# RouterOS script: capsman-download-packages -# Copyright (c) 2018-2023 Christian Hesse -# Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# download and cleanup packages for CAP installation from CAPsMAN -# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md - -:local 0 "capsman-download-packages"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global CleanFilePath; -:global DownloadPackage; -:global LogPrintExit2; -:global MkDir; -:global ScriptLock; -:global WaitFullyConnected; - -$ScriptLock $0; -$WaitFullyConnected; - -:local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; -:local InstalledVersion [ /system/package/update/get installed-version ]; -:local Updated false; - -:if ([ :len $PackagePath ] = 0) do={ - $LogPrintExit2 warning $0 ("The CAPsMAN package path is not defined, can not download packages.") true; -} - -:if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ - :if ([ $MkDir $PackagePath ] = false) do={ - $LogPrintExit2 warning $0 ("Creating directory at CAPsMAN package path (" . \ - $PackagePath . ") failed!") true; - } - $LogPrintExit2 info $0 ("Created directory at CAPsMAN package path (" . $PackagePath . \ - "). Please place your packages!") false; -} - -:foreach Package in=[ /file/find where type=package \ - package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ - :local File [ /file/get $Package ]; - :if ($File->"package-architecture" = "mips") do={ - :set ($File->"package-architecture") "mipsbe"; - } - :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ - ($File->"package-architecture") $PackagePath ] = true) do={ - :set Updated true; - /file/remove $Package; - } -} - -:if ([ :len [ /system/logging/find where topics~"error" !(topics~"!error") \ - !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ - $LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \ - "Probably can not download packages automatically.") false; -} else={ - :if ($Updated = false && [ /system/resource/get uptime ] < 2m) do={ - $LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false; - :delay 2m; - } -} - -:foreach Log in=[ /log/find where topics=({"caps"; "error"}) \ - message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \ - "-.*\\.npk', no such file") ] do={ - :local Message [ /log/get $Log message ]; - :local Package [ :pick $Message \ - ([ :find $Message "'" ] + 1) \ - [ :find $Message ("-" . $InstalledVersion . "-") ] ]; - :local Arch [ :pick $Message \ - ([ :find $Message ("-" . $InstalledVersion . "-") ] + 2 + [ :len $InstalledVersion ]) \ - [ :find $Message ".npk" ] ]; - :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ - :set Updated true; - } -} - -:if ($Updated = true) do={ - :if ([ :len [ /system/script/find where name="capsman-rolling-upgrade" ] ] > 0) do={ - /system/script/run capsman-rolling-upgrade; - } else={ - /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; - } -} +# dummy for migration diff --git a/capsman-download-packages.rsc b/capsman-download-packages.rsc new file mode 100644 index 0000000..08edd59 --- /dev/null +++ b/capsman-download-packages.rsc @@ -0,0 +1,86 @@ +#!rsc by RouterOS +# RouterOS script: capsman-download-packages +# Copyright (c) 2018-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# download and cleanup packages for CAP installation from CAPsMAN +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md + +:local 0 "capsman-download-packages"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global CleanFilePath; +:global DownloadPackage; +:global LogPrintExit2; +:global MkDir; +:global ScriptLock; +:global WaitFullyConnected; + +$ScriptLock $0; +$WaitFullyConnected; + +:local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; +:local InstalledVersion [ /system/package/update/get installed-version ]; +:local Updated false; + +:if ([ :len $PackagePath ] = 0) do={ + $LogPrintExit2 warning $0 ("The CAPsMAN package path is not defined, can not download packages.") true; +} + +:if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ + :if ([ $MkDir $PackagePath ] = false) do={ + $LogPrintExit2 warning $0 ("Creating directory at CAPsMAN package path (" . \ + $PackagePath . ") failed!") true; + } + $LogPrintExit2 info $0 ("Created directory at CAPsMAN package path (" . $PackagePath . \ + "). Please place your packages!") false; +} + +:foreach Package in=[ /file/find where type=package \ + package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ + :local File [ /file/get $Package ]; + :if ($File->"package-architecture" = "mips") do={ + :set ($File->"package-architecture") "mipsbe"; + } + :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ + ($File->"package-architecture") $PackagePath ] = true) do={ + :set Updated true; + /file/remove $Package; + } +} + +:if ([ :len [ /system/logging/find where topics~"error" !(topics~"!error") \ + !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ + $LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \ + "Probably can not download packages automatically.") false; +} else={ + :if ($Updated = false && [ /system/resource/get uptime ] < 2m) do={ + $LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false; + :delay 2m; + } +} + +:foreach Log in=[ /log/find where topics=({"caps"; "error"}) \ + message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \ + "-.*\\.npk', no such file") ] do={ + :local Message [ /log/get $Log message ]; + :local Package [ :pick $Message \ + ([ :find $Message "'" ] + 1) \ + [ :find $Message ("-" . $InstalledVersion . "-") ] ]; + :local Arch [ :pick $Message \ + ([ :find $Message ("-" . $InstalledVersion . "-") ] + 2 + [ :len $InstalledVersion ]) \ + [ :find $Message ".npk" ] ]; + :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ + :set Updated true; + } +} + +:if ($Updated = true) do={ + :if ([ :len [ /system/script/find where name="capsman-rolling-upgrade" ] ] > 0) do={ + /system/script/run capsman-rolling-upgrade; + } else={ + /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; + } +} diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index 1f4a51c..2da00ca 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -1,36 +1,3 @@ #!rsc by RouterOS -# RouterOS script: capsman-rolling-upgrade -# Copyright (c) 2018-2023 Christian Hesse -# Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# upgrade CAPs one after another -# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md - -:local 0 "capsman-rolling-upgrade"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; -:global ScriptLock; - -$ScriptLock $0; - -:local InstalledVersion [ /system/package/update/get installed-version ]; - -:local RemoteCapCount [ :len [ /caps-man/remote-cap/find ] ]; -:if ($RemoteCapCount > 0) do={ - :local Delay (600 / $RemoteCapCount); - :if ($Delay > 120) do={ :set Delay 120; } - :foreach RemoteCap in=[ /caps-man/remote-cap/find where version!=$InstalledVersion ] do={ - :local RemoteCapVal [ /caps-man/remote-cap/get $RemoteCap ]; - :if ([ :len $RemoteCapVal ] > 1) do={ - $LogPrintExit2 info $0 ("Starting upgrade for " . $RemoteCapVal->"name" . \ - " (" . $RemoteCapVal->"identity" . ")...") false; - /caps-man/remote-cap/upgrade $RemoteCap; - } else={ - $LogPrintExit2 warning $0 ("Remote CAP vanished, skipping upgrade.") false; - } - :delay ($Delay . "s"); - } -} +# dummy for migration diff --git a/capsman-rolling-upgrade.rsc b/capsman-rolling-upgrade.rsc new file mode 100644 index 0000000..1f4a51c --- /dev/null +++ b/capsman-rolling-upgrade.rsc @@ -0,0 +1,36 @@ +#!rsc by RouterOS +# RouterOS script: capsman-rolling-upgrade +# Copyright (c) 2018-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# upgrade CAPs one after another +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md + +:local 0 "capsman-rolling-upgrade"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global LogPrintExit2; +:global ScriptLock; + +$ScriptLock $0; + +:local InstalledVersion [ /system/package/update/get installed-version ]; + +:local RemoteCapCount [ :len [ /caps-man/remote-cap/find ] ]; +:if ($RemoteCapCount > 0) do={ + :local Delay (600 / $RemoteCapCount); + :if ($Delay > 120) do={ :set Delay 120; } + :foreach RemoteCap in=[ /caps-man/remote-cap/find where version!=$InstalledVersion ] do={ + :local RemoteCapVal [ /caps-man/remote-cap/get $RemoteCap ]; + :if ([ :len $RemoteCapVal ] > 1) do={ + $LogPrintExit2 info $0 ("Starting upgrade for " . $RemoteCapVal->"name" . \ + " (" . $RemoteCapVal->"identity" . ")...") false; + /caps-man/remote-cap/upgrade $RemoteCap; + } else={ + $LogPrintExit2 warning $0 ("Remote CAP vanished, skipping upgrade.") false; + } + :delay ($Delay . "s"); + } +} diff --git a/certificate-renew-issued b/certificate-renew-issued index c297b15..2da00ca 100644 --- a/certificate-renew-issued +++ b/certificate-renew-issued @@ -1,38 +1,3 @@ #!rsc by RouterOS -# RouterOS script: certificate-renew-issued -# Copyright (c) 2019-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# renew locally issued certificates -# https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md - -:local 0 "certificate-renew-issued"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global CertIssuedExportPass; - -:global LogPrintExit2; -:global MkDir; - -:foreach Cert in=[ /certificate/find where issued expires-after<3w ] do={ - :local CertVal [ /certificate/get $Cert ]; - /certificate/issued-revoke $Cert; - /certificate/set name=($CertVal->"name" . "-revoked-" . [ /system/clock/get date ]) $Cert; - /certificate/add name=($CertVal->"name") common-name=($CertVal->"common-name") \ - key-usage=($CertVal->"key-usage") subject-alt-name=($CertVal->"subject-alt-name"); - /certificate/sign ($CertVal->"name") ca=($CertVal->"ca"); - :if ([ :typeof ($CertIssuedExportPass->($CertVal->"common-name")) ] = "str") do={ - :if ([ $MkDir "cert-issued" ] = true) do={ - /certificate/export-certificate ($CertVal->"name") type=pkcs12 \ - file-name=("cert-issued/" . $CertVal->"common-name") \ - export-passphrase=($CertIssuedExportPass->($CertVal->"common-name")); - $LogPrintExit2 info $0 ("Issued a new certificate for \"" . $CertVal->"common-name" . \ - "\", exported to \"cert-issued/" . $CertVal->"common-name" . ".p12\".") false; - } else={ - $LogPrintExit2 warning $0 ("Failed creating directory, not exporting certificate.") false; - } - } else={ - $LogPrintExit2 info $0 ("Issued a new certificate for \"" . $CertVal->"common-name" . "\".") false; - } -} +# dummy for migration diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc new file mode 100644 index 0000000..c297b15 --- /dev/null +++ b/certificate-renew-issued.rsc @@ -0,0 +1,38 @@ +#!rsc by RouterOS +# RouterOS script: certificate-renew-issued +# Copyright (c) 2019-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# renew locally issued certificates +# https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md + +:local 0 "certificate-renew-issued"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global CertIssuedExportPass; + +:global LogPrintExit2; +:global MkDir; + +:foreach Cert in=[ /certificate/find where issued expires-after<3w ] do={ + :local CertVal [ /certificate/get $Cert ]; + /certificate/issued-revoke $Cert; + /certificate/set name=($CertVal->"name" . "-revoked-" . [ /system/clock/get date ]) $Cert; + /certificate/add name=($CertVal->"name") common-name=($CertVal->"common-name") \ + key-usage=($CertVal->"key-usage") subject-alt-name=($CertVal->"subject-alt-name"); + /certificate/sign ($CertVal->"name") ca=($CertVal->"ca"); + :if ([ :typeof ($CertIssuedExportPass->($CertVal->"common-name")) ] = "str") do={ + :if ([ $MkDir "cert-issued" ] = true) do={ + /certificate/export-certificate ($CertVal->"name") type=pkcs12 \ + file-name=("cert-issued/" . $CertVal->"common-name") \ + export-passphrase=($CertIssuedExportPass->($CertVal->"common-name")); + $LogPrintExit2 info $0 ("Issued a new certificate for \"" . $CertVal->"common-name" . \ + "\", exported to \"cert-issued/" . $CertVal->"common-name" . ".p12\".") false; + } else={ + $LogPrintExit2 warning $0 ("Failed creating directory, not exporting certificate.") false; + } + } else={ + $LogPrintExit2 info $0 ("Issued a new certificate for \"" . $CertVal->"common-name" . "\".") false; + } +} diff --git a/check-certificates b/check-certificates index 8a06f8b..2da00ca 100644 --- a/check-certificates +++ b/check-certificates @@ -1,138 +1,3 @@ #!rsc by RouterOS -# RouterOS script: check-certificates -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# check for certificate validity -# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md - -:local 0 "check-certificates"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global CertRenewPass; -:global CertRenewTime; -:global CertRenewUrl; -:global CertWarnTime; -:global Identity; - -:global CertificateAvailable -:global CertificateNameByCN; -:global IfThenElse; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global SendNotification2; -:global SymbolForNotification; -:global UrlEncode; -:global WaitForFile; -:global WaitFullyConnected; - -:local FormatExpire do={ - :global CharacterReplace; - :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; -} - -$WaitFullyConnected; - -:foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ - :local CertVal [ /certificate/get $Cert ]; - - :do { - :if ([ :len $CertRenewUrl ] = 0) do={ - $LogPrintExit2 info $0 ("No CertRenewUrl given.") true; - } - $LogPrintExit2 info $0 ("Attempting to renew certificate " . ($CertVal->"name") . ".") false; - - :foreach Type in={ ".pem"; ".p12" } do={ - :local CertFileName ([ $UrlEncode ($CertVal->"common-name") ] . $Type); - :do { - /tool/fetch check-certificate=yes-without-crl \ - ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; - $WaitForFile $CertFileName; - - :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~("^" . $CertFileName . "_[0-9]+\$") common-name!=($CertVal->"common-name") ] do={ - $CertificateNameByCN [ /certificate/get $CertInChain common-name ]; - } - } on-error={ - $LogPrintExit2 debug $0 ("Could not download certificate file " . $CertFileName) false; - } - } - - :local CertNew [ /certificate/find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ]; - :local CertNewVal [ /certificate/get $CertNew ]; - - :if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") ] = false) do={ - $LogPrintExit2 warning $0 ("The certificate chain is not available!") false; - } - - :if ($Cert != $CertNew) do={ - $LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; - - :if (($CertVal->"private-key") = true && ($CertVal->"private-key") != ($CertNewVal->"private-key")) do={ - /certificate/remove $CertNew; - $LogPrintExit2 warning $0 ("Old certificate '" . ($CertVal->"name") . "' has a private key, new certificate does not. Aborting renew.") true; - } - - /ip/service/set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; - - /ip/ipsec/identity/set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; - /ip/ipsec/identity/set remote-certificate=($CertNewVal->"name") [ find where remote-certificate=($CertVal->"name") ]; - - /ip/hotspot/profile/set ssl-certificate=($CertNewVal->"name") [ find where ssl-certificate=($CertVal->"name") ]; - - /certificate/remove $Cert; - /certificate/set $CertNew name=($CertVal->"name"); - } - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed"); \ - message=("A certificate on " . $Identity . " has been renewed.\n\n" . \ - "Name: " . ($CertVal->"name") . "\n" . \ - "CommonName: " . ($CertNewVal->"common-name") . "\n" . \ - "Private key: " . [ $IfThenElse (($CertNewVal->"private-key") = true) "available" "missing" ] . "\n" . \ - "Fingerprint: " . ($CertNewVal->"fingerprint") . "\n" . \ - "Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \ - "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ - "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]); silent=true }); - $LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " has been renewed.") false; - } on-error={ - $LogPrintExit2 debug $0 ("Could not renew certificate " . ($CertVal->"name") . ".") false; - } -} - -:foreach Cert in=[ /certificate/find where !revoked !scep-url !(expires-after=[]) \ - expires-after<$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!"); \ - message=("A certificate on " . $Identity . " " . $State . ".\n\n" . \ - "Name: " . ($CertVal->"name") . "\n" . \ - "CommonName: " . ($CertVal->"common-name") . "\n" . \ - "Private key: " . [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] . "\n" . \ - "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ - "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ - "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ - "Expires in: " . [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ]) }); - $LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " " . $State . \ - ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; - } -} +# dummy for migration diff --git a/check-certificates.rsc b/check-certificates.rsc new file mode 100644 index 0000000..8a06f8b --- /dev/null +++ b/check-certificates.rsc @@ -0,0 +1,138 @@ +#!rsc by RouterOS +# RouterOS script: check-certificates +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# check for certificate validity +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md + +:local 0 "check-certificates"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global CertRenewPass; +:global CertRenewTime; +:global CertRenewUrl; +:global CertWarnTime; +:global Identity; + +:global CertificateAvailable +:global CertificateNameByCN; +:global IfThenElse; +:global LogPrintExit2; +:global ParseKeyValueStore; +:global SendNotification2; +:global SymbolForNotification; +:global UrlEncode; +:global WaitForFile; +:global WaitFullyConnected; + +:local FormatExpire do={ + :global CharacterReplace; + :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; +} + +$WaitFullyConnected; + +:foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ + :local CertVal [ /certificate/get $Cert ]; + + :do { + :if ([ :len $CertRenewUrl ] = 0) do={ + $LogPrintExit2 info $0 ("No CertRenewUrl given.") true; + } + $LogPrintExit2 info $0 ("Attempting to renew certificate " . ($CertVal->"name") . ".") false; + + :foreach Type in={ ".pem"; ".p12" } do={ + :local CertFileName ([ $UrlEncode ($CertVal->"common-name") ] . $Type); + :do { + /tool/fetch check-certificate=yes-without-crl \ + ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; + $WaitForFile $CertFileName; + + :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~("^" . $CertFileName . "_[0-9]+\$") common-name!=($CertVal->"common-name") ] do={ + $CertificateNameByCN [ /certificate/get $CertInChain common-name ]; + } + } on-error={ + $LogPrintExit2 debug $0 ("Could not download certificate file " . $CertFileName) false; + } + } + + :local CertNew [ /certificate/find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ]; + :local CertNewVal [ /certificate/get $CertNew ]; + + :if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") ] = false) do={ + $LogPrintExit2 warning $0 ("The certificate chain is not available!") false; + } + + :if ($Cert != $CertNew) do={ + $LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; + + :if (($CertVal->"private-key") = true && ($CertVal->"private-key") != ($CertNewVal->"private-key")) do={ + /certificate/remove $CertNew; + $LogPrintExit2 warning $0 ("Old certificate '" . ($CertVal->"name") . "' has a private key, new certificate does not. Aborting renew.") true; + } + + /ip/service/set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; + + /ip/ipsec/identity/set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; + /ip/ipsec/identity/set remote-certificate=($CertNewVal->"name") [ find where remote-certificate=($CertVal->"name") ]; + + /ip/hotspot/profile/set ssl-certificate=($CertNewVal->"name") [ find where ssl-certificate=($CertVal->"name") ]; + + /certificate/remove $Cert; + /certificate/set $CertNew name=($CertVal->"name"); + } + + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed"); \ + message=("A certificate on " . $Identity . " has been renewed.\n\n" . \ + "Name: " . ($CertVal->"name") . "\n" . \ + "CommonName: " . ($CertNewVal->"common-name") . "\n" . \ + "Private key: " . [ $IfThenElse (($CertNewVal->"private-key") = true) "available" "missing" ] . "\n" . \ + "Fingerprint: " . ($CertNewVal->"fingerprint") . "\n" . \ + "Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \ + "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ + "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]); silent=true }); + $LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " has been renewed.") false; + } on-error={ + $LogPrintExit2 debug $0 ("Could not renew certificate " . ($CertVal->"name") . ".") false; + } +} + +:foreach Cert in=[ /certificate/find where !revoked !scep-url !(expires-after=[]) \ + expires-after<$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!"); \ + message=("A certificate on " . $Identity . " " . $State . ".\n\n" . \ + "Name: " . ($CertVal->"name") . "\n" . \ + "CommonName: " . ($CertVal->"common-name") . "\n" . \ + "Private key: " . [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] . "\n" . \ + "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ + "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ + "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ + "Expires in: " . [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ]) }); + $LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " " . $State . \ + ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; + } +} diff --git a/check-health b/check-health index e208bac..2da00ca 100644 --- a/check-health +++ b/check-health @@ -1,167 +1,3 @@ #!rsc by RouterOS -# RouterOS script: check-health -# Copyright (c) 2019-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# check for RouterOS health state -# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md - -:local 0 "check-health"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global CheckHealthCPUUtilization; -:global CheckHealthCPUUtilizationNotified; -:global CheckHealthFreeRAMNotified; -:global CheckHealthLast; -:global CheckHealthTemperature; -:global CheckHealthTemperatureDeviation; -:global CheckHealthTemperatureNotified; -:global CheckHealthVoltageLow; -:global CheckHealthVoltagePercent; -:global Identity; - -:global IfThenElse; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; - -:local TempToNum do={ - :global CharacterReplace; - :local T [ :toarray [ $CharacterReplace $1 "." "," ] ]; - :return ($T->0 * 10 + $T->1); -} - -$ScriptLock $0; - -:local Resource [ /system/resource/get ]; - -:set CheckHealthCPUUtilization (($CheckHealthCPUUtilization * 4 + ($Resource->"cpu-load") * 10) / 5); -: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 CheckHealthFreeRAM ($Resource->"free-memory" * 100 / $Resource->"total-memory"); -:if ($CheckHealthFreeRAM < 20 && $CheckHealthFreeRAMNotified != true) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "card-file-box,chart-decreasing" ] . "Health warning: free RAM"); \ - message=("The available free RAM on " . $Identity . " is at " . $CheckHealthFreeRAM . "% (" . \ - ($Resource->"free-memory" / 1024 / 1024) . "MiB)!") }); - :set CheckHealthFreeRAMNotified true; -} -:if ($CheckHealthFreeRAM > 30 && $CheckHealthFreeRAMNotified = true) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "card-file-box,chart-increasing" ] . "Health recovery: free RAM"); \ - message=("The available free RAM on " . $Identity . " increased to " . $CheckHealthFreeRAM . "% (" . \ - ($Resource->"free-memory" / 1024 / 1024) . "MiB).") }); - :set CheckHealthFreeRAMNotified false; -} - -:if ([ :len [ /system/health/find ] ] = 0) do={ - $LogPrintExit2 debug $0 ("Your device does not provide any health values.") true; -} - -:if ([ :typeof $CheckHealthLast ] != "array") do={ - :set CheckHealthLast ({}); -} -:if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ - :set CheckHealthTemperatureNotified ({}); -} - - -:foreach Voltage in=[ /system/health/find where type="V" ] do={ - :local Name [ /system/health/get $Voltage name ]; - :local Value [ /system/health/get $Voltage value ]; - - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :local NumCurr [ $TempToNum $Value ]; - :local NumLast [ $TempToNum ($CheckHealthLast->$Name) ]; - - :if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \ - $NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \ - $NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ - "old value: " . ($CheckHealthLast->$Name) . " V\n" . \ - "new value: " . $Value . " V") }); - } else={ - :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \ - message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") }); - } - :if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ - message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") }); - } - } - } - :set ($CheckHealthLast->$Name) $Value; -} - -:foreach PSU in=[ /system/health/find where name~"^psu.*-state\$" ] do={ - :local Name [ /system/health/get $PSU name ]; - :local Value [ /system/health/get $PSU value ]; - - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :if ($CheckHealthLast->$Name = "ok" && \ - $Value != "ok") do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ - message=("The power supply unit '" . $Name . "' on " . $Identity . " failed!") }); - } - :if ($CheckHealthLast->$Name != "ok" && \ - $Value = "ok") do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ - message=("The power supply unit '" . $Name . "' on " . $Identity . " recovered!") }); - } - } - :set ($CheckHealthLast->$Name) $Value; -} - -:foreach Temperature in=[ /system/health/find where type="C" ] do={ - :local Name [ /system/health/get $Temperature name ]; - :local Value [ /system/health/get $Temperature value ]; - - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ - $LogPrintExit2 info $0 ("No threshold given for " . $Name . ", assuming 50C.") false; - :set ($CheckHealthTemperature->$Name) 50; - } - :local Validate [ /system/health/get [ find where name=$Name ] value ]; - :while ($Value != $Validate) do={ - :set Value $Validate; - :set Validate [ /system/health/get [ find where name=$Name ] value ]; - } - :if ($Value > $CheckHealthTemperature->$Name && \ - $CheckHealthTemperatureNotified->$Name != true) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " is above threshold: " . \ - $Value . "\C2\B0" . "C") }); - :set ($CheckHealthTemperatureNotified->$Name) true; - } - :if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ - $CheckHealthTemperatureNotified->$Name = true) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ - $Value . "\C2\B0" . "C") }); - :set ($CheckHealthTemperatureNotified->$Name) false; - } - } - :set ($CheckHealthLast->$Name) $Value; -} +# dummy for migration diff --git a/check-health.rsc b/check-health.rsc new file mode 100644 index 0000000..e208bac --- /dev/null +++ b/check-health.rsc @@ -0,0 +1,167 @@ +#!rsc by RouterOS +# RouterOS script: check-health +# Copyright (c) 2019-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# check for RouterOS health state +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md + +:local 0 "check-health"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global CheckHealthCPUUtilization; +:global CheckHealthCPUUtilizationNotified; +:global CheckHealthFreeRAMNotified; +:global CheckHealthLast; +:global CheckHealthTemperature; +:global CheckHealthTemperatureDeviation; +:global CheckHealthTemperatureNotified; +:global CheckHealthVoltageLow; +:global CheckHealthVoltagePercent; +:global Identity; + +:global IfThenElse; +:global LogPrintExit2; +:global ScriptLock; +:global SendNotification2; +:global SymbolForNotification; + +:local TempToNum do={ + :global CharacterReplace; + :local T [ :toarray [ $CharacterReplace $1 "." "," ] ]; + :return ($T->0 * 10 + $T->1); +} + +$ScriptLock $0; + +:local Resource [ /system/resource/get ]; + +:set CheckHealthCPUUtilization (($CheckHealthCPUUtilization * 4 + ($Resource->"cpu-load") * 10) / 5); +: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 CheckHealthFreeRAM ($Resource->"free-memory" * 100 / $Resource->"total-memory"); +:if ($CheckHealthFreeRAM < 20 && $CheckHealthFreeRAMNotified != true) do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "card-file-box,chart-decreasing" ] . "Health warning: free RAM"); \ + message=("The available free RAM on " . $Identity . " is at " . $CheckHealthFreeRAM . "% (" . \ + ($Resource->"free-memory" / 1024 / 1024) . "MiB)!") }); + :set CheckHealthFreeRAMNotified true; +} +:if ($CheckHealthFreeRAM > 30 && $CheckHealthFreeRAMNotified = true) do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "card-file-box,chart-increasing" ] . "Health recovery: free RAM"); \ + message=("The available free RAM on " . $Identity . " increased to " . $CheckHealthFreeRAM . "% (" . \ + ($Resource->"free-memory" / 1024 / 1024) . "MiB).") }); + :set CheckHealthFreeRAMNotified false; +} + +:if ([ :len [ /system/health/find ] ] = 0) do={ + $LogPrintExit2 debug $0 ("Your device does not provide any health values.") true; +} + +:if ([ :typeof $CheckHealthLast ] != "array") do={ + :set CheckHealthLast ({}); +} +:if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ + :set CheckHealthTemperatureNotified ({}); +} + + +:foreach Voltage in=[ /system/health/find where type="V" ] do={ + :local Name [ /system/health/get $Voltage name ]; + :local Value [ /system/health/get $Voltage value ]; + + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ + :local NumCurr [ $TempToNum $Value ]; + :local NumLast [ $TempToNum ($CheckHealthLast->$Name) ]; + + :if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \ + $NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \ + $NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ + message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ + "old value: " . ($CheckHealthLast->$Name) . " V\n" . \ + "new value: " . $Value . " V") }); + } else={ + :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \ + message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") }); + } + :if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ + message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") }); + } + } + } + :set ($CheckHealthLast->$Name) $Value; +} + +:foreach PSU in=[ /system/health/find where name~"^psu.*-state\$" ] do={ + :local Name [ /system/health/get $PSU name ]; + :local Value [ /system/health/get $PSU value ]; + + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ + :if ($CheckHealthLast->$Name = "ok" && \ + $Value != "ok") do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ + message=("The power supply unit '" . $Name . "' on " . $Identity . " failed!") }); + } + :if ($CheckHealthLast->$Name != "ok" && \ + $Value = "ok") do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ + message=("The power supply unit '" . $Name . "' on " . $Identity . " recovered!") }); + } + } + :set ($CheckHealthLast->$Name) $Value; +} + +:foreach Temperature in=[ /system/health/find where type="C" ] do={ + :local Name [ /system/health/get $Temperature name ]; + :local Value [ /system/health/get $Temperature value ]; + + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ + :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ + $LogPrintExit2 info $0 ("No threshold given for " . $Name . ", assuming 50C.") false; + :set ($CheckHealthTemperature->$Name) 50; + } + :local Validate [ /system/health/get [ find where name=$Name ] value ]; + :while ($Value != $Validate) do={ + :set Value $Validate; + :set Validate [ /system/health/get [ find where name=$Name ] value ]; + } + :if ($Value > $CheckHealthTemperature->$Name && \ + $CheckHealthTemperatureNotified->$Name != true) do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ + message=("The " . $Name . " on " . $Identity . " is above threshold: " . \ + $Value . "\C2\B0" . "C") }); + :set ($CheckHealthTemperatureNotified->$Name) true; + } + :if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ + $CheckHealthTemperatureNotified->$Name = true) do={ + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ + message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ + $Value . "\C2\B0" . "C") }); + :set ($CheckHealthTemperatureNotified->$Name) false; + } + } + :set ($CheckHealthLast->$Name) $Value; +} diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 02e864b..2da00ca 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -1,82 +1,3 @@ #!rsc by RouterOS -# RouterOS script: check-lte-firmware-upgrade -# Copyright (c) 2018-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# check for LTE firmware upgrade, send notification -# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md - -:local 0 "check-lte-firmware-upgrade"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global SentLteFirmwareUpgradeNotification; - -:if ([ :typeof $SentLteFirmwareUpgradeNotification ] != "array") do={ - :global SentLteFirmwareUpgradeNotification ({}); -} - -:local CheckInterface do={ - :local Interface $1; - - :global Identity; - :global SentLteFirmwareUpgradeNotification; - - :global CharacterReplace; - :global LogPrintExit2; - :global ScriptFromTerminal; - :global SendNotification2; - :global SymbolForNotification; - - :local IntName [ /interface/lte/get $Interface name ]; - :local Firmware; - :local Info; - :do { - :set Firmware [ /interface/lte/firmware-upgrade $Interface once as-value ]; - :set Info [ /interface/lte/monitor $Interface once as-value ]; - } on-error={ - $LogPrintExit2 debug $0 ("Could not get latest LTE firmware version for interface " . \ - $IntName . ".") false; - :return false; - } - - :if (($Firmware->"installed") = ($Firmware->"latest")) do={ - :if ([ $ScriptFromTerminal $0 ] = true) do={ - $LogPrintExit2 info $0 ("No firmware upgrade available for LTE interface " . $IntName . ".") false; - } - :return true; - } - - :if ([ $ScriptFromTerminal $0 ] = true && \ - [ :len [ /system/script/find where name="unattended-lte-firmware-upgrade" ] ] > 0) do={ - :put ("Do you want to start unattended lte firmware upgrade for interface " . $IntName . "? [y/N]"); - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - /system/script/run unattended-lte-firmware-upgrade; - $LogPrintExit2 info $0 ("Scheduled lte firmware upgrade for interface " . $IntName . "...") false; - :return true; - } else={ - :put "Canceled..."; - } - } - - :if (($SentLteFirmwareUpgradeNotification->$IntName) = ($Firmware->"latest")) do={ - $LogPrintExit2 debug $0 ("Already sent the LTE firmware upgrade notification for version " . \ - ($Firmware->"latest") . ".") false; - :return false; - } - - $LogPrintExit2 info $0 ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ - "LTE interface " . $IntName . ".") false; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \ - message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \ - "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ - "Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \ - "Installed: " . ($Firmware->"installed") . "\n" . \ - "Available: " . ($Firmware->"latest")); silent=true }); - :set ($SentLteFirmwareUpgradeNotification->$IntName) ($Firmware->"latest"); -} - -:foreach Interface in=[ /interface/lte/find ] do={ - $CheckInterface $Interface; -} +# dummy for migration diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc new file mode 100644 index 0000000..02e864b --- /dev/null +++ b/check-lte-firmware-upgrade.rsc @@ -0,0 +1,82 @@ +#!rsc by RouterOS +# RouterOS script: check-lte-firmware-upgrade +# Copyright (c) 2018-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# check for LTE firmware upgrade, send notification +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md + +:local 0 "check-lte-firmware-upgrade"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global SentLteFirmwareUpgradeNotification; + +:if ([ :typeof $SentLteFirmwareUpgradeNotification ] != "array") do={ + :global SentLteFirmwareUpgradeNotification ({}); +} + +:local CheckInterface do={ + :local Interface $1; + + :global Identity; + :global SentLteFirmwareUpgradeNotification; + + :global CharacterReplace; + :global LogPrintExit2; + :global ScriptFromTerminal; + :global SendNotification2; + :global SymbolForNotification; + + :local IntName [ /interface/lte/get $Interface name ]; + :local Firmware; + :local Info; + :do { + :set Firmware [ /interface/lte/firmware-upgrade $Interface once as-value ]; + :set Info [ /interface/lte/monitor $Interface once as-value ]; + } on-error={ + $LogPrintExit2 debug $0 ("Could not get latest LTE firmware version for interface " . \ + $IntName . ".") false; + :return false; + } + + :if (($Firmware->"installed") = ($Firmware->"latest")) do={ + :if ([ $ScriptFromTerminal $0 ] = true) do={ + $LogPrintExit2 info $0 ("No firmware upgrade available for LTE interface " . $IntName . ".") false; + } + :return true; + } + + :if ([ $ScriptFromTerminal $0 ] = true && \ + [ :len [ /system/script/find where name="unattended-lte-firmware-upgrade" ] ] > 0) do={ + :put ("Do you want to start unattended lte firmware upgrade for interface " . $IntName . "? [y/N]"); + :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ + /system/script/run unattended-lte-firmware-upgrade; + $LogPrintExit2 info $0 ("Scheduled lte firmware upgrade for interface " . $IntName . "...") false; + :return true; + } else={ + :put "Canceled..."; + } + } + + :if (($SentLteFirmwareUpgradeNotification->$IntName) = ($Firmware->"latest")) do={ + $LogPrintExit2 debug $0 ("Already sent the LTE firmware upgrade notification for version " . \ + ($Firmware->"latest") . ".") false; + :return false; + } + + $LogPrintExit2 info $0 ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ + "LTE interface " . $IntName . ".") false; + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \ + message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \ + "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ + "Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \ + "Installed: " . ($Firmware->"installed") . "\n" . \ + "Available: " . ($Firmware->"latest")); silent=true }); + :set ($SentLteFirmwareUpgradeNotification->$IntName) ($Firmware->"latest"); +} + +:foreach Interface in=[ /interface/lte/find ] do={ + $CheckInterface $Interface; +} diff --git a/check-routeros-update b/check-routeros-update index d1c82c5..2da00ca 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -1,147 +1,3 @@ #!rsc by RouterOS -# RouterOS script: check-routeros-update -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# check for RouterOS update, send notification and/or install -# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md - -:local 0 "check-routeros-update"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Identity; -:global SafeUpdateAll; -:global SafeUpdateNeighbor; -:global SafeUpdatePatch; -:global SafeUpdateUrl; -:global SentRouterosUpdateNotification; - -:global DeviceInfo; -:global LogPrintExit2; -:global ScriptFromTerminal; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; -:global VersionToNum; -:global WaitFullyConnected; - -:local DoUpdate do={ - :if ([ :len [ /system/script/find where name="packages-update" ] ] > 0) do={ - /system/script/run packages-update; - } else={ - /system/package/update/install without-paging; - } - :error "Waiting for system to reboot."; -} - -$ScriptLock $0; - -$WaitFullyConnected; - -:if ([ :len [ /system/scheduler/find where name="reboot-for-update" ] ] > 0) do={ - :error "A reboot for update is already scheduled."; -} - -$LogPrintExit2 debug $0 ("Checking for updates...") false; -/system/package/update/check-for-updates without-paging as-value; -:local Update [ /system/package/update/get ]; - -:if ([ $ScriptFromTerminal $0 ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={ - $LogPrintExit2 info $0 ("System is already up to date.") true; -} - -:local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; -:local NumLatest [ $VersionToNum ($Update->"latest-version") ]; -:local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); - -:if ($NumLatest < 117505792) do={ - $LogPrintExit2 info $0 ("The version '" . ($Update->"latest-version") . "' is not a valid version.") true; -} - -:if ($NumInstalled < $NumLatest) do={ - :if ($SafeUpdateAll ~ "^YES,? ?PLEASE!?\$") do={ - $LogPrintExit2 info $0 ("Installing ALL versions automatically, including " . \ - $Update->"latest-version" . "...") false; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ - 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={ - $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ - message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ - ", updating on " . $Identity . "..."); link=$Link; silent=true }); - $DoUpdate; - } - - :if ($SafeUpdateNeighbor = true && [ :len [ /ip/neighbor/find where \ - version=($Update->"latest-version" . " (" . $Update->"channel" . ")") ] ] > 0) do={ - $LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ - message=("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \ - ", updating on " . $Identity . "..."); link=$Link; silent=true }); - $DoUpdate; - } - - :if ([ :len $SafeUpdateUrl ] > 0) do={ - :local Result; - :do { - :set Result [ /tool/fetch check-certificate=yes-without-crl \ - ($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \ - "&latest=" . $Update->"latest-version") output=user as-value ]; - } on-error={ - $LogPrintExit2 warning $0 ("Failed receiving safe version for " . $Update->"channel" . ".") false; - } - :if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={ - $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ - message=("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ - ", updating on " . $Identity . "..."); link=$Link; silent=true }); - $DoUpdate; - } - } - - :if ([ $ScriptFromTerminal $0 ] = true) do={ - :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - $DoUpdate; - } else={ - :put "Canceled..."; - } - } - - :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ - $LogPrintExit2 info $0 ("Already sent the RouterOS update notification for version " . \ - $Update->"latest-version" . ".") true; - } - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ - message=("A new RouterOS version " . ($Update->"latest-version") . \ - " is available for " . $Identity . ".\n\n" . \ - [ $DeviceInfo ]); link=$Link; silent=true }); - :set SentRouterosUpdateNotification ($Update->"latest-version"); -} - -:if ($NumInstalled > $NumLatest) do={ - :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ - $LogPrintExit2 info $0 ("Already sent the RouterOS downgrade notification for version " . \ - $Update->"latest-version" . ".") true; - } - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "warning-sign" ] . "RouterOS version"); \ - message=("A different RouterOS version " . ($Update->"latest-version") . \ - " is available for " . $Identity . ", but it is a downgrade.\n\n" . \ - [ $DeviceInfo ]); link=$Link; silent=true }); - $LogPrintExit2 info $0 ("A different RouterOS version " . ($Update->"latest-version") . \ - " is available for downgrade.") false; - :set SentRouterosUpdateNotification ($Update->"latest-version"); -} +# dummy for migration diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc new file mode 100644 index 0000000..d1c82c5 --- /dev/null +++ b/check-routeros-update.rsc @@ -0,0 +1,147 @@ +#!rsc by RouterOS +# RouterOS script: check-routeros-update +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# check for RouterOS update, send notification and/or install +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md + +:local 0 "check-routeros-update"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Identity; +:global SafeUpdateAll; +:global SafeUpdateNeighbor; +:global SafeUpdatePatch; +:global SafeUpdateUrl; +:global SentRouterosUpdateNotification; + +:global DeviceInfo; +:global LogPrintExit2; +:global ScriptFromTerminal; +:global ScriptLock; +:global SendNotification2; +:global SymbolForNotification; +:global VersionToNum; +:global WaitFullyConnected; + +:local DoUpdate do={ + :if ([ :len [ /system/script/find where name="packages-update" ] ] > 0) do={ + /system/script/run packages-update; + } else={ + /system/package/update/install without-paging; + } + :error "Waiting for system to reboot."; +} + +$ScriptLock $0; + +$WaitFullyConnected; + +:if ([ :len [ /system/scheduler/find where name="reboot-for-update" ] ] > 0) do={ + :error "A reboot for update is already scheduled."; +} + +$LogPrintExit2 debug $0 ("Checking for updates...") false; +/system/package/update/check-for-updates without-paging as-value; +:local Update [ /system/package/update/get ]; + +:if ([ $ScriptFromTerminal $0 ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={ + $LogPrintExit2 info $0 ("System is already up to date.") true; +} + +:local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; +:local NumLatest [ $VersionToNum ($Update->"latest-version") ]; +:local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); + +:if ($NumLatest < 117505792) do={ + $LogPrintExit2 info $0 ("The version '" . ($Update->"latest-version") . "' is not a valid version.") true; +} + +:if ($NumInstalled < $NumLatest) do={ + :if ($SafeUpdateAll ~ "^YES,? ?PLEASE!?\$") do={ + $LogPrintExit2 info $0 ("Installing ALL versions automatically, including " . \ + $Update->"latest-version" . "...") false; + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + 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={ + $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ + ", updating on " . $Identity . "..."); link=$Link; silent=true }); + $DoUpdate; + } + + :if ($SafeUpdateNeighbor = true && [ :len [ /ip/neighbor/find where \ + version=($Update->"latest-version" . " (" . $Update->"channel" . ")") ] ] > 0) do={ + $LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + message=("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \ + ", updating on " . $Identity . "..."); link=$Link; silent=true }); + $DoUpdate; + } + + :if ([ :len $SafeUpdateUrl ] > 0) do={ + :local Result; + :do { + :set Result [ /tool/fetch check-certificate=yes-without-crl \ + ($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \ + "&latest=" . $Update->"latest-version") output=user as-value ]; + } on-error={ + $LogPrintExit2 warning $0 ("Failed receiving safe version for " . $Update->"channel" . ".") false; + } + :if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={ + $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + message=("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ + ", updating on " . $Identity . "..."); link=$Link; silent=true }); + $DoUpdate; + } + } + + :if ([ $ScriptFromTerminal $0 ] = true) do={ + :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); + :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ + $DoUpdate; + } else={ + :put "Canceled..."; + } + } + + :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ + $LogPrintExit2 info $0 ("Already sent the RouterOS update notification for version " . \ + $Update->"latest-version" . ".") true; + } + + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + message=("A new RouterOS version " . ($Update->"latest-version") . \ + " is available for " . $Identity . ".\n\n" . \ + [ $DeviceInfo ]); link=$Link; silent=true }); + :set SentRouterosUpdateNotification ($Update->"latest-version"); +} + +:if ($NumInstalled > $NumLatest) do={ + :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ + $LogPrintExit2 info $0 ("Already sent the RouterOS downgrade notification for version " . \ + $Update->"latest-version" . ".") true; + } + + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "warning-sign" ] . "RouterOS version"); \ + message=("A different RouterOS version " . ($Update->"latest-version") . \ + " is available for " . $Identity . ", but it is a downgrade.\n\n" . \ + [ $DeviceInfo ]); link=$Link; silent=true }); + $LogPrintExit2 info $0 ("A different RouterOS version " . ($Update->"latest-version") . \ + " is available for downgrade.") false; + :set SentRouterosUpdateNotification ($Update->"latest-version"); +} diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index e814fa9..2da00ca 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -1,85 +1,3 @@ #!rsc by RouterOS -# RouterOS script: collect-wireless-mac.capsman -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# collect wireless mac adresses in access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md -# -# provides: lease-script, order=40 -# -# !! Do not edit this file, it is generated from template! - -:local 0 "collect-wireless-mac.capsman"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Identity; - -:global EitherOr; -:global GetMacVendor; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; - -$ScriptLock $0 false 10; - -:if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - /caps-man/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false; -} -:local PlaceBefore ([ /caps-man/access-list/find where comment="--- collected above ---" disabled ]->0); - -:foreach Reg in=[ /caps-man/registration-table/find ] do={ - :local RegVal; - :do { - :set RegVal [ /caps-man/registration-table/get $Reg ]; - } on-error={ - $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; - } - - :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /caps-man/access-list/get $AccessList comment ]) false; - } - - :if ([ :len $AccessList ] = 0) do={ - :local Address "no dhcp lease"; - :local DnsName "no dhcp lease"; - :local HostName "no dhcp lease"; - :local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); - :if ([ :len $Lease ] > 0) do={ - :set Address [ /ip/dhcp-server/lease/get $Lease address ]; - :set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; - :set DnsName "no dns name"; - :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); - :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ /ip/dns/static/get $DnsRec name ]; - } - } - :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrintExit2 info $0 $Message false; - /caps-man/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - "Controller: " . $Identity . "\n" . \ - "Interface: " . $RegVal->"interface" . "\n" . \ - "SSID: " . $RegVal->"ssid" . "\n" . \ - "MAC: " . $RegVal->"mac-address" . "\n" . \ - "Vendor: " . $Vendor . "\n" . \ - "Hostname: " . $HostName . "\n" . \ - "Address: " . $Address . "\n" . \ - "DNS name: " . $DnsName . "\n" . \ - "Date: " . $DateTime) }); - } - } else={ - $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; - } -} +# dummy for migration diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc new file mode 100644 index 0000000..e814fa9 --- /dev/null +++ b/collect-wireless-mac.capsman.rsc @@ -0,0 +1,85 @@ +#!rsc by RouterOS +# RouterOS script: collect-wireless-mac.capsman +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# collect wireless mac adresses in access list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md +# +# provides: lease-script, order=40 +# +# !! Do not edit this file, it is generated from template! + +:local 0 "collect-wireless-mac.capsman"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Identity; + +:global EitherOr; +:global GetMacVendor; +:global LogPrintExit2; +:global ScriptLock; +:global SendNotification2; +:global SymbolForNotification; + +$ScriptLock $0 false 10; + +:if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ + /caps-man/access-list/add comment="--- collected above ---" disabled=yes; + $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false; +} +:local PlaceBefore ([ /caps-man/access-list/find where comment="--- collected above ---" disabled ]->0); + +:foreach Reg in=[ /caps-man/registration-table/find ] do={ + :local RegVal; + :do { + :set RegVal [ /caps-man/registration-table/get $Reg ]; + } on-error={ + $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; + } + + :if ([ :len ($RegVal->"mac-address") ] > 0) do={ + :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ + [ /caps-man/access-list/get $AccessList comment ]) false; + } + + :if ([ :len $AccessList ] = 0) do={ + :local Address "no dhcp lease"; + :local DnsName "no dhcp lease"; + :local HostName "no dhcp lease"; + :local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); + :if ([ :len $Lease ] > 0) do={ + :set Address [ /ip/dhcp-server/lease/get $Lease address ]; + :set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; + :set DnsName "no dns name"; + :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); + :if ([ :len $DnsRec ] > 0) do={ + :set DnsName [ /ip/dns/static/get $DnsRec name ]; + } + } + :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); + :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; + :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ + "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); + $LogPrintExit2 info $0 $Message false; + /caps-man/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ + message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ + "Controller: " . $Identity . "\n" . \ + "Interface: " . $RegVal->"interface" . "\n" . \ + "SSID: " . $RegVal->"ssid" . "\n" . \ + "MAC: " . $RegVal->"mac-address" . "\n" . \ + "Vendor: " . $Vendor . "\n" . \ + "Hostname: " . $HostName . "\n" . \ + "Address: " . $Address . "\n" . \ + "DNS name: " . $DnsName . "\n" . \ + "Date: " . $DateTime) }); + } + } else={ + $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; + } +} diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index ee07f54..2da00ca 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -1,86 +1,3 @@ #!rsc by RouterOS -# RouterOS script: collect-wireless-mac.local -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# collect wireless mac adresses in access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md -# -# provides: lease-script, order=40 -# -# !! Do not edit this file, it is generated from template! - -:local 0 "collect-wireless-mac.local"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Identity; - -:global EitherOr; -:global GetMacVendor; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; - -$ScriptLock $0 false 10; - -:if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - /interface/wireless/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false; -} -:local PlaceBefore ([ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ]->0); - -:foreach Reg in=[ /interface/wireless/registration-table/find ] do={ - :local RegVal; - :do { - :set RegVal [ /interface/wireless/registration-table/get $Reg ]; - } on-error={ - $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; - } - - :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /interface/wireless/access-list/get $AccessList comment ]) false; - } - - :if ([ :len $AccessList ] = 0) do={ - :local Address "no dhcp lease"; - :local DnsName "no dhcp lease"; - :local HostName "no dhcp lease"; - :local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); - :if ([ :len $Lease ] > 0) do={ - :set Address [ /ip/dhcp-server/lease/get $Lease address ]; - :set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; - :set DnsName "no dns name"; - :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); - :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ /ip/dns/static/get $DnsRec name ]; - } - } - :set ($RegVal->"ssid") [ /interface/wireless/get [ find where name=($RegVal->"interface") ] ssid ]; - :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrintExit2 info $0 $Message false; - /interface/wireless/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - "Controller: " . $Identity . "\n" . \ - "Interface: " . $RegVal->"interface" . "\n" . \ - "SSID: " . $RegVal->"ssid" . "\n" . \ - "MAC: " . $RegVal->"mac-address" . "\n" . \ - "Vendor: " . $Vendor . "\n" . \ - "Hostname: " . $HostName . "\n" . \ - "Address: " . $Address . "\n" . \ - "DNS name: " . $DnsName . "\n" . \ - "Date: " . $DateTime) }); - } - } else={ - $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; - } -} +# dummy for migration diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc new file mode 100644 index 0000000..ee07f54 --- /dev/null +++ b/collect-wireless-mac.local.rsc @@ -0,0 +1,86 @@ +#!rsc by RouterOS +# RouterOS script: collect-wireless-mac.local +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# collect wireless mac adresses in access list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md +# +# provides: lease-script, order=40 +# +# !! Do not edit this file, it is generated from template! + +:local 0 "collect-wireless-mac.local"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Identity; + +:global EitherOr; +:global GetMacVendor; +:global LogPrintExit2; +:global ScriptLock; +:global SendNotification2; +:global SymbolForNotification; + +$ScriptLock $0 false 10; + +:if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ + /interface/wireless/access-list/add comment="--- collected above ---" disabled=yes; + $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false; +} +:local PlaceBefore ([ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ]->0); + +:foreach Reg in=[ /interface/wireless/registration-table/find ] do={ + :local RegVal; + :do { + :set RegVal [ /interface/wireless/registration-table/get $Reg ]; + } on-error={ + $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; + } + + :if ([ :len ($RegVal->"mac-address") ] > 0) do={ + :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ + [ /interface/wireless/access-list/get $AccessList comment ]) false; + } + + :if ([ :len $AccessList ] = 0) do={ + :local Address "no dhcp lease"; + :local DnsName "no dhcp lease"; + :local HostName "no dhcp lease"; + :local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); + :if ([ :len $Lease ] > 0) do={ + :set Address [ /ip/dhcp-server/lease/get $Lease address ]; + :set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; + :set DnsName "no dns name"; + :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); + :if ([ :len $DnsRec ] > 0) do={ + :set DnsName [ /ip/dns/static/get $DnsRec name ]; + } + } + :set ($RegVal->"ssid") [ /interface/wireless/get [ find where name=($RegVal->"interface") ] ssid ]; + :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); + :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; + :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ + "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); + $LogPrintExit2 info $0 $Message false; + /interface/wireless/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ + message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ + "Controller: " . $Identity . "\n" . \ + "Interface: " . $RegVal->"interface" . "\n" . \ + "SSID: " . $RegVal->"ssid" . "\n" . \ + "MAC: " . $RegVal->"mac-address" . "\n" . \ + "Vendor: " . $Vendor . "\n" . \ + "Hostname: " . $HostName . "\n" . \ + "Address: " . $Address . "\n" . \ + "DNS name: " . $DnsName . "\n" . \ + "Date: " . $DateTime) }); + } + } else={ + $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; + } +} diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template.rsc similarity index 100% rename from collect-wireless-mac.template rename to collect-wireless-mac.template.rsc diff --git a/daily-psk.capsman b/daily-psk.capsman index 17a09e1..2da00ca 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -1,96 +1,3 @@ #!rsc by RouterOS -# RouterOS script: daily-psk.capsman -# Copyright (c) 2013-2023 Christian Hesse -# Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# update daily PSK (pre shared key) -# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md -# -# !! Do not edit this file, it is generated from template! - -:local 0 "daily-psk.capsman"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global DailyPskMatchComment; -:global DailyPskQrCodeUrl; -:global Identity; - -:global LogPrintExit2; -:global SendNotification2; -:global SymbolForNotification; -:global UrlEncode; -:global WaitForFile; -:global WaitFullyConnected; - -$WaitFullyConnected; - -# return pseudo-random string for PSK -:local GeneratePSK do={ - :local Date [ :tostr $1 ]; - - :global DailyPskSecrets; - - :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun"; - "jul"; "aug"; "sep"; "oct"; "nov"; "dec" }; - - :local Month [ :pick $Date 0 3 ]; - :local Day [ :tonum [ :pick $Date 4 6 ] ]; - :local Year [ :pick $Date 7 11 ]; - - :for MIndex from=0 to=[ :len $Months ] do={ - :if ($Months->$MIndex = $Month) do={ - :set Month ($MIndex + 1); - } - } - - :local A ((14 - $Month) / 12); - :local B ($Year - $A); - :local C ($Month + 12 * $A - 2); - :local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); - :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); - - :return (($DailyPskSecrets->0->($Day - 1)) . \ - ($DailyPskSecrets->1->($Month - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); -} - -:local Seen ({}); -:local Date [ /system/clock/get date ]; -:local NewPsk [ $GeneratePSK $Date ]; - -:foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ - :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; - :local Configuration ([ /caps-man/configuration/find where ssid~$SsidRegExp ]->0); - :local Ssid [ /caps-man/configuration/get $Configuration ssid ]; - :local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ]; - :local Skip 0; - - :if ($NewPsk != $OldPsk) do={ - $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; - /caps-man/access-list/set $AccList private-passphrase=$NewPsk; - - :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ - :foreach SeenSsid in=$Seen do={ - :if ($SeenSsid = $Ssid) do={ - $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; - :set Skip 1; - } - } - - :if ($Skip = 0) do={ - :set Seen ($Seen, $Ssid); - :local Link ($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" . \ - "SSID: " . $Ssid . "\n" . \ - "PSK: " . $NewPsk . "\n" . \ - "Date: " . $Date . "\n\n" . \ - "A client device specific rule must not exist!"); link=$Link }); - } - } - } -} +# dummy for migration diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc new file mode 100644 index 0000000..17a09e1 --- /dev/null +++ b/daily-psk.capsman.rsc @@ -0,0 +1,96 @@ +#!rsc by RouterOS +# RouterOS script: daily-psk.capsman +# Copyright (c) 2013-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update daily PSK (pre shared key) +# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "daily-psk.capsman"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global DailyPskMatchComment; +:global DailyPskQrCodeUrl; +:global Identity; + +:global LogPrintExit2; +:global SendNotification2; +:global SymbolForNotification; +:global UrlEncode; +:global WaitForFile; +:global WaitFullyConnected; + +$WaitFullyConnected; + +# return pseudo-random string for PSK +:local GeneratePSK do={ + :local Date [ :tostr $1 ]; + + :global DailyPskSecrets; + + :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun"; + "jul"; "aug"; "sep"; "oct"; "nov"; "dec" }; + + :local Month [ :pick $Date 0 3 ]; + :local Day [ :tonum [ :pick $Date 4 6 ] ]; + :local Year [ :pick $Date 7 11 ]; + + :for MIndex from=0 to=[ :len $Months ] do={ + :if ($Months->$MIndex = $Month) do={ + :set Month ($MIndex + 1); + } + } + + :local A ((14 - $Month) / 12); + :local B ($Year - $A); + :local C ($Month + 12 * $A - 2); + :local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); + :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); + + :return (($DailyPskSecrets->0->($Day - 1)) . \ + ($DailyPskSecrets->1->($Month - 1)) . \ + ($DailyPskSecrets->2->$WeekDay)); +} + +:local Seen ({}); +:local Date [ /system/clock/get date ]; +:local NewPsk [ $GeneratePSK $Date ]; + +:foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ + :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; + :local Configuration ([ /caps-man/configuration/find where ssid~$SsidRegExp ]->0); + :local Ssid [ /caps-man/configuration/get $Configuration ssid ]; + :local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ]; + :local Skip 0; + + :if ($NewPsk != $OldPsk) do={ + $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + /caps-man/access-list/set $AccList private-passphrase=$NewPsk; + + :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ + :foreach SeenSsid in=$Seen do={ + :if ($SeenSsid = $Ssid) do={ + $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; + :set Skip 1; + } + } + + :if ($Skip = 0) do={ + :set Seen ($Seen, $Ssid); + :local Link ($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" . \ + "SSID: " . $Ssid . "\n" . \ + "PSK: " . $NewPsk . "\n" . \ + "Date: " . $Date . "\n\n" . \ + "A client device specific rule must not exist!"); link=$Link }); + } + } + } +} diff --git a/daily-psk.local b/daily-psk.local index 17a60f7..2da00ca 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -1,95 +1,3 @@ #!rsc by RouterOS -# RouterOS script: daily-psk.local -# Copyright (c) 2013-2023 Christian Hesse -# Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# update daily PSK (pre shared key) -# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md -# -# !! Do not edit this file, it is generated from template! - -:local 0 "daily-psk.local"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global DailyPskMatchComment; -:global DailyPskQrCodeUrl; -:global Identity; - -:global LogPrintExit2; -:global SendNotification2; -:global SymbolForNotification; -:global UrlEncode; -:global WaitForFile; -:global WaitFullyConnected; - -$WaitFullyConnected; - -# return pseudo-random string for PSK -:local GeneratePSK do={ - :local Date [ :tostr $1 ]; - - :global DailyPskSecrets; - - :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun"; - "jul"; "aug"; "sep"; "oct"; "nov"; "dec" }; - - :local Month [ :pick $Date 0 3 ]; - :local Day [ :tonum [ :pick $Date 4 6 ] ]; - :local Year [ :pick $Date 7 11 ]; - - :for MIndex from=0 to=[ :len $Months ] do={ - :if ($Months->$MIndex = $Month) do={ - :set Month ($MIndex + 1); - } - } - - :local A ((14 - $Month) / 12); - :local B ($Year - $A); - :local C ($Month + 12 * $A - 2); - :local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); - :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); - - :return (($DailyPskSecrets->0->($Day - 1)) . \ - ($DailyPskSecrets->1->($Month - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); -} - -:local Seen ({}); -:local Date [ /system/clock/get date ]; -:local NewPsk [ $GeneratePSK $Date ]; - -:foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ - :local IntName [ /interface/wireless/access-list/get $AccList interface ]; - :local Ssid [ /interface/wireless/get $IntName ssid ]; - :local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ]; - :local Skip 0; - - :if ($NewPsk != $OldPsk) do={ - $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; - /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; - - :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ - :foreach SeenSsid in=$Seen do={ - :if ($SeenSsid = $Ssid) do={ - $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; - :set Skip 1; - } - } - - :if ($Skip = 0) do={ - :set Seen ($Seen, $Ssid); - :local Link ($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" . \ - "SSID: " . $Ssid . "\n" . \ - "PSK: " . $NewPsk . "\n" . \ - "Date: " . $Date . "\n\n" . \ - "A client device specific rule must not exist!"); link=$Link }); - } - } - } -} +# dummy for migration diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc new file mode 100644 index 0000000..17a60f7 --- /dev/null +++ b/daily-psk.local.rsc @@ -0,0 +1,95 @@ +#!rsc by RouterOS +# RouterOS script: daily-psk.local +# Copyright (c) 2013-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update daily PSK (pre shared key) +# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "daily-psk.local"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global DailyPskMatchComment; +:global DailyPskQrCodeUrl; +:global Identity; + +:global LogPrintExit2; +:global SendNotification2; +:global SymbolForNotification; +:global UrlEncode; +:global WaitForFile; +:global WaitFullyConnected; + +$WaitFullyConnected; + +# return pseudo-random string for PSK +:local GeneratePSK do={ + :local Date [ :tostr $1 ]; + + :global DailyPskSecrets; + + :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun"; + "jul"; "aug"; "sep"; "oct"; "nov"; "dec" }; + + :local Month [ :pick $Date 0 3 ]; + :local Day [ :tonum [ :pick $Date 4 6 ] ]; + :local Year [ :pick $Date 7 11 ]; + + :for MIndex from=0 to=[ :len $Months ] do={ + :if ($Months->$MIndex = $Month) do={ + :set Month ($MIndex + 1); + } + } + + :local A ((14 - $Month) / 12); + :local B ($Year - $A); + :local C ($Month + 12 * $A - 2); + :local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); + :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); + + :return (($DailyPskSecrets->0->($Day - 1)) . \ + ($DailyPskSecrets->1->($Month - 1)) . \ + ($DailyPskSecrets->2->$WeekDay)); +} + +:local Seen ({}); +:local Date [ /system/clock/get date ]; +:local NewPsk [ $GeneratePSK $Date ]; + +:foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ + :local IntName [ /interface/wireless/access-list/get $AccList interface ]; + :local Ssid [ /interface/wireless/get $IntName ssid ]; + :local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ]; + :local Skip 0; + + :if ($NewPsk != $OldPsk) do={ + $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; + + :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ + :foreach SeenSsid in=$Seen do={ + :if ($SeenSsid = $Ssid) do={ + $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; + :set Skip 1; + } + } + + :if ($Skip = 0) do={ + :set Seen ($Seen, $Ssid); + :local Link ($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" . \ + "SSID: " . $Ssid . "\n" . \ + "PSK: " . $NewPsk . "\n" . \ + "Date: " . $Date . "\n\n" . \ + "A client device specific rule must not exist!"); link=$Link }); + } + } + } +} diff --git a/daily-psk.template b/daily-psk.template.rsc similarity index 100% rename from daily-psk.template rename to daily-psk.template.rsc diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index 55b76bf..2da00ca 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -1,30 +1,3 @@ #!rsc by RouterOS -# RouterOS script: dhcp-lease-comment.capsman -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, order=60 -# -# update dhcp-server lease comment with infos from access-list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md -# -# !! Do not edit this file, it is generated from template! - -:local 0 "dhcp-lease-comment.capsman"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; - -:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local NewComment; - :local AccessList ([ /caps-man/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - :set NewComment [ /caps-man/access-list/get $AccessList comment ]; - } - :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; - /ip/dhcp-server/lease/set comment=$NewComment $Lease; - } -} +# dummy for migration diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc new file mode 100644 index 0000000..55b76bf --- /dev/null +++ b/dhcp-lease-comment.capsman.rsc @@ -0,0 +1,30 @@ +#!rsc by RouterOS +# RouterOS script: dhcp-lease-comment.capsman +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=60 +# +# update dhcp-server lease comment with infos from access-list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "dhcp-lease-comment.capsman"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global LogPrintExit2; + +:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + :local NewComment; + :local AccessList ([ /caps-man/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + :set NewComment [ /caps-man/access-list/get $AccessList comment ]; + } + :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ + $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; + /ip/dhcp-server/lease/set comment=$NewComment $Lease; + } +} diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index 3f4d6c5..2da00ca 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -1,30 +1,3 @@ #!rsc by RouterOS -# RouterOS script: dhcp-lease-comment.local -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, order=60 -# -# update dhcp-server lease comment with infos from access-list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md -# -# !! Do not edit this file, it is generated from template! - -:local 0 "dhcp-lease-comment.local"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; - -:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local NewComment; - :local AccessList ([ /interface/wireless/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - :set NewComment [ /interface/wireless/access-list/get $AccessList comment ]; - } - :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; - /ip/dhcp-server/lease/set comment=$NewComment $Lease; - } -} +# dummy for migration diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc new file mode 100644 index 0000000..3f4d6c5 --- /dev/null +++ b/dhcp-lease-comment.local.rsc @@ -0,0 +1,30 @@ +#!rsc by RouterOS +# RouterOS script: dhcp-lease-comment.local +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=60 +# +# update dhcp-server lease comment with infos from access-list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "dhcp-lease-comment.local"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global LogPrintExit2; + +:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + :local NewComment; + :local AccessList ([ /interface/wireless/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + :set NewComment [ /interface/wireless/access-list/get $AccessList comment ]; + } + :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ + $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; + /ip/dhcp-server/lease/set comment=$NewComment $Lease; + } +} diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template.rsc similarity index 100% rename from dhcp-lease-comment.template rename to dhcp-lease-comment.template.rsc diff --git a/dhcp-to-dns b/dhcp-to-dns index 48f96b2..2da00ca 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -1,97 +1,3 @@ #!rsc by RouterOS -# RouterOS script: dhcp-to-dns -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, order=20 -# -# check DHCP leases and add/remove/update DNS entries -# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md - -:local 0 "dhcp-to-dns"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Domain; -:global HostNameInZone; -:global Identity; -:global PrefixInZone; -:global ServerNameInZone; - -:global CharacterReplace; -:global IfThenElse; -:global LogPrintExit2; -:global ScriptLock; - -$ScriptLock $0 false 10; - -:local Zone \ - ([ $IfThenElse ($PrefixInZone = true) "dhcp." ] . \ - [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); -:local Ttl 5m; -:local CommentPrefix ("managed by " . $0 . " for "); -:local CommentString ("--- " . $0 . " above ---"); - -:if ([ :len [ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ - /ip/dns/static/add comment=$CommentString name=- type=NXDOMAIN disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false; -} -:local PlaceBefore ([ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0); - -:foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={ - :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; - :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; - :if ([ :len [ /ip/dhcp-server/lease/find where mac-address=$MacAddress address=($DnsRecordVal->"address") status=bound ] ] > 0) do={ - $LogPrintExit2 debug $0 ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; - } else={ - :local Found false; - $LogPrintExit2 info $0 ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry.") false; - /ip/dns/static/remove $DnsRecord; - } -} - -:foreach Lease in=[ /ip/dhcp-server/lease/find where status=bound ] do={ - :local LeaseVal; - :do { - :set LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - } on-error={ - $LogPrintExit2 debug $0 ("A lease just vanished, ignoring.") false; - } - - :if ([ :len ($LeaseVal->"address") ] > 0) do={ - :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); - :local HostName [ $IfThenElse ([ :len ($LeaseVal->"host-name") ] = 0) \ - [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ] \ - [ $CharacterReplace ($LeaseVal->"host-name") " " "" ] ]; - - :local Fqdn ($HostName . "." . [ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); - :local DnsRecord [ /ip/dns/static/find where name=$Fqdn ]; - :if ([ :len $DnsRecord ] > 0) do={ - :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; - - :local DupMacLeases [ /ip/dhcp-server/lease/find where mac-address=($LeaseVal->"mac-address") status=bound ]; - :if ([ :len $DupMacLeases ] > 1) do={ - :set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; - } - - :if ([ :len ($LeaseVal->"host-name") ] > 0) do={ - :local HostNameLeases [ /ip/dhcp-server/lease/find where host-name=($LeaseVal->"host-name") status=bound ]; - :if ([ :len $HostNameLeases ] > 1) do={ - :set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($HostNameLeases->0) address ]; - } - } - - :if ($DnsIp = $LeaseVal->"address") do={ - $LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false; - } else={ - $LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . ".") false; - /ip/dns/static/set name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; - } - } else={ - $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false; - /ip/dns/static/add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; - } - } else={ - $LogPrintExit2 debug $0 ("No address available... Ignoring.") false; - } -} +# dummy for migration diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc new file mode 100644 index 0000000..48f96b2 --- /dev/null +++ b/dhcp-to-dns.rsc @@ -0,0 +1,97 @@ +#!rsc by RouterOS +# RouterOS script: dhcp-to-dns +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=20 +# +# check DHCP leases and add/remove/update DNS entries +# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md + +:local 0 "dhcp-to-dns"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Domain; +:global HostNameInZone; +:global Identity; +:global PrefixInZone; +:global ServerNameInZone; + +:global CharacterReplace; +:global IfThenElse; +:global LogPrintExit2; +:global ScriptLock; + +$ScriptLock $0 false 10; + +:local Zone \ + ([ $IfThenElse ($PrefixInZone = true) "dhcp." ] . \ + [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); +:local Ttl 5m; +:local CommentPrefix ("managed by " . $0 . " for "); +:local CommentString ("--- " . $0 . " above ---"); + +:if ([ :len [ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ + /ip/dns/static/add comment=$CommentString name=- type=NXDOMAIN disabled=yes; + $LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false; +} +:local PlaceBefore ([ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0); + +:foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={ + :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; + :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; + :if ([ :len [ /ip/dhcp-server/lease/find where mac-address=$MacAddress address=($DnsRecordVal->"address") status=bound ] ] > 0) do={ + $LogPrintExit2 debug $0 ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; + } else={ + :local Found false; + $LogPrintExit2 info $0 ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry.") false; + /ip/dns/static/remove $DnsRecord; + } +} + +:foreach Lease in=[ /ip/dhcp-server/lease/find where status=bound ] do={ + :local LeaseVal; + :do { + :set LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + } on-error={ + $LogPrintExit2 debug $0 ("A lease just vanished, ignoring.") false; + } + + :if ([ :len ($LeaseVal->"address") ] > 0) do={ + :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); + :local HostName [ $IfThenElse ([ :len ($LeaseVal->"host-name") ] = 0) \ + [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ] \ + [ $CharacterReplace ($LeaseVal->"host-name") " " "" ] ]; + + :local Fqdn ($HostName . "." . [ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); + :local DnsRecord [ /ip/dns/static/find where name=$Fqdn ]; + :if ([ :len $DnsRecord ] > 0) do={ + :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; + + :local DupMacLeases [ /ip/dhcp-server/lease/find where mac-address=($LeaseVal->"mac-address") status=bound ]; + :if ([ :len $DupMacLeases ] > 1) do={ + :set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; + } + + :if ([ :len ($LeaseVal->"host-name") ] > 0) do={ + :local HostNameLeases [ /ip/dhcp-server/lease/find where host-name=($LeaseVal->"host-name") status=bound ]; + :if ([ :len $HostNameLeases ] > 1) do={ + :set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($HostNameLeases->0) address ]; + } + } + + :if ($DnsIp = $LeaseVal->"address") do={ + $LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false; + } else={ + $LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . ".") false; + /ip/dns/static/set name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; + } + } else={ + $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false; + /ip/dns/static/add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + } + } else={ + $LogPrintExit2 debug $0 ("No address available... Ignoring.") false; + } +} diff --git a/doc/mod/scriptrunonce.md b/doc/mod/scriptrunonce.md index 5472bef..20760fb 100644 --- a/doc/mod/scriptrunonce.md +++ b/doc/mod/scriptrunonce.md @@ -28,8 +28,8 @@ The optional configuration goes to `global-config-overlay`. * `ScriptRunOnceUrlSuffix`: url suffix, appended to parameter If the parameter passed to the function is not a complete URL (starting -with protocol `ftp://`, `http://`, `https://` or `sftp://`) the values are -prepended and appended. +with protocol `ftp://`, `http://`, `https://` or `sftp://`) the base-url is +prepended, and file extension `.rsc` and url-suffix are appended. Usage and invocation -------------------- diff --git a/firmware-upgrade-reboot b/firmware-upgrade-reboot index cc45c38..2da00ca 100644 --- a/firmware-upgrade-reboot +++ b/firmware-upgrade-reboot @@ -1,42 +1,3 @@ #!rsc by RouterOS -# RouterOS script: firmware-upgrade-reboot -# Copyright (c) 2022-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# install firmware upgrade, and reboot -# https://git.eworm.de/cgit/routeros-scripts/about/doc/firmware-upgrade-reboot.md - -:local 0 "firmware-upgrade-reboot"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; -:global VersionToNum; - -:local RouterBoard [ /system/routerboard/get ]; -:if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ - $LogPrintExit2 info $0 ("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={ - $LogPrintExit2 info $0 ("Firmware version " . $RouterBoard->"upgrade-firmware" . \ - " is available, upgrading.") false; - /system/routerboard/upgrade; -} - -:while ([ :len [ /log/find where topics=({"system";"info";"critical"}) \ - message="Firmware upgraded successfully, please reboot for changes to take effect!" ] ] = 0) do={ - :delay 1s; -} - -:local Uptime [ /system/resource/get uptime ]; -:if ($Uptime < 1m) do={ - :delay $Uptime; -} - -$LogPrintExit2 info $0 ("Firmware upgrade successful, rebooting.") false; -/system/reboot; +# dummy for migration diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc new file mode 100644 index 0000000..cc45c38 --- /dev/null +++ b/firmware-upgrade-reboot.rsc @@ -0,0 +1,42 @@ +#!rsc by RouterOS +# RouterOS script: firmware-upgrade-reboot +# Copyright (c) 2022-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# install firmware upgrade, and reboot +# https://git.eworm.de/cgit/routeros-scripts/about/doc/firmware-upgrade-reboot.md + +:local 0 "firmware-upgrade-reboot"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global LogPrintExit2; +:global VersionToNum; + +:local RouterBoard [ /system/routerboard/get ]; +:if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ + $LogPrintExit2 info $0 ("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={ + $LogPrintExit2 info $0 ("Firmware version " . $RouterBoard->"upgrade-firmware" . \ + " is available, upgrading.") false; + /system/routerboard/upgrade; +} + +:while ([ :len [ /log/find where topics=({"system";"info";"critical"}) \ + message="Firmware upgraded successfully, please reboot for changes to take effect!" ] ] = 0) do={ + :delay 1s; +} + +:local Uptime [ /system/resource/get uptime ]; +:if ($Uptime < 1m) do={ + :delay $Uptime; +} + +$LogPrintExit2 info $0 ("Firmware upgrade successful, rebooting.") false; +/system/reboot; diff --git a/global-config b/global-config index 770efd0..2da00ca 100644 --- a/global-config +++ b/global-config @@ -1,220 +1,3 @@ #!rsc by RouterOS -# RouterOS script: global-config -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# global configuration -# https://git.eworm.de/cgit/routeros-scripts/about/ - -# Set this to 'true' to disable news and change notifications. -:global NoNewsAndChangesNotification false; - -# Add extra text (or emojis) in notification tags. -:global IdentityExtra ""; - -# This is used for DNS and backup file. -:global Domain "example.com"; -:global HostNameInZone true; -:global PrefixInZone true; -:global ServerNameInZone false; - -# You can send e-mail notifications. Configure the system's mail settings -# (/tool/e-mail), then install the module: -# $ScriptInstallUpdate mod/notification-email -# The to-address needs to be filled; cc-address can be empty, one address -# or a comma separated list of addresses. -:global EmailGeneralTo ""; -:global EmailGeneralCc ""; -#:global EmailGeneralTo "mail@example.com"; -#:global EmailGeneralCc "another@example.com,third@example.com"; - -# You can send Telegram notifications. Register a bot -# and add the token and chat ids here, then install the module: -# $ScriptInstallUpdate mod/notification-telegram -:global TelegramTokenId ""; -:global TelegramChatId ""; -#:global TelegramTokenId "123456:ABCDEF-GHI"; -#:global TelegramChatId "12345678"; -# Using telegram-chat you have to define trusted chat ids (not group ids!) -# or user names. Groups allow to chat with devices simultaneously. -#:global TelegramChatIdsTrusted { -# "12345678"; -# "example_user"; -#}; -:global TelegramChatGroups "(all)"; -#:global TelegramChatGroups "(all|home|office)"; -# This is whether or not to send Telegram messages with fixed-width font. -:global TelegramFixedWidthFont true; - -# You can send Matrix notifications. Configure these settings and -# install the module: -# $ScriptInstallUpdate mod/notification-matrix -:global MatrixHomeServer ""; -:global MatrixAccessToken ""; -:global MatrixRoom ""; -#:global MatrixHomeServer "matrix.org"; -#:global MatrixAccessToken "123456ABCDEFGHI..."; -#:global MatrixRoom "!example:matrix.org"; - -# It is possible to override e-mail, Telegram and Matrix setting for every -# script. This is done in arrays, where 'Override' is appended to the -# variable name, like this: -#:global EmailGeneralToOverride { -# "check-certificates"="override@example.com"; -# "backup-email"="backup@example.com"; -#} - -# Toggle this to disable symbols in notifications. -:global NotificationsWithSymbols true; -# Toggle this to disable color output in terminal/cli. -:global TerminalColorOutput true; - -# This defines what backups to generate and what password to use. -:global BackupSendBinary false; -:global BackupSendExport true; -:global BackupSendGlobalConfig true; -:global BackupPassword "v3ry-s3cr3t"; -:global BackupRandomDelay 0; -# These credentials are used to upload backup and config export files. -# SFTP authentication is tricky, you may have to limit authentication -# methods for your SSH server. -:global BackupUploadUrl "sftp://example.com/backup/"; -:global BackupUploadUser "mikrotik"; -:global BackupUploadPass "v3ry-s3cr3t"; - -# This defines what log messages to filter or include by topic or message -# text. Regular expressions are supported. Do *NOT* set an empty string, -# that will filter or include everything! -# These are filters, so excluding messages from forwarding. -:global LogForwardFilter "(debug|info)"; -:global LogForwardFilterMessage []; -#:global LogForwardFilterMessage "message text"; -#:global LogForwardFilterMessage "(message text|another text|...)"; -# ... and another setting with reverse logic. This includes messages even -# if filtered above. -:global LogForwardInclude []; -:global LogForwardIncludeMessage []; -#:global LogForwardInclude "account"; -#:global LogForwardIncludeMessage "message text"; - -# Specify an address to enable auto update to version assumed safe. -# The configured channel (bugfix, current, release-candidate) is appended. -:global SafeUpdateUrl ""; -#:global SafeUpdateUrl "https://example.com/ros/safe-update/"; -# Allow to install patch updates automatically. -:global SafeUpdatePatch false; -# Allow to install updates automatically if seen in neighbor list. -:global SafeUpdateNeighbor false; -# Install *ALL* updates automatically! -# Set to all upper-case "Yes, please!" to enable. -:global SafeUpdateAll "no"; - -# These thresholds control when to send health notification -# on temperature and voltage. -:global CheckHealthTemperature { - temperature=50; - cpu-temperature=70; - board-temperature1=50; - board-temperature2=50; -} -# This is deviation on recovery threshold against notification flooding. -:global CheckHealthTemperatureDeviation 3; -:global CheckHealthVoltageLow 115; -:global CheckHealthVoltagePercent 10; - -# Access-list entries matching this comment are updated -# with daily pseudo-random PSK. -:global DailyPskMatchComment "Daily PSK"; -:global DailyPskQrCodeUrl "https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi"; -:global DailyPskSecrets { - { "Abusive"; "Aggressive"; "Bored"; "Chemical"; "Cold"; - "Cruel"; "Curved"; "Delightful"; "Discreet"; "Elite"; - "Evasive"; "Faded"; "Flat"; "Future"; "Grandiose"; - "Hanging"; "Humorous"; "Interesting"; "Magenta"; - "Magnificent"; "Numerous"; "Optimal"; "Pathetic"; - "Possessive"; "Remarkable"; "Rightful"; "Ruthless"; - "Stale"; "Unusual"; "Useless"; "Various" }; - { "Adhesive"; "Amusing"; "Astonishing"; "Frantic"; - "Kindhearted"; "Limping"; "Roasted"; "Robust"; - "Staking"; "Thundering"; "Ultra"; "Unreal" }; - { "Belief"; "Button"; "Curtain"; "Edge"; "Jewel"; - "String"; "Whistle" } -} - -# Run different commands with multiple mode-button presses. -:global ModeButton { - 1="/system/script/run leds-toggle-mode;"; - 2=":global Identity; :global SendNotification; :global SymbolForNotification; \$SendNotification ([ \$SymbolForNotification \"earth\" ] . \"Hello...\") (\"Hello world, \" . \$Identity . \" calling!\");"; - 3="/system/shutdown;"; - 4="/system/reboot;"; - 5=":global BridgePortVlan; \$BridgePortVlan alt;"; -# add more here... -}; -# This led gives visual feedback if type is 'on' or 'off'. -:global ModeButtonLED "user-led"; - -# Run commands on SMS action. -:global SmsAction { - bridge-port-vlan-alt=":global BridgePortVlan; \$BridgePortVlan alt;"; - reboot="/system/reboot;"; - shutdown="/system/shutdown;"; -# add more here... -}; - -# Run commands by hooking into SMS forward. -:global SmsForwardHooks { - { match="magic string"; - allowed-number="12345678"; - command="/system/script/run ..." }; -# add more here... -}; - -# This is the address used to send gps data to. -:global GpsTrackUrl "https://example.com/index.php"; - -# Enable this to fetch scripts from given url. -:global ScriptUpdatesFetch true; -:global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/"; -# alternative urls - main: stable code - next: currently in development -#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/main/"; -#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/next/"; -#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/main/"; -#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/next/"; -:global ScriptUpdatesUrlSuffix ""; -# use next branch with default url (git.eworm.de) -#:global ScriptUpdatesUrlSuffix "\?h=next"; - -# Use this for defaults with $ScriptRunOnce -# Install module with: -# $ScriptInstallUpdate mod/scriptrunonce -:global ScriptRunOnceBaseUrl ""; -:global ScriptRunOnceUrlSuffix ""; - -# This project is developed in private spare time and usage is free of charge -# for you. If you like the scripts and think this is of value for you or your -# business please consider a donation: -# https://git.eworm.de/cgit/routeros-scripts/about/#donate -# Enable this to silence donation hint. -:global IDonate false; - -# Use this for certificate auto-renew -:global CertRenewUrl ""; -#:global CertRenewUrl "https://example.com/certificates/"; -:global CertRenewTime 3w; -:global CertRenewPass { - "v3ry-s3cr3t"; - "4n0th3r-s3cr3t"; -} -:global CertWarnTime 2w; -:global CertIssuedExportPass { - "cert1-cn"="v3ry-s3cr3t"; - "cert2-cn"="4n0th3r-s3cr3t"; -} - -# load custom settings from overlay -# Warning: Do *NOT* copy this code to overlay! -:do { - /system/script/run global-config-overlay; -} on-error={ - :log error ("Loading configuration from overlay failed!"); -} +# dummy for migration diff --git a/global-config-overlay b/global-config-overlay.rsc similarity index 100% rename from global-config-overlay rename to global-config-overlay.rsc diff --git a/global-config.changes b/global-config.changes index 3e0372a..be34365 100644 --- a/global-config.changes +++ b/global-config.changes @@ -103,6 +103,7 @@ 92="Made qr-code url configurable for 'daily-psk'."; 93="Added support to backup global-config-overlay in 'backup-email' and 'backup-upload'."; 94="Added support for host addresses in address-list for 'ipv6-update'."; + 95="Renamed script files in repository, running migration. No user interaction is required."; }; # Migration steps to be applied on script updates @@ -118,4 +119,5 @@ 81=":global NtpPool; :if ([ :len [ /system/script/find where name=\"rotate-ntp\" ] ] > 0) do={ /system/script/remove [ find where name=\"rotate-ntp\" ]; /system/scheduler/remove [ find where name=\"rotate-ntp\" ]; /system/ntp/client/set servers=\$NtpPool; };"; 82=":global CharacterReplace; :foreach Netwatch in=[ /tool/netwatch/find where comment~\"notify\" !disabled ] do={ /tool/netwatch/set \$Netwatch comment=[ \$CharacterReplace [ get \$Netwatch comment ] \"hostname=\" \"name=\" ]; };"; 84=":global ScriptInstallUpdate; :global EmailGeneralTo; :if ([ /tool/e-mail/get address ] != \"0.0.0.0\" && [ :len \$EmailGeneralTo ] > 0) do={ \$ScriptInstallUpdate mod/notification-email; }"; + 95=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Script in=[ /system/script/find where name~\"\\\\.rsc\\\$\" source~\"^#!rsc by RouterOS\\n\" ] do={ /system/script/set \$Script name=[ \$CharacterReplace [ get \$Script name ] \".rsc\" \"\" ]; }; \$ScriptInstallUpdate;"; }; diff --git a/global-config.rsc b/global-config.rsc new file mode 100644 index 0000000..770efd0 --- /dev/null +++ b/global-config.rsc @@ -0,0 +1,220 @@ +#!rsc by RouterOS +# RouterOS script: global-config +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# global configuration +# https://git.eworm.de/cgit/routeros-scripts/about/ + +# Set this to 'true' to disable news and change notifications. +:global NoNewsAndChangesNotification false; + +# Add extra text (or emojis) in notification tags. +:global IdentityExtra ""; + +# This is used for DNS and backup file. +:global Domain "example.com"; +:global HostNameInZone true; +:global PrefixInZone true; +:global ServerNameInZone false; + +# You can send e-mail notifications. Configure the system's mail settings +# (/tool/e-mail), then install the module: +# $ScriptInstallUpdate mod/notification-email +# The to-address needs to be filled; cc-address can be empty, one address +# or a comma separated list of addresses. +:global EmailGeneralTo ""; +:global EmailGeneralCc ""; +#:global EmailGeneralTo "mail@example.com"; +#:global EmailGeneralCc "another@example.com,third@example.com"; + +# You can send Telegram notifications. Register a bot +# and add the token and chat ids here, then install the module: +# $ScriptInstallUpdate mod/notification-telegram +:global TelegramTokenId ""; +:global TelegramChatId ""; +#:global TelegramTokenId "123456:ABCDEF-GHI"; +#:global TelegramChatId "12345678"; +# Using telegram-chat you have to define trusted chat ids (not group ids!) +# or user names. Groups allow to chat with devices simultaneously. +#:global TelegramChatIdsTrusted { +# "12345678"; +# "example_user"; +#}; +:global TelegramChatGroups "(all)"; +#:global TelegramChatGroups "(all|home|office)"; +# This is whether or not to send Telegram messages with fixed-width font. +:global TelegramFixedWidthFont true; + +# You can send Matrix notifications. Configure these settings and +# install the module: +# $ScriptInstallUpdate mod/notification-matrix +:global MatrixHomeServer ""; +:global MatrixAccessToken ""; +:global MatrixRoom ""; +#:global MatrixHomeServer "matrix.org"; +#:global MatrixAccessToken "123456ABCDEFGHI..."; +#:global MatrixRoom "!example:matrix.org"; + +# It is possible to override e-mail, Telegram and Matrix setting for every +# script. This is done in arrays, where 'Override' is appended to the +# variable name, like this: +#:global EmailGeneralToOverride { +# "check-certificates"="override@example.com"; +# "backup-email"="backup@example.com"; +#} + +# Toggle this to disable symbols in notifications. +:global NotificationsWithSymbols true; +# Toggle this to disable color output in terminal/cli. +:global TerminalColorOutput true; + +# This defines what backups to generate and what password to use. +:global BackupSendBinary false; +:global BackupSendExport true; +:global BackupSendGlobalConfig true; +:global BackupPassword "v3ry-s3cr3t"; +:global BackupRandomDelay 0; +# These credentials are used to upload backup and config export files. +# SFTP authentication is tricky, you may have to limit authentication +# methods for your SSH server. +:global BackupUploadUrl "sftp://example.com/backup/"; +:global BackupUploadUser "mikrotik"; +:global BackupUploadPass "v3ry-s3cr3t"; + +# This defines what log messages to filter or include by topic or message +# text. Regular expressions are supported. Do *NOT* set an empty string, +# that will filter or include everything! +# These are filters, so excluding messages from forwarding. +:global LogForwardFilter "(debug|info)"; +:global LogForwardFilterMessage []; +#:global LogForwardFilterMessage "message text"; +#:global LogForwardFilterMessage "(message text|another text|...)"; +# ... and another setting with reverse logic. This includes messages even +# if filtered above. +:global LogForwardInclude []; +:global LogForwardIncludeMessage []; +#:global LogForwardInclude "account"; +#:global LogForwardIncludeMessage "message text"; + +# Specify an address to enable auto update to version assumed safe. +# The configured channel (bugfix, current, release-candidate) is appended. +:global SafeUpdateUrl ""; +#:global SafeUpdateUrl "https://example.com/ros/safe-update/"; +# Allow to install patch updates automatically. +:global SafeUpdatePatch false; +# Allow to install updates automatically if seen in neighbor list. +:global SafeUpdateNeighbor false; +# Install *ALL* updates automatically! +# Set to all upper-case "Yes, please!" to enable. +:global SafeUpdateAll "no"; + +# These thresholds control when to send health notification +# on temperature and voltage. +:global CheckHealthTemperature { + temperature=50; + cpu-temperature=70; + board-temperature1=50; + board-temperature2=50; +} +# This is deviation on recovery threshold against notification flooding. +:global CheckHealthTemperatureDeviation 3; +:global CheckHealthVoltageLow 115; +:global CheckHealthVoltagePercent 10; + +# Access-list entries matching this comment are updated +# with daily pseudo-random PSK. +:global DailyPskMatchComment "Daily PSK"; +:global DailyPskQrCodeUrl "https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi"; +:global DailyPskSecrets { + { "Abusive"; "Aggressive"; "Bored"; "Chemical"; "Cold"; + "Cruel"; "Curved"; "Delightful"; "Discreet"; "Elite"; + "Evasive"; "Faded"; "Flat"; "Future"; "Grandiose"; + "Hanging"; "Humorous"; "Interesting"; "Magenta"; + "Magnificent"; "Numerous"; "Optimal"; "Pathetic"; + "Possessive"; "Remarkable"; "Rightful"; "Ruthless"; + "Stale"; "Unusual"; "Useless"; "Various" }; + { "Adhesive"; "Amusing"; "Astonishing"; "Frantic"; + "Kindhearted"; "Limping"; "Roasted"; "Robust"; + "Staking"; "Thundering"; "Ultra"; "Unreal" }; + { "Belief"; "Button"; "Curtain"; "Edge"; "Jewel"; + "String"; "Whistle" } +} + +# Run different commands with multiple mode-button presses. +:global ModeButton { + 1="/system/script/run leds-toggle-mode;"; + 2=":global Identity; :global SendNotification; :global SymbolForNotification; \$SendNotification ([ \$SymbolForNotification \"earth\" ] . \"Hello...\") (\"Hello world, \" . \$Identity . \" calling!\");"; + 3="/system/shutdown;"; + 4="/system/reboot;"; + 5=":global BridgePortVlan; \$BridgePortVlan alt;"; +# add more here... +}; +# This led gives visual feedback if type is 'on' or 'off'. +:global ModeButtonLED "user-led"; + +# Run commands on SMS action. +:global SmsAction { + bridge-port-vlan-alt=":global BridgePortVlan; \$BridgePortVlan alt;"; + reboot="/system/reboot;"; + shutdown="/system/shutdown;"; +# add more here... +}; + +# Run commands by hooking into SMS forward. +:global SmsForwardHooks { + { match="magic string"; + allowed-number="12345678"; + command="/system/script/run ..." }; +# add more here... +}; + +# This is the address used to send gps data to. +:global GpsTrackUrl "https://example.com/index.php"; + +# Enable this to fetch scripts from given url. +:global ScriptUpdatesFetch true; +:global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/"; +# alternative urls - main: stable code - next: currently in development +#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/main/"; +#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/next/"; +#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/main/"; +#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/next/"; +:global ScriptUpdatesUrlSuffix ""; +# use next branch with default url (git.eworm.de) +#:global ScriptUpdatesUrlSuffix "\?h=next"; + +# Use this for defaults with $ScriptRunOnce +# Install module with: +# $ScriptInstallUpdate mod/scriptrunonce +:global ScriptRunOnceBaseUrl ""; +:global ScriptRunOnceUrlSuffix ""; + +# This project is developed in private spare time and usage is free of charge +# for you. If you like the scripts and think this is of value for you or your +# business please consider a donation: +# https://git.eworm.de/cgit/routeros-scripts/about/#donate +# Enable this to silence donation hint. +:global IDonate false; + +# Use this for certificate auto-renew +:global CertRenewUrl ""; +#:global CertRenewUrl "https://example.com/certificates/"; +:global CertRenewTime 3w; +:global CertRenewPass { + "v3ry-s3cr3t"; + "4n0th3r-s3cr3t"; +} +:global CertWarnTime 2w; +:global CertIssuedExportPass { + "cert1-cn"="v3ry-s3cr3t"; + "cert2-cn"="4n0th3r-s3cr3t"; +} + +# load custom settings from overlay +# Warning: Do *NOT* copy this code to overlay! +:do { + /system/script/run global-config-overlay; +} on-error={ + :log error ("Loading configuration from overlay failed!"); +} diff --git a/global-functions b/global-functions index 996a6e1..366ef94 100644 --- a/global-functions +++ b/global-functions @@ -6,708 +6,27 @@ # # requires RouterOS, version=7.7 # -# global functions -# https://git.eworm.de/cgit/routeros-scripts/about/ - -:local 0 "global-functions"; +# WARNING: If you find this stripped version of global-functions +# on your Router something went wrong and migration failed. To +# recover run this function: $RouterOSScriptsRecover # expected configuration version -:global ExpectedConfigVersion 94; - -# global variables not to be changed by user -:global GlobalFunctionsReady false; -:global Identity [ /system/identity/get name ]; +:global ExpectedConfigVersion 95; # global functions -:global CertificateAvailable; -:global CertificateDownload; -:global CertificateNameByCN; -:global CharacterReplace; -:global CleanFilePath; -:global DeviceInfo; -:global Dos2Unix; -:global DownloadPackage; -:global EitherOr; -:global EscapeForRegEx; -:global GetMacVendor; -:global GetRandom20CharAlNum; -:global GetRandom20CharHex; -:global GetRandomNumber; -:global Grep; -:global HexToNum; -:global IfThenElse; -:global IsDefaultRouteReachable; -:global IsDNSResolving; -:global IsFullyConnected; -:global IsMacLocallyAdministered; -:global IsTimeSync; -:global LogPrintExit2; -:global MkDir; -:global NotificationFunctions; -:global ParseKeyValueStore; -:global PrettyPrint; -:global RandomDelay; -:global Read; -:global RequiredRouterOS; -:global ScriptFromTerminal; +:global RouterOSScriptsRecover; :global ScriptInstallUpdate; -:global ScriptLock; -:global SendNotification; -:global SendNotification2; -:global SymbolByUnicodeName; -:global SymbolForNotification; -:global Unix2Dos; -:global UrlEncode; -:global ValidateSyntax; -:global VersionToNum; -:global WaitDefaultRouteReachable; -:global WaitDNSResolving; -:global WaitForFile; -:global WaitFullyConnected; -:global WaitTimeSync; -# check and download required certificate -:set CertificateAvailable do={ - :local CommonName [ :tostr $1 ]; +# recover from failed migration +:set RouterOSScriptsRecover do={ + :global ScriptInstallUpdate; - :global CertificateDownload; - :global LogPrintExit2; - :global ParseKeyValueStore; - - :if ([ /system/resource/get free-hdd-space ] < 8388608 && \ - [ /certificate/settings/get crl-download ] = true && \ - [ /certificate/settings/get crl-store ] = "system") do={ - $LogPrintExit2 warning $0 ("This system has low free flash space but " . \ - "is configured to download certificate CRLs to system!") false; + :foreach Script in={ "global-config"; "global-functions" } do={ + /system/script/set name=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . ".rsc") output=user as-value]->"data"); + /system/script/run $Script; } - :if ([ :len [ /certificate/find where common-name=$CommonName ] ] = 0) do={ - $LogPrintExit2 info $0 ("Certificate with CommonName \"" . $CommonName . "\" not available.") false; - :if ([ $CertificateDownload $CommonName ] = false) do={ - :return false; - } - } - - :local CertVal [ /certificate/get [ find where common-name=$CommonName ] ]; - :while (($CertVal->"akid") != "" && ($CertVal->"akid") != ($CertVal->"skid")) do={ - :if ([ :len [ /certificate/find where skid=($CertVal->"akid") ] ] = 0) do={ - $LogPrintExit2 info $0 ("Certificate chain for \"" . $CommonName . \ - "\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\".") false; - :if ([ $CertificateDownload $CommonName ] = false) do={ - :return false; - } - } - :set CertVal [ /certificate/get [ find where skid=($CertVal->"akid") ] ]; - } - :return true; -} - -# download and import certificate -:set CertificateDownload do={ - :local CommonName [ :tostr $1 ]; - - :global ScriptUpdatesBaseUrl; - :global ScriptUpdatesUrlSuffix; - - :global CertificateNameByCN; - :global LogPrintExit2; - :global UrlEncode; - :global WaitForFile; - - $LogPrintExit2 info $0 ("Downloading and importing certificate with " . \ - "CommonName \"" . $CommonName . "\".") false; - :do { - :local LocalFileName ($CommonName . ".pem"); - :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); - /tool/fetch check-certificate=yes-without-crl \ - ($ScriptUpdatesBaseUrl . "certs/" . \ - $UrlFileName . $ScriptUpdatesUrlSuffix) \ - dst-path=$LocalFileName as-value; - $WaitForFile $LocalFileName; - /certificate/import file-name=$LocalFileName passphrase="" as-value; - /file/remove $LocalFileName; - - :foreach Cert in=[ /certificate/find where name~("^" . $LocalFileName . "_[0-9]+\$") ] do={ - $CertificateNameByCN [ /certificate/get $Cert common-name ]; - } - } on-error={ - $LogPrintExit2 warning $0 ("Failed importing certificate with " . \ - "CommonName \"" . $CommonName . "\"!") false; - :return false; - } - :return true; -} - -# name a certificate by its common-name -:set CertificateNameByCN do={ - :local CommonName [ :tostr $1 ]; - - :global CharacterReplace; - - :local Cert [ /certificate/find where common-name=$CommonName ]; - /certificate/set $Cert \ - name=[ $CharacterReplace [ $CharacterReplace [ $CharacterReplace $CommonName "'" "-" ] " " "-" ] "---" "-" ]; -} - -# character replace -:set CharacterReplace do={ - :local String [ :tostr $1 ]; - :local ReplaceFrom [ :tostr $2 ]; - :local ReplaceWith [ :tostr $3 ]; - :local Return ""; - - :if ($ReplaceFrom = "") do={ - :return $String; - } - - :while ([ :typeof [ :find $String $ReplaceFrom ] ] != "nil") do={ - :local Pos [ :find $String $ReplaceFrom ]; - :set Return ($Return . [ :pick $String 0 $Pos ] . $ReplaceWith); - :set String [ :pick $String ($Pos + [ :len $ReplaceFrom ]) [ :len $String ] ]; - } - - :return ($Return . $String); -} - -# clean file path -:set CleanFilePath do={ - :local Path [ :tostr $1 ]; - - :global CharacterReplace; - - :while ($Path ~ "//") do={ - :set $Path [ $CharacterReplace $Path "//" "/" ]; - } - :if ([ :pick $Path 0 ] = "/") do={ - :set Path [ :pick $Path 1 [ :len $Path ] ]; - } - :if ([ :pick $Path ([ :len $Path ] - 1) ] = "/") do={ - :set Path [ :pick $Path 0 ([ :len $Path ] - 1) ]; - } - - :return $Path; -} - -# get readable device info -:set DeviceInfo do={ - :global ExpectedConfigVersion; - :global Identity; - - :global IfThenElse; - - :local Resource [ /system/resource/get ]; - :local RouterBoard; - :do { - :set RouterBoard [[ :parse "/system/routerboard/get" ]]; - } on-error={ } - :local License [ /system/license/get ]; - :local Update [ /system/package/update/get ]; - - :return ( \ - "Hostname: " . $Identity . \ - "\nBoard name: " . $Resource->"board-name" . \ - "\nArchitecture: " . $Resource->"architecture-name" . \ - [ $IfThenElse ($RouterBoard->"routerboard" = true) \ - ("\nModel: " . $RouterBoard->"model" . \ - [ $IfThenElse ([ :len ($RouterBoard->"revision") ] > 0) \ - (" " . $RouterBoard->"revision") ] . \ - "\nSerial number: " . $RouterBoard->"serial-number") ] . \ - [ $IfThenElse ([ :len ($License->"level") ] > 0) \ - ("\nLicense: " . $License->"level") ] . \ - "\nRouterOS:" . \ - "\n Channel: " . $Update->"channel" . \ - "\n Installed: " . $Update->"installed-version" . \ - [ $IfThenElse ([ :typeof ($Update->"latest-version") ] != "nothing" && \ - $Update->"installed-version" != $Update->"latest-version") \ - ("\n Available: " . $Update->"latest-version") ] . \ - [ $IfThenElse ($RouterBoard->"routerboard" = true && \ - $RouterBoard->"current-firmware" != $RouterBoard->"upgrade-firmware") \ - ("\n Firmware: " . $RouterBoard->"current-firmware") ] . \ - "\nRouterOS-Scripts:" . \ - "\n Version: " . $ExpectedConfigVersion); -} - -# convert line endings, DOS -> UNIX -:set Dos2Unix do={ - :local Input [ :tostr $1 ]; - - :global CharacterReplace; - - :return [ $CharacterReplace $Input ("\r\n") ("\n") ]; -} - -# download package from upgrade server -:set DownloadPackage do={ - :local PkgName [ :tostr $1 ]; - :local PkgVer [ :tostr $2 ]; - :local PkgArch [ :tostr $3 ]; - :local PkgDir [ :tostr $4 ]; - - :global CertificateAvailable; - :global CleanFilePath; - :global LogPrintExit2; - :global MkDir; - :global WaitForFile; - - :if ([ :len $PkgName ] = 0) do={ :return false; } - :if ([ :len $PkgVer ] = 0) do={ :set PkgVer [ /system/package/update/get installed-version ]; } - :if ([ :len $PkgArch ] = 0) do={ :set PkgArch [ /system/resource/get architecture-name ]; } - - :if ($PkgName = "system") do={ :set PkgName "routeros"; } - - :local PkgFile ($PkgName . "-" . $PkgVer . "-" . $PkgArch . ".npk"); - :if ($PkgArch = "x86_64") do={ :set PkgFile ($PkgName . "-" . $PkgVer . ".npk"); } - :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; - - :if ([ $MkDir $PkgDir ] = false) do={ - $LogPrintExit2 warning $0 ("Failed creating directory, not downloading package.") false; - :return false; - } - - :if ([ :len [ /file/find where name=$PkgDest type="package" ] ] > 0) do={ - $LogPrintExit2 info $0 ("Package file " . $PkgName . " already exists.") false; - :return true; - } - - :if ([ $CertificateAvailable "R3" ] = false) do={ - $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; - } - - :local Url ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile); - $LogPrintExit2 info $0 ("Downloading package file '" . $PkgName . "'...") false; - $LogPrintExit2 debug $0 ("... from url: " . $Url) false; - :local Retry 3; - :while ($Retry > 0) do={ - :do { - /tool/fetch check-certificate=yes-without-crl $Url dst-path=$PkgDest; - $WaitForFile $PkgDest; - - :if ([ /file/get [ find where name=$PkgDest ] type ] = "package") do={ - :return true; - } - } on-error={ - $LogPrintExit2 debug $0 ("Downloading package file failed.") false; - } - - /file/remove [ find where name=$PkgDest ]; - :set Retry ($Retry - 1); - } - - $LogPrintExit2 warning $0 ("Downloading package file '" . $PkgName . "' failed.") false; - :return false; -} - -# return either first (if "true") or second -:set EitherOr do={ - :global IfThenElse; - - :if ([ :typeof $1 ] = "num") do={ - :return [ $IfThenElse ($1 != 0) $1 $2 ]; - } - :return [ $IfThenElse ([ :len [ :tostr $1 ] ] > 0) $1 $2 ]; -} - -# escape for regular expression -:set EscapeForRegEx do={ - :local Input [ :tostr $1 ]; - - :if ([ :len $Input ] = 0) do={ - :return ""; - } - - :local Return ""; - :local Chars ("^.[]\$()|*+\?{}\\"); - - :for I from=0 to=([ :len $Input ] - 1) do={ - :local Char [ :pick $Input $I ]; - :if ([ :find $Chars $Char ]) do={ - :set Char ("\\" . $Char); - } - :set Return ($Return . $Char); - } - - :return $Return; -} - -# get MAC vendor -:set GetMacVendor do={ - :local Mac [ :tostr $1 ]; - - :global CertificateAvailable; - :global IsMacLocallyAdministered; - :global LogPrintExit2; - - :if ([ $IsMacLocallyAdministered $Mac ] = true) do={ - :return "locally administered"; - } - - :do { - :if ([ $CertificateAvailable "R3" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; - } - :local Vendor ([ /tool/fetch check-certificate=yes-without-crl \ - ("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data"); - :return $Vendor; - } on-error={ - :do { - /tool/fetch check-certificate=yes-without-crl ("https://api.macvendors.com/") \ - output=none as-value; - $LogPrintExit2 debug $0 ("The mac vendor is not known in database.") false; - } on-error={ - $LogPrintExit2 warning $0 ("Failed getting mac vendor.") false; - } - :return "unknown vendor"; - } -} - -# generate random 20 chars alphabetical (A-Z & a-z) and numerical (0-9) -:set GetRandom20CharAlNum do={ - :global EitherOr; - - :return [ :rndstr length=[ $EitherOr [ :tonum $1 ] 20 ] from="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" ]; -} - -# generate random 20 chars hex (0-9 and a-f) -:set GetRandom20CharHex do={ - :global EitherOr; - - :return [ :rndstr length=[ $EitherOr [ :tonum $1 ] 20 ] from="0123456789abcdef" ]; -} - -# generate random number -:set GetRandomNumber do={ - :global EitherOr; - - :return [ :rndnum from=0 to=[ $EitherOr [ :tonum $1 ] 4294967295 ] ]; -} - -# return first line that matches a pattern -:set Grep do={ - :local Input ([ :tostr $1 ] . "\n"); - :local Pattern [ :tostr $2 ]; - - :if ([ :typeof [ :find $Input $Pattern ] ] = "nil") do={ - :return []; - } - - :do { - :local Line [ :pick $Input 0 [ :find $Input "\n" ] ]; - :if ([ :typeof [ :find $Line $Pattern ] ] = "num") do={ - :return $Line; - } - :set Input [ :pick $Input ([ :find $Input "\n" ] + 1) [ :len $Input ] ]; - } while=([ :len $Input ] > 0); - - :return []; -} - -# convert from hex (string) to num -:set HexToNum do={ - :local Input [ :tostr $1 ]; - :local Hex "0123456789abcdef0123456789ABCDEF"; - :local Multi 1; - :local Return 0; - - :for I from=([ :len $Input ] - 1) to=0 do={ - :set Return ($Return + (([ :find $Hex [ :pick $Input $I ] ] % 16) * $Multi)); - :set Multi ($Multi * 16); - } - - :return $Return; -} - -# mimic conditional/ternary operator (condition ? consequent : alternative) -:set IfThenElse do={ - :if ([ :tostr $1 ] = "true" || [ :tobool $1 ] = true) do={ - :return $2; - } - :return $3; -} - -# check if default route is reachable -:set IsDefaultRouteReachable do={ - :if ([ :len [ /ip/route/find where dst-address=0.0.0.0/0 active routing-table=main ] ] > 0) do={ - :return true; - } - :return false; -} - -# check if DNS is resolving -:set IsDNSResolving do={ - :global CharacterReplace; - - :do { - :resolve "low-ttl.eworm.de"; - } on-error={ - :return false; - } - :return true; -} - -# check if system is is fully connected (default route reachable, DNS resolving, time sync) -:set IsFullyConnected do={ - :global IsDefaultRouteReachable; - :global IsDNSResolving; - :global IsTimeSync; - - :if ([ $IsDefaultRouteReachable ] = false) do={ - :return false; - } - :if ([ $IsDNSResolving ] = false) do={ - :return false; - } - :if ([ $IsTimeSync ] = false) do={ - :return false; - } - :return true; -} - -# check if mac address is locally administered -:set IsMacLocallyAdministered do={ - :if ([ :tonum ("0x" . [ :pick $1 0 [ :find $1 ":" ] ]) ] & 2 = 2) do={ - :return true; - } - :return false; -} - -# check if system time is sync -:set IsTimeSync do={ - :global IsTimeSyncCached; - - :global LogPrintExit2; - - :if ($IsTimeSyncCached = true) do={ - :return true; - } - - :if ([ /system/ntp/client/get enabled ] = true) do={ - :if ([ /system/ntp/client/get status ] = "synchronized") do={ - :set IsTimeSyncCached true; - :return true; - } - :return false; - } - - :if ([ /system/license/get ]->"level" = "free" || \ - [ /system/resource/get ]->"board-name" = "x86") do={ - $LogPrintExit2 debug $0 ("No ntp client configured, relying on RTC for CHR free license and x86.") false; - :return true; - } - - :if ([ /ip/cloud/get update-time ] = true) do={ - :if ([ :typeof [ /ip/cloud/get public-address ] ] = "ip") do={ - :set IsTimeSyncCached true; - :return true; - } - :return false; - } - - $LogPrintExit2 debug $0 ("No time source configured! Returning gracefully...") false; - :return true; -} - -# log and print with same text, optionally exit -:set LogPrintExit2 do={ - :local Severity [ :tostr $1 ]; - :local Name [ :tostr $2 ]; - :local Message [ :tostr $3 ]; - :local Exit [ :tostr $4 ]; - - :global PrintDebug; - :global PrintDebugOverride; - - :global EitherOr; - - :local Debug [ $EitherOr ($PrintDebugOverride->$Name) $PrintDebug ]; - - :local PrintSeverity do={ - :global TerminalColorOutput; - - :if ($TerminalColorOutput != true) do={ - :return $1; - } - - :local Color { debug=96; info=97; warning=93; error=91 }; - :return ("\1B[" . $Color->$1 . "m" . $1 . "\1B[0m"); - } - - :local Log ([ $EitherOr $Name "" ] . ": " . $Message); - :if ($Severity ~ ("^(debug|error|info)\$")) do={ - :if ($Severity = "debug") do={ :log debug $Log; } - :if ($Severity = "error") do={ :log error $Log; } - :if ($Severity = "info" ) do={ :log info $Log; } - } else={ - :log warning $Log; - :set Severity "warning"; - } - - :if ($Severity != "debug" || $Debug = true) do={ - :put ([ $PrintSeverity $Severity ] . ": " . $Message); - } - - :if ($Exit = "true") do={ - :error ("Hard error to exit."); - } -} - -# create directory -:set MkDir do={ - :local Path [ :tostr $1 ]; - - :global CharacterReplace; - :global CleanFilePath; - :global GetRandom20CharAlNum; - :global LogPrintExit2; - :global RequiredRouterOS; - :global WaitForFile; - - :set Path [ $CleanFilePath $Path ]; - - :if ($Path = "") do={ - :return true; - } - - :if ([ :len [ /file/find where name=$Path type="directory" ] ] = 1) do={ - :return true; - } - - :local Error false; - :local PathNext ""; - :foreach Dir in=[ :toarray [ $CharacterReplace $Path "/" "," ] ] do={ - :local Continue false; - :set PathNext [ $CleanFilePath ($PathNext . "/" . $Dir) ]; - - :if ([ :len [ /file/find where name=$PathNext !(name="tmpfs") type="directory" ] ] = 1) do={ - :set Continue true; - } - - :if ($Continue = false && $PathNext = "tmpfs") do={ - :if ([ :len [ /disk/find where slot=tmpfs type=tmpfs ] ] = 0) do={ - $LogPrintExit2 info $0 ("Creating disk of type tmpfs.") false; - /file/remove [ find where name="tmpfs" type="directory" ]; - :do { - /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/get total-memory ] / 3); - $WaitForFile "tmpfs"; - } on-error={ - $LogPrintExit2 warning $0 ("Creating disk of type tmpfs failed!") false; - :set Error true; - } - } - :set Continue true; - } - - :if ($Continue = false && [ :len [ /file/find where name=$PathNext ] ] = 1) do={ - $LogPrintExit2 warning $0 ("The path '" . $PathNext . "' exists, but is not a directory.") false; - :return false; - } - - :if ($Continue = false) do={ - :local Name ($PathNext . "-" . [ $GetRandom20CharAlNum 6 ]); - :do { - /ip/smb/share/add disabled=yes directory=$PathNext name=$Name; - $WaitForFile $PathNext; - } on-error={ - $LogPrintExit2 warning $0 ("Making directory '" . $PathNext . "' failed!") false; - :set Error true; - } - /ip/smb/share/remove [ find where name=$Name ]; - :if ($Error = true) do={ - :return false; - } - } - } - :return true; -} - -# prepare NotificationFunctions array -:if ([ :typeof $NotificationFunctions ] != "array") do={ - :set NotificationFunctions ({}); -} - -# parse key value store -:set ParseKeyValueStore do={ - :local Source $1; - :if ([ :typeof $Source ] != "array") do={ - :set Source [ :tostr $1 ]; - } - :local Result ({}); - :foreach KeyValue in=[ :toarray $Source ] do={ - :if ([ :find $KeyValue "=" ]) do={ - :set ($Result->[ :pick $KeyValue 0 [ :find $KeyValue "=" ] ]) \ - [ :pick $KeyValue ([ :find $KeyValue "=" ] + 1) [ :len $KeyValue ] ]; - } else={ - :set ($Result->$KeyValue) true; - } - } - :return $Result; -} - -# print lines with trailing carriage return -:set PrettyPrint do={ - :local Input [ :tostr $1 ]; - - :global Unix2Dos; - - :put [ $Unix2Dos $Input ]; -} - -# delay a random amount of seconds -:set RandomDelay do={ - :global EitherOr; - :global GetRandomNumber; - - :delay ([ $GetRandomNumber $1 ] . [ $EitherOr $2 "s" ]); -} - -# read input from user -:set Read do={ - :return; -} - -# check for required RouterOS version -:set RequiredRouterOS do={ - :local Caller [ :tostr $1 ]; - :local Required [ :tostr $2 ]; - :local Warn [ :tostr $3 ]; - - :global IfThenElse; - :global LogPrintExit2; - :global VersionToNum; - - :if (!($Required ~ "^\\d+\\.\\d+((beta|rc|\\.)\\d+|)\$")) do={ - $LogPrintExit2 error $0 ("No valid RouterOS version: " . $Required) false; - :return false; - } - - :if ([ $VersionToNum $Required ] > [ $VersionToNum [ /system/package/update/get installed-version ] ]) do={ - :if ($Warn = "true") do={ - $LogPrintExit2 warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = ("\$")) "function" "script" ] . \ - " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!") false; - } - :return false; - } - :return true; -} - -# check if script is run from terminal -:set ScriptFromTerminal do={ - :local Script [ :tostr $1 ]; - - :global LogPrintExit2; - - :foreach Job in=[ /system/script/job/find where script=$Script ] do={ - :set Job [ /system/script/job/get $Job ]; - :while ([ :typeof ($Job->"parent") ] = "id") do={ - :set Job [ /system/script/job/get [ find where .id=($Job->"parent") ] ]; - } - :if (($Job->"type") = "login") do={ - $LogPrintExit2 debug $0 ("Script " . $Script . " started from terminal.") false; - :return true; - } - } - $LogPrintExit2 debug $0 ("Script " . $Script . " NOT started from terminal.") false; - - :return false; + $ScriptInstallUpdate; } # install new scripts, update existing scripts @@ -779,7 +98,7 @@ :local UrlSuffix $ScriptUpdatesUrlSuffix; :if ([ :typeof ($Comment->"base-url") ] = "str") do={ :set BaseUrl ($Comment->"base-url"); } :if ([ :typeof ($Comment->"url-suffix") ] = "str") do={ :set UrlSuffix ($Comment->"url-suffix"); } - :local Url ($BaseUrl . $ScriptVal->"name" . $UrlSuffix); + :local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix); $LogPrintExit2 debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url) false; :local Result [ /tool/fetch check-certificate=yes-without-crl $Url output=user as-value ]; @@ -863,7 +182,7 @@ :local ChangeLogCode; :do { - :local Url ($ScriptUpdatesBaseUrl . "global-config.changes" . $ScriptUpdatesUrlSuffix); + :local Url ($ScriptUpdatesBaseUrl . "news-and-changes.rsc" . $ScriptUpdatesUrlSuffix); $LogPrintExit2 debug $0 ("Fetching news, changes and migration: " . $Url) false; :local Result [ /tool/fetch check-certificate=yes-without-crl $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ @@ -940,353 +259,3 @@ :set GlobalConfigMigration; } } - -# lock script against multiple invocation -:set ScriptLock do={ - :local Script [ :tostr $1 ]; - :local DoReturn $2; - :local WaitMax ([ :tonum $3 ] * 10); - - :global GetRandom20CharAlNum; - :global IfThenElse; - :global LogPrintExit2; - - :global ScriptLockOrder; - :if ([ :typeof $ScriptLockOrder ] = "nothing") do={ - :set ScriptLockOrder ({}); - } - :if ([ :typeof ($ScriptLockOrder->$Script) ] = "nothing") do={ - :set ($ScriptLockOrder->$Script) ({}); - } - - :local JobCount do={ - :local Script [ :tostr $1 ]; - - :return [ :len [ /system/script/job/find where script=$Script ] ]; - } - - :local TicketCount do={ - :local Script [ :tostr $1 ]; - - :global ScriptLockOrder; - - :local Count 0; - :foreach Ticket in=($ScriptLockOrder->$Script) do={ - :if ([ :typeof $Ticket ] != "nothing") do={ - :set Count ($Count + 1); - } - } - :return $Count; - } - - :local IsFirstTicket do={ - :local Script [ :tostr $1 ]; - :local Check [ :tostr $2 ]; - - :global ScriptLockOrder; - - :foreach Ticket in=($ScriptLockOrder->$Script) do={ - :if ($Ticket = $Check) do={ :return true; } - :if ([ :typeof $Ticket ] != "nothing" && $Ticket != $Check) do={ :return false; } - } - :return false; - } - - :local AddTicket do={ - :local Script [ :tostr $1 ]; - :local Add [ :tostr $2 ]; - - :global ScriptLockOrder; - - :while (true) do={ - :local Pos [ :len ($ScriptLockOrder->$Script) ]; - :set ($ScriptLockOrder->$Script->$Pos) $Add; - :delay 10ms; - :if (($ScriptLockOrder->$Script->$Pos) = $Add) do={ :return true; } - } - } - - :local RemoveTicket do={ - :local Script [ :tostr $1 ]; - :local Remove [ :tostr $2 ]; - - :global ScriptLockOrder; - - :foreach Id,Ticket in=($ScriptLockOrder->$Script) do={ - :while (($ScriptLockOrder->$Script->$Id) = $Remove) do={ - :set ($ScriptLockOrder->$Script->$Id); - :delay 10ms; - } - } - } - - :local CleanupTickets do={ - :local Script [ :tostr $1 ]; - - :global ScriptLockOrder; - - :foreach Ticket in=($ScriptLockOrder->$Script) do={ - :if ([ :typeof $Ticket ] != "nothing") do={ - :return false; - } - } - - :set ($ScriptLockOrder->$Script) ({}); - } - - :if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={ - $LogPrintExit2 error $0 ("A script named '" . $Script . "' does not exist!") true; - } - - :if ([ $JobCount $Script ] = 0) do={ - $LogPrintExit2 error $0 ("No script '" . $Script . "' is running!") true; - } - - :if ([ $TicketCount $Script ] >= [ $JobCount $Script ]) do={ - $LogPrintExit2 error $0 ("More tickets than running scripts '" . $Script . "', resetting!") false; - :set ($ScriptLockOrder->$Script) ({}); - /system/script/job/remove [ find where script=$Script ]; - } - - :local MyTicket [ $GetRandom20CharAlNum 6 ]; - $AddTicket $Script $MyTicket; - - :local WaitCount 0; - :while ($WaitMax > $WaitCount && ([ $IsFirstTicket $Script $MyTicket ] = false || [ $TicketCount $Script ] < [ $JobCount $Script ])) do={ - :set WaitCount ($WaitCount + 1); - :delay 100ms; - } - - :if ([ $IsFirstTicket $Script $MyTicket ] = true && [ $TicketCount $Script ] = [ $JobCount $Script ]) do={ - $RemoveTicket $Script $MyTicket; - $CleanupTickets $Script; - :return false; - } - - $RemoveTicket $Script $MyTicket; - $LogPrintExit2 info $0 ("Script '" . $Script . "' started more than once" . [ $IfThenElse ($WaitCount > 0) \ - " and timed out waiting for lock" "" ] . "... Aborting.") [ $IfThenElse ($DoReturn = true) false true ]; - :return true; -} - -# send notification via NotificationFunctions - expects at least two string arguments -:set SendNotification do={ - :global SendNotification2; - - $SendNotification2 ({ subject=$1; message=$2; link=$3; silent=$4 }); -} - -# send notification via NotificationFunctions - expects one array argument -:set SendNotification2 do={ - :local Notification $1; - - :global NotificationFunctions; - - :foreach FunctionName,Discard in=$NotificationFunctions do={ - ($NotificationFunctions->$FunctionName) \ - ("\$NotificationFunctions->\"" . $FunctionName . "\"") \ - $Notification; - } -} - -# return UTF-8 symbol for unicode name -:set SymbolByUnicodeName do={ - :local Symbols { - "abacus"="\F0\9F\A7\AE"; - "alarm-clock"="\E2\8F\B0"; - "calendar"="\F0\9F\93\85"; - "card-file-box"="\F0\9F\97\83"; - "chart-decreasing"="\F0\9F\93\89"; - "chart-increasing"="\F0\9F\93\88"; - "cloud"="\E2\98\81"; - "cross-mark"="\E2\9D\8C"; - "earth"="\F0\9F\8C\8D"; - "fire"="\F0\9F\94\A5"; - "floppy-disk"="\F0\9F\92\BE"; - "high-voltage-sign"="\E2\9A\A1"; - "incoming-envelope"="\F0\9F\93\A8"; - "link"="\F0\9F\94\97"; - "lock-with-ink-pen"="\F0\9F\94\8F"; - "memo"="\F0\9F\93\9D"; - "mobile-phone"="\F0\9F\93\B1"; - "pushpin"="\F0\9F\93\8C"; - "scissors"="\E2\9C\82"; - "sparkles"="\E2\9C\A8"; - "speech-balloon"="\F0\9F\92\AC"; - "up-arrow"="\E2\AC\86"; - "warning-sign"="\E2\9A\A0"; - "white-heavy-check-mark"="\E2\9C\85" - } - - :return (($Symbols->$1) . "\EF\B8\8F"); -} - -# return symbol for notification -:set SymbolForNotification do={ - :global NotificationsWithSymbols; - :global SymbolByUnicodeName; - - :if ($NotificationsWithSymbols != true) do={ - :return ""; - } - :local Return ""; - :foreach Symbol in=[ :toarray $1 ] do={ - :set Return ($Return . [ $SymbolByUnicodeName $Symbol ]); - } - :return ($Return . " "); -} - -# convert line endings, UNIX -> DOS -:set Unix2Dos do={ - :local Input [ :tostr $1 ]; - - :global CharacterReplace; - - :return [ $CharacterReplace [ $CharacterReplace $Input \ - ("\n") ("\r\n") ] ("\r\r\n") ("\r\n") ]; -} - -# url encoding -:set UrlEncode do={ - :local Input [ :tostr $1 ]; - - :if ([ :len $Input ] = 0) do={ - :return ""; - } - - :local Return ""; - :local Chars ("\n\r !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~"); - :local Subs { "%0A"; "%0D"; "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27"; - "%28"; "%29"; "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; "%3F"; - "%40"; "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; "%7E" }; - - :for I from=0 to=([ :len $Input ] - 1) do={ - :local Char [ :pick $Input $I ]; - :local Replace [ :find $Chars $Char ]; - - :if ([ :typeof $Replace ] = "num") do={ - :set Char ($Subs->$Replace); - } - :set Return ($Return . $Char); - } - - :return $Return; -} - -# basic syntax validation -:set ValidateSyntax do={ - :local Code [ :tostr $1 ]; - - :do { - [ :parse (":local Validate do={\n" . $Code . "\n}") ]; - } on-error={ - :return false; - } - :return true; -} - -# convert version string to numeric value -:set VersionToNum do={ - :local Input [ :tostr $1 ]; - :local Multi 0x1000000; - :local Return 0; - - :global CharacterReplace; - - :set Input [ $CharacterReplace [ $CharacterReplace [ $CharacterReplace $Input \ - "." "," ] "beta" ",beta," ] "rc" ",rc," ]; - - :foreach Value in=([ :toarray $Input ], 0) do={ - :local Num [ :tonum $Value ]; - :if ($Multi = 0x100) do={ - :if ([ :typeof $Num ] = "num") do={ - :set Return ($Return + 0xff00); - :set Multi ($Multi / 0x100); - } else={ - :if ($Value = "beta") do={ :set Return ($Return + 0x3f00); } - :if ($Value = "rc") do={ :set Return ($Return + 0x7f00); } - } - } - :if ([ :typeof $Num ] = "num") do={ :set Return ($Return + ($Value * $Multi)); } - :set Multi ($Multi / 0x100); - } - - :return $Return; -} - -# wait for default route to be reachable -:set WaitDefaultRouteReachable do={ - :global IsDefaultRouteReachable; - - :while ([ $IsDefaultRouteReachable ] = false) do={ - :delay 1s; - } -} - -# wait for DNS to resolve -:set WaitDNSResolving do={ - :global IsDNSResolving; - - :while ([ $IsDNSResolving ] = false) do={ - :delay 1s; - } -} - -# wait for file to be available -:set WaitForFile do={ - :local FileName [ :tostr $1 ]; - :local WaitTime [ :totime $2 ]; - - :global CleanFilePath; - :global EitherOr; - - :set FileName [ $CleanFilePath $FileName ]; - :local I 1; - :local Delay ([ :totime [ $EitherOr $WaitTime 2s ] ] / 20); - - :while ([ :len [ /file/find where name=$FileName ] ] = 0) do={ - :if ($I >= 20) do={ - :return false; - } - :delay $Delay; - :set I ($I + 1); - } - :return true; -} - -# wait to be fully connected (default route is reachable, time is sync, DNS resolves) -:set WaitFullyConnected do={ - :global WaitDefaultRouteReachable; - :global WaitDNSResolving; - :global WaitTimeSync; - - $WaitDefaultRouteReachable; - $WaitTimeSync; - $WaitDNSResolving; -} - -# wait for time to become synced -:set WaitTimeSync do={ - :global IsTimeSync; - - :while ([ $IsTimeSync ] = false) do={ - :delay 1s; - } -} - -# load modules -:foreach Script in=[ /system/script/find where name ~ "^mod/." ] do={ - :local ScriptVal [ /system/script/get $Script ]; - :if ([ $ValidateSyntax ($ScriptVal->"source") ] = true) do={ - :do { - /system/script/run $Script; - } on-error={ - $LogPrintExit2 error $0 ("Module '" . $ScriptVal->"name" . "' failed to run.") false; - } - } else={ - $LogPrintExit2 error $0 ("Module '" . $ScriptVal->"name" . "' failed syntax validation, skipping.") false; - } -} - -# signal we are ready -:set GlobalFunctionsReady true; diff --git a/global-functions.rsc b/global-functions.rsc new file mode 100644 index 0000000..6f3bb86 --- /dev/null +++ b/global-functions.rsc @@ -0,0 +1,1292 @@ +#!rsc by RouterOS +# RouterOS script: global-functions +# Copyright (c) 2013-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.7 +# +# global functions +# https://git.eworm.de/cgit/routeros-scripts/about/ + +:local 0 "global-functions"; + +# expected configuration version +:global ExpectedConfigVersion 95; + +# global variables not to be changed by user +:global GlobalFunctionsReady false; +:global Identity [ /system/identity/get name ]; + +# global functions +:global CertificateAvailable; +:global CertificateDownload; +:global CertificateNameByCN; +:global CharacterReplace; +:global CleanFilePath; +:global DeviceInfo; +:global Dos2Unix; +:global DownloadPackage; +:global EitherOr; +:global EscapeForRegEx; +:global GetMacVendor; +:global GetRandom20CharAlNum; +:global GetRandom20CharHex; +:global GetRandomNumber; +:global Grep; +:global HexToNum; +:global IfThenElse; +:global IsDefaultRouteReachable; +:global IsDNSResolving; +:global IsFullyConnected; +:global IsMacLocallyAdministered; +:global IsTimeSync; +:global LogPrintExit2; +:global MkDir; +:global NotificationFunctions; +:global ParseKeyValueStore; +:global PrettyPrint; +:global RandomDelay; +:global Read; +:global RequiredRouterOS; +:global ScriptFromTerminal; +:global ScriptInstallUpdate; +:global ScriptLock; +:global SendNotification; +:global SendNotification2; +:global SymbolByUnicodeName; +:global SymbolForNotification; +:global Unix2Dos; +:global UrlEncode; +:global ValidateSyntax; +:global VersionToNum; +:global WaitDefaultRouteReachable; +:global WaitDNSResolving; +:global WaitForFile; +:global WaitFullyConnected; +:global WaitTimeSync; + +# check and download required certificate +:set CertificateAvailable do={ + :local CommonName [ :tostr $1 ]; + + :global CertificateDownload; + :global LogPrintExit2; + :global ParseKeyValueStore; + + :if ([ /system/resource/get free-hdd-space ] < 8388608 && \ + [ /certificate/settings/get crl-download ] = true && \ + [ /certificate/settings/get crl-store ] = "system") do={ + $LogPrintExit2 warning $0 ("This system has low free flash space but " . \ + "is configured to download certificate CRLs to system!") false; + } + + :if ([ :len [ /certificate/find where common-name=$CommonName ] ] = 0) do={ + $LogPrintExit2 info $0 ("Certificate with CommonName \"" . $CommonName . "\" not available.") false; + :if ([ $CertificateDownload $CommonName ] = false) do={ + :return false; + } + } + + :local CertVal [ /certificate/get [ find where common-name=$CommonName ] ]; + :while (($CertVal->"akid") != "" && ($CertVal->"akid") != ($CertVal->"skid")) do={ + :if ([ :len [ /certificate/find where skid=($CertVal->"akid") ] ] = 0) do={ + $LogPrintExit2 info $0 ("Certificate chain for \"" . $CommonName . \ + "\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\".") false; + :if ([ $CertificateDownload $CommonName ] = false) do={ + :return false; + } + } + :set CertVal [ /certificate/get [ find where skid=($CertVal->"akid") ] ]; + } + :return true; +} + +# download and import certificate +:set CertificateDownload do={ + :local CommonName [ :tostr $1 ]; + + :global ScriptUpdatesBaseUrl; + :global ScriptUpdatesUrlSuffix; + + :global CertificateNameByCN; + :global LogPrintExit2; + :global UrlEncode; + :global WaitForFile; + + $LogPrintExit2 info $0 ("Downloading and importing certificate with " . \ + "CommonName \"" . $CommonName . "\".") false; + :do { + :local LocalFileName ($CommonName . ".pem"); + :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); + /tool/fetch check-certificate=yes-without-crl \ + ($ScriptUpdatesBaseUrl . "certs/" . \ + $UrlFileName . $ScriptUpdatesUrlSuffix) \ + dst-path=$LocalFileName as-value; + $WaitForFile $LocalFileName; + /certificate/import file-name=$LocalFileName passphrase="" as-value; + /file/remove $LocalFileName; + + :foreach Cert in=[ /certificate/find where name~("^" . $LocalFileName . "_[0-9]+\$") ] do={ + $CertificateNameByCN [ /certificate/get $Cert common-name ]; + } + } on-error={ + $LogPrintExit2 warning $0 ("Failed importing certificate with " . \ + "CommonName \"" . $CommonName . "\"!") false; + :return false; + } + :return true; +} + +# name a certificate by its common-name +:set CertificateNameByCN do={ + :local CommonName [ :tostr $1 ]; + + :global CharacterReplace; + + :local Cert [ /certificate/find where common-name=$CommonName ]; + /certificate/set $Cert \ + name=[ $CharacterReplace [ $CharacterReplace [ $CharacterReplace $CommonName "'" "-" ] " " "-" ] "---" "-" ]; +} + +# character replace +:set CharacterReplace do={ + :local String [ :tostr $1 ]; + :local ReplaceFrom [ :tostr $2 ]; + :local ReplaceWith [ :tostr $3 ]; + :local Return ""; + + :if ($ReplaceFrom = "") do={ + :return $String; + } + + :while ([ :typeof [ :find $String $ReplaceFrom ] ] != "nil") do={ + :local Pos [ :find $String $ReplaceFrom ]; + :set Return ($Return . [ :pick $String 0 $Pos ] . $ReplaceWith); + :set String [ :pick $String ($Pos + [ :len $ReplaceFrom ]) [ :len $String ] ]; + } + + :return ($Return . $String); +} + +# clean file path +:set CleanFilePath do={ + :local Path [ :tostr $1 ]; + + :global CharacterReplace; + + :while ($Path ~ "//") do={ + :set $Path [ $CharacterReplace $Path "//" "/" ]; + } + :if ([ :pick $Path 0 ] = "/") do={ + :set Path [ :pick $Path 1 [ :len $Path ] ]; + } + :if ([ :pick $Path ([ :len $Path ] - 1) ] = "/") do={ + :set Path [ :pick $Path 0 ([ :len $Path ] - 1) ]; + } + + :return $Path; +} + +# get readable device info +:set DeviceInfo do={ + :global ExpectedConfigVersion; + :global Identity; + + :global IfThenElse; + + :local Resource [ /system/resource/get ]; + :local RouterBoard; + :do { + :set RouterBoard [[ :parse "/system/routerboard/get" ]]; + } on-error={ } + :local License [ /system/license/get ]; + :local Update [ /system/package/update/get ]; + + :return ( \ + "Hostname: " . $Identity . \ + "\nBoard name: " . $Resource->"board-name" . \ + "\nArchitecture: " . $Resource->"architecture-name" . \ + [ $IfThenElse ($RouterBoard->"routerboard" = true) \ + ("\nModel: " . $RouterBoard->"model" . \ + [ $IfThenElse ([ :len ($RouterBoard->"revision") ] > 0) \ + (" " . $RouterBoard->"revision") ] . \ + "\nSerial number: " . $RouterBoard->"serial-number") ] . \ + [ $IfThenElse ([ :len ($License->"level") ] > 0) \ + ("\nLicense: " . $License->"level") ] . \ + "\nRouterOS:" . \ + "\n Channel: " . $Update->"channel" . \ + "\n Installed: " . $Update->"installed-version" . \ + [ $IfThenElse ([ :typeof ($Update->"latest-version") ] != "nothing" && \ + $Update->"installed-version" != $Update->"latest-version") \ + ("\n Available: " . $Update->"latest-version") ] . \ + [ $IfThenElse ($RouterBoard->"routerboard" = true && \ + $RouterBoard->"current-firmware" != $RouterBoard->"upgrade-firmware") \ + ("\n Firmware: " . $RouterBoard->"current-firmware") ] . \ + "\nRouterOS-Scripts:" . \ + "\n Version: " . $ExpectedConfigVersion); +} + +# convert line endings, DOS -> UNIX +:set Dos2Unix do={ + :local Input [ :tostr $1 ]; + + :global CharacterReplace; + + :return [ $CharacterReplace $Input ("\r\n") ("\n") ]; +} + +# download package from upgrade server +:set DownloadPackage do={ + :local PkgName [ :tostr $1 ]; + :local PkgVer [ :tostr $2 ]; + :local PkgArch [ :tostr $3 ]; + :local PkgDir [ :tostr $4 ]; + + :global CertificateAvailable; + :global CleanFilePath; + :global LogPrintExit2; + :global MkDir; + :global WaitForFile; + + :if ([ :len $PkgName ] = 0) do={ :return false; } + :if ([ :len $PkgVer ] = 0) do={ :set PkgVer [ /system/package/update/get installed-version ]; } + :if ([ :len $PkgArch ] = 0) do={ :set PkgArch [ /system/resource/get architecture-name ]; } + + :if ($PkgName = "system") do={ :set PkgName "routeros"; } + + :local PkgFile ($PkgName . "-" . $PkgVer . "-" . $PkgArch . ".npk"); + :if ($PkgArch = "x86_64") do={ :set PkgFile ($PkgName . "-" . $PkgVer . ".npk"); } + :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; + + :if ([ $MkDir $PkgDir ] = false) do={ + $LogPrintExit2 warning $0 ("Failed creating directory, not downloading package.") false; + :return false; + } + + :if ([ :len [ /file/find where name=$PkgDest type="package" ] ] > 0) do={ + $LogPrintExit2 info $0 ("Package file " . $PkgName . " already exists.") false; + :return true; + } + + :if ([ $CertificateAvailable "R3" ] = false) do={ + $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; + } + + :local Url ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile); + $LogPrintExit2 info $0 ("Downloading package file '" . $PkgName . "'...") false; + $LogPrintExit2 debug $0 ("... from url: " . $Url) false; + :local Retry 3; + :while ($Retry > 0) do={ + :do { + /tool/fetch check-certificate=yes-without-crl $Url dst-path=$PkgDest; + $WaitForFile $PkgDest; + + :if ([ /file/get [ find where name=$PkgDest ] type ] = "package") do={ + :return true; + } + } on-error={ + $LogPrintExit2 debug $0 ("Downloading package file failed.") false; + } + + /file/remove [ find where name=$PkgDest ]; + :set Retry ($Retry - 1); + } + + $LogPrintExit2 warning $0 ("Downloading package file '" . $PkgName . "' failed.") false; + :return false; +} + +# return either first (if "true") or second +:set EitherOr do={ + :global IfThenElse; + + :if ([ :typeof $1 ] = "num") do={ + :return [ $IfThenElse ($1 != 0) $1 $2 ]; + } + :return [ $IfThenElse ([ :len [ :tostr $1 ] ] > 0) $1 $2 ]; +} + +# escape for regular expression +:set EscapeForRegEx do={ + :local Input [ :tostr $1 ]; + + :if ([ :len $Input ] = 0) do={ + :return ""; + } + + :local Return ""; + :local Chars ("^.[]\$()|*+\?{}\\"); + + :for I from=0 to=([ :len $Input ] - 1) do={ + :local Char [ :pick $Input $I ]; + :if ([ :find $Chars $Char ]) do={ + :set Char ("\\" . $Char); + } + :set Return ($Return . $Char); + } + + :return $Return; +} + +# get MAC vendor +:set GetMacVendor do={ + :local Mac [ :tostr $1 ]; + + :global CertificateAvailable; + :global IsMacLocallyAdministered; + :global LogPrintExit2; + + :if ([ $IsMacLocallyAdministered $Mac ] = true) do={ + :return "locally administered"; + } + + :do { + :if ([ $CertificateAvailable "R3" ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; + } + :local Vendor ([ /tool/fetch check-certificate=yes-without-crl \ + ("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data"); + :return $Vendor; + } on-error={ + :do { + /tool/fetch check-certificate=yes-without-crl ("https://api.macvendors.com/") \ + output=none as-value; + $LogPrintExit2 debug $0 ("The mac vendor is not known in database.") false; + } on-error={ + $LogPrintExit2 warning $0 ("Failed getting mac vendor.") false; + } + :return "unknown vendor"; + } +} + +# generate random 20 chars alphabetical (A-Z & a-z) and numerical (0-9) +:set GetRandom20CharAlNum do={ + :global EitherOr; + + :return [ :rndstr length=[ $EitherOr [ :tonum $1 ] 20 ] from="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" ]; +} + +# generate random 20 chars hex (0-9 and a-f) +:set GetRandom20CharHex do={ + :global EitherOr; + + :return [ :rndstr length=[ $EitherOr [ :tonum $1 ] 20 ] from="0123456789abcdef" ]; +} + +# generate random number +:set GetRandomNumber do={ + :global EitherOr; + + :return [ :rndnum from=0 to=[ $EitherOr [ :tonum $1 ] 4294967295 ] ]; +} + +# return first line that matches a pattern +:set Grep do={ + :local Input ([ :tostr $1 ] . "\n"); + :local Pattern [ :tostr $2 ]; + + :if ([ :typeof [ :find $Input $Pattern ] ] = "nil") do={ + :return []; + } + + :do { + :local Line [ :pick $Input 0 [ :find $Input "\n" ] ]; + :if ([ :typeof [ :find $Line $Pattern ] ] = "num") do={ + :return $Line; + } + :set Input [ :pick $Input ([ :find $Input "\n" ] + 1) [ :len $Input ] ]; + } while=([ :len $Input ] > 0); + + :return []; +} + +# convert from hex (string) to num +:set HexToNum do={ + :local Input [ :tostr $1 ]; + :local Hex "0123456789abcdef0123456789ABCDEF"; + :local Multi 1; + :local Return 0; + + :for I from=([ :len $Input ] - 1) to=0 do={ + :set Return ($Return + (([ :find $Hex [ :pick $Input $I ] ] % 16) * $Multi)); + :set Multi ($Multi * 16); + } + + :return $Return; +} + +# mimic conditional/ternary operator (condition ? consequent : alternative) +:set IfThenElse do={ + :if ([ :tostr $1 ] = "true" || [ :tobool $1 ] = true) do={ + :return $2; + } + :return $3; +} + +# check if default route is reachable +:set IsDefaultRouteReachable do={ + :if ([ :len [ /ip/route/find where dst-address=0.0.0.0/0 active routing-table=main ] ] > 0) do={ + :return true; + } + :return false; +} + +# check if DNS is resolving +:set IsDNSResolving do={ + :global CharacterReplace; + + :do { + :resolve "low-ttl.eworm.de"; + } on-error={ + :return false; + } + :return true; +} + +# check if system is is fully connected (default route reachable, DNS resolving, time sync) +:set IsFullyConnected do={ + :global IsDefaultRouteReachable; + :global IsDNSResolving; + :global IsTimeSync; + + :if ([ $IsDefaultRouteReachable ] = false) do={ + :return false; + } + :if ([ $IsDNSResolving ] = false) do={ + :return false; + } + :if ([ $IsTimeSync ] = false) do={ + :return false; + } + :return true; +} + +# check if mac address is locally administered +:set IsMacLocallyAdministered do={ + :if ([ :tonum ("0x" . [ :pick $1 0 [ :find $1 ":" ] ]) ] & 2 = 2) do={ + :return true; + } + :return false; +} + +# check if system time is sync +:set IsTimeSync do={ + :global IsTimeSyncCached; + + :global LogPrintExit2; + + :if ($IsTimeSyncCached = true) do={ + :return true; + } + + :if ([ /system/ntp/client/get enabled ] = true) do={ + :if ([ /system/ntp/client/get status ] = "synchronized") do={ + :set IsTimeSyncCached true; + :return true; + } + :return false; + } + + :if ([ /system/license/get ]->"level" = "free" || \ + [ /system/resource/get ]->"board-name" = "x86") do={ + $LogPrintExit2 debug $0 ("No ntp client configured, relying on RTC for CHR free license and x86.") false; + :return true; + } + + :if ([ /ip/cloud/get update-time ] = true) do={ + :if ([ :typeof [ /ip/cloud/get public-address ] ] = "ip") do={ + :set IsTimeSyncCached true; + :return true; + } + :return false; + } + + $LogPrintExit2 debug $0 ("No time source configured! Returning gracefully...") false; + :return true; +} + +# log and print with same text, optionally exit +:set LogPrintExit2 do={ + :local Severity [ :tostr $1 ]; + :local Name [ :tostr $2 ]; + :local Message [ :tostr $3 ]; + :local Exit [ :tostr $4 ]; + + :global PrintDebug; + :global PrintDebugOverride; + + :global EitherOr; + + :local Debug [ $EitherOr ($PrintDebugOverride->$Name) $PrintDebug ]; + + :local PrintSeverity do={ + :global TerminalColorOutput; + + :if ($TerminalColorOutput != true) do={ + :return $1; + } + + :local Color { debug=96; info=97; warning=93; error=91 }; + :return ("\1B[" . $Color->$1 . "m" . $1 . "\1B[0m"); + } + + :local Log ([ $EitherOr $Name "" ] . ": " . $Message); + :if ($Severity ~ ("^(debug|error|info)\$")) do={ + :if ($Severity = "debug") do={ :log debug $Log; } + :if ($Severity = "error") do={ :log error $Log; } + :if ($Severity = "info" ) do={ :log info $Log; } + } else={ + :log warning $Log; + :set Severity "warning"; + } + + :if ($Severity != "debug" || $Debug = true) do={ + :put ([ $PrintSeverity $Severity ] . ": " . $Message); + } + + :if ($Exit = "true") do={ + :error ("Hard error to exit."); + } +} + +# create directory +:set MkDir do={ + :local Path [ :tostr $1 ]; + + :global CharacterReplace; + :global CleanFilePath; + :global GetRandom20CharAlNum; + :global LogPrintExit2; + :global RequiredRouterOS; + :global WaitForFile; + + :set Path [ $CleanFilePath $Path ]; + + :if ($Path = "") do={ + :return true; + } + + :if ([ :len [ /file/find where name=$Path type="directory" ] ] = 1) do={ + :return true; + } + + :local Error false; + :local PathNext ""; + :foreach Dir in=[ :toarray [ $CharacterReplace $Path "/" "," ] ] do={ + :local Continue false; + :set PathNext [ $CleanFilePath ($PathNext . "/" . $Dir) ]; + + :if ([ :len [ /file/find where name=$PathNext !(name="tmpfs") type="directory" ] ] = 1) do={ + :set Continue true; + } + + :if ($Continue = false && $PathNext = "tmpfs") do={ + :if ([ :len [ /disk/find where slot=tmpfs type=tmpfs ] ] = 0) do={ + $LogPrintExit2 info $0 ("Creating disk of type tmpfs.") false; + /file/remove [ find where name="tmpfs" type="directory" ]; + :do { + /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/get total-memory ] / 3); + $WaitForFile "tmpfs"; + } on-error={ + $LogPrintExit2 warning $0 ("Creating disk of type tmpfs failed!") false; + :set Error true; + } + } + :set Continue true; + } + + :if ($Continue = false && [ :len [ /file/find where name=$PathNext ] ] = 1) do={ + $LogPrintExit2 warning $0 ("The path '" . $PathNext . "' exists, but is not a directory.") false; + :return false; + } + + :if ($Continue = false) do={ + :local Name ($PathNext . "-" . [ $GetRandom20CharAlNum 6 ]); + :do { + /ip/smb/share/add disabled=yes directory=$PathNext name=$Name; + $WaitForFile $PathNext; + } on-error={ + $LogPrintExit2 warning $0 ("Making directory '" . $PathNext . "' failed!") false; + :set Error true; + } + /ip/smb/share/remove [ find where name=$Name ]; + :if ($Error = true) do={ + :return false; + } + } + } + :return true; +} + +# prepare NotificationFunctions array +:if ([ :typeof $NotificationFunctions ] != "array") do={ + :set NotificationFunctions ({}); +} + +# parse key value store +:set ParseKeyValueStore do={ + :local Source $1; + :if ([ :typeof $Source ] != "array") do={ + :set Source [ :tostr $1 ]; + } + :local Result ({}); + :foreach KeyValue in=[ :toarray $Source ] do={ + :if ([ :find $KeyValue "=" ]) do={ + :set ($Result->[ :pick $KeyValue 0 [ :find $KeyValue "=" ] ]) \ + [ :pick $KeyValue ([ :find $KeyValue "=" ] + 1) [ :len $KeyValue ] ]; + } else={ + :set ($Result->$KeyValue) true; + } + } + :return $Result; +} + +# print lines with trailing carriage return +:set PrettyPrint do={ + :local Input [ :tostr $1 ]; + + :global Unix2Dos; + + :put [ $Unix2Dos $Input ]; +} + +# delay a random amount of seconds +:set RandomDelay do={ + :global EitherOr; + :global GetRandomNumber; + + :delay ([ $GetRandomNumber $1 ] . [ $EitherOr $2 "s" ]); +} + +# read input from user +:set Read do={ + :return; +} + +# check for required RouterOS version +:set RequiredRouterOS do={ + :local Caller [ :tostr $1 ]; + :local Required [ :tostr $2 ]; + :local Warn [ :tostr $3 ]; + + :global IfThenElse; + :global LogPrintExit2; + :global VersionToNum; + + :if (!($Required ~ "^\\d+\\.\\d+((beta|rc|\\.)\\d+|)\$")) do={ + $LogPrintExit2 error $0 ("No valid RouterOS version: " . $Required) false; + :return false; + } + + :if ([ $VersionToNum $Required ] > [ $VersionToNum [ /system/package/update/get installed-version ] ]) do={ + :if ($Warn = "true") do={ + $LogPrintExit2 warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = ("\$")) "function" "script" ] . \ + " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!") false; + } + :return false; + } + :return true; +} + +# check if script is run from terminal +:set ScriptFromTerminal do={ + :local Script [ :tostr $1 ]; + + :global LogPrintExit2; + + :foreach Job in=[ /system/script/job/find where script=$Script ] do={ + :set Job [ /system/script/job/get $Job ]; + :while ([ :typeof ($Job->"parent") ] = "id") do={ + :set Job [ /system/script/job/get [ find where .id=($Job->"parent") ] ]; + } + :if (($Job->"type") = "login") do={ + $LogPrintExit2 debug $0 ("Script " . $Script . " started from terminal.") false; + :return true; + } + } + $LogPrintExit2 debug $0 ("Script " . $Script . " NOT started from terminal.") false; + + :return false; +} + +# install new scripts, update existing scripts +:set ScriptInstallUpdate do={ + :local Scripts [ :toarray $1 ]; + :local NewComment [ :tostr $2 ]; + + :global ExpectedConfigVersion; + :global Identity; + :global IDonate; + :global NoNewsAndChangesNotification; + :global NotificationsWithSymbols; + :global ScriptUpdatesBaseUrl; + :global ScriptUpdatesFetch; + :global ScriptUpdatesUrlSuffix; + + :global CertificateAvailable; + :global EitherOr; + :global Grep; + :global IfThenElse; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global RequiredRouterOS; + :global SendNotification2; + :global SymbolForNotification; + :global ValidateSyntax; + + :if ([ $CertificateAvailable "R3" ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; + } + + :if ([ $CertificateAvailable "E1" ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; + } + + :foreach Script in=$Scripts do={ + :if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={ + $LogPrintExit2 info $0 ("Adding new script: " . $Script) false; + /system/script/add name=$Script owner=$Script source="#!rsc by RouterOS\n" comment=$NewComment; + } + } + + :local ExpectedConfigVersionBefore $ExpectedConfigVersion; + :local ReloadGlobalFunctions false; + :local ReloadGlobalConfig false; + + :foreach Script in=[ /system/script/find where source~"^#!rsc by RouterOS\n" ] do={ + :local ScriptVal [ /system/script/get $Script ]; + :local ScriptFile [ /file/find where name=("script-updates/" . $ScriptVal->"name") . ".rsc" ]; + :local SourceNew; + :if ([ :len $ScriptFile ] > 0) do={ + :set SourceNew [ /file/get $ScriptFile contents ]; + /file/remove $ScriptFile; + } + + :foreach Scheduler in=[ /system/scheduler/find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ + :local SchedulerVal [ /system/scheduler/get $Scheduler ]; + :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ + $LogPrintExit2 warning $0 ("Policies differ for script '" . $ScriptVal->"name" . \ + "' and its scheduler '" . $SchedulerVal->"name" . "'!") false; + } + } + + :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ + :local Comment [ $ParseKeyValueStore ($ScriptVal->"comment") ]; + :if (!($Comment->"ignore" = true)) do={ + :do { + :local BaseUrl $ScriptUpdatesBaseUrl; + :local UrlSuffix $ScriptUpdatesUrlSuffix; + :if ([ :typeof ($Comment->"base-url") ] = "str") do={ :set BaseUrl ($Comment->"base-url"); } + :if ([ :typeof ($Comment->"url-suffix") ] = "str") do={ :set UrlSuffix ($Comment->"url-suffix"); } + :local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix); + + $LogPrintExit2 debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url) false; + :local Result [ /tool/fetch check-certificate=yes-without-crl $Url output=user as-value ]; + :if ($Result->"status" = "finished") do={ + :set SourceNew ($Result->"data"); + } + } on-error={ + :if ($ScriptVal->"source" = "#!rsc by RouterOS\n") do={ + $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . \ + "', removing dummy. Typo on installation?") false; + /system/script/remove $Script; + } else={ + $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!") false; + } + } + } + } + + :if ([ :len $SourceNew ] > 0) do={ + :if ($SourceNew != $ScriptVal->"source") do={ + :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ + :local Required ([ $ParseKeyValueStore [ $Grep $SourceNew "# requires RouterOS, " ] ]->"version"); + :if ([ $RequiredRouterOS $0 [ $EitherOr $Required "0.0" ] false ] = true) do={ + :if ([ $ValidateSyntax $SourceNew ] = true) do={ + $LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; + /system/script/set owner=($ScriptVal->"name") source=$SourceNew $Script; + :if ($ScriptVal->"name" = "global-config") do={ + :set ReloadGlobalConfig true; + } + :if ($ScriptVal->"name" = "global-functions" || $ScriptVal->"name" ~ ("^mod/.")) do={ + :set ReloadGlobalFunctions true; + } + } else={ + $LogPrintExit2 warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . \ + "' failed! Ignoring!") false; + } + } else={ + $LogPrintExit2 warning $0 ("The script '" . $ScriptVal->"name" . "' requires RouterOS " . \ + $Required . ", which is not met by your installation. Ignoring!") false; + } + } else={ + $LogPrintExit2 warning $0 ("Looks like new script '" . $ScriptVal->"name" . \ + "' is not valid (missing shebang). Ignoring!") false; + } + } else={ + $LogPrintExit2 debug $0 ("Script '" . $ScriptVal->"name" . "' did not change.") false; + } + } else={ + $LogPrintExit2 debug $0 ("No update for script '" . $ScriptVal->"name" . "'.") false; + } + } + + :if ($ReloadGlobalFunctions = true) do={ + $LogPrintExit2 info $0 ("Reloading global functions.") false; + :do { + /system/script/run global-functions; + } on-error={ + $LogPrintExit2 error $0 ("Reloading global functions failed!") false; + } + } + + :if ($ReloadGlobalConfig = true) do={ + $LogPrintExit2 info $0 ("Reloading global configuration.") false; + :do { + /system/script/run global-config; + } on-error={ + $LogPrintExit2 error $0 ("Reloading global configuration failed!" . \ + " Syntax error or missing overlay\?") false; + } + } + + :if ($ExpectedConfigVersionBefore > $ExpectedConfigVersion) do={ + $LogPrintExit2 warning $0 ("The configuration version decreased from " . \ + $ExpectedConfigVersionBefore . " to " . $ExpectedConfigVersion . \ + ". Installed an older version?") false; + } + + :if ($ExpectedConfigVersionBefore < $ExpectedConfigVersion) do={ + :global GlobalConfigChanges; + :global GlobalConfigMigration; + :local ChangeLogCode; + + :do { + :local Url ($ScriptUpdatesBaseUrl . "news-and-changes.rsc" . $ScriptUpdatesUrlSuffix); + $LogPrintExit2 debug $0 ("Fetching news, changes and migration: " . $Url) false; + :local Result [ /tool/fetch check-certificate=yes-without-crl $Url output=user as-value ]; + :if ($Result->"status" = "finished") do={ + :set ChangeLogCode ($Result->"data"); + } + } on-error={ + $LogPrintExit2 warning $0 ("Failed fetching news, changes and migration!") false; + } + + :if ([ :len $ChangeLogCode ] > 0) do={ + :if ([ $ValidateSyntax $ChangeLogCode ] = true) do={ + :do { + [ :parse $ChangeLogCode ]; + } on-error={ + $LogPrintExit2 warning $0 ("The changelog failed to run!") false; + } + } else={ + $LogPrintExit2 warning $0 ("The changelog failed syntax validation!") false; + } + } + + :if ([ :len $GlobalConfigMigration ] > 0) do={ + :for I from=($ExpectedConfigVersionBefore + 1) to=$ExpectedConfigVersion do={ + :local Migration ($GlobalConfigMigration->[ :tostr $I ]); + :if ([ :typeof $Migration ] = "str") do={ + :if ([ $ValidateSyntax $Migration ] = true) do={ + $LogPrintExit2 info $0 ("Applying migration for change " . $I . ": " . $Migration) false; + :do { + [ :parse $Migration ]; + } on-error={ + $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed to run!") false; + } + } else={ + $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed syntax validation!") false; + } + } + } + } + + :local NotificationMessage ("The configuration version on " . $Identity . " increased " . \ + "to " . $ExpectedConfigVersion . ", current configuration may need modification. " . \ + "Please review and update global-config-overlay, then re-run global-config."); + $LogPrintExit2 info $0 ($NotificationMessage) false; + + :if ([ :len $GlobalConfigChanges ] > 0) do={ + :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); + :for I from=($ExpectedConfigVersionBefore + 1) to=$ExpectedConfigVersion do={ + :local Change ($GlobalConfigChanges->[ :tostr $I ]); + :set NotificationMessage ($NotificationMessage . "\n " . \ + [ $IfThenElse ($NotificationsWithSymbols = true) ("\E2\97\8F") "*" ] . " " . $Change); + $LogPrintExit2 info $0 ("Change " . $I . ": " . $Change) false; + } + } else={ + :set NotificationMessage ($NotificationMessage . "\n\nNews and changes are not available."); + } + + :if ($NoNewsAndChangesNotification != true) do={ + :local Link; + :if ($IDonate != true) do={ + :set NotificationMessage ($NotificationMessage . \ + "\n\n==== donation hint ====\n" . \ + "This project is developed in private spare time and usage is " . \ + "free of charge for you. If you like the scripts and think this is " . \ + "of value for you or your business please consider a donation."); + :set Link "https://git.eworm.de/cgit/routeros-scripts/about/#donate"; + } + + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "pushpin" ] . "News and configuration changes"); \ + message=$NotificationMessage; link=$Link }); + } + + :set GlobalConfigChanges; + :set GlobalConfigMigration; + } +} + +# lock script against multiple invocation +:set ScriptLock do={ + :local Script [ :tostr $1 ]; + :local DoReturn $2; + :local WaitMax ([ :tonum $3 ] * 10); + + :global GetRandom20CharAlNum; + :global IfThenElse; + :global LogPrintExit2; + + :global ScriptLockOrder; + :if ([ :typeof $ScriptLockOrder ] = "nothing") do={ + :set ScriptLockOrder ({}); + } + :if ([ :typeof ($ScriptLockOrder->$Script) ] = "nothing") do={ + :set ($ScriptLockOrder->$Script) ({}); + } + + :local JobCount do={ + :local Script [ :tostr $1 ]; + + :return [ :len [ /system/script/job/find where script=$Script ] ]; + } + + :local TicketCount do={ + :local Script [ :tostr $1 ]; + + :global ScriptLockOrder; + + :local Count 0; + :foreach Ticket in=($ScriptLockOrder->$Script) do={ + :if ([ :typeof $Ticket ] != "nothing") do={ + :set Count ($Count + 1); + } + } + :return $Count; + } + + :local IsFirstTicket do={ + :local Script [ :tostr $1 ]; + :local Check [ :tostr $2 ]; + + :global ScriptLockOrder; + + :foreach Ticket in=($ScriptLockOrder->$Script) do={ + :if ($Ticket = $Check) do={ :return true; } + :if ([ :typeof $Ticket ] != "nothing" && $Ticket != $Check) do={ :return false; } + } + :return false; + } + + :local AddTicket do={ + :local Script [ :tostr $1 ]; + :local Add [ :tostr $2 ]; + + :global ScriptLockOrder; + + :while (true) do={ + :local Pos [ :len ($ScriptLockOrder->$Script) ]; + :set ($ScriptLockOrder->$Script->$Pos) $Add; + :delay 10ms; + :if (($ScriptLockOrder->$Script->$Pos) = $Add) do={ :return true; } + } + } + + :local RemoveTicket do={ + :local Script [ :tostr $1 ]; + :local Remove [ :tostr $2 ]; + + :global ScriptLockOrder; + + :foreach Id,Ticket in=($ScriptLockOrder->$Script) do={ + :while (($ScriptLockOrder->$Script->$Id) = $Remove) do={ + :set ($ScriptLockOrder->$Script->$Id); + :delay 10ms; + } + } + } + + :local CleanupTickets do={ + :local Script [ :tostr $1 ]; + + :global ScriptLockOrder; + + :foreach Ticket in=($ScriptLockOrder->$Script) do={ + :if ([ :typeof $Ticket ] != "nothing") do={ + :return false; + } + } + + :set ($ScriptLockOrder->$Script) ({}); + } + + :if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={ + $LogPrintExit2 error $0 ("A script named '" . $Script . "' does not exist!") true; + } + + :if ([ $JobCount $Script ] = 0) do={ + $LogPrintExit2 error $0 ("No script '" . $Script . "' is running!") true; + } + + :if ([ $TicketCount $Script ] >= [ $JobCount $Script ]) do={ + $LogPrintExit2 error $0 ("More tickets than running scripts '" . $Script . "', resetting!") false; + :set ($ScriptLockOrder->$Script) ({}); + /system/script/job/remove [ find where script=$Script ]; + } + + :local MyTicket [ $GetRandom20CharAlNum 6 ]; + $AddTicket $Script $MyTicket; + + :local WaitCount 0; + :while ($WaitMax > $WaitCount && ([ $IsFirstTicket $Script $MyTicket ] = false || [ $TicketCount $Script ] < [ $JobCount $Script ])) do={ + :set WaitCount ($WaitCount + 1); + :delay 100ms; + } + + :if ([ $IsFirstTicket $Script $MyTicket ] = true && [ $TicketCount $Script ] = [ $JobCount $Script ]) do={ + $RemoveTicket $Script $MyTicket; + $CleanupTickets $Script; + :return false; + } + + $RemoveTicket $Script $MyTicket; + $LogPrintExit2 info $0 ("Script '" . $Script . "' started more than once" . [ $IfThenElse ($WaitCount > 0) \ + " and timed out waiting for lock" "" ] . "... Aborting.") [ $IfThenElse ($DoReturn = true) false true ]; + :return true; +} + +# send notification via NotificationFunctions - expects at least two string arguments +:set SendNotification do={ + :global SendNotification2; + + $SendNotification2 ({ subject=$1; message=$2; link=$3; silent=$4 }); +} + +# send notification via NotificationFunctions - expects one array argument +:set SendNotification2 do={ + :local Notification $1; + + :global NotificationFunctions; + + :foreach FunctionName,Discard in=$NotificationFunctions do={ + ($NotificationFunctions->$FunctionName) \ + ("\$NotificationFunctions->\"" . $FunctionName . "\"") \ + $Notification; + } +} + +# return UTF-8 symbol for unicode name +:set SymbolByUnicodeName do={ + :local Symbols { + "abacus"="\F0\9F\A7\AE"; + "alarm-clock"="\E2\8F\B0"; + "calendar"="\F0\9F\93\85"; + "card-file-box"="\F0\9F\97\83"; + "chart-decreasing"="\F0\9F\93\89"; + "chart-increasing"="\F0\9F\93\88"; + "cloud"="\E2\98\81"; + "cross-mark"="\E2\9D\8C"; + "earth"="\F0\9F\8C\8D"; + "fire"="\F0\9F\94\A5"; + "floppy-disk"="\F0\9F\92\BE"; + "high-voltage-sign"="\E2\9A\A1"; + "incoming-envelope"="\F0\9F\93\A8"; + "link"="\F0\9F\94\97"; + "lock-with-ink-pen"="\F0\9F\94\8F"; + "memo"="\F0\9F\93\9D"; + "mobile-phone"="\F0\9F\93\B1"; + "pushpin"="\F0\9F\93\8C"; + "scissors"="\E2\9C\82"; + "sparkles"="\E2\9C\A8"; + "speech-balloon"="\F0\9F\92\AC"; + "up-arrow"="\E2\AC\86"; + "warning-sign"="\E2\9A\A0"; + "white-heavy-check-mark"="\E2\9C\85" + } + + :return (($Symbols->$1) . "\EF\B8\8F"); +} + +# return symbol for notification +:set SymbolForNotification do={ + :global NotificationsWithSymbols; + :global SymbolByUnicodeName; + + :if ($NotificationsWithSymbols != true) do={ + :return ""; + } + :local Return ""; + :foreach Symbol in=[ :toarray $1 ] do={ + :set Return ($Return . [ $SymbolByUnicodeName $Symbol ]); + } + :return ($Return . " "); +} + +# convert line endings, UNIX -> DOS +:set Unix2Dos do={ + :local Input [ :tostr $1 ]; + + :global CharacterReplace; + + :return [ $CharacterReplace [ $CharacterReplace $Input \ + ("\n") ("\r\n") ] ("\r\r\n") ("\r\n") ]; +} + +# url encoding +:set UrlEncode do={ + :local Input [ :tostr $1 ]; + + :if ([ :len $Input ] = 0) do={ + :return ""; + } + + :local Return ""; + :local Chars ("\n\r !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~"); + :local Subs { "%0A"; "%0D"; "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27"; + "%28"; "%29"; "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; "%3F"; + "%40"; "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; "%7E" }; + + :for I from=0 to=([ :len $Input ] - 1) do={ + :local Char [ :pick $Input $I ]; + :local Replace [ :find $Chars $Char ]; + + :if ([ :typeof $Replace ] = "num") do={ + :set Char ($Subs->$Replace); + } + :set Return ($Return . $Char); + } + + :return $Return; +} + +# basic syntax validation +:set ValidateSyntax do={ + :local Code [ :tostr $1 ]; + + :do { + [ :parse (":local Validate do={\n" . $Code . "\n}") ]; + } on-error={ + :return false; + } + :return true; +} + +# convert version string to numeric value +:set VersionToNum do={ + :local Input [ :tostr $1 ]; + :local Multi 0x1000000; + :local Return 0; + + :global CharacterReplace; + + :set Input [ $CharacterReplace [ $CharacterReplace [ $CharacterReplace $Input \ + "." "," ] "beta" ",beta," ] "rc" ",rc," ]; + + :foreach Value in=([ :toarray $Input ], 0) do={ + :local Num [ :tonum $Value ]; + :if ($Multi = 0x100) do={ + :if ([ :typeof $Num ] = "num") do={ + :set Return ($Return + 0xff00); + :set Multi ($Multi / 0x100); + } else={ + :if ($Value = "beta") do={ :set Return ($Return + 0x3f00); } + :if ($Value = "rc") do={ :set Return ($Return + 0x7f00); } + } + } + :if ([ :typeof $Num ] = "num") do={ :set Return ($Return + ($Value * $Multi)); } + :set Multi ($Multi / 0x100); + } + + :return $Return; +} + +# wait for default route to be reachable +:set WaitDefaultRouteReachable do={ + :global IsDefaultRouteReachable; + + :while ([ $IsDefaultRouteReachable ] = false) do={ + :delay 1s; + } +} + +# wait for DNS to resolve +:set WaitDNSResolving do={ + :global IsDNSResolving; + + :while ([ $IsDNSResolving ] = false) do={ + :delay 1s; + } +} + +# wait for file to be available +:set WaitForFile do={ + :local FileName [ :tostr $1 ]; + :local WaitTime [ :totime $2 ]; + + :global CleanFilePath; + :global EitherOr; + + :set FileName [ $CleanFilePath $FileName ]; + :local I 1; + :local Delay ([ :totime [ $EitherOr $WaitTime 2s ] ] / 20); + + :while ([ :len [ /file/find where name=$FileName ] ] = 0) do={ + :if ($I >= 20) do={ + :return false; + } + :delay $Delay; + :set I ($I + 1); + } + :return true; +} + +# wait to be fully connected (default route is reachable, time is sync, DNS resolves) +:set WaitFullyConnected do={ + :global WaitDefaultRouteReachable; + :global WaitDNSResolving; + :global WaitTimeSync; + + $WaitDefaultRouteReachable; + $WaitTimeSync; + $WaitDNSResolving; +} + +# wait for time to become synced +:set WaitTimeSync do={ + :global IsTimeSync; + + :while ([ $IsTimeSync ] = false) do={ + :delay 1s; + } +} + +# load modules +:foreach Script in=[ /system/script/find where name ~ "^mod/." ] do={ + :local ScriptVal [ /system/script/get $Script ]; + :if ([ $ValidateSyntax ($ScriptVal->"source") ] = true) do={ + :do { + /system/script/run $Script; + } on-error={ + $LogPrintExit2 error $0 ("Module '" . $ScriptVal->"name" . "' failed to run.") false; + } + } else={ + $LogPrintExit2 error $0 ("Module '" . $ScriptVal->"name" . "' failed syntax validation, skipping.") false; + } +} + +# signal we are ready +:set GlobalFunctionsReady true; diff --git a/global-wait b/global-wait index fe1928b..2da00ca 100644 --- a/global-wait +++ b/global-wait @@ -1,11 +1,3 @@ #!rsc by RouterOS -# RouterOS script: global-wait -# Copyright (c) 2020-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# wait for global-functions to finish -# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md - -:local 0 "global-wait"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +# dummy for migration diff --git a/global-wait.rsc b/global-wait.rsc new file mode 100644 index 0000000..fe1928b --- /dev/null +++ b/global-wait.rsc @@ -0,0 +1,11 @@ +#!rsc by RouterOS +# RouterOS script: global-wait +# Copyright (c) 2020-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# wait for global-functions to finish +# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md + +:local 0 "global-wait"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/gps-track b/gps-track index d0d1232..2da00ca 100644 --- a/gps-track +++ b/gps-track @@ -1,34 +1,3 @@ #!rsc by RouterOS -# RouterOS script: gps-track -# Copyright (c) 2018-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# track gps data by sending json data to http server -# https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md - -:local 0 "gps-track"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global GpsTrackUrl; -:global Identity; - -:global LogPrintExit2; - -:local CoordinateFormat [ /system/gps/get coordinate-format ]; -:local Gps [ /system/gps/monitor once as-value ]; - -:if ($Gps->"valid" = true) do={ - /tool/fetch check-certificate=yes-without-crl $GpsTrackUrl output=none \ - http-method=post http-header-field="Content-Type: application/json" \ - http-data=("{" . \ - "\"lat\":\"" . ($Gps->"latitude") . "\"," . \ - "\"lon\":\"" . ($Gps->"longitude") . "\"," . \ - "\"identity\":\"" . $Identity . "\"" . \ - "}") as-value; - $LogPrintExit2 debug $0 ("Sending GPS data in " . $CoordinateFormat . " format: " . \ - "lat: " . ($Gps->"latitude") . " " . \ - "lon: " . ($Gps->"longitude")) false; -} else={ - $LogPrintExit2 debug $0 ("GPS data not valid.") false; -} +# dummy for migration diff --git a/gps-track.rsc b/gps-track.rsc new file mode 100644 index 0000000..d0d1232 --- /dev/null +++ b/gps-track.rsc @@ -0,0 +1,34 @@ +#!rsc by RouterOS +# RouterOS script: gps-track +# Copyright (c) 2018-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# track gps data by sending json data to http server +# https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md + +:local 0 "gps-track"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global GpsTrackUrl; +:global Identity; + +:global LogPrintExit2; + +:local CoordinateFormat [ /system/gps/get coordinate-format ]; +:local Gps [ /system/gps/monitor once as-value ]; + +:if ($Gps->"valid" = true) do={ + /tool/fetch check-certificate=yes-without-crl $GpsTrackUrl output=none \ + http-method=post http-header-field="Content-Type: application/json" \ + http-data=("{" . \ + "\"lat\":\"" . ($Gps->"latitude") . "\"," . \ + "\"lon\":\"" . ($Gps->"longitude") . "\"," . \ + "\"identity\":\"" . $Identity . "\"" . \ + "}") as-value; + $LogPrintExit2 debug $0 ("Sending GPS data in " . $CoordinateFormat . " format: " . \ + "lat: " . ($Gps->"latitude") . " " . \ + "lon: " . ($Gps->"longitude")) false; +} else={ + $LogPrintExit2 debug $0 ("GPS data not valid.") false; +} diff --git a/hotspot-to-wpa b/hotspot-to-wpa index dbce9ff..2da00ca 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -1,72 +1,3 @@ #!rsc by RouterOS -# RouterOS script: hotspot-to-wpa -# Copyright (c) 2019-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# add private WPA passphrase after hotspot login -# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md - -:local 0 "hotspot-to-wpa"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; - -:local MacAddress $"mac-address"; -:local UserName $username; -:local Date [ /system/clock/get date ]; -:local UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; -:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; -:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; - -:if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; -} -:local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - -:if ([ :len [ /caps-man/access-list/find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; -} -:local Template [ /caps-man/access-list/get ([ find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; - -:if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; -} - -# allow login page to load -:delay 1s; - -$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ").") false; -/caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; -/caps-man/access-list/add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - mac-address=$MacAddress private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" place-before=$PlaceBefore; - -:local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ - comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; -:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; -:if ([ :len $PrivatePassphrase ] > 0) do={ - :if ($PrivatePassphrase = "ignore") do={ - /caps-man/access-list/set $Entry !private-passphrase; - } else={ - /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; - } -} -:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; -:if ([ :len $SsidRegexp ] > 0) do={ - /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; -} -:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; -:if ([ :len $VlanId ] > 0) do={ - /caps-man/access-list/set $Entry vlan-id=$VlanId; -} -:local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; -:if ([ :len $VlanMode] > 0) do={ - /caps-man/access-list/set $Entry vlan-mode=$VlanMode; -} +# dummy for migration diff --git a/hotspot-to-wpa-cleanup b/hotspot-to-wpa-cleanup index 15f63f9..2da00ca 100644 --- a/hotspot-to-wpa-cleanup +++ b/hotspot-to-wpa-cleanup @@ -1,51 +1,3 @@ #!rsc by RouterOS -# RouterOS script: hotspot-to-wpa-cleanup -# Copyright (c) 2021-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, order=80 -# -# manage and clean up private WPA passphrase after hotspot login -# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md - -:local 0 "hotspot-to-wpa-cleanup"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; -:global ScriptLock; - -$ScriptLock $0 false 10; - -:foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ - :local ClientVal [ /caps-man/registration-table/get $Client ]; - :local Lease [ /ip/dhcp-server/lease/find where server~"wpa" dynamic \ - mac-address=($ClientVal->"mac-address") ]; - :if ([ :len $Lease ] > 0) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static.") false; - /ip/dhcp-server/lease/make-static $Lease; - /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; - } -} - -:foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" and \ - !(comment~[ /system/clock/get date ]) ] do={ - :local ClientVal [ /caps-man/access-list/get $Client ]; - :if ([ :len [ /ip/dhcp-server/lease/find where server~"wpa" !dynamic \ - mac-address=($ClientVal->"mac-address") ] ] = 0) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " did not connect to WPA, removing from access list.") false; - /caps-man/access-list/remove $Client; - } -} - -:foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status=waiting \ - last-seen>4w comment~"^hotspot-to-wpa:" ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for long time, removing.") false; - /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - mac-address=($LeaseVal->"mac-address") ]; - /ip/dhcp-server/lease/remove $Lease; -} +# dummy for migration diff --git a/hotspot-to-wpa-cleanup.rsc b/hotspot-to-wpa-cleanup.rsc new file mode 100644 index 0000000..15f63f9 --- /dev/null +++ b/hotspot-to-wpa-cleanup.rsc @@ -0,0 +1,51 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa-cleanup +# Copyright (c) 2021-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=80 +# +# manage and clean up private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md + +:local 0 "hotspot-to-wpa-cleanup"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global LogPrintExit2; +:global ScriptLock; + +$ScriptLock $0 false 10; + +:foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ + :local ClientVal [ /caps-man/registration-table/get $Client ]; + :local Lease [ /ip/dhcp-server/lease/find where server~"wpa" dynamic \ + mac-address=($ClientVal->"mac-address") ]; + :if ([ :len $Lease ] > 0) do={ + $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ + " connected to WPA, making lease static.") false; + /ip/dhcp-server/lease/make-static $Lease; + /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; + } +} + +:foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" and \ + !(comment~[ /system/clock/get date ]) ] do={ + :local ClientVal [ /caps-man/access-list/get $Client ]; + :if ([ :len [ /ip/dhcp-server/lease/find where server~"wpa" !dynamic \ + mac-address=($ClientVal->"mac-address") ] ] = 0) do={ + $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ + " did not connect to WPA, removing from access list.") false; + /caps-man/access-list/remove $Client; + } +} + +:foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status=waiting \ + last-seen>4w comment~"^hotspot-to-wpa:" ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ + " was not seen for long time, removing.") false; + /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ + mac-address=($LeaseVal->"mac-address") ]; + /ip/dhcp-server/lease/remove $Lease; +} diff --git a/hotspot-to-wpa.rsc b/hotspot-to-wpa.rsc new file mode 100644 index 0000000..dbce9ff --- /dev/null +++ b/hotspot-to-wpa.rsc @@ -0,0 +1,72 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa +# Copyright (c) 2019-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# add private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md + +:local 0 "hotspot-to-wpa"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global EitherOr; +:global LogPrintExit2; +:global ParseKeyValueStore; + +:local MacAddress $"mac-address"; +:local UserName $username; +:local Date [ /system/clock/get date ]; +:local UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; +:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; +:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; + +:if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; +} +:local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + +:if ([ :len [ /caps-man/access-list/find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ + /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; +} +:local Template [ /caps-man/access-list/get ([ find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; + +:if ($Template->"action" = "reject") do={ + $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; +} + +# allow login page to load +:delay 1s; + +$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ").") false; +/caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; +/caps-man/access-list/add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + mac-address=$MacAddress private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" place-before=$PlaceBefore; + +:local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ + comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; +:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; +:if ([ :len $PrivatePassphrase ] > 0) do={ + :if ($PrivatePassphrase = "ignore") do={ + /caps-man/access-list/set $Entry !private-passphrase; + } else={ + /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; + } +} +:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; +:if ([ :len $SsidRegexp ] > 0) do={ + /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; +} +:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; +:if ([ :len $VlanId ] > 0) do={ + /caps-man/access-list/set $Entry vlan-id=$VlanId; +} +:local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; +:if ([ :len $VlanMode] > 0) do={ + /caps-man/access-list/set $Entry vlan-mode=$VlanMode; +} diff --git a/ip-addr-bridge b/ip-addr-bridge index 99fcba5..2da00ca 100644 --- a/ip-addr-bridge +++ b/ip-addr-bridge @@ -1,18 +1,3 @@ #!rsc by RouterOS -# RouterOS script: ip-addr-bridge -# Copyright (c) 2018-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# enable or disable ip addresses based on bridge port state -# https://git.eworm.de/cgit/routeros-scripts/about/doc/ip-addr-bridge.md - -:foreach Bridge in=[ /interface/bridge/find ] do={ - :local BrName [ /interface/bridge/get $Bridge name ]; - :if ([ :len [ /interface/bridge/port/find where bridge=$BrName ] ] > 0) do={ - :if ([ :len [ /interface/bridge/port/find where bridge=$BrName and inactive=no ] ] = 0) do={ - /ip/address/disable [ find where !dynamic interface=$BrName ]; - } else={ - /ip/address/enable [ find where !dynamic interface=$BrName ]; - } - } -} +# dummy for migration diff --git a/ip-addr-bridge.rsc b/ip-addr-bridge.rsc new file mode 100644 index 0000000..99fcba5 --- /dev/null +++ b/ip-addr-bridge.rsc @@ -0,0 +1,18 @@ +#!rsc by RouterOS +# RouterOS script: ip-addr-bridge +# Copyright (c) 2018-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# enable or disable ip addresses based on bridge port state +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ip-addr-bridge.md + +:foreach Bridge in=[ /interface/bridge/find ] do={ + :local BrName [ /interface/bridge/get $Bridge name ]; + :if ([ :len [ /interface/bridge/port/find where bridge=$BrName ] ] > 0) do={ + :if ([ :len [ /interface/bridge/port/find where bridge=$BrName and inactive=no ] ] = 0) do={ + /ip/address/disable [ find where !dynamic interface=$BrName ]; + } else={ + /ip/address/enable [ find where !dynamic interface=$BrName ]; + } + } +} diff --git a/ipsec-to-dns b/ipsec-to-dns index 530c714..2da00ca 100644 --- a/ipsec-to-dns +++ b/ipsec-to-dns @@ -1,69 +1,3 @@ #!rsc by RouterOS -# RouterOS script: ipsec-to-dns -# Copyright (c) 2021-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# and add/remove/update DNS entries from IPSec mode-config -# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipsec-to-dns.md - -:local 0 "ipsec-to-dns"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Domain; -:global HostNameInZone; -:global Identity; -:global PrefixInZone; - -:global CharacterReplace; -:global EscapeForRegEx; -:global IfThenElse; -:global LogPrintExit2; - -:local Zone \ - ([ $IfThenElse ($PrefixInZone = true) "ipsec." ] . \ - [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); -:local Ttl 5m; -:local CommentPrefix ("managed by " . $0 . " for "); -:local CommentString ("--- " . $0 . " above ---"); - -:if ([ :len [ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ - /ip/dns/static/add comment=$CommentString name=- type=NXDOMAIN disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false; -} -:local PlaceBefore ([ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0); - -:foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={ - :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; - :local PeerId [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; - :if ([ :len [ /ip/ipsec/active-peers/find where id~("^(CN=)?" . [ $EscapeForRegEx $PeerId ] . "\$") \ - dynamic-address=($DnsRecordVal->"address") ] ] > 0) do={ - $LogPrintExit2 debug $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; - } else={ - :local Found false; - $LogPrintExit2 info $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") has gone, deleting DNS entry.") false; - /ip/dns/static/remove $DnsRecord; - } -} - -:foreach Peer in=[ /ip/ipsec/active-peers/find where !(dynamic-address=[]) ] do={ - :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; - :local PeerId [ $CharacterReplace ($PeerVal->"id") "CN=" "" ]; - :local Comment ($CommentPrefix . $PeerId); - :local HostName [ :pick $PeerId 0 [ :find ($PeerId . ".") "." ] ]; - - :local Fqdn ($HostName . "." . $Zone); - :local DnsRecord [ /ip/dns/static/find where name=$Fqdn ]; - :if ([ :len $DnsRecord ] > 0) do={ - :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; - :if ($DnsIp = $PeerVal->"dynamic-address") do={ - $LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false; - } else={ - $LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $PeerVal->"dynamic-address" . ".") false; - /ip/dns/static/set name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment $DnsRecord; - } - } else={ - $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $PeerVal->"dynamic-address" . ".") false; - /ip/dns/static/add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; - } -} +# dummy for migration diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc new file mode 100644 index 0000000..530c714 --- /dev/null +++ b/ipsec-to-dns.rsc @@ -0,0 +1,69 @@ +#!rsc by RouterOS +# RouterOS script: ipsec-to-dns +# Copyright (c) 2021-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# and add/remove/update DNS entries from IPSec mode-config +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipsec-to-dns.md + +:local 0 "ipsec-to-dns"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Domain; +:global HostNameInZone; +:global Identity; +:global PrefixInZone; + +:global CharacterReplace; +:global EscapeForRegEx; +:global IfThenElse; +:global LogPrintExit2; + +:local Zone \ + ([ $IfThenElse ($PrefixInZone = true) "ipsec." ] . \ + [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); +:local Ttl 5m; +:local CommentPrefix ("managed by " . $0 . " for "); +:local CommentString ("--- " . $0 . " above ---"); + +:if ([ :len [ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ + /ip/dns/static/add comment=$CommentString name=- type=NXDOMAIN disabled=yes; + $LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false; +} +:local PlaceBefore ([ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0); + +:foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={ + :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; + :local PeerId [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; + :if ([ :len [ /ip/ipsec/active-peers/find where id~("^(CN=)?" . [ $EscapeForRegEx $PeerId ] . "\$") \ + dynamic-address=($DnsRecordVal->"address") ] ] > 0) do={ + $LogPrintExit2 debug $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; + } else={ + :local Found false; + $LogPrintExit2 info $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") has gone, deleting DNS entry.") false; + /ip/dns/static/remove $DnsRecord; + } +} + +:foreach Peer in=[ /ip/ipsec/active-peers/find where !(dynamic-address=[]) ] do={ + :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; + :local PeerId [ $CharacterReplace ($PeerVal->"id") "CN=" "" ]; + :local Comment ($CommentPrefix . $PeerId); + :local HostName [ :pick $PeerId 0 [ :find ($PeerId . ".") "." ] ]; + + :local Fqdn ($HostName . "." . $Zone); + :local DnsRecord [ /ip/dns/static/find where name=$Fqdn ]; + :if ([ :len $DnsRecord ] > 0) do={ + :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; + :if ($DnsIp = $PeerVal->"dynamic-address") do={ + $LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false; + } else={ + $LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $PeerVal->"dynamic-address" . ".") false; + /ip/dns/static/set name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment $DnsRecord; + } + } else={ + $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $PeerVal->"dynamic-address" . ".") false; + /ip/dns/static/add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + } +} diff --git a/ipv6-update b/ipv6-update index 2838feb..2da00ca 100644 --- a/ipv6-update +++ b/ipv6-update @@ -1,76 +1,3 @@ #!rsc by RouterOS -# RouterOS script: ipv6-update -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# update firewall and dns settings on IPv6 prefix change -# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md - -:local 0 "ipv6-update"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local PdPrefix $"pd-prefix"; - -:global LogPrintExit2; -:global ParseKeyValueStore; - -:if ([ :typeof $PdPrefix ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from ipv6 dhcp-client.") true; -} - -:local Pool [ /ipv6/pool/get [ find where prefix=$PdPrefix ] name ]; -:if ([ :len [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={ - /ipv6/firewall/address-list/add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool); - $LogPrintExit2 warning $0 ("Added ipv6 address list entry for ipv6-pool-" . $Pool) false; -} -:local AddrList [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ]; -:local OldPrefix [ /ipv6/firewall/address-list/get ($AddrList->0) address ]; - -:if ($OldPrefix != $PdPrefix) do={ - $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix) false; - /ipv6/firewall/address-list/set address=$PdPrefix $AddrList; - - # give the interfaces a moment to receive their addresses - :delay 2s; - - :foreach ListEntry in=[ /ipv6/firewall/address-list/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ - :local ListEntryVal [ /ipv6/firewall/address-list/get $ListEntry ]; - :local Comment [ $ParseKeyValueStore ($ListEntryVal->"comment") ]; - - :local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; - :if ([ :len $Prefix ] = 1) do={ - :set Prefix [ /ipv6/address/get $Prefix address ]; - - :if ([ :typeof [ :find ($ListEntryVal->"address") "/128" ] ] = "num" ) do={ - :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); - :local Address ($ListEntryVal->"address"); - :local Address ($Prefix | ([ :toip6 [ :pick $Address 0 [ :find $Address "/128" ] ] ] & ::ffff:ffff:ffff:ffff)); - - $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 host address " . $Address . \ - " from interface " . ($Comment->"interface")) false; - /ipv6/firewall/address-list/set address=$Address $ListEntry; - } else={ - $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $Prefix . \ - " from interface " . ($Comment->"interface")) false; - /ipv6/firewall/address-list/set address=$Prefix $ListEntry; - } - } - } - - :foreach Record in=[ /ip/dns/static/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ - :local RecordVal [ /ip/dns/static/get $Record ]; - :local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ]; - - :local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; - :if ([ :len $Prefix ] = 1) do={ - :set Prefix [ /ipv6/address/get $Prefix address ]; - :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); - :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); - - $LogPrintExit2 info $0 ("Updating DNS record for " . ($RecordVal->"name") . \ - ($RecordVal->"regexp") . " to " . $Address) false; - /ip/dns/static/set address=$Address $Record; - } - } -} +# dummy for migration diff --git a/ipv6-update.rsc b/ipv6-update.rsc new file mode 100644 index 0000000..2838feb --- /dev/null +++ b/ipv6-update.rsc @@ -0,0 +1,76 @@ +#!rsc by RouterOS +# RouterOS script: ipv6-update +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update firewall and dns settings on IPv6 prefix change +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md + +:local 0 "ipv6-update"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:local PdPrefix $"pd-prefix"; + +:global LogPrintExit2; +:global ParseKeyValueStore; + +:if ([ :typeof $PdPrefix ] = "nothing") do={ + $LogPrintExit2 error $0 ("This script is supposed to run from ipv6 dhcp-client.") true; +} + +:local Pool [ /ipv6/pool/get [ find where prefix=$PdPrefix ] name ]; +:if ([ :len [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={ + /ipv6/firewall/address-list/add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool); + $LogPrintExit2 warning $0 ("Added ipv6 address list entry for ipv6-pool-" . $Pool) false; +} +:local AddrList [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ]; +:local OldPrefix [ /ipv6/firewall/address-list/get ($AddrList->0) address ]; + +:if ($OldPrefix != $PdPrefix) do={ + $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix) false; + /ipv6/firewall/address-list/set address=$PdPrefix $AddrList; + + # give the interfaces a moment to receive their addresses + :delay 2s; + + :foreach ListEntry in=[ /ipv6/firewall/address-list/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ + :local ListEntryVal [ /ipv6/firewall/address-list/get $ListEntry ]; + :local Comment [ $ParseKeyValueStore ($ListEntryVal->"comment") ]; + + :local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; + :if ([ :len $Prefix ] = 1) do={ + :set Prefix [ /ipv6/address/get $Prefix address ]; + + :if ([ :typeof [ :find ($ListEntryVal->"address") "/128" ] ] = "num" ) do={ + :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); + :local Address ($ListEntryVal->"address"); + :local Address ($Prefix | ([ :toip6 [ :pick $Address 0 [ :find $Address "/128" ] ] ] & ::ffff:ffff:ffff:ffff)); + + $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 host address " . $Address . \ + " from interface " . ($Comment->"interface")) false; + /ipv6/firewall/address-list/set address=$Address $ListEntry; + } else={ + $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $Prefix . \ + " from interface " . ($Comment->"interface")) false; + /ipv6/firewall/address-list/set address=$Prefix $ListEntry; + } + } + } + + :foreach Record in=[ /ip/dns/static/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ + :local RecordVal [ /ip/dns/static/get $Record ]; + :local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ]; + + :local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; + :if ([ :len $Prefix ] = 1) do={ + :set Prefix [ /ipv6/address/get $Prefix address ]; + :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); + :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); + + $LogPrintExit2 info $0 ("Updating DNS record for " . ($RecordVal->"name") . \ + ($RecordVal->"regexp") . " to " . $Address) false; + /ip/dns/static/set address=$Address $Record; + } + } +} diff --git a/lease-script b/lease-script index 346d52b..2da00ca 100644 --- a/lease-script +++ b/lease-script @@ -1,51 +1,3 @@ #!rsc by RouterOS -# RouterOS script: lease-script -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# run scripts on DHCP lease -# https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md - -:local 0 "lease-script"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Grep; -:global IfThenElse; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; - -:if ([ :typeof $leaseActIP ] = "nothing" || \ - [ :typeof $leaseActMAC ] = "nothing" || \ - [ :typeof $leaseServerName ] = "nothing" || \ - [ :typeof $leaseBound ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from ip dhcp-server.") true; -} - -$LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \ - "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC) false; - -$ScriptLock $0 false 10; - -:if ([ :len [ /system/script/job/find where script=$0 ] ] > 1) do={ - $LogPrintExit2 debug $0 ("More invocations are waiting, exiting early.") true; -} - -:local RunOrder ({}); - -:foreach Script in=[ /system/script/find where source~("\n# provides: lease-script, ") ] do={ - :local ScriptVal [ /system/script/get $Script ]; - :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") "# provides: lease-script, " ] ]; - - :set ($RunOrder->($Store->"order")) ($ScriptVal->"name"); -} - -:foreach Order,Script in=$RunOrder do={ - :do { - $LogPrintExit2 debug $0 ("Running script with order " . $Order . ": " . $Script) false; - /system/script/run $Script; - } on-error={ - $LogPrintExit2 warning $0 ("Running script '" . $Script . "' failed!") false; - } -} +# dummy for migration diff --git a/lease-script.rsc b/lease-script.rsc new file mode 100644 index 0000000..346d52b --- /dev/null +++ b/lease-script.rsc @@ -0,0 +1,51 @@ +#!rsc by RouterOS +# RouterOS script: lease-script +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# run scripts on DHCP lease +# https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md + +:local 0 "lease-script"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Grep; +:global IfThenElse; +:global LogPrintExit2; +:global ParseKeyValueStore; +:global ScriptLock; + +:if ([ :typeof $leaseActIP ] = "nothing" || \ + [ :typeof $leaseActMAC ] = "nothing" || \ + [ :typeof $leaseServerName ] = "nothing" || \ + [ :typeof $leaseBound ] = "nothing") do={ + $LogPrintExit2 error $0 ("This script is supposed to run from ip dhcp-server.") true; +} + +$LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \ + "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC) false; + +$ScriptLock $0 false 10; + +:if ([ :len [ /system/script/job/find where script=$0 ] ] > 1) do={ + $LogPrintExit2 debug $0 ("More invocations are waiting, exiting early.") true; +} + +:local RunOrder ({}); + +:foreach Script in=[ /system/script/find where source~("\n# provides: lease-script, ") ] do={ + :local ScriptVal [ /system/script/get $Script ]; + :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") "# provides: lease-script, " ] ]; + + :set ($RunOrder->($Store->"order")) ($ScriptVal->"name"); +} + +:foreach Order,Script in=$RunOrder do={ + :do { + $LogPrintExit2 debug $0 ("Running script with order " . $Order . ": " . $Script) false; + /system/script/run $Script; + } on-error={ + $LogPrintExit2 warning $0 ("Running script '" . $Script . "' failed!") false; + } +} diff --git a/leds-day-mode b/leds-day-mode index ca2e8d8..2da00ca 100644 --- a/leds-day-mode +++ b/leds-day-mode @@ -1,9 +1,3 @@ #!rsc by RouterOS -# RouterOS script: leds-day-mode -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# enable LEDs -# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md - -/system/leds/settings/set all-leds-off=never; +# dummy for migration diff --git a/leds-day-mode.rsc b/leds-day-mode.rsc new file mode 100644 index 0000000..ca2e8d8 --- /dev/null +++ b/leds-day-mode.rsc @@ -0,0 +1,9 @@ +#!rsc by RouterOS +# RouterOS script: leds-day-mode +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# enable LEDs +# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md + +/system/leds/settings/set all-leds-off=never; diff --git a/leds-night-mode b/leds-night-mode index cdd8127..2da00ca 100644 --- a/leds-night-mode +++ b/leds-night-mode @@ -1,9 +1,3 @@ #!rsc by RouterOS -# RouterOS script: leds-night-mode -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# disable LEDs -# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md - -/system/leds/settings/set all-leds-off=immediate; +# dummy for migration diff --git a/leds-night-mode.rsc b/leds-night-mode.rsc new file mode 100644 index 0000000..cdd8127 --- /dev/null +++ b/leds-night-mode.rsc @@ -0,0 +1,9 @@ +#!rsc by RouterOS +# RouterOS script: leds-night-mode +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# disable LEDs +# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md + +/system/leds/settings/set all-leds-off=immediate; diff --git a/leds-toggle-mode b/leds-toggle-mode index da972b7..2da00ca 100644 --- a/leds-toggle-mode +++ b/leds-toggle-mode @@ -1,13 +1,3 @@ #!rsc by RouterOS -# RouterOS script: leds-toggle-mode -# Copyright (c) 2018-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# toggle LEDs mode -# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md - -:if ([ /system/leds/settings/get all-leds-off ] = "never") do={ - /system/leds/settings/set all-leds-off=immediate; -} else={ - /system/leds/settings/set all-leds-off=never; -} +# dummy for migration diff --git a/leds-toggle-mode.rsc b/leds-toggle-mode.rsc new file mode 100644 index 0000000..da972b7 --- /dev/null +++ b/leds-toggle-mode.rsc @@ -0,0 +1,13 @@ +#!rsc by RouterOS +# RouterOS script: leds-toggle-mode +# Copyright (c) 2018-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# toggle LEDs mode +# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md + +:if ([ /system/leds/settings/get all-leds-off ] = "never") do={ + /system/leds/settings/set all-leds-off=immediate; +} else={ + /system/leds/settings/set all-leds-off=never; +} diff --git a/log-forward b/log-forward index 96cb257..2da00ca 100644 --- a/log-forward +++ b/log-forward @@ -1,90 +1,3 @@ #!rsc by RouterOS -# RouterOS script: log-forward -# Copyright (c) 2020-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# forward log messages via notification -# https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md - -:local 0 "log-forward"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Identity; -:global LogForwardFilter; -:global LogForwardFilterMessage; -:global LogForwardInclude; -:global LogForwardIncludeMessage; -:global LogForwardLast; -:global LogForwardRateLimit; -:global NotificationsWithSymbols; - -:global EitherOr; -:global HexToNum; -:global IfThenElse; -:global LogForwardFilterLogForwarding; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; - -$ScriptLock $0; - -:if ([ :typeof $LogForwardRateLimit ] = "nothing") do={ - :set LogForwardRateLimit 0; -} - -:if ($LogForwardRateLimit > 30) do={ - :set LogForwardRateLimit ($LogForwardRateLimit - 1); - $LogPrintExit2 info $0 ("Rate limit in action, not forwarding logs, if any!") true; -} - -:local Count 0; -:local Duplicates false; -:local Last [ $IfThenElse ([ :len $LogForwardLast ] > 0) [ $HexToNum $LogForwardLast ] -1 ]; -:local Messages ""; -:local Warning false; -:local MessageVal; -:local MessageDups ({}); - -:local LogForwardFilterLogForwardingCached [ $EitherOr [ $LogForwardFilterLogForwarding ] ("\$^") ]; -:foreach Message in=[ /log/find where (!(message="") and \ - !(message~$LogForwardFilterLogForwardingCached) and \ - !(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \ - topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={ - :set MessageVal [ /log/get $Message ]; - - :if ($Last < [ $HexToNum ($MessageVal->".id") ]) do={ - :local DupCount ($MessageDups->($MessageVal->"message")); - :if ($MessageVal->"topics" ~ "(emergency|alert|critical|error|warning)") do={ - :set Warning true; - } - :if ($DupCount < 3) do={ - :set Messages ($Messages . "\n" . [ $IfThenElse ($NotificationsWithSymbols = true) (" \E2\97\8F ") ] . \ - $MessageVal->"time" . " " . [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message"); - } else={ - :set Duplicates true; - } - :set ($MessageDups->($MessageVal->"message")) ($DupCount + 1); - :set Count ($Count + 1); - } -} - -:if ($Count > 0) do={ - :set LogForwardRateLimit ($LogForwardRateLimit + 10); - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification [ $IfThenElse ($Warning = true) "warning-sign" "memo" ] ] . \ - "Log Forwarding"); \ - message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) "this message" \ - ("these " . $Count . " messages") ] . " after " . [ /system/resource/get uptime ] . " uptime." . \ - [ $IfThenElse ($Duplicates = true) (" Multi-repeated messages have been skipped.") ] . \ - [ $IfThenElse ($LogForwardRateLimit > 30) ("\nRate limit in action, delaying forwarding.") ] . \ - "\n" . $Messages) }); - - :set LogForwardLast ($MessageVal->".id"); -} else={ - :if ($LogForwardRateLimit > 0) do={ - :set LogForwardRateLimit ($LogForwardRateLimit - 1); - } -} +# dummy for migration diff --git a/log-forward.rsc b/log-forward.rsc new file mode 100644 index 0000000..96cb257 --- /dev/null +++ b/log-forward.rsc @@ -0,0 +1,90 @@ +#!rsc by RouterOS +# RouterOS script: log-forward +# Copyright (c) 2020-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# forward log messages via notification +# https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md + +:local 0 "log-forward"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Identity; +:global LogForwardFilter; +:global LogForwardFilterMessage; +:global LogForwardInclude; +:global LogForwardIncludeMessage; +:global LogForwardLast; +:global LogForwardRateLimit; +:global NotificationsWithSymbols; + +:global EitherOr; +:global HexToNum; +:global IfThenElse; +:global LogForwardFilterLogForwarding; +:global LogPrintExit2; +:global ScriptLock; +:global SendNotification2; +:global SymbolForNotification; + +$ScriptLock $0; + +:if ([ :typeof $LogForwardRateLimit ] = "nothing") do={ + :set LogForwardRateLimit 0; +} + +:if ($LogForwardRateLimit > 30) do={ + :set LogForwardRateLimit ($LogForwardRateLimit - 1); + $LogPrintExit2 info $0 ("Rate limit in action, not forwarding logs, if any!") true; +} + +:local Count 0; +:local Duplicates false; +:local Last [ $IfThenElse ([ :len $LogForwardLast ] > 0) [ $HexToNum $LogForwardLast ] -1 ]; +:local Messages ""; +:local Warning false; +:local MessageVal; +:local MessageDups ({}); + +:local LogForwardFilterLogForwardingCached [ $EitherOr [ $LogForwardFilterLogForwarding ] ("\$^") ]; +:foreach Message in=[ /log/find where (!(message="") and \ + !(message~$LogForwardFilterLogForwardingCached) and \ + !(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \ + topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={ + :set MessageVal [ /log/get $Message ]; + + :if ($Last < [ $HexToNum ($MessageVal->".id") ]) do={ + :local DupCount ($MessageDups->($MessageVal->"message")); + :if ($MessageVal->"topics" ~ "(emergency|alert|critical|error|warning)") do={ + :set Warning true; + } + :if ($DupCount < 3) do={ + :set Messages ($Messages . "\n" . [ $IfThenElse ($NotificationsWithSymbols = true) (" \E2\97\8F ") ] . \ + $MessageVal->"time" . " " . [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message"); + } else={ + :set Duplicates true; + } + :set ($MessageDups->($MessageVal->"message")) ($DupCount + 1); + :set Count ($Count + 1); + } +} + +:if ($Count > 0) do={ + :set LogForwardRateLimit ($LogForwardRateLimit + 10); + + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification [ $IfThenElse ($Warning = true) "warning-sign" "memo" ] ] . \ + "Log Forwarding"); \ + message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) "this message" \ + ("these " . $Count . " messages") ] . " after " . [ /system/resource/get uptime ] . " uptime." . \ + [ $IfThenElse ($Duplicates = true) (" Multi-repeated messages have been skipped.") ] . \ + [ $IfThenElse ($LogForwardRateLimit > 30) ("\nRate limit in action, delaying forwarding.") ] . \ + "\n" . $Messages) }); + + :set LogForwardLast ($MessageVal->".id"); +} else={ + :if ($LogForwardRateLimit > 0) do={ + :set LogForwardRateLimit ($LogForwardRateLimit - 1); + } +} diff --git a/mod/bridge-port-to b/mod/bridge-port-to index f752d30..2da00ca 100644 --- a/mod/bridge-port-to +++ b/mod/bridge-port-to @@ -1,65 +1,3 @@ #!rsc by RouterOS -# RouterOS script: mod/bridge-port-to -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# reset bridge ports to default bridge -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-to.md - -:global BridgePortTo; - -:set BridgePortTo do={ - :local BridgePortTo [ :tostr $1 ]; - - :global IfThenElse; - :global LogPrintExit2; - :global ParseKeyValueStore; - - :local InterfaceReEnable ({}); - :foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={ - :local BridgePortVal [ /interface/bridge/port/get $BridgePort ]; - :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ - :if ($Config = $BridgePortTo) do={ - :local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; - - :if ($BridgeDefault = "dhcp-client") do={ - :if ([ :len $DHCPClient ] != 1) do={ - $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ - " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; - } - :local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ]; - - :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ - $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; - /interface/bridge/port/disable $BridgePort; - :delay 200ms; - /ip/dhcp-client/enable $DHCPClient; - } - } else={ - :if ($BridgePortVal->"disabled" = true || $BridgeDefault != $BridgePortVal->"bridge") do={ - $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ - " bridge " . $BridgeDefault . ", disabling dhcp client.") false; - :if ([ :len $DHCPClient ] = 1) do={ - /ip/dhcp-client/disable $DHCPClient; - :delay 200ms; - } - :local Disable [ /interface/ethernet/find where name=$BridgePortVal->"interface" ]; - :if ([ :len $Disable ] > 0) do={ - /interface/ethernet/disable $Disable; - :set InterfaceReEnable ($InterfaceReEnable, $Disable); - } - /interface/bridge/port/set disabled=no bridge=$BridgeDefault $BridgePort; - } else={ - $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ - " bridge " . $BridgeDefault . ".") false; - } - } - } - } - } - :if ([ :len $InterfaceReEnable ] > 0) do={ - :delay 2s; - $LogPrintExit2 info $0 ("Re-enabling interfaces...") false; - /interface/ethernet/enable $InterfaceReEnable; - } -} +# dummy for migration diff --git a/mod/bridge-port-to.rsc b/mod/bridge-port-to.rsc new file mode 100644 index 0000000..f752d30 --- /dev/null +++ b/mod/bridge-port-to.rsc @@ -0,0 +1,65 @@ +#!rsc by RouterOS +# RouterOS script: mod/bridge-port-to +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# reset bridge ports to default bridge +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-to.md + +:global BridgePortTo; + +:set BridgePortTo do={ + :local BridgePortTo [ :tostr $1 ]; + + :global IfThenElse; + :global LogPrintExit2; + :global ParseKeyValueStore; + + :local InterfaceReEnable ({}); + :foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={ + :local BridgePortVal [ /interface/bridge/port/get $BridgePort ]; + :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ + :if ($Config = $BridgePortTo) do={ + :local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; + + :if ($BridgeDefault = "dhcp-client") do={ + :if ([ :len $DHCPClient ] != 1) do={ + $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ + " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; + } + :local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ]; + + :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ + $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; + /interface/bridge/port/disable $BridgePort; + :delay 200ms; + /ip/dhcp-client/enable $DHCPClient; + } + } else={ + :if ($BridgePortVal->"disabled" = true || $BridgeDefault != $BridgePortVal->"bridge") do={ + $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ + " bridge " . $BridgeDefault . ", disabling dhcp client.") false; + :if ([ :len $DHCPClient ] = 1) do={ + /ip/dhcp-client/disable $DHCPClient; + :delay 200ms; + } + :local Disable [ /interface/ethernet/find where name=$BridgePortVal->"interface" ]; + :if ([ :len $Disable ] > 0) do={ + /interface/ethernet/disable $Disable; + :set InterfaceReEnable ($InterfaceReEnable, $Disable); + } + /interface/bridge/port/set disabled=no bridge=$BridgeDefault $BridgePort; + } else={ + $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ + " bridge " . $BridgeDefault . ".") false; + } + } + } + } + } + :if ([ :len $InterfaceReEnable ] > 0) do={ + :delay 2s; + $LogPrintExit2 info $0 ("Re-enabling interfaces...") false; + /interface/ethernet/enable $InterfaceReEnable; + } +} diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan index 8fb64e1..2da00ca 100644 --- a/mod/bridge-port-vlan +++ b/mod/bridge-port-vlan @@ -1,73 +1,3 @@ #!rsc by RouterOS -# RouterOS script: mod/bridge-port-vlan -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# manage VLANs on bridge ports -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-vlan.md - -:global BridgePortVlan; - -:global BridgePortVlan do={ - :local ConfigTo [ :tostr $1 ]; - - :global IfThenElse; - :global LogPrintExit2; - :global ParseKeyValueStore; - - :local InterfaceReEnable ({}); - :foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={ - :local BridgePortVal [ /interface/bridge/port/get $BridgePort ]; - :foreach Config,Vlan in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ - :if ($Config = $ConfigTo) do={ - :local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; - - :if ($Vlan = "dhcp-client") do={ - :if ([ :len $DHCPClient ] != 1) do={ - $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ - " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; - } - :local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ]; - - :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ - $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; - /interface/bridge/port/disable $BridgePort; - :delay 200ms; - /ip/dhcp-client/enable $DHCPClient; - } - } else={ - :local VlanName $Vlan; - :if ($Vlan != [ :tostr [ :tonum $Vlan ] ]) do={ - :do { - :set $Vlan ([ /interface/bridge/vlan/get [ find where comment=$Vlan ] vlan-ids ]->0); - } on-error={ - $LogPrintExit2 warning $0 ("Could not find VLAN '" . $Vlan . "' for interface " . $BridgePortVal->"interface" . "!") true; - } - } - :if ($BridgePortVal->"disabled" = true || $Vlan != $BridgePortVal->"pvid") do={ - $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $ConfigTo . \ - " vlan " . $Vlan . [ $IfThenElse ($Vlan != $VlanName) (" (" . $VlanName . ")") ] . ", disabling dhcp client.") false; - :if ([ :len $DHCPClient ] = 1) do={ - /ip/dhcp-client/disable $DHCPClient; - :delay 200ms; - } - :local Disable [ /interface/ethernet/find where name=$BridgePortVal->"interface" ]; - :if ([ :len $Disable ] > 0) do={ - /interface/ethernet/disable $Disable; - :set InterfaceReEnable ($InterfaceReEnable, $Disable); - } - /interface/bridge/port/set disabled=no pvid=$Vlan $BridgePort; - } else={ - $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \ - " vlan " . $Vlan . ".") false; - } - } - } - } - } - :if ([ :len $InterfaceReEnable ] > 0) do={ - :delay 2s; - $LogPrintExit2 info $0 ("Re-enabling interfaces...") false; - /interface/ethernet/enable $InterfaceReEnable; - } -} +# dummy for migration diff --git a/mod/bridge-port-vlan.rsc b/mod/bridge-port-vlan.rsc new file mode 100644 index 0000000..8fb64e1 --- /dev/null +++ b/mod/bridge-port-vlan.rsc @@ -0,0 +1,73 @@ +#!rsc by RouterOS +# RouterOS script: mod/bridge-port-vlan +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# manage VLANs on bridge ports +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-vlan.md + +:global BridgePortVlan; + +:global BridgePortVlan do={ + :local ConfigTo [ :tostr $1 ]; + + :global IfThenElse; + :global LogPrintExit2; + :global ParseKeyValueStore; + + :local InterfaceReEnable ({}); + :foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={ + :local BridgePortVal [ /interface/bridge/port/get $BridgePort ]; + :foreach Config,Vlan in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ + :if ($Config = $ConfigTo) do={ + :local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; + + :if ($Vlan = "dhcp-client") do={ + :if ([ :len $DHCPClient ] != 1) do={ + $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ + " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; + } + :local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ]; + + :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ + $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; + /interface/bridge/port/disable $BridgePort; + :delay 200ms; + /ip/dhcp-client/enable $DHCPClient; + } + } else={ + :local VlanName $Vlan; + :if ($Vlan != [ :tostr [ :tonum $Vlan ] ]) do={ + :do { + :set $Vlan ([ /interface/bridge/vlan/get [ find where comment=$Vlan ] vlan-ids ]->0); + } on-error={ + $LogPrintExit2 warning $0 ("Could not find VLAN '" . $Vlan . "' for interface " . $BridgePortVal->"interface" . "!") true; + } + } + :if ($BridgePortVal->"disabled" = true || $Vlan != $BridgePortVal->"pvid") do={ + $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $ConfigTo . \ + " vlan " . $Vlan . [ $IfThenElse ($Vlan != $VlanName) (" (" . $VlanName . ")") ] . ", disabling dhcp client.") false; + :if ([ :len $DHCPClient ] = 1) do={ + /ip/dhcp-client/disable $DHCPClient; + :delay 200ms; + } + :local Disable [ /interface/ethernet/find where name=$BridgePortVal->"interface" ]; + :if ([ :len $Disable ] > 0) do={ + /interface/ethernet/disable $Disable; + :set InterfaceReEnable ($InterfaceReEnable, $Disable); + } + /interface/bridge/port/set disabled=no pvid=$Vlan $BridgePort; + } else={ + $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \ + " vlan " . $Vlan . ".") false; + } + } + } + } + } + :if ([ :len $InterfaceReEnable ] > 0) do={ + :delay 2s; + $LogPrintExit2 info $0 ("Re-enabling interfaces...") false; + /interface/ethernet/enable $InterfaceReEnable; + } +} diff --git a/mod/inspectvar b/mod/inspectvar index 8bb5c5f..2da00ca 100644 --- a/mod/inspectvar +++ b/mod/inspectvar @@ -1,54 +1,3 @@ #!rsc by RouterOS -# RouterOS script: mod/inspectvar -# Copyright (c) 2020-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md - -:global InspectVar; -:global InspectVarReturn; - -# inspect variable and print on terminal -:set InspectVar do={ - :global InspectVarReturn; - :global PrettyPrint; - - $PrettyPrint [ $InspectVarReturn $1 ]; -} - -# inspect variable and return formatted string -:set InspectVarReturn do={ - :local Input $1; - :local Level (0 + [ :tonum $2 ]); - - :global IfThenElse; - :global InspectVarReturn; - - :local IndentReturn do={ - :local Prefix [ :tostr $1 ]; - :local Value [ :tostr $2 ]; - :local Level [ :tonum $3 ]; - - :local Indent ""; - :for I from=1 to=$Level step=1 do={ - :set Indent ($Indent . " "); - } - :return ($Indent . "-" . $Prefix . "-> " . $Value); - } - - :local TypeOf [ :typeof $Input ]; - :local Return [ $IndentReturn "type" $TypeOf $Level ]; - - :if ($TypeOf = "array") do={ - :foreach Key,Value in=$Input do={ - :set $Return ($Return . "\n" . \ - [ $IndentReturn "key" $Key ($Level + 1) ] . "\n" . \ - [ $InspectVarReturn $Value ($Level + 2) ]); - } - } else={ - :if ($TypeOf != "nothing") do={ - :set $Return ($Return . "\n" . \ - [ $IndentReturn "value" [ $IfThenElse ([ :len $Input ] > 80) \ - ([ :pick $Input 0 77 ] . "...") $Input ] $Level ]); - } - } - :return $Return; -} +# +# dummy for migration diff --git a/mod/inspectvar.rsc b/mod/inspectvar.rsc new file mode 100644 index 0000000..8bb5c5f --- /dev/null +++ b/mod/inspectvar.rsc @@ -0,0 +1,54 @@ +#!rsc by RouterOS +# RouterOS script: mod/inspectvar +# Copyright (c) 2020-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global InspectVar; +:global InspectVarReturn; + +# inspect variable and print on terminal +:set InspectVar do={ + :global InspectVarReturn; + :global PrettyPrint; + + $PrettyPrint [ $InspectVarReturn $1 ]; +} + +# inspect variable and return formatted string +:set InspectVarReturn do={ + :local Input $1; + :local Level (0 + [ :tonum $2 ]); + + :global IfThenElse; + :global InspectVarReturn; + + :local IndentReturn do={ + :local Prefix [ :tostr $1 ]; + :local Value [ :tostr $2 ]; + :local Level [ :tonum $3 ]; + + :local Indent ""; + :for I from=1 to=$Level step=1 do={ + :set Indent ($Indent . " "); + } + :return ($Indent . "-" . $Prefix . "-> " . $Value); + } + + :local TypeOf [ :typeof $Input ]; + :local Return [ $IndentReturn "type" $TypeOf $Level ]; + + :if ($TypeOf = "array") do={ + :foreach Key,Value in=$Input do={ + :set $Return ($Return . "\n" . \ + [ $IndentReturn "key" $Key ($Level + 1) ] . "\n" . \ + [ $InspectVarReturn $Value ($Level + 2) ]); + } + } else={ + :if ($TypeOf != "nothing") do={ + :set $Return ($Return . "\n" . \ + [ $IndentReturn "value" [ $IfThenElse ([ :len $Input ] > 80) \ + ([ :pick $Input 0 77 ] . "...") $Input ] $Level ]); + } + } + :return $Return; +} diff --git a/mod/ipcalc b/mod/ipcalc index 92e246f..2da00ca 100644 --- a/mod/ipcalc +++ b/mod/ipcalc @@ -1,46 +1,3 @@ #!rsc by RouterOS -# RouterOS script: mod/ipcalc -# Copyright (c) 2020-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md - -:global IPCalc; -:global IPCalcReturn; - -# print netmask, network, min host, max host and broadcast -:set IPCalc do={ - :local Input [ :tostr $1 ]; - - :global IPCalcReturn; - :global PrettyPrint; - - :local Values [ $IPCalcReturn $1 ]; - - $PrettyPrint ( \ - "Address: " . $Values->"address" . "\n" . \ - "Netmask: " . $Values->"netmask" . "\n" . \ - "Network: " . $Values->"network" . "\n" . \ - "HostMin: " . $Values->"hostmin" . "\n" . \ - "HostMax: " . $Values->"hostmax" . "\n" . \ - "Broadcast: " . $Values->"broadcast"); -} - -# calculate and return netmask, network, min host, max host and broadcast -:set IPCalcReturn do={ - :local Input [ :tostr $1 ]; - :local Address [ :toip [ :pick $Input 0 [ :find $Input "/" ] ] ]; - :local Bits [ :tonum [ :pick $Input ([ :find $Input "/" ] + 1) [ :len $Input ] ] ]; - :local Mask ((255.255.255.255 << (32 - $Bits)) & 255.255.255.255); - - :local Return { - "address"=$Address; - "netmask"=$Mask; - "networkaddress"=($Address & $Mask); - "networkbits"=$Bits; - "network"=(($Address & $Mask) . "/" . $Bits); - "hostmin"=(($Address & $Mask) | 0.0.0.1); - "hostmax"=(($Address | ~$Mask) ^ 0.0.0.1); - "broadcast"=($Address | ~$Mask); - } - - :return $Return; -} +# +# dummy for migration diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc new file mode 100644 index 0000000..92e246f --- /dev/null +++ b/mod/ipcalc.rsc @@ -0,0 +1,46 @@ +#!rsc by RouterOS +# RouterOS script: mod/ipcalc +# Copyright (c) 2020-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global IPCalc; +:global IPCalcReturn; + +# print netmask, network, min host, max host and broadcast +:set IPCalc do={ + :local Input [ :tostr $1 ]; + + :global IPCalcReturn; + :global PrettyPrint; + + :local Values [ $IPCalcReturn $1 ]; + + $PrettyPrint ( \ + "Address: " . $Values->"address" . "\n" . \ + "Netmask: " . $Values->"netmask" . "\n" . \ + "Network: " . $Values->"network" . "\n" . \ + "HostMin: " . $Values->"hostmin" . "\n" . \ + "HostMax: " . $Values->"hostmax" . "\n" . \ + "Broadcast: " . $Values->"broadcast"); +} + +# calculate and return netmask, network, min host, max host and broadcast +:set IPCalcReturn do={ + :local Input [ :tostr $1 ]; + :local Address [ :toip [ :pick $Input 0 [ :find $Input "/" ] ] ]; + :local Bits [ :tonum [ :pick $Input ([ :find $Input "/" ] + 1) [ :len $Input ] ] ]; + :local Mask ((255.255.255.255 << (32 - $Bits)) & 255.255.255.255); + + :local Return { + "address"=$Address; + "netmask"=$Mask; + "networkaddress"=($Address & $Mask); + "networkbits"=$Bits; + "network"=(($Address & $Mask) . "/" . $Bits); + "hostmin"=(($Address & $Mask) | 0.0.0.1); + "hostmax"=(($Address | ~$Mask) ^ 0.0.0.1); + "broadcast"=($Address | ~$Mask); + } + + :return $Return; +} diff --git a/mod/notification-email b/mod/notification-email index b03e176..2da00ca 100644 --- a/mod/notification-email +++ b/mod/notification-email @@ -1,206 +1,3 @@ #!rsc by RouterOS -# RouterOS script: mod/notification-email -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md - -:global FlushEmailQueue; -:global LogForwardFilterLogForwarding; -:global NotificationEMailSubject; -:global NotificationFunctions; -:global QuotedPrintable; -:global SendEMail; -:global SendEMail2; - -# flush e-mail queue -:set FlushEmailQueue do={ - :global EmailQueue; - - :global EitherOr; - :global IsDNSResolving; - :global IsTimeSync; - :global LogPrintExit2; - - :local AllDone true; - :local QueueLen [ :len $EmailQueue ]; - :local Scheduler [ /system/scheduler/find where name=$0 ]; - - :if ([ :len $Scheduler ] > 0 && [ /system/scheduler/get $Scheduler interval ] < 1m) do={ - /system/scheduler/set interval=1m comment="Doing initial checks..." $Scheduler; - } - - :if ([ /tool/e-mail/get last-status ] = "in-progress") do={ - $LogPrintExit2 debug $0 ("Sending mail is currently in progress, not flushing.") false; - :return false; - } - - :if ([ $IsTimeSync ] = false) do={ - $LogPrintExit2 debug $0 ("Time is not synced, not flushing.") false; - :return false; - } - - :if ([ :typeof [ :toip [ /tool/e-mail/get address ] ] ] != "ip" && [ $IsDNSResolving ] = false) do={ - $LogPrintExit2 debug $0 ("Server address is a DNS name and resolving fails, not flushing.") false; - :return false; - } - - :if ([ :len $Scheduler ] > 0 && $QueueLen = 0) do={ - $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; - } - - /system/scheduler/set interval=([ $EitherOr $QueueLen 1 ] . "m") comment="Sending..." $Scheduler; - - :foreach Id,Message in=$EmailQueue do={ - :if ([ :typeof $Message ] = "array" ) do={ - :local Attach ({}); - :while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; } - :foreach File in=[ :toarray [ $EitherOr ($Message->"attach") "" ] ] do={ - :if ([ :len [ /file/find where name=$File ] ] = 1) do={ - :set Attach ($Attach, $File); - } else={ - $LogPrintExit2 warning $0 ("File '" . $File . "' does not exist, can not attach.") false; - } - } - /tool/e-mail/send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \ - body=($Message->"body") file=$Attach; - :local Wait true; - :do { - :delay 1s; - :local Status [ /tool/e-mail/get last-status ]; - :if ($Status = "succeeded") do={ - :set ($EmailQueue->$Id); - :set Wait false; - :if (($Message->"remove-attach") = true) do={ - :foreach File in=$Attach do={ - /file/remove $File; - } - } - } - :if ($Status = "failed") do={ - :set AllDone false; - :set Wait false; - } - } while=($Wait = true); - } - } - - :if ($AllDone = true && $QueueLen = [ :len $EmailQueue ]) do={ - /system/scheduler/remove $Scheduler; - :set EmailQueue; - } else={ - /system/scheduler/set interval=1m comment="Waiting for retry..." $Scheduler; - } -} - -# generate filter for log-forward -:set LogForwardFilterLogForwarding do={ - :global EscapeForRegEx; - :global NotificationEMailSubject; - :global SymbolForNotification; - - :return ("^Error sending e-mail <(" . \ - [ $EscapeForRegEx [ $NotificationEMailSubject ([ $SymbolForNotification \ - "memo" ] . "Log Forwarding") ] ] . "|" . \ - [ $EscapeForRegEx [ $NotificationEMailSubject ([ $SymbolForNotification \ - "warning-sign" ] . "Log Forwarding") ] ] . ")>:"); -} - -# generate the e-mail subject -:set NotificationEMailSubject do={ - :global Identity; - :global IdentityExtra; - - :global QuotedPrintable; - - :return [ $QuotedPrintable ("[" . $IdentityExtra . $Identity . "] " . $1) ]; -} - -# send notification via e-mail - expects one array argument -:set ($NotificationFunctions->"email") do={ - :local Notification $1; - - :global EmailGeneralTo; - :global EmailGeneralToOverride; - :global EmailGeneralCc; - :global EmailGeneralCcOverride; - :global EmailQueue; - - :global EitherOr; - :global IfThenElse; - :global NotificationEMailSubject; - - :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; - :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; - - :local EMailSettings [ /tool/e-mail/get ]; - :if ([ :len $To ] = 0 || ($EMailSettings->"address") = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={ - :return false; - } - - :if ([ :typeof $EmailQueue ] = "nothing") do={ - :set EmailQueue ({}); - } - :local Signature [ /system/note/get note ]; - :set ($EmailQueue->[ :len $EmailQueue ]) { - to=$To; cc=$Cc; - subject=[ $NotificationEMailSubject ($Notification->"subject") ]; - body=(($Notification->"message") . \ - [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ - [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \ - attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") }; - :if ([ :len [ /system/scheduler/find where name="\$FlushEmailQueue" ] ] = 0) do={ - /system/scheduler/add name="\$FlushEmailQueue" interval=1s start-time=startup \ - comment="Queuing new mail..." on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); - } -} - -# convert string to quoted-printable -:global QuotedPrintable do={ - :local Input [ :tostr $1 ]; - - :if ([ :len $Input ] = 0) do={ - :return $Input; - } - - :local Return ""; - :local Chars ("\80\81\82\83\84\85\86\87\88\89\8A\8B\8C\8D\8E\8F\90\91\92\93\94\95\96\97" . \ - "\98\99\9A\9B\9C\9D\9E\9F\A0\A1\A2\A3\A4\A5\A6\A7\A8\A9\AA\AB\AC\AD\AE\AF\B0\B1\B2\B3" . \ - "\B4\B5\B6\B7\B8\B9\BA\BB\BC\BD\BE\BF\C0\C1\C2\C3\C4\C5\C6\C7\C8\C9\CA\CB\CC\CD\CE\CF" . \ - "\D0\D1\D2\D3\D4\D5\D6\D7\D8\D9\DA\DB\DC\DD\DE\DF\E0\E1\E2\E3\E4\E5\E6\E7\E8\E9\EA\EB" . \ - "\EC\ED\EE\EF\F0\F1\F2\F3\F4\F5\F6\F7\F8\F9\FA\FB\FC\FD\FE\FF"); - :local Hex { "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"; "9"; "A"; "B"; "C"; "D"; "E"; "F" }; - - :for I from=0 to=([ :len $Input ] - 1) do={ - :local Char [ :pick $Input $I ]; - :local Replace [ :find $Chars $Char ]; - - :if ($Char = "=") do={ - :set Char "=3D"; - } - :if ([ :typeof $Replace ] = "num") do={ - :set Char ("=" . ($Hex->($Replace / 16 + 8)) . ($Hex->($Replace % 16))); - } - :set Return ($Return . $Char); - } - - :if ($Input = $Return) do={ - :return $Input; - } - - :return ("=\?utf-8\?Q\?" . $Return . "\?="); -} - -# send notification via e-mail - expects at least two string arguments -:set SendEMail do={ - :global SendEMail2; - - $SendEMail2 ({ subject=$1; message=$2; link=$3 }); -} - -# send notification via e-mail - expects one array argument -:set SendEMail2 do={ - :local Notification $1; - - :global NotificationFunctions; - - ($NotificationFunctions->"email") ("\$NotificationFunctions->\"email\"") $Notification; -} +# +# dummy for migration diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc new file mode 100644 index 0000000..b03e176 --- /dev/null +++ b/mod/notification-email.rsc @@ -0,0 +1,206 @@ +#!rsc by RouterOS +# RouterOS script: mod/notification-email +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global FlushEmailQueue; +:global LogForwardFilterLogForwarding; +:global NotificationEMailSubject; +:global NotificationFunctions; +:global QuotedPrintable; +:global SendEMail; +:global SendEMail2; + +# flush e-mail queue +:set FlushEmailQueue do={ + :global EmailQueue; + + :global EitherOr; + :global IsDNSResolving; + :global IsTimeSync; + :global LogPrintExit2; + + :local AllDone true; + :local QueueLen [ :len $EmailQueue ]; + :local Scheduler [ /system/scheduler/find where name=$0 ]; + + :if ([ :len $Scheduler ] > 0 && [ /system/scheduler/get $Scheduler interval ] < 1m) do={ + /system/scheduler/set interval=1m comment="Doing initial checks..." $Scheduler; + } + + :if ([ /tool/e-mail/get last-status ] = "in-progress") do={ + $LogPrintExit2 debug $0 ("Sending mail is currently in progress, not flushing.") false; + :return false; + } + + :if ([ $IsTimeSync ] = false) do={ + $LogPrintExit2 debug $0 ("Time is not synced, not flushing.") false; + :return false; + } + + :if ([ :typeof [ :toip [ /tool/e-mail/get address ] ] ] != "ip" && [ $IsDNSResolving ] = false) do={ + $LogPrintExit2 debug $0 ("Server address is a DNS name and resolving fails, not flushing.") false; + :return false; + } + + :if ([ :len $Scheduler ] > 0 && $QueueLen = 0) do={ + $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; + } + + /system/scheduler/set interval=([ $EitherOr $QueueLen 1 ] . "m") comment="Sending..." $Scheduler; + + :foreach Id,Message in=$EmailQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :local Attach ({}); + :while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; } + :foreach File in=[ :toarray [ $EitherOr ($Message->"attach") "" ] ] do={ + :if ([ :len [ /file/find where name=$File ] ] = 1) do={ + :set Attach ($Attach, $File); + } else={ + $LogPrintExit2 warning $0 ("File '" . $File . "' does not exist, can not attach.") false; + } + } + /tool/e-mail/send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \ + body=($Message->"body") file=$Attach; + :local Wait true; + :do { + :delay 1s; + :local Status [ /tool/e-mail/get last-status ]; + :if ($Status = "succeeded") do={ + :set ($EmailQueue->$Id); + :set Wait false; + :if (($Message->"remove-attach") = true) do={ + :foreach File in=$Attach do={ + /file/remove $File; + } + } + } + :if ($Status = "failed") do={ + :set AllDone false; + :set Wait false; + } + } while=($Wait = true); + } + } + + :if ($AllDone = true && $QueueLen = [ :len $EmailQueue ]) do={ + /system/scheduler/remove $Scheduler; + :set EmailQueue; + } else={ + /system/scheduler/set interval=1m comment="Waiting for retry..." $Scheduler; + } +} + +# generate filter for log-forward +:set LogForwardFilterLogForwarding do={ + :global EscapeForRegEx; + :global NotificationEMailSubject; + :global SymbolForNotification; + + :return ("^Error sending e-mail <(" . \ + [ $EscapeForRegEx [ $NotificationEMailSubject ([ $SymbolForNotification \ + "memo" ] . "Log Forwarding") ] ] . "|" . \ + [ $EscapeForRegEx [ $NotificationEMailSubject ([ $SymbolForNotification \ + "warning-sign" ] . "Log Forwarding") ] ] . ")>:"); +} + +# generate the e-mail subject +:set NotificationEMailSubject do={ + :global Identity; + :global IdentityExtra; + + :global QuotedPrintable; + + :return [ $QuotedPrintable ("[" . $IdentityExtra . $Identity . "] " . $1) ]; +} + +# send notification via e-mail - expects one array argument +:set ($NotificationFunctions->"email") do={ + :local Notification $1; + + :global EmailGeneralTo; + :global EmailGeneralToOverride; + :global EmailGeneralCc; + :global EmailGeneralCcOverride; + :global EmailQueue; + + :global EitherOr; + :global IfThenElse; + :global NotificationEMailSubject; + + :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; + :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; + + :local EMailSettings [ /tool/e-mail/get ]; + :if ([ :len $To ] = 0 || ($EMailSettings->"address") = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={ + :return false; + } + + :if ([ :typeof $EmailQueue ] = "nothing") do={ + :set EmailQueue ({}); + } + :local Signature [ /system/note/get note ]; + :set ($EmailQueue->[ :len $EmailQueue ]) { + to=$To; cc=$Cc; + subject=[ $NotificationEMailSubject ($Notification->"subject") ]; + body=(($Notification->"message") . \ + [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ + [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \ + attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") }; + :if ([ :len [ /system/scheduler/find where name="\$FlushEmailQueue" ] ] = 0) do={ + /system/scheduler/add name="\$FlushEmailQueue" interval=1s start-time=startup \ + comment="Queuing new mail..." on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); + } +} + +# convert string to quoted-printable +:global QuotedPrintable do={ + :local Input [ :tostr $1 ]; + + :if ([ :len $Input ] = 0) do={ + :return $Input; + } + + :local Return ""; + :local Chars ("\80\81\82\83\84\85\86\87\88\89\8A\8B\8C\8D\8E\8F\90\91\92\93\94\95\96\97" . \ + "\98\99\9A\9B\9C\9D\9E\9F\A0\A1\A2\A3\A4\A5\A6\A7\A8\A9\AA\AB\AC\AD\AE\AF\B0\B1\B2\B3" . \ + "\B4\B5\B6\B7\B8\B9\BA\BB\BC\BD\BE\BF\C0\C1\C2\C3\C4\C5\C6\C7\C8\C9\CA\CB\CC\CD\CE\CF" . \ + "\D0\D1\D2\D3\D4\D5\D6\D7\D8\D9\DA\DB\DC\DD\DE\DF\E0\E1\E2\E3\E4\E5\E6\E7\E8\E9\EA\EB" . \ + "\EC\ED\EE\EF\F0\F1\F2\F3\F4\F5\F6\F7\F8\F9\FA\FB\FC\FD\FE\FF"); + :local Hex { "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"; "9"; "A"; "B"; "C"; "D"; "E"; "F" }; + + :for I from=0 to=([ :len $Input ] - 1) do={ + :local Char [ :pick $Input $I ]; + :local Replace [ :find $Chars $Char ]; + + :if ($Char = "=") do={ + :set Char "=3D"; + } + :if ([ :typeof $Replace ] = "num") do={ + :set Char ("=" . ($Hex->($Replace / 16 + 8)) . ($Hex->($Replace % 16))); + } + :set Return ($Return . $Char); + } + + :if ($Input = $Return) do={ + :return $Input; + } + + :return ("=\?utf-8\?Q\?" . $Return . "\?="); +} + +# send notification via e-mail - expects at least two string arguments +:set SendEMail do={ + :global SendEMail2; + + $SendEMail2 ({ subject=$1; message=$2; link=$3 }); +} + +# send notification via e-mail - expects one array argument +:set SendEMail2 do={ + :local Notification $1; + + :global NotificationFunctions; + + ($NotificationFunctions->"email") ("\$NotificationFunctions->\"email\"") $Notification; +} diff --git a/mod/notification-matrix b/mod/notification-matrix index 6266b75..2da00ca 100644 --- a/mod/notification-matrix +++ b/mod/notification-matrix @@ -1,165 +1,3 @@ #!rsc by RouterOS -# RouterOS script: mod/notification-matrix -# Copyright (c) 2013-2023 Michael Gisbers -# Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md - -:global FlushMatrixQueue; -:global NotificationFunctions; -:global SendMatrix; -:global SendMatrix2; - -# flush Matrix queue -:set FlushMatrixQueue do={ - :global MatrixQueue; - - :global IsFullyConnected; - :global LogPrintExit2; - - :if ([ $IsFullyConnected ] = false) do={ - $LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false; - :return false; - } - - :local AllDone true; - :local QueueLen [ :len $MatrixQueue ]; - - :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ - $LogPrintExit2 warning $0 ("Flushing Matrix messages from scheduler, but queue is empty.") false; - } - - :foreach Id,Message in=$MatrixQueue do={ - :if ([ :typeof $Message ] = "array" ) do={ - :do { - /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ - ("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \ - "/send/m.room.message?access_token=" . $Message->"accesstoken") \ - http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Message->"plain" . "\"," . \ - "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ - $Message->"formatted" . "\" }") as-value; - :set ($MatrixQueue->$Id); - } on-error={ - $LogPrintExit2 debug $0 ("Sending queued Matrix message failed.") false; - :set AllDone false; - } - } - } - - :if ($AllDone = true && $QueueLen = [ :len $MatrixQueue ]) do={ - /system/scheduler/remove [ find where name=$0 ]; - :set MatrixQueue; - } -} - -# send notification via Matrix - expects one array argument -:set ($NotificationFunctions->"matrix") do={ - :local Notification $1; - - :global Identity; - :global IdentityExtra; - :global MatrixAccessToken; - :global MatrixAccessTokenOverride; - :global MatrixHomeServer; - :global MatrixHomeServerOverride; - :global MatrixQueue; - :global MatrixRoom; - :global MatrixRoomOverride; - - :global EitherOr; - :global LogPrintExit2; - :global SymbolForNotification; - - :local PrepareText do={ - :local Input [ :tostr $1 ]; - - :if ([ :len $Input ] = 0) do={ - :return ""; - } - - :local Return ""; - :local Chars { - "plain"={ "\\"; "\""; "\n" }; - "format"={ "\\"; "\""; "\n"; "&"; "<"; ">" }; - } - :local Subs { - "plain"={ "\\\\"; "\\\""; "\\n" }; - "format"={ "\\\\"; """; "
    "; "&"; "<"; ">" }; - } - - :for I from=0 to=([ :len $Input ] - 1) do={ - :local Char [ :pick $Input $I ]; - :local Replace [ :find ($Chars->$2) $Char ]; - - :if ([ :typeof $Replace ] = "num") do={ - :set Char ($Subs->$2->$Replace); - } - :set Return ($Return . $Char); - } - - :return $Return; - } - - :local AccessToken [ $EitherOr ($MatrixAccessTokenOverride->($Notification->"origin")) $MatrixAccessToken ]; - :local HomeServer [ $EitherOr ($MatrixHomeServerOverride->($Notification->"origin")) $MatrixHomeServer ]; - :local Room [ $EitherOr ($MatrixRoomOverride->($Notification->"origin")) $MatrixRoom ]; - - :if ([ :len $AccessToken ] = 0 || [ :len $HomeServer ] = 0 || [ :len $Room ] = 0) do={ - :return false; - } - - :local Plain [ $PrepareText ("## [" . $IdentityExtra . $Identity . "] " . \ - ($Notification->"subject") . "\n```\n" . ($Notification->"message") . "\n```") "plain" ]; - :local Formatted ("

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

    " . "
    " . \
    -    [ $PrepareText ($Notification->"message") "format" ] . "
    "); - :if ([ :len ($Notification->"link") ] > 0) do={ - :set Plain ($Plain . "\\n" . [ $SymbolForNotification "link" ] . \ - [ $PrepareText ("[" . $Notification->"link" . "](" . $Notification->"link" . ")") "plain" ]); - :set Formatted ($Formatted . "
    " . [ $SymbolForNotification "link" ] . \ - "
    "link") "format" ] . "\\\">" . \ - [ $PrepareText ($Notification->"link") "format" ] . ""); - } - - :do { - /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ - ("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \ - "/send/m.room.message?access_token=" . $AccessToken) \ - http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Plain . "\"," . \ - "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ - $Formatted . "\" }") as-value; - } on-error={ - $LogPrintExit2 info $0 ("Failed sending Matrix notification! Queuing...") false; - - :if ([ :typeof $MatrixQueue ] = "nothing") do={ - :set MatrixQueue ({}); - } - :local Text ([ $SymbolForNotification "alarm-clock" ] . \ - "This message was queued since " . [ /system/clock/get date ] . \ - " " . [ /system/clock/get time ] . " and may be obsolete."); - :set Plain ($Plain . "\\n" . $Text); - :set Formatted ($Formatted . "
    " . $Text); - :set ($MatrixQueue->[ :len $MatrixQueue ]) { room=$Room; \ - accesstoken=$AccessToken; homeserver=$HomeServer; \ - plain=$Plain; formatted=$Formatted }; - :if ([ :len [ /system/scheduler/find where name="\$FlushMatrixQueue" ] ] = 0) do={ - /system/scheduler/add name="\$FlushMatrixQueue" interval=1m start-time=startup \ - on-event=(":global FlushMatrixQueue; \$FlushMatrixQueue;"); - } - } -} - -# send notification via Matrix - expects at least two string arguments -:set SendMatrix do={ - :global SendMatrix2; - - $SendMatrix2 ({ subject=$1; message=$2; link=$3 }); -} - -# send notification via Matrix - expects one array argument -:set SendMatrix2 do={ - :local Notification $1; - - :global NotificationFunctions; - - ($NotificationFunctions->"matrix") ("\$NotificationFunctions->\"matrix\"") $Notification; -} +# +# dummy for migration diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc new file mode 100644 index 0000000..6266b75 --- /dev/null +++ b/mod/notification-matrix.rsc @@ -0,0 +1,165 @@ +#!rsc by RouterOS +# RouterOS script: mod/notification-matrix +# Copyright (c) 2013-2023 Michael Gisbers +# Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global FlushMatrixQueue; +:global NotificationFunctions; +:global SendMatrix; +:global SendMatrix2; + +# flush Matrix queue +:set FlushMatrixQueue do={ + :global MatrixQueue; + + :global IsFullyConnected; + :global LogPrintExit2; + + :if ([ $IsFullyConnected ] = false) do={ + $LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false; + :return false; + } + + :local AllDone true; + :local QueueLen [ :len $MatrixQueue ]; + + :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ + $LogPrintExit2 warning $0 ("Flushing Matrix messages from scheduler, but queue is empty.") false; + } + + :foreach Id,Message in=$MatrixQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :do { + /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \ + "/send/m.room.message?access_token=" . $Message->"accesstoken") \ + http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Message->"plain" . "\"," . \ + "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ + $Message->"formatted" . "\" }") as-value; + :set ($MatrixQueue->$Id); + } on-error={ + $LogPrintExit2 debug $0 ("Sending queued Matrix message failed.") false; + :set AllDone false; + } + } + } + + :if ($AllDone = true && $QueueLen = [ :len $MatrixQueue ]) do={ + /system/scheduler/remove [ find where name=$0 ]; + :set MatrixQueue; + } +} + +# send notification via Matrix - expects one array argument +:set ($NotificationFunctions->"matrix") do={ + :local Notification $1; + + :global Identity; + :global IdentityExtra; + :global MatrixAccessToken; + :global MatrixAccessTokenOverride; + :global MatrixHomeServer; + :global MatrixHomeServerOverride; + :global MatrixQueue; + :global MatrixRoom; + :global MatrixRoomOverride; + + :global EitherOr; + :global LogPrintExit2; + :global SymbolForNotification; + + :local PrepareText do={ + :local Input [ :tostr $1 ]; + + :if ([ :len $Input ] = 0) do={ + :return ""; + } + + :local Return ""; + :local Chars { + "plain"={ "\\"; "\""; "\n" }; + "format"={ "\\"; "\""; "\n"; "&"; "<"; ">" }; + } + :local Subs { + "plain"={ "\\\\"; "\\\""; "\\n" }; + "format"={ "\\\\"; """; "
    "; "&"; "<"; ">" }; + } + + :for I from=0 to=([ :len $Input ] - 1) do={ + :local Char [ :pick $Input $I ]; + :local Replace [ :find ($Chars->$2) $Char ]; + + :if ([ :typeof $Replace ] = "num") do={ + :set Char ($Subs->$2->$Replace); + } + :set Return ($Return . $Char); + } + + :return $Return; + } + + :local AccessToken [ $EitherOr ($MatrixAccessTokenOverride->($Notification->"origin")) $MatrixAccessToken ]; + :local HomeServer [ $EitherOr ($MatrixHomeServerOverride->($Notification->"origin")) $MatrixHomeServer ]; + :local Room [ $EitherOr ($MatrixRoomOverride->($Notification->"origin")) $MatrixRoom ]; + + :if ([ :len $AccessToken ] = 0 || [ :len $HomeServer ] = 0 || [ :len $Room ] = 0) do={ + :return false; + } + + :local Plain [ $PrepareText ("## [" . $IdentityExtra . $Identity . "] " . \ + ($Notification->"subject") . "\n```\n" . ($Notification->"message") . "\n```") "plain" ]; + :local Formatted ("

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

    " . "
    " . \
    +    [ $PrepareText ($Notification->"message") "format" ] . "
    "); + :if ([ :len ($Notification->"link") ] > 0) do={ + :set Plain ($Plain . "\\n" . [ $SymbolForNotification "link" ] . \ + [ $PrepareText ("[" . $Notification->"link" . "](" . $Notification->"link" . ")") "plain" ]); + :set Formatted ($Formatted . "
    " . [ $SymbolForNotification "link" ] . \ + ""link") "format" ] . "\\\">" . \ + [ $PrepareText ($Notification->"link") "format" ] . ""); + } + + :do { + /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \ + "/send/m.room.message?access_token=" . $AccessToken) \ + http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Plain . "\"," . \ + "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ + $Formatted . "\" }") as-value; + } on-error={ + $LogPrintExit2 info $0 ("Failed sending Matrix notification! Queuing...") false; + + :if ([ :typeof $MatrixQueue ] = "nothing") do={ + :set MatrixQueue ({}); + } + :local Text ([ $SymbolForNotification "alarm-clock" ] . \ + "This message was queued since " . [ /system/clock/get date ] . \ + " " . [ /system/clock/get time ] . " and may be obsolete."); + :set Plain ($Plain . "\\n" . $Text); + :set Formatted ($Formatted . "
    " . $Text); + :set ($MatrixQueue->[ :len $MatrixQueue ]) { room=$Room; \ + accesstoken=$AccessToken; homeserver=$HomeServer; \ + plain=$Plain; formatted=$Formatted }; + :if ([ :len [ /system/scheduler/find where name="\$FlushMatrixQueue" ] ] = 0) do={ + /system/scheduler/add name="\$FlushMatrixQueue" interval=1m start-time=startup \ + on-event=(":global FlushMatrixQueue; \$FlushMatrixQueue;"); + } + } +} + +# send notification via Matrix - expects at least two string arguments +:set SendMatrix do={ + :global SendMatrix2; + + $SendMatrix2 ({ subject=$1; message=$2; link=$3 }); +} + +# send notification via Matrix - expects one array argument +:set SendMatrix2 do={ + :local Notification $1; + + :global NotificationFunctions; + + ($NotificationFunctions->"matrix") ("\$NotificationFunctions->\"matrix\"") $Notification; +} diff --git a/mod/notification-telegram b/mod/notification-telegram index c90e3f0..2da00ca 100644 --- a/mod/notification-telegram +++ b/mod/notification-telegram @@ -1,176 +1,3 @@ #!rsc by RouterOS -# RouterOS script: mod/notification-telegram -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md - -:global FlushTelegramQueue; -:global NotificationFunctions; -:global SendTelegram; -:global SendTelegram2; - -# flush telegram queue -:set FlushTelegramQueue do={ - :global TelegramQueue; - - :global IsFullyConnected; - :global LogPrintExit2; - - :if ([ $IsFullyConnected ] = false) do={ - $LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false; - :return false; - } - - :local AllDone true; - :local QueueLen [ :len $TelegramQueue ]; - - :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ - $LogPrintExit2 warning $0 ("Flushing Telegram messages from scheduler, but queue is empty.") false; - } - - :foreach Id,Message in=$TelegramQueue do={ - :if ([ :typeof $Message ] = "array" ) do={ - :do { - /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ - ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ - http-data=("chat_id=" . ($Message->"chatid") . \ - "&disable_notification=" . ($Message->"silent") . \ - "&reply_to_message_id=" . ($Notification->"replyto") . \ - "&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \ - "&text=" . ($Message->"text")) as-value; - :set ($TelegramQueue->$Id); - } on-error={ - $LogPrintExit2 debug $0 ("Sending queued Telegram message failed.") false; - :set AllDone false; - } - } - } - - :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ - /system/scheduler/remove [ find where name=$0 ]; - :set TelegramQueue; - } -} - -# send notification via telegram - expects one array argument -:set ($NotificationFunctions->"telegram") do={ - :local Notification $1; - - :global Identity; - :global IdentityExtra; - :global TelegramChatId; - :global TelegramChatIdOverride; - :global TelegramFixedWidthFont; - :global TelegramQueue; - :global TelegramTokenId; - :global TelegramTokenIdOverride; - - :global CertificateAvailable; - :global CharacterReplace; - :global EitherOr; - :global IfThenElse; - :global LogPrintExit2; - :global SymbolForNotification; - :global UrlEncode; - - :local EscapeMD do={ - :global TelegramFixedWidthFont; - - :global CharacterReplace; - :global IfThenElse; - - :if ($TelegramFixedWidthFont != true) do={ - :return ($1 . [ $IfThenElse ($2 = "body") ("\n") "" ]); - } - - :local Return $1; - :local Chars { - "body"={ "\\"; "`" }; - "plain"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">"; - "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; - } - :foreach Char in=($Chars->$2) do={ - :set Return [ $CharacterReplace $Return $Char ("\\" . $Char) ]; - } - - :if ($2 = "body") do={ - :return ("```\n" . $Return . "\n```"); - } - - :return $Return; - } - - :local ChatId [ $EitherOr ($Notification->"chatid") \ - [ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ] ]; - :local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ]; - - :if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={ - :return false; - } - - :local Truncated false; - :local Text ("*__" . [ $EscapeMD ("[" . $IdentityExtra . $Identity . "] " . \ - ($Notification->"subject")) "plain" ] . "__*\n\n"); - :local LenSubject [ :len $Text ]; - :local LenMessage [ :len ($Notification->"message") ]; - :local LenLink [ :len ($Notification->"link") ]; - :local LenSum ($LenSubject + $LenMessage + $LenLink); - :if ($LenSum > 3968) do={ - :set Text ($Text . [ $EscapeMD ([ :pick ($Notification->"message") 0 (3840 - $LenSubject - $LenLink) ] . "...") "body" ]); - :set Truncated true; - } else={ - :set Text ($Text . [ $EscapeMD ($Notification->"message") "body" ]); - } - :if ($LenLink > 0) do={ - :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD ($Notification->"link") "plain" ]); - } - :if ($Truncated = true) do={ - :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ - [ $EscapeMD ("The message was too long and has been truncated, cut off " . \ - (($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%!") "plain" ]); - } - :set Text [ $UrlEncode $Text ]; - :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; - - :do { - :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; - } - /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ - ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ - http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ - "&reply_to_message_id=" . ($Notification->"replyto") . \ - "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; - } on-error={ - $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; - - :if ([ :typeof $TelegramQueue ] = "nothing") do={ - :set TelegramQueue ({}); - } - :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ - [ $EscapeMD ("This message was queued since " . [ /system/clock/get date ] . \ - " " . [ /system/clock/get time ] . " and may be obsolete.") "plain" ]) ]); - :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; - parsemode=$ParseMode; text=$Text; silent=($Notification->"silent"); - replyto=($Notification->"replyto") }; - :if ([ :len [ /system/scheduler/find where name="\$FlushTelegramQueue" ] ] = 0) do={ - /system/scheduler/add name="\$FlushTelegramQueue" interval=1m start-time=startup \ - on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;"); - } - } -} - -# send notification via telegram - expects at least two string arguments -:set SendTelegram do={ - :global SendTelegram2; - - $SendTelegram2 ({ subject=$1; message=$2; link=$3; silent=$4 }); -} - -# send notification via telegram - expects one array argument -:set SendTelegram2 do={ - :local Notification $1; - - :global NotificationFunctions; - - ($NotificationFunctions->"telegram") ("\$NotificationFunctions->\"telegram\"") $Notification; -} +# +# dummy for migration diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc new file mode 100644 index 0000000..c90e3f0 --- /dev/null +++ b/mod/notification-telegram.rsc @@ -0,0 +1,176 @@ +#!rsc by RouterOS +# RouterOS script: mod/notification-telegram +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global FlushTelegramQueue; +:global NotificationFunctions; +:global SendTelegram; +:global SendTelegram2; + +# flush telegram queue +:set FlushTelegramQueue do={ + :global TelegramQueue; + + :global IsFullyConnected; + :global LogPrintExit2; + + :if ([ $IsFullyConnected ] = false) do={ + $LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false; + :return false; + } + + :local AllDone true; + :local QueueLen [ :len $TelegramQueue ]; + + :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ + $LogPrintExit2 warning $0 ("Flushing Telegram messages from scheduler, but queue is empty.") false; + } + + :foreach Id,Message in=$TelegramQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :do { + /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ + http-data=("chat_id=" . ($Message->"chatid") . \ + "&disable_notification=" . ($Message->"silent") . \ + "&reply_to_message_id=" . ($Notification->"replyto") . \ + "&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \ + "&text=" . ($Message->"text")) as-value; + :set ($TelegramQueue->$Id); + } on-error={ + $LogPrintExit2 debug $0 ("Sending queued Telegram message failed.") false; + :set AllDone false; + } + } + } + + :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ + /system/scheduler/remove [ find where name=$0 ]; + :set TelegramQueue; + } +} + +# send notification via telegram - expects one array argument +:set ($NotificationFunctions->"telegram") do={ + :local Notification $1; + + :global Identity; + :global IdentityExtra; + :global TelegramChatId; + :global TelegramChatIdOverride; + :global TelegramFixedWidthFont; + :global TelegramQueue; + :global TelegramTokenId; + :global TelegramTokenIdOverride; + + :global CertificateAvailable; + :global CharacterReplace; + :global EitherOr; + :global IfThenElse; + :global LogPrintExit2; + :global SymbolForNotification; + :global UrlEncode; + + :local EscapeMD do={ + :global TelegramFixedWidthFont; + + :global CharacterReplace; + :global IfThenElse; + + :if ($TelegramFixedWidthFont != true) do={ + :return ($1 . [ $IfThenElse ($2 = "body") ("\n") "" ]); + } + + :local Return $1; + :local Chars { + "body"={ "\\"; "`" }; + "plain"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">"; + "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; + } + :foreach Char in=($Chars->$2) do={ + :set Return [ $CharacterReplace $Return $Char ("\\" . $Char) ]; + } + + :if ($2 = "body") do={ + :return ("```\n" . $Return . "\n```"); + } + + :return $Return; + } + + :local ChatId [ $EitherOr ($Notification->"chatid") \ + [ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ] ]; + :local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ]; + + :if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={ + :return false; + } + + :local Truncated false; + :local Text ("*__" . [ $EscapeMD ("[" . $IdentityExtra . $Identity . "] " . \ + ($Notification->"subject")) "plain" ] . "__*\n\n"); + :local LenSubject [ :len $Text ]; + :local LenMessage [ :len ($Notification->"message") ]; + :local LenLink [ :len ($Notification->"link") ]; + :local LenSum ($LenSubject + $LenMessage + $LenLink); + :if ($LenSum > 3968) do={ + :set Text ($Text . [ $EscapeMD ([ :pick ($Notification->"message") 0 (3840 - $LenSubject - $LenLink) ] . "...") "body" ]); + :set Truncated true; + } else={ + :set Text ($Text . [ $EscapeMD ($Notification->"message") "body" ]); + } + :if ($LenLink > 0) do={ + :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD ($Notification->"link") "plain" ]); + } + :if ($Truncated = true) do={ + :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ + [ $EscapeMD ("The message was too long and has been truncated, cut off " . \ + (($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%!") "plain" ]); + } + :set Text [ $UrlEncode $Text ]; + :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; + + :do { + :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; + } + /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ + http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ + "&reply_to_message_id=" . ($Notification->"replyto") . \ + "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; + } on-error={ + $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; + + :if ([ :typeof $TelegramQueue ] = "nothing") do={ + :set TelegramQueue ({}); + } + :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ + [ $EscapeMD ("This message was queued since " . [ /system/clock/get date ] . \ + " " . [ /system/clock/get time ] . " and may be obsolete.") "plain" ]) ]); + :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; + parsemode=$ParseMode; text=$Text; silent=($Notification->"silent"); + replyto=($Notification->"replyto") }; + :if ([ :len [ /system/scheduler/find where name="\$FlushTelegramQueue" ] ] = 0) do={ + /system/scheduler/add name="\$FlushTelegramQueue" interval=1m start-time=startup \ + on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;"); + } + } +} + +# send notification via telegram - expects at least two string arguments +:set SendTelegram do={ + :global SendTelegram2; + + $SendTelegram2 ({ subject=$1; message=$2; link=$3; silent=$4 }); +} + +# send notification via telegram - expects one array argument +:set SendTelegram2 do={ + :local Notification $1; + + :global NotificationFunctions; + + ($NotificationFunctions->"telegram") ("\$NotificationFunctions->\"telegram\"") $Notification; +} diff --git a/mod/scriptrunonce b/mod/scriptrunonce index 7b87b4c..2da00ca 100644 --- a/mod/scriptrunonce +++ b/mod/scriptrunonce @@ -1,46 +1,3 @@ #!rsc by RouterOS -# RouterOS script: mod/scriptrunonece -# Copyright (c) 2020-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md - -:global ScriptRunOnce; - -# fetch and run script(s) once -:set ScriptRunOnce do={ - :local Scripts [ :toarray $1 ]; - - :global ScriptRunOnceBaseUrl; - :global ScriptRunOnceUrlSuffix; - - :global LogPrintExit2; - :global ValidateSyntax; - - :foreach Script in=$Scripts do={ - :if (!($Script ~ "^(ftp|https\?|sftp)://")) do={ - :if ([ :len $ScriptRunOnceBaseUrl ] = 0) do={ - $LogPrintExit2 warning $0 ("Script '" . $Script . "' is not an url and base url is not available.") true; - } - :set Script ($ScriptRunOnceBaseUrl . $Script . $ScriptRunOnceUrlSuffix); - } - - :local Source; - :do { - :set Source ([ /tool/fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data"); - } on-error={ - $LogPrintExit2 warning $0 ("Failed fetching script '" . $Script . "'!") false; - } - - :if ([ :len $Source ] > 0) do={ - :if ([ $ValidateSyntax $Source ] = true) do={ - :do { - $LogPrintExit2 info $0 ("Running script '" . $Script . "' now.") false; - [ :parse $Source ]; - } on-error={ - $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed to run!") false; - } - } else={ - $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed syntax validation!") false; - } - } - } -} +# +# dummy for migration diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc new file mode 100644 index 0000000..96c49c3 --- /dev/null +++ b/mod/scriptrunonce.rsc @@ -0,0 +1,46 @@ +#!rsc by RouterOS +# RouterOS script: mod/scriptrunonece +# Copyright (c) 2020-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global ScriptRunOnce; + +# fetch and run script(s) once +:set ScriptRunOnce do={ + :local Scripts [ :toarray $1 ]; + + :global ScriptRunOnceBaseUrl; + :global ScriptRunOnceUrlSuffix; + + :global LogPrintExit2; + :global ValidateSyntax; + + :foreach Script in=$Scripts do={ + :if (!($Script ~ "^(ftp|https\?|sftp)://")) do={ + :if ([ :len $ScriptRunOnceBaseUrl ] = 0) do={ + $LogPrintExit2 warning $0 ("Script '" . $Script . "' is not an url and base url is not available.") true; + } + :set Script ($ScriptRunOnceBaseUrl . $Script . ".rsc" . $ScriptRunOnceUrlSuffix); + } + + :local Source; + :do { + :set Source ([ /tool/fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data"); + } on-error={ + $LogPrintExit2 warning $0 ("Failed fetching script '" . $Script . "'!") false; + } + + :if ([ :len $Source ] > 0) do={ + :if ([ $ValidateSyntax $Source ] = true) do={ + :do { + $LogPrintExit2 info $0 ("Running script '" . $Script . "' now.") false; + [ :parse $Source ]; + } on-error={ + $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed to run!") false; + } + } else={ + $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed syntax validation!") false; + } + } + } +} diff --git a/mode-button b/mode-button index 52ab00e..2da00ca 100644 --- a/mode-button +++ b/mode-button @@ -1,76 +1,3 @@ #!rsc by RouterOS -# RouterOS script: mode-button -# Copyright (c) 2018-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# act on multiple mode and reset button presses -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md - -:local 0 "mode-button"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global ModeButton; - -:global LogPrintExit2; - -:set ($ModeButton->"count") ($ModeButton->"count" + 1); - -:local Scheduler [ /system/scheduler/find where name="ModeButtonScheduler" ]; - -:if ([ :len $Scheduler ] = 0) do={ - $LogPrintExit2 info $0 ("Creating scheduler ModeButtonScheduler, counting presses...") false; - :global ModeButtonScheduler do={ - :global ModeButton; - - :global LogPrintExit2; - :global ModeButtonScheduler; - :global ValidateSyntax; - - :local LEDInvert do={ - :global ModeButtonLED; - - :global IfThenElse; - - :local LED [ /system/leds/find where leds=$ModeButtonLED type~"^(on|off)\$" interface=[] ]; - :if ([ :len $LED ] = 0) do={ - :return false; - } - /system/leds/set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED; - } - - :local Count ($ModeButton->"count"); - :local Code ($ModeButton->[ :tostr $Count ]); - - :set ($ModeButton->"count") 0; - :set ModeButtonScheduler; - /system/scheduler/remove ModeButtonScheduler; - - :if ([ :len $Code ] > 0) do={ - :if ([ $ValidateSyntax $Code ] = true) do={ - $LogPrintExit2 info $0 ("Acting on " . $Count . " mode-button presses: " . $Code) false; - - :for I from=1 to=$Count do={ - $LEDInvert; - :if ([ /system/routerboard/settings/get silent-boot ] = false) do={ - :beep length=200ms; - } - :delay 200ms; - $LEDInvert; - :delay 200ms; - } - - [ :parse $Code ]; - } else={ - $LogPrintExit2 warning $0 ("The code for " . $Count . " mode-button presses failed syntax validation!") false; - } - } else={ - $LogPrintExit2 info $0 ("No action defined for " . $Count . " mode-button presses.") false; - } - } - /system/scheduler/add name="ModeButtonScheduler" \ - on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s; -} else={ - $LogPrintExit2 debug $0 ("Updating scheduler ModeButtonScheduler...") false; - /system/scheduler/set $Scheduler start-time=[ /system/clock/get time ]; -} +# dummy for migration diff --git a/mode-button.rsc b/mode-button.rsc new file mode 100644 index 0000000..52ab00e --- /dev/null +++ b/mode-button.rsc @@ -0,0 +1,76 @@ +#!rsc by RouterOS +# RouterOS script: mode-button +# Copyright (c) 2018-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# act on multiple mode and reset button presses +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md + +:local 0 "mode-button"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global ModeButton; + +:global LogPrintExit2; + +:set ($ModeButton->"count") ($ModeButton->"count" + 1); + +:local Scheduler [ /system/scheduler/find where name="ModeButtonScheduler" ]; + +:if ([ :len $Scheduler ] = 0) do={ + $LogPrintExit2 info $0 ("Creating scheduler ModeButtonScheduler, counting presses...") false; + :global ModeButtonScheduler do={ + :global ModeButton; + + :global LogPrintExit2; + :global ModeButtonScheduler; + :global ValidateSyntax; + + :local LEDInvert do={ + :global ModeButtonLED; + + :global IfThenElse; + + :local LED [ /system/leds/find where leds=$ModeButtonLED type~"^(on|off)\$" interface=[] ]; + :if ([ :len $LED ] = 0) do={ + :return false; + } + /system/leds/set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED; + } + + :local Count ($ModeButton->"count"); + :local Code ($ModeButton->[ :tostr $Count ]); + + :set ($ModeButton->"count") 0; + :set ModeButtonScheduler; + /system/scheduler/remove ModeButtonScheduler; + + :if ([ :len $Code ] > 0) do={ + :if ([ $ValidateSyntax $Code ] = true) do={ + $LogPrintExit2 info $0 ("Acting on " . $Count . " mode-button presses: " . $Code) false; + + :for I from=1 to=$Count do={ + $LEDInvert; + :if ([ /system/routerboard/settings/get silent-boot ] = false) do={ + :beep length=200ms; + } + :delay 200ms; + $LEDInvert; + :delay 200ms; + } + + [ :parse $Code ]; + } else={ + $LogPrintExit2 warning $0 ("The code for " . $Count . " mode-button presses failed syntax validation!") false; + } + } else={ + $LogPrintExit2 info $0 ("No action defined for " . $Count . " mode-button presses.") false; + } + } + /system/scheduler/add name="ModeButtonScheduler" \ + on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s; +} else={ + $LogPrintExit2 debug $0 ("Updating scheduler ModeButtonScheduler...") false; + /system/scheduler/set $Scheduler start-time=[ /system/clock/get time ]; +} diff --git a/netwatch-dns b/netwatch-dns index 4eb3285..2da00ca 100644 --- a/netwatch-dns +++ b/netwatch-dns @@ -1,94 +1,3 @@ #!rsc by RouterOS -# RouterOS script: netwatch-dns -# Copyright (c) 2022-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# monitor and manage dns/doh with netwatch -# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-dns.md - -:local 0 "netwatch-dns"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global CertificateAvailable; -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; - -$ScriptLock $0; - -:if ([ /system/resource/get uptime ] < 5m) do={ - $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; -} - -:local DnsServers ({}); -:local DnsFallback ({}); -:local DnsCurrent [ /ip/dns/get servers ]; - -:foreach Host in=[ /tool/netwatch/find where comment~"dns" !disabled ] do={ - :local HostVal [ /tool/netwatch/get $Host ]; - :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; - - :if ($HostVal->"status" = "up" && $HostInfo->"disabled" != true) do={ - :if ($HostInfo->"dns" = true) do={ - :set DnsServers ($DnsServers, $HostVal->"host"); - } - :if ($HostInfo->"dns-fallback" = true) do={ - :set DnsFallback ($DnsFallback, $HostVal->"host"); - } - } -} - -:if ([ :len $DnsServers ] > 0) do={ - :if ($DnsServers != $DnsCurrent) do={ - $LogPrintExit2 info $0 ("Updating DNS servers: " . [ :tostr $DnsServers ]) false; - /ip/dns/set servers=$DnsServers; - /ip/dns/cache/flush; - } -} else={ - :if ([ :len $DnsFallback ] > 0) do={ - :if ($DnsFallback != $DnsCurrent) do={ - $LogPrintExit2 info $0 ("Updating DNS servers to fallback: " . \ - [ :tostr $DnsFallback ]) false; - /ip/dns/set servers=$DnsFallback; - /ip/dns/cache/flush; - } - } -} - -:local DohServer ""; -:local DohCurrent [ /ip/dns/get use-doh-server ]; -:local DohCert ""; - -:foreach Host in=[ /tool/netwatch/find where comment~"doh" !disabled ] do={ - :local HostVal [ /tool/netwatch/get $Host ]; - :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; - - :if ($HostVal->"status" = "up" && $HostInfo->"doh" = true && \ - $HostInfo->"disabled" != true && $DohServer = "") do={ - :set DohServer [ $EitherOr ($HostInfo->"doh-url") \ - ("https://" . $HostVal->"host" . "/dns-query") ]; - :set DohCert ($HostInfo->"doh-cert"); - } -} - -:if ($DohServer != "") do={ - :if ($DohServer != $DohCurrent) do={ - $LogPrintExit2 info $0 ("Updating DoH server: " . $DohServer) false; - :if ([ :len $DohCert ] > 0) do={ - /ip/dns/set use-doh-server=""; - :if ([ $CertificateAvailable $DohCert ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; - } - } - /ip/dns/set use-doh-server=$DohServer; - /ip/dns/cache/flush; - } -} else={ - :if ($DohCurrent != "") do={ - $LogPrintExit2 info $0 ("DoH server (" . $DohCurrent . ") is down, disabling.") false; - /ip/dns/set use-doh-server=""; - /ip/dns/cache/flush; - } -} +# dummy for migration diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc new file mode 100644 index 0000000..4eb3285 --- /dev/null +++ b/netwatch-dns.rsc @@ -0,0 +1,94 @@ +#!rsc by RouterOS +# RouterOS script: netwatch-dns +# Copyright (c) 2022-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# monitor and manage dns/doh with netwatch +# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-dns.md + +:local 0 "netwatch-dns"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global CertificateAvailable; +:global EitherOr; +:global LogPrintExit2; +:global ParseKeyValueStore; +:global ScriptLock; + +$ScriptLock $0; + +:if ([ /system/resource/get uptime ] < 5m) do={ + $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; +} + +:local DnsServers ({}); +:local DnsFallback ({}); +:local DnsCurrent [ /ip/dns/get servers ]; + +:foreach Host in=[ /tool/netwatch/find where comment~"dns" !disabled ] do={ + :local HostVal [ /tool/netwatch/get $Host ]; + :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; + + :if ($HostVal->"status" = "up" && $HostInfo->"disabled" != true) do={ + :if ($HostInfo->"dns" = true) do={ + :set DnsServers ($DnsServers, $HostVal->"host"); + } + :if ($HostInfo->"dns-fallback" = true) do={ + :set DnsFallback ($DnsFallback, $HostVal->"host"); + } + } +} + +:if ([ :len $DnsServers ] > 0) do={ + :if ($DnsServers != $DnsCurrent) do={ + $LogPrintExit2 info $0 ("Updating DNS servers: " . [ :tostr $DnsServers ]) false; + /ip/dns/set servers=$DnsServers; + /ip/dns/cache/flush; + } +} else={ + :if ([ :len $DnsFallback ] > 0) do={ + :if ($DnsFallback != $DnsCurrent) do={ + $LogPrintExit2 info $0 ("Updating DNS servers to fallback: " . \ + [ :tostr $DnsFallback ]) false; + /ip/dns/set servers=$DnsFallback; + /ip/dns/cache/flush; + } + } +} + +:local DohServer ""; +:local DohCurrent [ /ip/dns/get use-doh-server ]; +:local DohCert ""; + +:foreach Host in=[ /tool/netwatch/find where comment~"doh" !disabled ] do={ + :local HostVal [ /tool/netwatch/get $Host ]; + :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; + + :if ($HostVal->"status" = "up" && $HostInfo->"doh" = true && \ + $HostInfo->"disabled" != true && $DohServer = "") do={ + :set DohServer [ $EitherOr ($HostInfo->"doh-url") \ + ("https://" . $HostVal->"host" . "/dns-query") ]; + :set DohCert ($HostInfo->"doh-cert"); + } +} + +:if ($DohServer != "") do={ + :if ($DohServer != $DohCurrent) do={ + $LogPrintExit2 info $0 ("Updating DoH server: " . $DohServer) false; + :if ([ :len $DohCert ] > 0) do={ + /ip/dns/set use-doh-server=""; + :if ([ $CertificateAvailable $DohCert ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; + } + } + /ip/dns/set use-doh-server=$DohServer; + /ip/dns/cache/flush; + } +} else={ + :if ($DohCurrent != "") do={ + $LogPrintExit2 info $0 ("DoH server (" . $DohCurrent . ") is down, disabling.") false; + /ip/dns/set use-doh-server=""; + /ip/dns/cache/flush; + } +} diff --git a/netwatch-notify b/netwatch-notify index d04d23f..2da00ca 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -1,186 +1,3 @@ #!rsc by RouterOS -# RouterOS script: netwatch-notify -# Copyright (c) 2020-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# monitor netwatch and send notifications -# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md - -:local 0 "netwatch-notify"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global NetwatchNotify; - -:global EitherOr; -:global IfThenElse; -:global IsDNSResolving; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptFromTerminal; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; - -:local NetwatchNotifyHook do={ - :local Name [ :tostr $1 ]; - :local Type [ :tostr $2 ]; - :local State [ :tostr $3 ]; - :local Hook [ :tostr $4 ]; - - :global LogPrintExit2; - :global ValidateSyntax; - - :if ([ $ValidateSyntax $Hook ] = true) do={ - :do { - [ :parse $Hook ]; - } on-error={ - $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . \ - "' failed to run.") false; - :return ("The hook failed to run."); - } - } else={ - $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . \ - "' failed syntax validation.") false; - :return ("The hook failed syntax validation."); - } - - $LogPrintExit2 info $0 ("Ran hook on " . $Type . " '" . $Name . "' " . $State . ": " . \ - $Hook) false; - :return ("Ran hook:\n" . $Hook); -} - -$ScriptLock $0; - -:local ScriptFromTerminalCached [ $ScriptFromTerminal $0 ]; - -:if ([ /system/resource/get uptime ] < 5m) do={ - $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; -} - -:if ([ :typeof $NetwatchNotify ] = "nothing") do={ - :set NetwatchNotify ({}); -} - -:foreach Host in=[ /tool/netwatch/find where comment~"notify" !disabled ] do={ - :local HostVal [ /tool/netwatch/get $Host ]; - :local Type [ $IfThenElse ($HostVal->"type" ~ "^(https?-get|tcp-conn)\$") "service" "host" ]; - :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; - :local HostDetails ($HostVal->"host" . \ - [ $IfThenElse ([ :len ($HostInfo->"resolve") ] > 0) (", " . $HostInfo->"resolve") ]); - - :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ - :local Name [ $EitherOr ($HostInfo->"name") ($HostVal->"name") ]; - - :local Metric { "count-down"=0; "count-up"=0; "notified"=false; "resolve-failcnt"=0 }; - :if ([ :typeof ($NetwatchNotify->$Name) ] = "array") do={ - :set $Metric ($NetwatchNotify->$Name); - } - - :if ([ :typeof ($HostInfo->"resolve") ] = "str") do={ - :if ([ $IsDNSResolving ] = true) do={ - :do { - :local Resolve [ :resolve ($HostInfo->"resolve") ]; - :if ($Resolve != $HostVal->"host") do={ - $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ - ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ - $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ - ", updating.") false; - /tool/netwatch/set host=$Resolve $Host; - :set ($Metric->"resolve-failcnt") 0; - } - } on-error={ - :set ($Metric->"resolve-failcnt") ($Metric->"resolve-failcnt" + 1); - :if ($Metric->"resolve-failcnt" = 3) do={ - $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \ - ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ - $HostInfo->"name") "" ] . "' failed.") false; - } - } - } - } - - :if ($HostVal->"status" = "up") do={ - :local CountDown ($Metric->"count-down"); - :if ($CountDown > 0) do={ - $LogPrintExit2 info $0 \ - ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is up.") false; - :set ($Metric->"count-down") 0; - } - :set ($Metric->"count-up") ($Metric->"count-up" + 1); - :if ($Metric->"notified" = true) do={ - :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ - ") is up since " . $HostVal->"since" . ".\n" . \ - "It was down for " . $CountDown . " checks since " . ($Metric->"since") . "."); - :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "up" \ - ($HostInfo->"up-hook") ]); - } - $SendNotification2 ({ origin=$0; silent=($HostInfo->"silent"); \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . \ - $Name . " up"); \ - message=$Message }); - } - :set ($Metric->"notified") false; - :set ($Metric->"parent") ($HostInfo->"parent"); - :set ($Metric->"since"); - } else={ - :set ($Metric->"count-down") ($Metric->"count-down" + 1); - :set ($Metric->"count-up") 0; - :set ($Metric->"parent") ($HostInfo->"parent"); - :set ($Metric->"since") ($HostVal->"since"); - :local CountDown [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; - :local Parent ($HostInfo->"parent"); - :local ParentUp false; - :while ([ :len $Parent ] > 0) do={ - :set CountDown ($CountDown + 1); - :set Parent ($NetwatchNotify->$Parent->"parent"); - } - :set Parent ($HostInfo->"parent"); - :local ParentNotified false; - :while ($ParentNotified = false && [ :len $Parent ] > 0) do={ - :set ParentNotified [ $IfThenElse (($NetwatchNotify->$Parent->"notified") = true) \ - true false ]; - :set ParentUp ($NetwatchNotify->$Parent->"count-up"); - :if ($ParentNotified = false) do={ - :set Parent ($NetwatchNotify->$Parent->"parent"); - } - } - :if ($Metric->"notified" = false || $Metric->"count-down" % 120 = 0 || \ - $ScriptFromTerminalCached = true) do={ - $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ - ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is down for " . \ - $Metric->"count-down" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ - ($Metric->"notified" = true) ("already notified.") ($CountDown - $Metric->"count-down" . \ - " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]) false; - } - :if ((($CountDown * 2) - ($Metric->"count-down" * 3)) / 2 = 0 && \ - [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ - $NetwatchNotifyHook $Name $Type "pre-down" ($HostInfo->"pre-down-hook"); - } - :if ($ParentNotified = false && $Metric->"count-down" >= $CountDown && \ - ($ParentUp = false || $ParentUp > 2) && $Metric->"notified" != true) do={ - :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ - ") is down since " . $HostVal->"since" . "."); - :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "down" \ - ($HostInfo->"down-hook") ]); - } - :if ($HostInfo->"no-down-notification" != true) do={ - $SendNotification2 ({ origin=$0; silent=($HostInfo->"silent"); \ - subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . \ - $Name . " down"); \ - message=$Message }); - } - :set ($Metric->"notified") true; - } - } - :set ($NetwatchNotify->$Name) { - "count-down"=($Metric->"count-down"); - "count-up"=($Metric->"count-up"); - "notified"=($Metric->"notified"); - "parent"=($Metric->"parent"); - "resolve-failcnt"=($Metric->"resolve-failcnt"); - "since"=($Metric->"since") }; - } -} +# dummy for migration diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc new file mode 100644 index 0000000..d04d23f --- /dev/null +++ b/netwatch-notify.rsc @@ -0,0 +1,186 @@ +#!rsc by RouterOS +# RouterOS script: netwatch-notify +# Copyright (c) 2020-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# monitor netwatch and send notifications +# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md + +:local 0 "netwatch-notify"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global NetwatchNotify; + +:global EitherOr; +:global IfThenElse; +:global IsDNSResolving; +:global LogPrintExit2; +:global ParseKeyValueStore; +:global ScriptFromTerminal; +:global ScriptLock; +:global SendNotification2; +:global SymbolForNotification; + +:local NetwatchNotifyHook do={ + :local Name [ :tostr $1 ]; + :local Type [ :tostr $2 ]; + :local State [ :tostr $3 ]; + :local Hook [ :tostr $4 ]; + + :global LogPrintExit2; + :global ValidateSyntax; + + :if ([ $ValidateSyntax $Hook ] = true) do={ + :do { + [ :parse $Hook ]; + } on-error={ + $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . \ + "' failed to run.") false; + :return ("The hook failed to run."); + } + } else={ + $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . \ + "' failed syntax validation.") false; + :return ("The hook failed syntax validation."); + } + + $LogPrintExit2 info $0 ("Ran hook on " . $Type . " '" . $Name . "' " . $State . ": " . \ + $Hook) false; + :return ("Ran hook:\n" . $Hook); +} + +$ScriptLock $0; + +:local ScriptFromTerminalCached [ $ScriptFromTerminal $0 ]; + +:if ([ /system/resource/get uptime ] < 5m) do={ + $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; +} + +:if ([ :typeof $NetwatchNotify ] = "nothing") do={ + :set NetwatchNotify ({}); +} + +:foreach Host in=[ /tool/netwatch/find where comment~"notify" !disabled ] do={ + :local HostVal [ /tool/netwatch/get $Host ]; + :local Type [ $IfThenElse ($HostVal->"type" ~ "^(https?-get|tcp-conn)\$") "service" "host" ]; + :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; + :local HostDetails ($HostVal->"host" . \ + [ $IfThenElse ([ :len ($HostInfo->"resolve") ] > 0) (", " . $HostInfo->"resolve") ]); + + :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ + :local Name [ $EitherOr ($HostInfo->"name") ($HostVal->"name") ]; + + :local Metric { "count-down"=0; "count-up"=0; "notified"=false; "resolve-failcnt"=0 }; + :if ([ :typeof ($NetwatchNotify->$Name) ] = "array") do={ + :set $Metric ($NetwatchNotify->$Name); + } + + :if ([ :typeof ($HostInfo->"resolve") ] = "str") do={ + :if ([ $IsDNSResolving ] = true) do={ + :do { + :local Resolve [ :resolve ($HostInfo->"resolve") ]; + :if ($Resolve != $HostVal->"host") do={ + $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ + ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ + $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ + ", updating.") false; + /tool/netwatch/set host=$Resolve $Host; + :set ($Metric->"resolve-failcnt") 0; + } + } on-error={ + :set ($Metric->"resolve-failcnt") ($Metric->"resolve-failcnt" + 1); + :if ($Metric->"resolve-failcnt" = 3) do={ + $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \ + ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ + $HostInfo->"name") "" ] . "' failed.") false; + } + } + } + } + + :if ($HostVal->"status" = "up") do={ + :local CountDown ($Metric->"count-down"); + :if ($CountDown > 0) do={ + $LogPrintExit2 info $0 \ + ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is up.") false; + :set ($Metric->"count-down") 0; + } + :set ($Metric->"count-up") ($Metric->"count-up" + 1); + :if ($Metric->"notified" = true) do={ + :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ + ") is up since " . $HostVal->"since" . ".\n" . \ + "It was down for " . $CountDown . " checks since " . ($Metric->"since") . "."); + :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "up" \ + ($HostInfo->"up-hook") ]); + } + $SendNotification2 ({ origin=$0; silent=($HostInfo->"silent"); \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . \ + $Name . " up"); \ + message=$Message }); + } + :set ($Metric->"notified") false; + :set ($Metric->"parent") ($HostInfo->"parent"); + :set ($Metric->"since"); + } else={ + :set ($Metric->"count-down") ($Metric->"count-down" + 1); + :set ($Metric->"count-up") 0; + :set ($Metric->"parent") ($HostInfo->"parent"); + :set ($Metric->"since") ($HostVal->"since"); + :local CountDown [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; + :local Parent ($HostInfo->"parent"); + :local ParentUp false; + :while ([ :len $Parent ] > 0) do={ + :set CountDown ($CountDown + 1); + :set Parent ($NetwatchNotify->$Parent->"parent"); + } + :set Parent ($HostInfo->"parent"); + :local ParentNotified false; + :while ($ParentNotified = false && [ :len $Parent ] > 0) do={ + :set ParentNotified [ $IfThenElse (($NetwatchNotify->$Parent->"notified") = true) \ + true false ]; + :set ParentUp ($NetwatchNotify->$Parent->"count-up"); + :if ($ParentNotified = false) do={ + :set Parent ($NetwatchNotify->$Parent->"parent"); + } + } + :if ($Metric->"notified" = false || $Metric->"count-down" % 120 = 0 || \ + $ScriptFromTerminalCached = true) do={ + $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ + ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is down for " . \ + $Metric->"count-down" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ + ($Metric->"notified" = true) ("already notified.") ($CountDown - $Metric->"count-down" . \ + " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]) false; + } + :if ((($CountDown * 2) - ($Metric->"count-down" * 3)) / 2 = 0 && \ + [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ + $NetwatchNotifyHook $Name $Type "pre-down" ($HostInfo->"pre-down-hook"); + } + :if ($ParentNotified = false && $Metric->"count-down" >= $CountDown && \ + ($ParentUp = false || $ParentUp > 2) && $Metric->"notified" != true) do={ + :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ + ") is down since " . $HostVal->"since" . "."); + :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "down" \ + ($HostInfo->"down-hook") ]); + } + :if ($HostInfo->"no-down-notification" != true) do={ + $SendNotification2 ({ origin=$0; silent=($HostInfo->"silent"); \ + subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . \ + $Name . " down"); \ + message=$Message }); + } + :set ($Metric->"notified") true; + } + } + :set ($NetwatchNotify->$Name) { + "count-down"=($Metric->"count-down"); + "count-up"=($Metric->"count-up"); + "notified"=($Metric->"notified"); + "parent"=($Metric->"parent"); + "resolve-failcnt"=($Metric->"resolve-failcnt"); + "since"=($Metric->"since") }; + } +} diff --git a/news-and-changes.rsc b/news-and-changes.rsc new file mode 100644 index 0000000..e532496 --- /dev/null +++ b/news-and-changes.rsc @@ -0,0 +1,16 @@ +# News, changes and migration by RouterOS Scripts +# Copyright (c) 2019-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global IfThenElse; +:global RequiredRouterOS; + +# News, changes and migration up to change 95 are in global-config.changes! + +# Changes for global-config to be added to notification on script updates +:global GlobalConfigChanges { +}; + +# Migration steps to be applied on script updates +:global GlobalConfigMigration { +}; diff --git a/ospf-to-leds b/ospf-to-leds index 12ec820..2da00ca 100644 --- a/ospf-to-leds +++ b/ospf-to-leds @@ -1,35 +1,3 @@ #!rsc by RouterOS -# RouterOS script: ospf-to-leds -# Copyright (c) 2020-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# visualize ospf instance state via leds -# https://git.eworm.de/cgit/routeros-scripts/about/doc/ospf-to-leds.md - -:local 0 "ospf-to-leds"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; -:global ParseKeyValueStore; - -:foreach Instance in=[ /routing/ospf/instance/find where comment~"^ospf-to-leds," ] do={ - :local InstanceVal [ /routing/ospf/instance/get $Instance ]; - :local LED ([ $ParseKeyValueStore ($InstanceVal->"comment") ]->"leds"); - :local LEDType [ /system/leds/get [ find where leds=$LED ] type ]; - - :local NeighborCount 0; - :foreach Area in=[ /routing/ospf/area/find where instance=($InstanceVal->"name") ] do={ - :local AreaName [ /routing/ospf/area/get $Area name ]; - :set NeighborCount ($NeighborCount + [ :len [ /routing/ospf/neighbor/find where area=$AreaName ] ]); - } - - :if ($NeighborCount > 0 && $LEDType = "off") do={ - $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " has " . $NeighborCount . " neighbors, led on!") false; - /system/leds/set type=on [ find where leds=$LED ]; - } - :if ($NeighborCount = 0 && $LEDType = "on") do={ - $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " has no neighbors, led off!") false; - /system/leds/set type=off [ find where leds=$LED ]; - } -} +# dummy for migration diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc new file mode 100644 index 0000000..12ec820 --- /dev/null +++ b/ospf-to-leds.rsc @@ -0,0 +1,35 @@ +#!rsc by RouterOS +# RouterOS script: ospf-to-leds +# Copyright (c) 2020-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# visualize ospf instance state via leds +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ospf-to-leds.md + +:local 0 "ospf-to-leds"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global LogPrintExit2; +:global ParseKeyValueStore; + +:foreach Instance in=[ /routing/ospf/instance/find where comment~"^ospf-to-leds," ] do={ + :local InstanceVal [ /routing/ospf/instance/get $Instance ]; + :local LED ([ $ParseKeyValueStore ($InstanceVal->"comment") ]->"leds"); + :local LEDType [ /system/leds/get [ find where leds=$LED ] type ]; + + :local NeighborCount 0; + :foreach Area in=[ /routing/ospf/area/find where instance=($InstanceVal->"name") ] do={ + :local AreaName [ /routing/ospf/area/get $Area name ]; + :set NeighborCount ($NeighborCount + [ :len [ /routing/ospf/neighbor/find where area=$AreaName ] ]); + } + + :if ($NeighborCount > 0 && $LEDType = "off") do={ + $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " has " . $NeighborCount . " neighbors, led on!") false; + /system/leds/set type=on [ find where leds=$LED ]; + } + :if ($NeighborCount = 0 && $LEDType = "on") do={ + $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " has no neighbors, led off!") false; + /system/leds/set type=off [ find where leds=$LED ]; + } +} diff --git a/packages-update b/packages-update index 5162103..2da00ca 100644 --- a/packages-update +++ b/packages-update @@ -1,98 +1,3 @@ #!rsc by RouterOS -# RouterOS script: packages-update -# Copyright (c) 2019-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# download packages and reboot for installation -# https://git.eworm.de/cgit/routeros-scripts/about/doc/packages-update.md - -:local 0 "packages-update"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global DownloadPackage; -:global LogPrintExit2; -:global ScriptFromTerminal; -:global ScriptLock; -:global VersionToNum; - -$ScriptLock $0; - -:local Update [ /system/package/update/get ]; - -:if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ - $LogPrintExit2 warning $0 ("Latest version is not known.") true; -} - -:if ($Update->"installed-version" = $Update->"latest-version") do={ - $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is already installed.") true; -} - -:local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; -:local NumLatest [ $VersionToNum ($Update->"latest-version") ]; - -:local DoDowngrade false; -:if ($NumInstalled > $NumLatest) do={ - :if ([ $ScriptFromTerminal $0 ] = true) do={ - :put "Latest version is older than installed one. Want to downgrade? [y/N]"; - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - :set DoDowngrade true; - } else={ - :put "Canceled..."; - } - } else={ - $LogPrintExit2 warning $0 ("Not installing downgrade automatically.") true; - } -} - -:foreach Package in=[ /system/package/find where !bundle ] do={ - :local PkgName [ /system/package/get $Package name ]; - :if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ - $LogPrintExit2 error $0 ("Download for package " . $PkgName . " failed, update aborted.") true; - } -} - -:foreach Script in=[ /system/script/find where source~"\n# provides: backup-script\n" ] do={ - :local ScriptName [ /system/script/get $Script name ]; - :do { - $LogPrintExit2 info $0 ("Running backup script " . $ScriptName . " before update.") false; - /system/script/run $Script; - } on-error={ - $LogPrintExit2 warning $0 ("Running backup script " . $ScriptName . " before update failed!") false; - :if ([ $ScriptFromTerminal $0 ] = true) do={ - :put "Do you want to continue anyway? [y/N]"; - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - $LogPrintExit2 info $0 ("User requested to continue anyway.") false; - } else={ - $LogPrintExit2 info $0 ("Canceled update...") true; - } - } else={ - $LogPrintExit2 info $0 ("Canceled non-interactive update.") true; - } - } -} - -:if ($DoDowngrade = true) do={ - $LogPrintExit2 info $0 ("Rebooting for downgrade.") false; - :delay 1s; - /system/package/downgrade; -} - -:if ([ $ScriptFromTerminal $0 ] = true) do={ - :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; - :if (([ /terminal/inkey timeout=60 ] % 32) = 19) do={ - :global RebootForUpdate do={ - :global RandomDelay; - $RandomDelay 3600; - /system/reboot; - } - /system/scheduler/add name="reboot-for-update" start-time=03:00:00 interval=1d \ - on-event=("/system/scheduler/remove reboot-for-update; " . \ - ":global RebootForUpdate; \$RebootForUpdate;"); - $LogPrintExit2 info $0 ("Scheduled reboot for update between 03:00 and 04:00.") true; - } -} - -$LogPrintExit2 info $0 ("Rebooting for update.") false; -:delay 1s; -/system/reboot; +# dummy for migration diff --git a/packages-update.rsc b/packages-update.rsc new file mode 100644 index 0000000..5162103 --- /dev/null +++ b/packages-update.rsc @@ -0,0 +1,98 @@ +#!rsc by RouterOS +# RouterOS script: packages-update +# Copyright (c) 2019-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# download packages and reboot for installation +# https://git.eworm.de/cgit/routeros-scripts/about/doc/packages-update.md + +:local 0 "packages-update"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global DownloadPackage; +:global LogPrintExit2; +:global ScriptFromTerminal; +:global ScriptLock; +:global VersionToNum; + +$ScriptLock $0; + +:local Update [ /system/package/update/get ]; + +:if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ + $LogPrintExit2 warning $0 ("Latest version is not known.") true; +} + +:if ($Update->"installed-version" = $Update->"latest-version") do={ + $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is already installed.") true; +} + +:local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; +:local NumLatest [ $VersionToNum ($Update->"latest-version") ]; + +:local DoDowngrade false; +:if ($NumInstalled > $NumLatest) do={ + :if ([ $ScriptFromTerminal $0 ] = true) do={ + :put "Latest version is older than installed one. Want to downgrade? [y/N]"; + :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ + :set DoDowngrade true; + } else={ + :put "Canceled..."; + } + } else={ + $LogPrintExit2 warning $0 ("Not installing downgrade automatically.") true; + } +} + +:foreach Package in=[ /system/package/find where !bundle ] do={ + :local PkgName [ /system/package/get $Package name ]; + :if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ + $LogPrintExit2 error $0 ("Download for package " . $PkgName . " failed, update aborted.") true; + } +} + +:foreach Script in=[ /system/script/find where source~"\n# provides: backup-script\n" ] do={ + :local ScriptName [ /system/script/get $Script name ]; + :do { + $LogPrintExit2 info $0 ("Running backup script " . $ScriptName . " before update.") false; + /system/script/run $Script; + } on-error={ + $LogPrintExit2 warning $0 ("Running backup script " . $ScriptName . " before update failed!") false; + :if ([ $ScriptFromTerminal $0 ] = true) do={ + :put "Do you want to continue anyway? [y/N]"; + :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ + $LogPrintExit2 info $0 ("User requested to continue anyway.") false; + } else={ + $LogPrintExit2 info $0 ("Canceled update...") true; + } + } else={ + $LogPrintExit2 info $0 ("Canceled non-interactive update.") true; + } + } +} + +:if ($DoDowngrade = true) do={ + $LogPrintExit2 info $0 ("Rebooting for downgrade.") false; + :delay 1s; + /system/package/downgrade; +} + +:if ([ $ScriptFromTerminal $0 ] = true) do={ + :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; + :if (([ /terminal/inkey timeout=60 ] % 32) = 19) do={ + :global RebootForUpdate do={ + :global RandomDelay; + $RandomDelay 3600; + /system/reboot; + } + /system/scheduler/add name="reboot-for-update" start-time=03:00:00 interval=1d \ + on-event=("/system/scheduler/remove reboot-for-update; " . \ + ":global RebootForUpdate; \$RebootForUpdate;"); + $LogPrintExit2 info $0 ("Scheduled reboot for update between 03:00 and 04:00.") true; + } +} + +$LogPrintExit2 info $0 ("Rebooting for update.") false; +:delay 1s; +/system/reboot; diff --git a/ppp-on-up b/ppp-on-up index ac01c97..2da00ca 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -1,34 +1,3 @@ #!rsc by RouterOS -# RouterOS script: ppp-on-up -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# run scripts on ppp up -# https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md - -:local 0 "ppp-on-up"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; - -:local Interface $interface; - -:if ([ :typeof $Interface ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from ppp on-up script hook.") true; -} - -:local IntName [ /interface/get $Interface name ]; -$LogPrintExit2 info $0 ("PPP interface " . $IntName . " is up.") false; - -/ipv6/dhcp-client/release [ find where interface=$IntName !disabled ]; - -:foreach Script in=[ /system/script/find where source~("\n# provides: ppp-on-up\n") ] do={ - :local ScriptName [ /system/script/get $Script name ]; - :do { - $LogPrintExit2 debug $0 ("Running script: " . $ScriptName) false; - /system/script/run $Script; - } on-error={ - $LogPrintExit2 warning $0 ("Running script '" . $ScriptName . "' failed!") false; - } -} +# dummy for migration diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc new file mode 100644 index 0000000..ac01c97 --- /dev/null +++ b/ppp-on-up.rsc @@ -0,0 +1,34 @@ +#!rsc by RouterOS +# RouterOS script: ppp-on-up +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# run scripts on ppp up +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md + +:local 0 "ppp-on-up"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global LogPrintExit2; + +:local Interface $interface; + +:if ([ :typeof $Interface ] = "nothing") do={ + $LogPrintExit2 error $0 ("This script is supposed to run from ppp on-up script hook.") true; +} + +:local IntName [ /interface/get $Interface name ]; +$LogPrintExit2 info $0 ("PPP interface " . $IntName . " is up.") false; + +/ipv6/dhcp-client/release [ find where interface=$IntName !disabled ]; + +:foreach Script in=[ /system/script/find where source~("\n# provides: ppp-on-up\n") ] do={ + :local ScriptName [ /system/script/get $Script name ]; + :do { + $LogPrintExit2 debug $0 ("Running script: " . $ScriptName) false; + /system/script/run $Script; + } on-error={ + $LogPrintExit2 warning $0 ("Running script '" . $ScriptName . "' failed!") false; + } +} diff --git a/sms-action b/sms-action index f5de11f..2da00ca 100644 --- a/sms-action +++ b/sms-action @@ -1,31 +1,3 @@ #!rsc by RouterOS -# RouterOS script: sms-action -# Copyright (c) 2018-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# run action on received SMS -# https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-action.md - -:local 0 "sms-action"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global SmsAction; - -:global LogPrintExit2; -:global ValidateSyntax; - -:local Action $action; - -:if ([ :typeof $Action ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from SMS hook with action=...") true; -} - -:local Code ($SmsAction->$Action); -:if ([ $ValidateSyntax $Code ] = true) do={ - :log info ("Acting on SMS action '" . $Action . "': " . $Code); - :delay 1s; - [ :parse $Code ]; -} else={ - $LogPrintExit2 warning $0 ("The code for action '" . $Action . "' failed syntax validation!") false; -} +# dummy for migration diff --git a/sms-action.rsc b/sms-action.rsc new file mode 100644 index 0000000..f5de11f --- /dev/null +++ b/sms-action.rsc @@ -0,0 +1,31 @@ +#!rsc by RouterOS +# RouterOS script: sms-action +# Copyright (c) 2018-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# run action on received SMS +# https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-action.md + +:local 0 "sms-action"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global SmsAction; + +:global LogPrintExit2; +:global ValidateSyntax; + +:local Action $action; + +:if ([ :typeof $Action ] = "nothing") do={ + $LogPrintExit2 error $0 ("This script is supposed to run from SMS hook with action=...") true; +} + +:local Code ($SmsAction->$Action); +:if ([ $ValidateSyntax $Code ] = true) do={ + :log info ("Acting on SMS action '" . $Action . "': " . $Code); + :delay 1s; + [ :parse $Code ]; +} else={ + $LogPrintExit2 warning $0 ("The code for action '" . $Action . "' failed syntax validation!") false; +} diff --git a/sms-forward b/sms-forward index 802da48..2da00ca 100644 --- a/sms-forward +++ b/sms-forward @@ -1,84 +1,3 @@ #!rsc by RouterOS -# RouterOS script: sms-forward -# Copyright (c) 2013-2023 Christian Hesse -# Anatoly Bubenkov -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# forward SMS to e-mail -# https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md - -:local 0 "sms-forward"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Identity; -:global SmsForwardHooks; - -:global IfThenElse; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; -:global ValidateSyntax; -:global WaitFullyConnected; - -$ScriptLock $0; - -:if ([ /tool/sms/get receive-enabled ] = false) do={ - $LogPrintExit2 warning $0 ("Receiving of SMS is not enabled.") true; -} - -$WaitFullyConnected; - -:local Settings [ /tool/sms/get ]; - -# forward SMS in a loop -:while ([ :len [ /tool/sms/inbox/find ] ] > 0) do={ - :local Phone [ /tool/sms/inbox/get ([ find ]->0) phone ]; - :local Messages ""; - :local Delete ({}); - - :foreach Sms in=[ /tool/sms/inbox/find where phone=$Phone ] do={ - :local SmsVal [ /tool/sms/inbox/get $Sms ]; - - :if ($Phone = $Settings->"allowed-number" && \ - ($SmsVal->"message")~("^:cmd " . $Settings->"secret" . " script ")) do={ - $LogPrintExit2 debug $0 ("Removing SMS, which started a script.") false; - /tool/sms/inbox/remove $Sms; - } else={ - :set Messages ($Messages . "\n\nOn " . $SmsVal->"timestamp" . \ - " type " . $SmsVal->"type" . ":\n" . $SmsVal->"message"); - :foreach Hook in=$SmsForwardHooks do={ - :if ($Phone~($Hook->"allowed-number") && ($SmsVal->"message")~($Hook->"match")) do={ - :if ([ $ValidateSyntax ($Hook->"command") ] = true) do={ - $LogPrintExit2 info $0 ("Running hook '" . $Hook->"match" . "': " . \ - $Hook->"command") false; - :do { - [ :parse ($Hook->"command") ]; - :set Messages ($Messages . "\n\nRan hook '" . $Hook->"match" . "':\n" . \ - $Hook->"command"); - } on-error={ - $LogPrintExit2 warning $0 ("The code for hook '" . $Hook->"match" . \ - "' failed to run!") false; - } - } else={ - $LogPrintExit2 warning $0 ("The code for hook '" . $Hook->"match" . \ - "' failed syntax validation!") false; - } - } - } - :set Delete ($Delete, $Sms); - } - } - - :if ([ :len $Messages ] > 0) do={ - :local Count [ :len $Delete ]; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "incoming-envelope" ] . "SMS Forwarding from " . $Phone); \ - message=("Received " . [ $IfThenElse ($Count = 1) "this message" ("these " . $Count . " messages") ] . \ - " by " . $Identity . " from " . $Phone . ":" . $Messages) }); - :foreach Sms in=$Delete do={ - /tool/sms/inbox/remove $Sms; - } - } -} +# dummy for migration diff --git a/sms-forward.rsc b/sms-forward.rsc new file mode 100644 index 0000000..802da48 --- /dev/null +++ b/sms-forward.rsc @@ -0,0 +1,84 @@ +#!rsc by RouterOS +# RouterOS script: sms-forward +# Copyright (c) 2013-2023 Christian Hesse +# Anatoly Bubenkov +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# forward SMS to e-mail +# https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md + +:local 0 "sms-forward"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Identity; +:global SmsForwardHooks; + +:global IfThenElse; +:global LogPrintExit2; +:global ScriptLock; +:global SendNotification2; +:global SymbolForNotification; +:global ValidateSyntax; +:global WaitFullyConnected; + +$ScriptLock $0; + +:if ([ /tool/sms/get receive-enabled ] = false) do={ + $LogPrintExit2 warning $0 ("Receiving of SMS is not enabled.") true; +} + +$WaitFullyConnected; + +:local Settings [ /tool/sms/get ]; + +# forward SMS in a loop +:while ([ :len [ /tool/sms/inbox/find ] ] > 0) do={ + :local Phone [ /tool/sms/inbox/get ([ find ]->0) phone ]; + :local Messages ""; + :local Delete ({}); + + :foreach Sms in=[ /tool/sms/inbox/find where phone=$Phone ] do={ + :local SmsVal [ /tool/sms/inbox/get $Sms ]; + + :if ($Phone = $Settings->"allowed-number" && \ + ($SmsVal->"message")~("^:cmd " . $Settings->"secret" . " script ")) do={ + $LogPrintExit2 debug $0 ("Removing SMS, which started a script.") false; + /tool/sms/inbox/remove $Sms; + } else={ + :set Messages ($Messages . "\n\nOn " . $SmsVal->"timestamp" . \ + " type " . $SmsVal->"type" . ":\n" . $SmsVal->"message"); + :foreach Hook in=$SmsForwardHooks do={ + :if ($Phone~($Hook->"allowed-number") && ($SmsVal->"message")~($Hook->"match")) do={ + :if ([ $ValidateSyntax ($Hook->"command") ] = true) do={ + $LogPrintExit2 info $0 ("Running hook '" . $Hook->"match" . "': " . \ + $Hook->"command") false; + :do { + [ :parse ($Hook->"command") ]; + :set Messages ($Messages . "\n\nRan hook '" . $Hook->"match" . "':\n" . \ + $Hook->"command"); + } on-error={ + $LogPrintExit2 warning $0 ("The code for hook '" . $Hook->"match" . \ + "' failed to run!") false; + } + } else={ + $LogPrintExit2 warning $0 ("The code for hook '" . $Hook->"match" . \ + "' failed syntax validation!") false; + } + } + } + :set Delete ($Delete, $Sms); + } + } + + :if ([ :len $Messages ] > 0) do={ + :local Count [ :len $Delete ]; + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "incoming-envelope" ] . "SMS Forwarding from " . $Phone); \ + message=("Received " . [ $IfThenElse ($Count = 1) "this message" ("these " . $Count . " messages") ] . \ + " by " . $Identity . " from " . $Phone . ":" . $Messages) }); + :foreach Sms in=$Delete do={ + /tool/sms/inbox/remove $Sms; + } + } +} diff --git a/ssh-keys-import b/ssh-keys-import index b40a997..2da00ca 100644 --- a/ssh-keys-import +++ b/ssh-keys-import @@ -1,11 +1,3 @@ #!rsc by RouterOS -# RouterOS script: ssh-keys-import -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# import ssh keys from file -# https://git.eworm.de/cgit/routeros-scripts/about/doc/ssh-keys-import.md - -:foreach Key in=[ /file/find where type="ssh key" ] do={ - /user/ssh-key/import user=admin public-key-file=[ /file/get $Key name ]; -} +# dummy for migration diff --git a/ssh-keys-import.rsc b/ssh-keys-import.rsc new file mode 100644 index 0000000..b40a997 --- /dev/null +++ b/ssh-keys-import.rsc @@ -0,0 +1,11 @@ +#!rsc by RouterOS +# RouterOS script: ssh-keys-import +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# import ssh keys from file +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ssh-keys-import.md + +:foreach Key in=[ /file/find where type="ssh key" ] do={ + /user/ssh-key/import user=admin public-key-file=[ /file/get $Key name ]; +} diff --git a/super-mario-theme b/super-mario-theme index 7787a12..2da00ca 100644 --- a/super-mario-theme +++ b/super-mario-theme @@ -1,69 +1,3 @@ #!rsc by RouterOS -# RouterOS script: super-mario-theme -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# play Super Mario theme -# https://git.eworm.de/cgit/routeros-scripts/about/doc/super-mario-theme.md - -:local Beeps { - { 660; 100 }; 150; { 660; 100 }; 300; { 660; 100 }; 300; - { 510; 100 }; 100; { 660; 100 }; 300; { 770; 100 }; 550; - { 380; 100 }; 575; { 510; 100 }; 450; { 380; 100 }; 400; - { 320; 100 }; 500; { 440; 100 }; 300; { 480; 80 }; 330; - { 450; 100 }; 150; { 430; 100 }; 300; { 380; 100 }; 200; - { 660; 80 }; 200; { 760; 50 }; 150; { 860; 100 }; 300; - { 700; 80 }; 150; { 760; 50 }; 350; { 660; 80 }; 300; - { 520; 80 }; 150; { 580; 80 }; 150; { 480; 80 }; 500; - { 510; 100 }; 450; { 380; 100 }; 400; { 320; 100 }; 500; - { 440; 100 }; 300; { 480; 80 }; 330; { 450; 100 }; 150; - { 430; 100 }; 300; { 380; 100 }; 200; { 660; 80 }; 200; - { 760; 50 }; 150; { 860; 100 }; 300; { 700; 80 }; 150; - { 760; 50 }; 350; { 660; 80 }; 300; { 520; 80 }; 150; - { 580; 80 }; 150; { 480; 80 }; 500; { 500; 100 }; 300; - { 760; 100 }; 100; { 720; 100 }; 150; { 680; 100 }; 150; - { 620; 150 }; 300; { 650; 150 }; 300; { 380; 100 }; 150; - { 430; 100 }; 150; { 500; 100 }; 300; { 430; 100 }; 150; - { 500; 100 }; 100; { 570; 100 }; 220; { 500; 100 }; 300; - { 760; 100 }; 100; { 720; 100 }; 150; { 680; 100 }; 150; - { 620; 150 }; 300; { 650; 200 }; 300; { 1020; 80 }; 300; - { 1020; 80 }; 150; { 1020; 80 }; 300; { 380; 100 }; 300; - { 500; 100 }; 300; { 760; 100 }; 100; { 720; 100 }; 150; - { 680; 100 }; 150; { 620; 150 }; 300; { 650; 150 }; 300; - { 380; 100 }; 150; { 430; 100 }; 150; { 500; 100 }; 300; - { 430; 100 }; 150; { 500; 100 }; 100; { 570; 100 }; 420; - { 585; 100 }; 450; { 550; 100 }; 420; { 500; 100 }; 360; - { 380; 100 }; 300; { 500; 100 }; 300; { 500; 100 }; 150; - { 500; 100 }; 300; { 500; 100 }; 300; { 760; 100 }; 100; - { 720; 100 }; 150; { 680; 100 }; 150; { 620; 150 }; 300; - { 650; 150 }; 300; { 380; 100 }; 150; { 430; 100 }; 150; - { 500; 100 }; 300; { 430; 100 }; 150; { 500; 100 }; 100; - { 570; 100 }; 220; { 500; 100 }; 300; { 760; 100 }; 100; - { 720; 100 }; 150; { 680; 100 }; 150; { 620; 150 }; 300; - { 650; 200 }; 300; { 1020; 80 }; 300; { 1020; 80 }; 150; - { 1020; 80 }; 300; { 380; 100 }; 300; { 500; 100 }; 300; - { 760; 100 }; 100; { 720; 100 }; 150; { 680; 100 }; 150; - { 620; 150 }; 300; { 650; 150 }; 300; { 380; 100 }; 150; - { 430; 100 }; 150; { 500; 100 }; 300; { 430; 100 }; 150; - { 500; 100 }; 100; { 570; 100 }; 420; { 585; 100 }; 450; - { 550; 100 }; 420; { 500; 100 }; 360; { 380; 100 }; 300; - { 500; 100 }; 300; { 500; 100 }; 150; { 500; 100 }; 300; - { 500; 60 }; 150; { 500; 80 }; 300; { 500; 60 }; 350; - { 500; 80 }; 150; { 580; 80 }; 350; { 660; 80 }; 150; - { 500; 80 }; 300; { 430; 80 }; 150; { 380; 80 }; 600; - { 500; 60 }; 150; { 500; 80 }; 300; { 500; 60 }; 350; - { 500; 80 }; 150; { 580; 80 }; 150; { 660; 80 }; 550; - { 870; 80 }; 325; { 760; 80 }; 600; { 500; 60 }; 150; - { 500; 80 }; 300; { 500; 60 }; 350; { 500; 80 }; 150; - { 580; 80 }; 350; { 660; 80 }; 150; { 500; 80 }; 300; - { 430; 80 }; 150; { 380; 80 }; 600; { 660; 100 }; 150; - { 660; 100 }; 300; { 660; 100 }; 300; { 510; 100 }; 100; - { 660; 100 }; 300; { 770; 100 }; 550; { 380; 100 }; 575 }; - -:foreach Beep in=$Beeps do={ - :if ([ :len $Beep ] = 2) do={ - :beep frequency=($Beep->0) length=(($Beep->1) . "ms"); - } else={ - :delay ($Beep . "ms"); - } -} +# dummy for migration diff --git a/super-mario-theme.rsc b/super-mario-theme.rsc new file mode 100644 index 0000000..7787a12 --- /dev/null +++ b/super-mario-theme.rsc @@ -0,0 +1,69 @@ +#!rsc by RouterOS +# RouterOS script: super-mario-theme +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# play Super Mario theme +# https://git.eworm.de/cgit/routeros-scripts/about/doc/super-mario-theme.md + +:local Beeps { + { 660; 100 }; 150; { 660; 100 }; 300; { 660; 100 }; 300; + { 510; 100 }; 100; { 660; 100 }; 300; { 770; 100 }; 550; + { 380; 100 }; 575; { 510; 100 }; 450; { 380; 100 }; 400; + { 320; 100 }; 500; { 440; 100 }; 300; { 480; 80 }; 330; + { 450; 100 }; 150; { 430; 100 }; 300; { 380; 100 }; 200; + { 660; 80 }; 200; { 760; 50 }; 150; { 860; 100 }; 300; + { 700; 80 }; 150; { 760; 50 }; 350; { 660; 80 }; 300; + { 520; 80 }; 150; { 580; 80 }; 150; { 480; 80 }; 500; + { 510; 100 }; 450; { 380; 100 }; 400; { 320; 100 }; 500; + { 440; 100 }; 300; { 480; 80 }; 330; { 450; 100 }; 150; + { 430; 100 }; 300; { 380; 100 }; 200; { 660; 80 }; 200; + { 760; 50 }; 150; { 860; 100 }; 300; { 700; 80 }; 150; + { 760; 50 }; 350; { 660; 80 }; 300; { 520; 80 }; 150; + { 580; 80 }; 150; { 480; 80 }; 500; { 500; 100 }; 300; + { 760; 100 }; 100; { 720; 100 }; 150; { 680; 100 }; 150; + { 620; 150 }; 300; { 650; 150 }; 300; { 380; 100 }; 150; + { 430; 100 }; 150; { 500; 100 }; 300; { 430; 100 }; 150; + { 500; 100 }; 100; { 570; 100 }; 220; { 500; 100 }; 300; + { 760; 100 }; 100; { 720; 100 }; 150; { 680; 100 }; 150; + { 620; 150 }; 300; { 650; 200 }; 300; { 1020; 80 }; 300; + { 1020; 80 }; 150; { 1020; 80 }; 300; { 380; 100 }; 300; + { 500; 100 }; 300; { 760; 100 }; 100; { 720; 100 }; 150; + { 680; 100 }; 150; { 620; 150 }; 300; { 650; 150 }; 300; + { 380; 100 }; 150; { 430; 100 }; 150; { 500; 100 }; 300; + { 430; 100 }; 150; { 500; 100 }; 100; { 570; 100 }; 420; + { 585; 100 }; 450; { 550; 100 }; 420; { 500; 100 }; 360; + { 380; 100 }; 300; { 500; 100 }; 300; { 500; 100 }; 150; + { 500; 100 }; 300; { 500; 100 }; 300; { 760; 100 }; 100; + { 720; 100 }; 150; { 680; 100 }; 150; { 620; 150 }; 300; + { 650; 150 }; 300; { 380; 100 }; 150; { 430; 100 }; 150; + { 500; 100 }; 300; { 430; 100 }; 150; { 500; 100 }; 100; + { 570; 100 }; 220; { 500; 100 }; 300; { 760; 100 }; 100; + { 720; 100 }; 150; { 680; 100 }; 150; { 620; 150 }; 300; + { 650; 200 }; 300; { 1020; 80 }; 300; { 1020; 80 }; 150; + { 1020; 80 }; 300; { 380; 100 }; 300; { 500; 100 }; 300; + { 760; 100 }; 100; { 720; 100 }; 150; { 680; 100 }; 150; + { 620; 150 }; 300; { 650; 150 }; 300; { 380; 100 }; 150; + { 430; 100 }; 150; { 500; 100 }; 300; { 430; 100 }; 150; + { 500; 100 }; 100; { 570; 100 }; 420; { 585; 100 }; 450; + { 550; 100 }; 420; { 500; 100 }; 360; { 380; 100 }; 300; + { 500; 100 }; 300; { 500; 100 }; 150; { 500; 100 }; 300; + { 500; 60 }; 150; { 500; 80 }; 300; { 500; 60 }; 350; + { 500; 80 }; 150; { 580; 80 }; 350; { 660; 80 }; 150; + { 500; 80 }; 300; { 430; 80 }; 150; { 380; 80 }; 600; + { 500; 60 }; 150; { 500; 80 }; 300; { 500; 60 }; 350; + { 500; 80 }; 150; { 580; 80 }; 150; { 660; 80 }; 550; + { 870; 80 }; 325; { 760; 80 }; 600; { 500; 60 }; 150; + { 500; 80 }; 300; { 500; 60 }; 350; { 500; 80 }; 150; + { 580; 80 }; 350; { 660; 80 }; 150; { 500; 80 }; 300; + { 430; 80 }; 150; { 380; 80 }; 600; { 660; 100 }; 150; + { 660; 100 }; 300; { 660; 100 }; 300; { 510; 100 }; 100; + { 660; 100 }; 300; { 770; 100 }; 550; { 380; 100 }; 575 }; + +:foreach Beep in=$Beeps do={ + :if ([ :len $Beep ] = 2) do={ + :beep frequency=($Beep->0) length=(($Beep->1) . "ms"); + } else={ + :delay ($Beep . "ms"); + } +} diff --git a/telegram-chat b/telegram-chat index ba2a3ff..2da00ca 100644 --- a/telegram-chat +++ b/telegram-chat @@ -1,150 +1,3 @@ #!rsc by RouterOS -# RouterOS script: telegram-chat -# Copyright (c) 2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# use Telegram to chat with your Router and send commands -# https://git.eworm.de/cgit/routeros-scripts/about/doc/telegram-chat.md - -:local 0 "telegram-chat"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Identity; -:global TelegramChatActive; -:global TelegramChatGroups; -:global TelegramChatId; -:global TelegramChatIdsTrusted; -:global TelegramChatOffset; -:global TelegramChatRunTime; -:global TelegramTokenId; - -:global CertificateAvailable; -:global EitherOr; -:global EscapeForRegEx; -:global GetRandom20CharAlNum; -:global IfThenElse; -:global LogPrintExit2; -:global MkDir; -:global ScriptLock; -:global SendTelegram2; -:global SymbolForNotification; -:global ValidateSyntax; -:global WaitForFile; -:global WaitFullyConnected; - -$ScriptLock $0; - -$WaitFullyConnected; - -:if ([ :typeof $TelegramChatOffset ] != "array") do={ - :set TelegramChatOffset { 0; 0; 0 }; -} - -:if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; -} - -:local JsonGetKey do={ - :local Array [ :toarray $1 ]; - :local Key [ :tostr $2 ]; - - :for I from=0 to=([ :len $Array ] - 1) do={ - :if (($Array->$I) = $Key) do={ - :if ($Array->($I + 1) = ":") do={ - :return ($Array->($I + 2)); - } - :return [ :pick ($Array->($I + 1)) 1 [ :len ($Array->($I + 1)) ] ]; - } - } - - :return false; -} - -:local Data; -:do { - :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ - ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=" . \ - $TelegramChatOffset->0 . "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); - :set Data [ :pick $Data ([ :find $Data "[" ] + 1) ([ :len $Data ] - 2) ]; -} on-error={ - $LogPrintExit2 debug $0 ("Failed getting updates from Telegram.") true; -} - -:local UpdateID 0; -:local Uptime [ /system/resource/get uptime ]; -:foreach Update in=[ :toarray $Data ] do={ - :set UpdateID [ $JsonGetKey $Update "update_id" ]; - :if (($TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={ - :local Trusted false; - :local Message [ $JsonGetKey $Update "message" ]; - :local MessageId [ $JsonGetKey $Message "message_id" ]; - :local From [ $JsonGetKey $Message "from" ]; - :local FromID [ $JsonGetKey $From "id" ]; - :local FromUserName [ $JsonGetKey $From "username" ]; - :local ChatID [ $JsonGetKey [ $JsonGetKey $Message "chat" ] "id" ]; - :local Text [ $JsonGetKey $Message "text" ]; - :foreach IdsTrusted in=($TelegramChatId, $TelegramChatIdsTrusted) do={ - :if ($FromID = $IdsTrusted || $FromUserName = $IdsTrusted) do={ - :set Trusted true; - } - } - - :if ($Trusted = true) do={ - :if ([ :pick $Text 0 1 ] = "!") do={ - :if ($Text ~ ("^! *(" . [ $EscapeForRegEx $Identity ] . "|@" . $TelegramChatGroups . ")\$")) do={ - :set TelegramChatActive true; - } else={ - :set TelegramChatActive false; - } - $LogPrintExit2 info $0 ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . \ - " from update " . $UpdateID . "!") false; - } else={ - :if ($TelegramChatActive = true && $Text != false && [ :len $Text ] > 0) do={ - :if ([ $ValidateSyntax $Text ] = true) do={ - :local State ""; - :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); - $MkDir "tmpfs/telegram-chat"; - $LogPrintExit2 info $0 ("Running command from update " . $UpdateID . ": " . $Text) false; - :exec script=(":do {\n" . $Text . "\n} on-error={ :execute script=\"/\" file=" . $File . ".failed };" . \ - ":execute script=\"/\" file=" . $File . ".done") file=$File; - :if ([ $WaitForFile ($File . ".done.txt") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ - :set State "The command did not finish, still running in background.\n\n"; - } - :if ([ :len [ /file/find where name=($File . ".failed.txt") ] ] > 0) do={ - :set State "The command failed with an error!\n\n"; - } - :local Content [ /file/get ($File . ".txt") contents ]; - $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; replyto=$MessageId; \ - subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Command:\n" . $Text . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ - ("Output:\n" . $Content) [ $IfThenElse ([ /file/get ($File . ".txt") size ] > 0) \ - ("Output exceeds file read size.") ("No output.") ] ]) }); - /file/remove "tmpfs/telegram-chat"; - } else={ - $LogPrintExit2 info $0 ("The command from update " . $UpdateID . " failed syntax validation!") false; - $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; replyto=$MessageId; \ - subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Command:\n" . $Text . "\n\nThe command failed syntax validation!") }); - } - } - } - } else={ - :local Message ("Received a message from untrusted contact " . \ - [ $IfThenElse ($FromUserName = false) "without username" ("'" . $FromUserName . "'") ] . \ - " (ID " . $FromID . ") in update " . $UpdateID . "!"); - :if ($Text ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ - $LogPrintExit2 warning $0 $Message false; - $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; replyto=$MessageId; \ - subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("You are not trusted.") }); - } else={ - $LogPrintExit2 info $0 $Message false; - } - } - } else={ - $LogPrintExit2 debug $0 ("Already handled update " . $UpdateID . ".") false; - } -} -:set TelegramChatOffset ([ :pick $TelegramChatOffset 1 3 ], \ - [ $IfThenElse ($UpdateID >= $TelegramChatOffset->2) ($UpdateID + 1) ($TelegramChatOffset->2) ]); +# dummy for migration diff --git a/telegram-chat.rsc b/telegram-chat.rsc new file mode 100644 index 0000000..ba2a3ff --- /dev/null +++ b/telegram-chat.rsc @@ -0,0 +1,150 @@ +#!rsc by RouterOS +# RouterOS script: telegram-chat +# Copyright (c) 2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# use Telegram to chat with your Router and send commands +# https://git.eworm.de/cgit/routeros-scripts/about/doc/telegram-chat.md + +:local 0 "telegram-chat"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Identity; +:global TelegramChatActive; +:global TelegramChatGroups; +:global TelegramChatId; +:global TelegramChatIdsTrusted; +:global TelegramChatOffset; +:global TelegramChatRunTime; +:global TelegramTokenId; + +:global CertificateAvailable; +:global EitherOr; +:global EscapeForRegEx; +:global GetRandom20CharAlNum; +:global IfThenElse; +:global LogPrintExit2; +:global MkDir; +:global ScriptLock; +:global SendTelegram2; +:global SymbolForNotification; +:global ValidateSyntax; +:global WaitForFile; +:global WaitFullyConnected; + +$ScriptLock $0; + +$WaitFullyConnected; + +:if ([ :typeof $TelegramChatOffset ] != "array") do={ + :set TelegramChatOffset { 0; 0; 0 }; +} + +:if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; +} + +:local JsonGetKey do={ + :local Array [ :toarray $1 ]; + :local Key [ :tostr $2 ]; + + :for I from=0 to=([ :len $Array ] - 1) do={ + :if (($Array->$I) = $Key) do={ + :if ($Array->($I + 1) = ":") do={ + :return ($Array->($I + 2)); + } + :return [ :pick ($Array->($I + 1)) 1 [ :len ($Array->($I + 1)) ] ]; + } + } + + :return false; +} + +:local Data; +:do { + :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ + ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=" . \ + $TelegramChatOffset->0 . "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); + :set Data [ :pick $Data ([ :find $Data "[" ] + 1) ([ :len $Data ] - 2) ]; +} on-error={ + $LogPrintExit2 debug $0 ("Failed getting updates from Telegram.") true; +} + +:local UpdateID 0; +:local Uptime [ /system/resource/get uptime ]; +:foreach Update in=[ :toarray $Data ] do={ + :set UpdateID [ $JsonGetKey $Update "update_id" ]; + :if (($TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={ + :local Trusted false; + :local Message [ $JsonGetKey $Update "message" ]; + :local MessageId [ $JsonGetKey $Message "message_id" ]; + :local From [ $JsonGetKey $Message "from" ]; + :local FromID [ $JsonGetKey $From "id" ]; + :local FromUserName [ $JsonGetKey $From "username" ]; + :local ChatID [ $JsonGetKey [ $JsonGetKey $Message "chat" ] "id" ]; + :local Text [ $JsonGetKey $Message "text" ]; + :foreach IdsTrusted in=($TelegramChatId, $TelegramChatIdsTrusted) do={ + :if ($FromID = $IdsTrusted || $FromUserName = $IdsTrusted) do={ + :set Trusted true; + } + } + + :if ($Trusted = true) do={ + :if ([ :pick $Text 0 1 ] = "!") do={ + :if ($Text ~ ("^! *(" . [ $EscapeForRegEx $Identity ] . "|@" . $TelegramChatGroups . ")\$")) do={ + :set TelegramChatActive true; + } else={ + :set TelegramChatActive false; + } + $LogPrintExit2 info $0 ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . \ + " from update " . $UpdateID . "!") false; + } else={ + :if ($TelegramChatActive = true && $Text != false && [ :len $Text ] > 0) do={ + :if ([ $ValidateSyntax $Text ] = true) do={ + :local State ""; + :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); + $MkDir "tmpfs/telegram-chat"; + $LogPrintExit2 info $0 ("Running command from update " . $UpdateID . ": " . $Text) false; + :exec script=(":do {\n" . $Text . "\n} on-error={ :execute script=\"/\" file=" . $File . ".failed };" . \ + ":execute script=\"/\" file=" . $File . ".done") file=$File; + :if ([ $WaitForFile ($File . ".done.txt") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ + :set State "The command did not finish, still running in background.\n\n"; + } + :if ([ :len [ /file/find where name=($File . ".failed.txt") ] ] > 0) do={ + :set State "The command failed with an error!\n\n"; + } + :local Content [ /file/get ($File . ".txt") contents ]; + $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; replyto=$MessageId; \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=("Command:\n" . $Text . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ + ("Output:\n" . $Content) [ $IfThenElse ([ /file/get ($File . ".txt") size ] > 0) \ + ("Output exceeds file read size.") ("No output.") ] ]) }); + /file/remove "tmpfs/telegram-chat"; + } else={ + $LogPrintExit2 info $0 ("The command from update " . $UpdateID . " failed syntax validation!") false; + $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; replyto=$MessageId; \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=("Command:\n" . $Text . "\n\nThe command failed syntax validation!") }); + } + } + } + } else={ + :local Message ("Received a message from untrusted contact " . \ + [ $IfThenElse ($FromUserName = false) "without username" ("'" . $FromUserName . "'") ] . \ + " (ID " . $FromID . ") in update " . $UpdateID . "!"); + :if ($Text ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ + $LogPrintExit2 warning $0 $Message false; + $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; replyto=$MessageId; \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=("You are not trusted.") }); + } else={ + $LogPrintExit2 info $0 $Message false; + } + } + } else={ + $LogPrintExit2 debug $0 ("Already handled update " . $UpdateID . ".") false; + } +} +:set TelegramChatOffset ([ :pick $TelegramChatOffset 1 3 ], \ + [ $IfThenElse ($UpdateID >= $TelegramChatOffset->2) ($UpdateID + 1) ($TelegramChatOffset->2) ]); diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index eac65c3..2da00ca 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -1,45 +1,3 @@ #!rsc by RouterOS -# RouterOS script: unattended-lte-firmware-upgrade -# Copyright (c) 2018-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# schedule unattended lte firmware upgrade -# https://git.eworm.de/cgit/routeros-scripts/about/doc/unattended-lte-firmware-upgrade.md - -:foreach Interface in=[ /interface/lte/find where running ] do={ - :local Firmware; - :local IntName [ /interface/lte/get $Interface name ]; - :do { - :set Firmware [ /interface/lte/firmware-upgrade $Interface once as-value ]; - } on-error={ - :log debug ("Could not get latest LTE firmware version for interface " . $IntName . "."); - } - - :if ([ :typeof $Firmware ] = "array") do={ - :if (($Firmware->"installed") != ($Firmware->"latest")) do={ - :log info ("Scheduling LTE firmware upgrade for interface " . $IntName . "."); - - :global LTEFirmwareUpgrade do={ - :global LTEFirmwareUpgrade; - :set LTEFirmwareUpgrade; - - /system/scheduler/remove ($1 . "-firmware-upgrade"); - /interface/lte/firmware-upgrade $1 upgrade=yes; - :log info ("LTE firmware upgrade on '" . $1 . "' finished, waiting for reset."); - :delay 240s; - :local Firmware [ /interface/lte/firmware-upgrade $1 once as-value ]; - :if (($Firmware->"installed") != ($Firmware->"latest")) do={ - :log warning ("LTE firmware versions still differ. Resetting again..."); - /interface/lte/at-chat $1 input="AT+RESET"; - } - } - - /system/scheduler/add name=($IntName . "-firmware-upgrade") start-time=startup interval=2s \ - on-event=(":global LTEFirmwareUpgrade; \$LTEFirmwareUpgrade \"" . $IntName . "\";"); - } else={ - :log info ("The LTE firmware is up to date on interface " . $IntName . "."); - } - } else={ - :log info ("No LTE firmware information available for interface " . $IntName . "."); - } -} +# dummy for migration diff --git a/unattended-lte-firmware-upgrade.rsc b/unattended-lte-firmware-upgrade.rsc new file mode 100644 index 0000000..eac65c3 --- /dev/null +++ b/unattended-lte-firmware-upgrade.rsc @@ -0,0 +1,45 @@ +#!rsc by RouterOS +# RouterOS script: unattended-lte-firmware-upgrade +# Copyright (c) 2018-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# schedule unattended lte firmware upgrade +# https://git.eworm.de/cgit/routeros-scripts/about/doc/unattended-lte-firmware-upgrade.md + +:foreach Interface in=[ /interface/lte/find where running ] do={ + :local Firmware; + :local IntName [ /interface/lte/get $Interface name ]; + :do { + :set Firmware [ /interface/lte/firmware-upgrade $Interface once as-value ]; + } on-error={ + :log debug ("Could not get latest LTE firmware version for interface " . $IntName . "."); + } + + :if ([ :typeof $Firmware ] = "array") do={ + :if (($Firmware->"installed") != ($Firmware->"latest")) do={ + :log info ("Scheduling LTE firmware upgrade for interface " . $IntName . "."); + + :global LTEFirmwareUpgrade do={ + :global LTEFirmwareUpgrade; + :set LTEFirmwareUpgrade; + + /system/scheduler/remove ($1 . "-firmware-upgrade"); + /interface/lte/firmware-upgrade $1 upgrade=yes; + :log info ("LTE firmware upgrade on '" . $1 . "' finished, waiting for reset."); + :delay 240s; + :local Firmware [ /interface/lte/firmware-upgrade $1 once as-value ]; + :if (($Firmware->"installed") != ($Firmware->"latest")) do={ + :log warning ("LTE firmware versions still differ. Resetting again..."); + /interface/lte/at-chat $1 input="AT+RESET"; + } + } + + /system/scheduler/add name=($IntName . "-firmware-upgrade") start-time=startup interval=2s \ + on-event=(":global LTEFirmwareUpgrade; \$LTEFirmwareUpgrade \"" . $IntName . "\";"); + } else={ + :log info ("The LTE firmware is up to date on interface " . $IntName . "."); + } + } else={ + :log info ("No LTE firmware information available for interface " . $IntName . "."); + } +} diff --git a/update-gre-address b/update-gre-address index 2958055..2da00ca 100644 --- a/update-gre-address +++ b/update-gre-address @@ -1,32 +1,3 @@ #!rsc by RouterOS -# RouterOS script: update-gre-address -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# update gre interface remote address with dynamic address from -# ipsec remote peer -# https://git.eworm.de/cgit/routeros-scripts/about/doc/update-gre-address.md - -:local 0 "update-gre-address"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global CharacterReplace; -:global LogPrintExit2; - -/interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; - -:foreach Peer in=[ /ip/ipsec/active-peers/find ] do={ - :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; - :local GreInt [ /interface/gre/find where comment=($PeerVal->"id") or comment=[ $CharacterReplace ($PeerVal->"id") "CN=" "" ] ]; - :if ([ :len $GreInt ] > 0) do={ - :local GreIntVal [ /interface/gre/get $GreInt ]; - :if ([ :typeof ($PeerVal->"dynamic-address") ] = "str" && \ - ($PeerVal->"dynamic-address" != $GreIntVal->"remote-address" || \ - $GreIntVal->"disabled" = true)) do={ - $LogPrintExit2 info $0 ("Updating remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address") false; - /interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$PeerVal->"dynamic-address" name!=$GreIntVal->"name" ]; - /interface/gre/set $GreInt remote-address=($PeerVal->"dynamic-address") disabled=no; - } - } -} +# dummy for migration diff --git a/update-gre-address.rsc b/update-gre-address.rsc new file mode 100644 index 0000000..2958055 --- /dev/null +++ b/update-gre-address.rsc @@ -0,0 +1,32 @@ +#!rsc by RouterOS +# RouterOS script: update-gre-address +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update gre interface remote address with dynamic address from +# ipsec remote peer +# https://git.eworm.de/cgit/routeros-scripts/about/doc/update-gre-address.md + +:local 0 "update-gre-address"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global CharacterReplace; +:global LogPrintExit2; + +/interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; + +:foreach Peer in=[ /ip/ipsec/active-peers/find ] do={ + :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; + :local GreInt [ /interface/gre/find where comment=($PeerVal->"id") or comment=[ $CharacterReplace ($PeerVal->"id") "CN=" "" ] ]; + :if ([ :len $GreInt ] > 0) do={ + :local GreIntVal [ /interface/gre/get $GreInt ]; + :if ([ :typeof ($PeerVal->"dynamic-address") ] = "str" && \ + ($PeerVal->"dynamic-address" != $GreIntVal->"remote-address" || \ + $GreIntVal->"disabled" = true)) do={ + $LogPrintExit2 info $0 ("Updating remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address") false; + /interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$PeerVal->"dynamic-address" name!=$GreIntVal->"name" ]; + /interface/gre/set $GreInt remote-address=($PeerVal->"dynamic-address") disabled=no; + } + } +} diff --git a/update-tunnelbroker b/update-tunnelbroker index 84d7430..2da00ca 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -1,55 +1,3 @@ #!rsc by RouterOS -# RouterOS script: update-tunnelbroker -# Copyright (c) 2013-2023 Christian Hesse -# Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: ppp-on-up -# -# update local address of tunnelbroker interface -# https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md - -:local 0 "update-tunnelbroker"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global CertificateAvailable; -:global LogPrintExit2; -:global ParseKeyValueStore; - -:if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ - $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; -} - -:foreach Interface in=[ /interface/6to4/find where comment~"^tunnelbroker" !disabled ] do={ - :local I 0; - :local Response ""; - :local InterfaceVal [ /interface/6to4/get $Interface ]; - :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; - - :while ($I < 3 && $Response = "") do={ - :do { - :set Response ([ /tool/fetch check-certificate=yes-without-crl \ - ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ - user=($Comment->"user") password=($Comment->"pass") output=user as-value ]->"data"); - } on-error={ - :delay 10s; - :set I ($I + 1); - } - } - - :if (!($Response~"^(good|nochg) ")) do={ - $LogPrintExit2 error $0 ("Failed sending the local address to tunnelbroker or unexpected response!") true; - } - - :local PublicAddress [ :pick $Response ([ :find $Response " " ] + 1) [ :find $Response "\n" ] ]; - - :if ($PublicAddress != $InterfaceVal->"local-address") do={ - :if ([ :len [ /ip/address find where address~("^" . $PublicAddress . "/") ] ] < 1) do={ - $LogPrintExit2 warning $0 ("The address " . $PublicAddress . " is not configured on your device. NAT by ISP?") false; - } - - $LogPrintExit2 info $0 ("Local address changed, updating tunnel configuration with address: " . $PublicAddress) false; - /interface/6to4/set $Interface local-address=$PublicAddress; - } -} +# dummy for migration diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc new file mode 100644 index 0000000..84d7430 --- /dev/null +++ b/update-tunnelbroker.rsc @@ -0,0 +1,55 @@ +#!rsc by RouterOS +# RouterOS script: update-tunnelbroker +# Copyright (c) 2013-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: ppp-on-up +# +# update local address of tunnelbroker interface +# https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md + +:local 0 "update-tunnelbroker"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global CertificateAvailable; +:global LogPrintExit2; +:global ParseKeyValueStore; + +:if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ + $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; +} + +:foreach Interface in=[ /interface/6to4/find where comment~"^tunnelbroker" !disabled ] do={ + :local I 0; + :local Response ""; + :local InterfaceVal [ /interface/6to4/get $Interface ]; + :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; + + :while ($I < 3 && $Response = "") do={ + :do { + :set Response ([ /tool/fetch check-certificate=yes-without-crl \ + ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ + user=($Comment->"user") password=($Comment->"pass") output=user as-value ]->"data"); + } on-error={ + :delay 10s; + :set I ($I + 1); + } + } + + :if (!($Response~"^(good|nochg) ")) do={ + $LogPrintExit2 error $0 ("Failed sending the local address to tunnelbroker or unexpected response!") true; + } + + :local PublicAddress [ :pick $Response ([ :find $Response " " ] + 1) [ :find $Response "\n" ] ]; + + :if ($PublicAddress != $InterfaceVal->"local-address") do={ + :if ([ :len [ /ip/address find where address~("^" . $PublicAddress . "/") ] ] < 1) do={ + $LogPrintExit2 warning $0 ("The address " . $PublicAddress . " is not configured on your device. NAT by ISP?") false; + } + + $LogPrintExit2 info $0 ("Local address changed, updating tunnel configuration with address: " . $PublicAddress) false; + /interface/6to4/set $Interface local-address=$PublicAddress; + } +} From e902e3fdd5cefda19d1562a126bfebe22038d904 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Mar 2023 12:08:30 +0100 Subject: [PATCH 1384/2612] global-functions: $ScriptInstallUpdate: make sure not to match self --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 6f3bb86..642b800 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -801,7 +801,7 @@ :if ([ :len $SourceNew ] > 0) do={ :if ($SourceNew != $ScriptVal->"source") do={ :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ - :local Required ([ $ParseKeyValueStore [ $Grep $SourceNew "# requires RouterOS, " ] ]->"version"); + :local Required ([ $ParseKeyValueStore [ $Grep $SourceNew ("\23 requires RouterOS, ") ] ]->"version"); :if ([ $RequiredRouterOS $0 [ $EitherOr $Required "0.0" ] false ] = true) do={ :if ([ $ValidateSyntax $SourceNew ] = true) do={ $LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; From 7912091f63ecc56e769d354973fa6fad6d793048 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Mar 2023 12:21:07 +0100 Subject: [PATCH 1385/2612] lease-script: make sure not to match self --- lease-script.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lease-script.rsc b/lease-script.rsc index 346d52b..cc56a1f 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -36,7 +36,7 @@ $ScriptLock $0 false 10; :foreach Script in=[ /system/script/find where source~("\n# provides: lease-script, ") ] do={ :local ScriptVal [ /system/script/get $Script ]; - :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") "# provides: lease-script, " ] ]; + :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") ("\23 provides: lease-script, ") ] ]; :set ($RunOrder->($Store->"order")) ($ScriptVal->"name"); } From 56ae457d777620afce8d92ac61b1701eb3ed9922 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 10 Mar 2023 09:46:16 +0100 Subject: [PATCH 1386/2612] global-functions: $ScriptInstallUpdate: add proper version in user agent This allows me to identify what RouterOS versions are run on devices fetching my scripts, which may helps to decide what incompatible changes to push. --- global-functions.rsc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 642b800..6e3f00a 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -753,6 +753,7 @@ :local ExpectedConfigVersionBefore $ExpectedConfigVersion; :local ReloadGlobalFunctions false; :local ReloadGlobalConfig false; + :local UserAgent ("User-Agent: Mikrotik/" . [ /system/resource/get version ] . " Fetch"); :foreach Script in=[ /system/script/find where source~"^#!rsc by RouterOS\n" ] do={ :local ScriptVal [ /system/script/get $Script ]; @@ -782,7 +783,8 @@ :local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix); $LogPrintExit2 debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url) false; - :local Result [ /tool/fetch check-certificate=yes-without-crl $Url output=user as-value ]; + :local Result [ /tool/fetch check-certificate=yes-without-crl http-header-field=$UserAgent \ + $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set SourceNew ($Result->"data"); } @@ -865,7 +867,8 @@ :do { :local Url ($ScriptUpdatesBaseUrl . "news-and-changes.rsc" . $ScriptUpdatesUrlSuffix); $LogPrintExit2 debug $0 ("Fetching news, changes and migration: " . $Url) false; - :local Result [ /tool/fetch check-certificate=yes-without-crl $Url output=user as-value ]; + :local Result [ /tool/fetch check-certificate=yes-without-crl http-header-field=$UserAgent \ + $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set ChangeLogCode ($Result->"data"); } From 3b5026ea8d8e8f9867b85d91c81d2296265d6d6a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 Mar 2023 09:18:11 +0100 Subject: [PATCH 1387/2612] drop dummy scripts used for migration This now causes expected warnings on first run of $ScriptInstallUpdate. The migration still works, as we keep `global-config.changes` and `global-functions`. --- accesslist-duplicates.capsman | 3 --- accesslist-duplicates.local | 3 --- backup-cloud | 3 --- backup-email | 3 --- backup-partition | 3 --- backup-upload | 3 --- capsman-download-packages | 3 --- capsman-rolling-upgrade | 3 --- certificate-renew-issued | 3 --- check-certificates | 3 --- check-health | 3 --- check-lte-firmware-upgrade | 3 --- check-routeros-update | 3 --- collect-wireless-mac.capsman | 3 --- collect-wireless-mac.local | 3 --- daily-psk.capsman | 3 --- daily-psk.local | 3 --- dhcp-lease-comment.capsman | 3 --- dhcp-lease-comment.local | 3 --- dhcp-to-dns | 3 --- firmware-upgrade-reboot | 3 --- global-config | 3 --- global-config.changes | 2 +- global-wait | 3 --- gps-track | 3 --- hotspot-to-wpa | 3 --- hotspot-to-wpa-cleanup | 3 --- ip-addr-bridge | 3 --- ipsec-to-dns | 3 --- ipv6-update | 3 --- lease-script | 3 --- leds-day-mode | 3 --- leds-night-mode | 3 --- leds-toggle-mode | 3 --- log-forward | 3 --- mod/bridge-port-to | 3 --- mod/bridge-port-vlan | 3 --- mod/inspectvar | 3 --- mod/ipcalc | 3 --- mod/notification-email | 3 --- mod/notification-matrix | 3 --- mod/notification-telegram | 3 --- mod/scriptrunonce | 3 --- mode-button | 3 --- netwatch-dns | 3 --- netwatch-notify | 3 --- ospf-to-leds | 3 --- packages-update | 3 --- ppp-on-up | 3 --- sms-action | 3 --- sms-forward | 3 --- ssh-keys-import | 3 --- super-mario-theme | 3 --- telegram-chat | 3 --- unattended-lte-firmware-upgrade | 3 --- update-gre-address | 3 --- update-tunnelbroker | 3 --- 57 files changed, 1 insertion(+), 169 deletions(-) delete mode 100644 accesslist-duplicates.capsman delete mode 100644 accesslist-duplicates.local delete mode 100644 backup-cloud delete mode 100644 backup-email delete mode 100644 backup-partition delete mode 100644 backup-upload delete mode 100644 capsman-download-packages delete mode 100644 capsman-rolling-upgrade delete mode 100644 certificate-renew-issued delete mode 100644 check-certificates delete mode 100644 check-health delete mode 100644 check-lte-firmware-upgrade delete mode 100644 check-routeros-update delete mode 100644 collect-wireless-mac.capsman delete mode 100644 collect-wireless-mac.local delete mode 100644 daily-psk.capsman delete mode 100644 daily-psk.local delete mode 100644 dhcp-lease-comment.capsman delete mode 100644 dhcp-lease-comment.local delete mode 100644 dhcp-to-dns delete mode 100644 firmware-upgrade-reboot delete mode 100644 global-config delete mode 100644 global-wait delete mode 100644 gps-track delete mode 100644 hotspot-to-wpa delete mode 100644 hotspot-to-wpa-cleanup delete mode 100644 ip-addr-bridge delete mode 100644 ipsec-to-dns delete mode 100644 ipv6-update delete mode 100644 lease-script delete mode 100644 leds-day-mode delete mode 100644 leds-night-mode delete mode 100644 leds-toggle-mode delete mode 100644 log-forward delete mode 100644 mod/bridge-port-to delete mode 100644 mod/bridge-port-vlan delete mode 100644 mod/inspectvar delete mode 100644 mod/ipcalc delete mode 100644 mod/notification-email delete mode 100644 mod/notification-matrix delete mode 100644 mod/notification-telegram delete mode 100644 mod/scriptrunonce delete mode 100644 mode-button delete mode 100644 netwatch-dns delete mode 100644 netwatch-notify delete mode 100644 ospf-to-leds delete mode 100644 packages-update delete mode 100644 ppp-on-up delete mode 100644 sms-action delete mode 100644 sms-forward delete mode 100644 ssh-keys-import delete mode 100644 super-mario-theme delete mode 100644 telegram-chat delete mode 100644 unattended-lte-firmware-upgrade delete mode 100644 update-gre-address delete mode 100644 update-tunnelbroker diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman deleted file mode 100644 index 2da00ca..0000000 --- a/accesslist-duplicates.capsman +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local deleted file mode 100644 index 2da00ca..0000000 --- a/accesslist-duplicates.local +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/backup-cloud b/backup-cloud deleted file mode 100644 index 2da00ca..0000000 --- a/backup-cloud +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/backup-email b/backup-email deleted file mode 100644 index 2da00ca..0000000 --- a/backup-email +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/backup-partition b/backup-partition deleted file mode 100644 index 2da00ca..0000000 --- a/backup-partition +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/backup-upload b/backup-upload deleted file mode 100644 index 2da00ca..0000000 --- a/backup-upload +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/capsman-download-packages b/capsman-download-packages deleted file mode 100644 index 2da00ca..0000000 --- a/capsman-download-packages +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade deleted file mode 100644 index 2da00ca..0000000 --- a/capsman-rolling-upgrade +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/certificate-renew-issued b/certificate-renew-issued deleted file mode 100644 index 2da00ca..0000000 --- a/certificate-renew-issued +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/check-certificates b/check-certificates deleted file mode 100644 index 2da00ca..0000000 --- a/check-certificates +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/check-health b/check-health deleted file mode 100644 index 2da00ca..0000000 --- a/check-health +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade deleted file mode 100644 index 2da00ca..0000000 --- a/check-lte-firmware-upgrade +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/check-routeros-update b/check-routeros-update deleted file mode 100644 index 2da00ca..0000000 --- a/check-routeros-update +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman deleted file mode 100644 index 2da00ca..0000000 --- a/collect-wireless-mac.capsman +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local deleted file mode 100644 index 2da00ca..0000000 --- a/collect-wireless-mac.local +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/daily-psk.capsman b/daily-psk.capsman deleted file mode 100644 index 2da00ca..0000000 --- a/daily-psk.capsman +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/daily-psk.local b/daily-psk.local deleted file mode 100644 index 2da00ca..0000000 --- a/daily-psk.local +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman deleted file mode 100644 index 2da00ca..0000000 --- a/dhcp-lease-comment.capsman +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local deleted file mode 100644 index 2da00ca..0000000 --- a/dhcp-lease-comment.local +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/dhcp-to-dns b/dhcp-to-dns deleted file mode 100644 index 2da00ca..0000000 --- a/dhcp-to-dns +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/firmware-upgrade-reboot b/firmware-upgrade-reboot deleted file mode 100644 index 2da00ca..0000000 --- a/firmware-upgrade-reboot +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/global-config b/global-config deleted file mode 100644 index 2da00ca..0000000 --- a/global-config +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/global-config.changes b/global-config.changes index be34365..47cfbc6 100644 --- a/global-config.changes +++ b/global-config.changes @@ -103,7 +103,7 @@ 92="Made qr-code url configurable for 'daily-psk'."; 93="Added support to backup global-config-overlay in 'backup-email' and 'backup-upload'."; 94="Added support for host addresses in address-list for 'ipv6-update'."; - 95="Renamed script files in repository, running migration. No user interaction is required."; + 95="Renamed script files in repository, running migration. Warnings (one per script) are expected, no user interaction is required."; }; # Migration steps to be applied on script updates diff --git a/global-wait b/global-wait deleted file mode 100644 index 2da00ca..0000000 --- a/global-wait +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/gps-track b/gps-track deleted file mode 100644 index 2da00ca..0000000 --- a/gps-track +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/hotspot-to-wpa b/hotspot-to-wpa deleted file mode 100644 index 2da00ca..0000000 --- a/hotspot-to-wpa +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/hotspot-to-wpa-cleanup b/hotspot-to-wpa-cleanup deleted file mode 100644 index 2da00ca..0000000 --- a/hotspot-to-wpa-cleanup +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/ip-addr-bridge b/ip-addr-bridge deleted file mode 100644 index 2da00ca..0000000 --- a/ip-addr-bridge +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/ipsec-to-dns b/ipsec-to-dns deleted file mode 100644 index 2da00ca..0000000 --- a/ipsec-to-dns +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/ipv6-update b/ipv6-update deleted file mode 100644 index 2da00ca..0000000 --- a/ipv6-update +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/lease-script b/lease-script deleted file mode 100644 index 2da00ca..0000000 --- a/lease-script +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/leds-day-mode b/leds-day-mode deleted file mode 100644 index 2da00ca..0000000 --- a/leds-day-mode +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/leds-night-mode b/leds-night-mode deleted file mode 100644 index 2da00ca..0000000 --- a/leds-night-mode +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/leds-toggle-mode b/leds-toggle-mode deleted file mode 100644 index 2da00ca..0000000 --- a/leds-toggle-mode +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/log-forward b/log-forward deleted file mode 100644 index 2da00ca..0000000 --- a/log-forward +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/mod/bridge-port-to b/mod/bridge-port-to deleted file mode 100644 index 2da00ca..0000000 --- a/mod/bridge-port-to +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan deleted file mode 100644 index 2da00ca..0000000 --- a/mod/bridge-port-vlan +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/mod/inspectvar b/mod/inspectvar deleted file mode 100644 index 2da00ca..0000000 --- a/mod/inspectvar +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/mod/ipcalc b/mod/ipcalc deleted file mode 100644 index 2da00ca..0000000 --- a/mod/ipcalc +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/mod/notification-email b/mod/notification-email deleted file mode 100644 index 2da00ca..0000000 --- a/mod/notification-email +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/mod/notification-matrix b/mod/notification-matrix deleted file mode 100644 index 2da00ca..0000000 --- a/mod/notification-matrix +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/mod/notification-telegram b/mod/notification-telegram deleted file mode 100644 index 2da00ca..0000000 --- a/mod/notification-telegram +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/mod/scriptrunonce b/mod/scriptrunonce deleted file mode 100644 index 2da00ca..0000000 --- a/mod/scriptrunonce +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/mode-button b/mode-button deleted file mode 100644 index 2da00ca..0000000 --- a/mode-button +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/netwatch-dns b/netwatch-dns deleted file mode 100644 index 2da00ca..0000000 --- a/netwatch-dns +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/netwatch-notify b/netwatch-notify deleted file mode 100644 index 2da00ca..0000000 --- a/netwatch-notify +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/ospf-to-leds b/ospf-to-leds deleted file mode 100644 index 2da00ca..0000000 --- a/ospf-to-leds +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/packages-update b/packages-update deleted file mode 100644 index 2da00ca..0000000 --- a/packages-update +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/ppp-on-up b/ppp-on-up deleted file mode 100644 index 2da00ca..0000000 --- a/ppp-on-up +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/sms-action b/sms-action deleted file mode 100644 index 2da00ca..0000000 --- a/sms-action +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/sms-forward b/sms-forward deleted file mode 100644 index 2da00ca..0000000 --- a/sms-forward +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/ssh-keys-import b/ssh-keys-import deleted file mode 100644 index 2da00ca..0000000 --- a/ssh-keys-import +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/super-mario-theme b/super-mario-theme deleted file mode 100644 index 2da00ca..0000000 --- a/super-mario-theme +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/telegram-chat b/telegram-chat deleted file mode 100644 index 2da00ca..0000000 --- a/telegram-chat +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade deleted file mode 100644 index 2da00ca..0000000 --- a/unattended-lte-firmware-upgrade +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/update-gre-address b/update-gre-address deleted file mode 100644 index 2da00ca..0000000 --- a/update-gre-address +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/update-tunnelbroker b/update-tunnelbroker deleted file mode 100644 index 2da00ca..0000000 --- a/update-tunnelbroker +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration From 650c362ed903209bb2144b3d4a89f46ca4865a38 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 20 Mar 2023 12:18:32 +0100 Subject: [PATCH 1388/2612] netwatch-notify: support note in notification --- doc/netwatch-notify.md | 7 +++++++ global-functions.rsc | 2 +- netwatch-notify.rsc | 6 ++++++ news-and-changes.rsc | 2 ++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 5bbd657..aa1204a 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -88,6 +88,13 @@ powered off, but accessibility is of interest. Go and get your coffee â˜•ī¸ before sending the print job. +### Add a note in notification + +For some extra information it is possible to add a text note. This is +included verbatim into the notification. + + /tool/netwatch/add comment="notify, name=example, note=Do not touch!" host=10.0.0.31; + Also notification settings are required for [e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or diff --git a/global-functions.rsc b/global-functions.rsc index 6e3f00a..512cf34 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 95; +:global ExpectedConfigVersion 96; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index d04d23f..3f47304 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -112,6 +112,9 @@ $ScriptLock $0; :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ ") is up since " . $HostVal->"since" . ".\n" . \ "It was down for " . $CountDown . " checks since " . ($Metric->"since") . "."); + :if ([ :typeof ($HostInfo->"note") ] = "str") do={ + :set Message ($Message . "\n\nNote:\n" . ($HostInfo->"note")); + } :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "up" \ ($HostInfo->"up-hook") ]); @@ -162,6 +165,9 @@ $ScriptLock $0; ($ParentUp = false || $ParentUp > 2) && $Metric->"notified" != true) do={ :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ ") is down since " . $HostVal->"since" . "."); + :if ([ :typeof ($HostInfo->"note") ] = "str") do={ + :set Message ($Message . "\n\nNote:\n" . ($HostInfo->"note")); + } :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "down" \ ($HostInfo->"down-hook") ]); diff --git a/news-and-changes.rsc b/news-and-changes.rsc index e532496..e809db2 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -9,8 +9,10 @@ # Changes for global-config to be added to notification on script updates :global GlobalConfigChanges { + 96="Added support for notes in 'netwatch-notify', these are included verbatim into the notification."; }; # Migration steps to be applied on script updates :global GlobalConfigMigration { + 0; }; From f7962f5d794a6152c1348c35a382f25a74ea64b5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 20 Mar 2023 12:22:46 +0100 Subject: [PATCH 1389/2612] doc/netwatch-notify: move hint on notification settings up --- doc/netwatch-notify.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index aa1204a..99335a1 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -38,6 +38,11 @@ The hosts to be checked have to be added to netwatch with specific comment: /tool/netwatch/add comment="notify, name=example.com" host=[ :resolve "example.com" ]; +Also notification settings are required for +[e-mail](mod/notification-email.md), +[matrix](mod/notification-matrix.md) and/or +[telegram](mod/notification-telegram.md). + ### Hooks It is possible to run an up hook command (`up-hook`) or down hook command @@ -95,11 +100,6 @@ included verbatim into the notification. /tool/netwatch/add comment="notify, name=example, note=Do not touch!" host=10.0.0.31; -Also notification settings are required for -[e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md) and/or -[telegram](mod/notification-telegram.md). - Tips & Tricks ------------- From b66364d716979848cc0f1f058ce6ba4920a2572d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 20 Mar 2023 13:32:39 +0100 Subject: [PATCH 1390/2612] doc/netwatch-notify: prevent escaping code in hook by creating a script --- doc/netwatch-notify.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 99335a1..6df233b 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -55,6 +55,9 @@ Also there is a `pre-down-hook` that fires at two thirds of failed checks required for the notification. The idea is to fix the issue before a notification is sent. +Getting the escaping right may be troublesome. Please consider adding a +script in `/system/script`, then running that from hook. + ### Count threshould The count threshould (default is 5 checks) is configurable as well: From 524c1fc032db7e4c361b90fe912fef036f1f59e2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 20 Mar 2023 16:32:34 +0100 Subject: [PATCH 1391/2612] README: badge in style flat and with color --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9c3f703..2d6b41f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ RouterOS Scripts ================ -[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/stargazers) -[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/network) -[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/watchers) +[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) +[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) +[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) ![RouterOS Scripts Logo](logo.svg) From 6e8c98e43d6f69882a3472416a1c2d08672aa9fa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Mar 2023 08:58:20 +0100 Subject: [PATCH 1392/2612] ipsec-to-dns: allow the matching separator string in name --- ipsec-to-dns.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index 530c714..a81a23c 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -27,11 +27,11 @@ :local CommentPrefix ("managed by " . $0 . " for "); :local CommentString ("--- " . $0 . " above ---"); -:if ([ :len [ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ - /ip/dns/static/add comment=$CommentString name=- type=NXDOMAIN disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false; +: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 comment=$CommentString name=- type=NXDOMAIN disabled ]->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 ] do={ :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; From 58a42f4ece0c73471a8c3ce6a6c87f9f3f08adf1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Mar 2023 08:59:58 +0100 Subject: [PATCH 1393/2612] ipsec-to-dns: match comment on beginning of line --- ipsec-to-dns.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index a81a23c..a476e74 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -33,7 +33,7 @@ } :local PlaceBefore ([ /ip/dns/static/find where (name=$CommentString or (comment=$CommentString and name=-)) type=NXDOMAIN disabled ]->0); -:foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={ +:foreach DnsRecord in=[ /ip/dns/static/find where comment~("^" . $CommentPrefix) ] do={ :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; :local PeerId [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; :if ([ :len [ /ip/ipsec/active-peers/find where id~("^(CN=)?" . [ $EscapeForRegEx $PeerId ] . "\$") \ From 3d589def7d5a1919f41c6f6cd128ff7c383e7a3d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Mar 2023 08:42:59 +0100 Subject: [PATCH 1394/2612] dhcp-to-dns: allow the matching separator string in name --- dhcp-to-dns.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 48f96b2..6e2c2a9 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -32,11 +32,11 @@ $ScriptLock $0 false 10; :local CommentPrefix ("managed by " . $0 . " for "); :local CommentString ("--- " . $0 . " above ---"); -:if ([ :len [ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ - /ip/dns/static/add comment=$CommentString name=- type=NXDOMAIN disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false; +: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 comment=$CommentString name=- type=NXDOMAIN disabled ]->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 ] do={ :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; From 682a09c94b777083e9a60c65e2f8c574850cfc20 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Mar 2023 22:49:33 +0100 Subject: [PATCH 1395/2612] dhcp-to-dns: match comment on beginning of line --- dhcp-to-dns.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 6e2c2a9..0914330 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -38,7 +38,7 @@ $ScriptLock $0 false 10; } :local PlaceBefore ([ /ip/dns/static/find where (name=$CommentString or (comment=$CommentString and name=-)) type=NXDOMAIN disabled ]->0); -:foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={ +:foreach DnsRecord in=[ /ip/dns/static/find where comment~("^" . $CommentPrefix) ] do={ :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; :if ([ :len [ /ip/dhcp-server/lease/find where mac-address=$MacAddress address=($DnsRecordVal->"address") status=bound ] ] > 0) do={ From 3396aefac9bd8c6d16112282b6f76be64deafa07 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Mar 2023 10:04:50 +0100 Subject: [PATCH 1396/2612] lease-script: add script name in order This makes sure scripts with the same order can not conflict. --- lease-script.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lease-script.rsc b/lease-script.rsc index cc56a1f..9b43e18 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -38,7 +38,7 @@ $ScriptLock $0 false 10; :local ScriptVal [ /system/script/get $Script ]; :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") ("\23 provides: lease-script, ") ] ]; - :set ($RunOrder->($Store->"order")) ($ScriptVal->"name"); + :set ($RunOrder->($Store->"order" . "-" . $ScriptVal->"name")) ($ScriptVal->"name"); } :foreach Order,Script in=$RunOrder do={ From 4a0f395fe127f82d35e0ac40af081a2391a36da5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Mar 2023 20:49:43 +0100 Subject: [PATCH 1397/2612] dhcp-to-dns: split fqdn to host name and domain --- dhcp-to-dns.rsc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 0914330..59daef4 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -63,9 +63,9 @@ $ScriptLock $0 false 10; :local HostName [ $IfThenElse ([ :len ($LeaseVal->"host-name") ] = 0) \ [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ] \ [ $CharacterReplace ($LeaseVal->"host-name") " " "" ] ]; + :local Domain ([ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); - :local Fqdn ($HostName . "." . [ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); - :local DnsRecord [ /ip/dns/static/find where name=$Fqdn ]; + :local DnsRecord [ /ip/dns/static/find where name=($HostName . "." . $Domain) ]; :if ([ :len $DnsRecord ] > 0) do={ :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; @@ -82,14 +82,14 @@ $ScriptLock $0 false 10; } :if ($DnsIp = $LeaseVal->"address") do={ - $LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false; + $LogPrintExit2 debug $0 ("DNS entry for " . ($HostName . "." . $Domain) . " does not need updating.") false; } else={ - $LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . ".") false; - /ip/dns/static/set name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; + $LogPrintExit2 info $0 ("Replacing DNS entry for " . ($HostName . "." . $Domain) . ", new address is " . $LeaseVal->"address" . ".") false; + /ip/dns/static/set name=($HostName . "." . $Domain) address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; } } else={ - $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false; - /ip/dns/static/add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + $LogPrintExit2 info $0 ("Adding new DNS entry for " . ($HostName . "." . $Domain) . ", address is " . $LeaseVal->"address" . ".") false; + /ip/dns/static/add name=($HostName . "." . $Domain) address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } else={ $LogPrintExit2 debug $0 ("No address available... Ignoring.") false; From aac87098814e10d4ec36ba2a77a29c2018869774 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Mar 2023 20:59:15 +0100 Subject: [PATCH 1398/2612] dhcp-to-dns: always create A record with mac address... ... and an optional CNAME with host name. --- dhcp-to-dns.rsc | 23 +++++++++++++---------- global-functions.rsc | 2 +- news-and-changes.rsc | 3 ++- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 59daef4..ee12697 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -38,7 +38,7 @@ $ScriptLock $0 false 10; } :local PlaceBefore ([ /ip/dns/static/find where (name=$CommentString or (comment=$CommentString and name=-)) type=NXDOMAIN disabled ]->0); -:foreach DnsRecord in=[ /ip/dns/static/find where comment~("^" . $CommentPrefix) ] do={ +:foreach DnsRecord in=[ /ip/dns/static/find where comment~("^" . $CommentPrefix) !(type=CNAME) ] do={ :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; :if ([ :len [ /ip/dhcp-server/lease/find where mac-address=$MacAddress address=($DnsRecordVal->"address") status=bound ] ] > 0) do={ @@ -47,6 +47,7 @@ $ScriptLock $0 false 10; :local Found false; $LogPrintExit2 info $0 ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry.") false; /ip/dns/static/remove $DnsRecord; + /ip/dns/static/remove [ find where type=CNAME cname=($DnsRecordVal->"name") comment=($DnsRecordVal->"comment") ]; } } @@ -60,12 +61,11 @@ $ScriptLock $0 false 10; :if ([ :len ($LeaseVal->"address") ] > 0) do={ :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); - :local HostName [ $IfThenElse ([ :len ($LeaseVal->"host-name") ] = 0) \ - [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ] \ - [ $CharacterReplace ($LeaseVal->"host-name") " " "" ] ]; + :local MacDash [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ]; + :local HostName [ $CharacterReplace ($LeaseVal->"host-name") " " "" ]; :local Domain ([ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); - :local DnsRecord [ /ip/dns/static/find where name=($HostName . "." . $Domain) ]; + :local DnsRecord [ /ip/dns/static/find where name=($MacDash . "." . $Domain) ]; :if ([ :len $DnsRecord ] > 0) do={ :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; @@ -82,14 +82,17 @@ $ScriptLock $0 false 10; } :if ($DnsIp = $LeaseVal->"address") do={ - $LogPrintExit2 debug $0 ("DNS entry for " . ($HostName . "." . $Domain) . " does not need updating.") false; + $LogPrintExit2 debug $0 ("DNS entry for " . ($MacDash . "." . $Domain) . " does not need updating.") false; } else={ - $LogPrintExit2 info $0 ("Replacing DNS entry for " . ($HostName . "." . $Domain) . ", new address is " . $LeaseVal->"address" . ".") false; - /ip/dns/static/set name=($HostName . "." . $Domain) address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; + $LogPrintExit2 info $0 ("Replacing DNS entry for " . ($MacDash . "." . $Domain) . ", new address is " . $LeaseVal->"address" . ".") false; + /ip/dns/static/set name=($MacDash . "." . $Domain) address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; } } else={ - $LogPrintExit2 info $0 ("Adding new DNS entry for " . ($HostName . "." . $Domain) . ", address is " . $LeaseVal->"address" . ".") false; - /ip/dns/static/add name=($HostName . "." . $Domain) address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + $LogPrintExit2 info $0 ("Adding new DNS entry for " . ($MacDash . "." . $Domain) . ", address is " . $LeaseVal->"address" . ".") false; + /ip/dns/static/add name=($MacDash . "." . $Domain) type=A address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + :if ([ :len $HostName ] > 0) do={ + /ip/dns/static/add name=($HostName . "." . $Domain) type=CNAME cname=($MacDash . "." . $Domain) ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + } } } else={ $LogPrintExit2 debug $0 ("No address available... Ignoring.") false; diff --git a/global-functions.rsc b/global-functions.rsc index 512cf34..2249fe9 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 96; +:global ExpectedConfigVersion 97; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index e809db2..d21ea6b 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -10,9 +10,10 @@ # Changes for global-config to be added to notification on script updates :global GlobalConfigChanges { 96="Added support for notes in 'netwatch-notify', these are included verbatim into the notification."; + 97="Modified 'dhcp-to-dns' to always add A records for names with mac address, and optionally add CNAME records if the host name is available."; }; # Migration steps to be applied on script updates :global GlobalConfigMigration { - 0; + 97=":local Rec [ /ip/dns/static/find where comment~\"^managed by dhcp-to-dns for \" ]; :if ([ :len \$Rec ] > 0) do={ /ip/dns/static/remove \$Rec; /system/script/run dhcp-to-dns; }"; }; From 8c728bb6ab7ad27c223af536be50438d51ee360c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Mar 2023 08:46:35 +0100 Subject: [PATCH 1399/2612] dhcp-to-dns: do not update records based on host name --- dhcp-to-dns.rsc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index ee12697..8f5b842 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -74,13 +74,6 @@ $ScriptLock $0 false 10; :set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; } - :if ([ :len ($LeaseVal->"host-name") ] > 0) do={ - :local HostNameLeases [ /ip/dhcp-server/lease/find where host-name=($LeaseVal->"host-name") status=bound ]; - :if ([ :len $HostNameLeases ] > 1) do={ - :set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($HostNameLeases->0) address ]; - } - } - :if ($DnsIp = $LeaseVal->"address") do={ $LogPrintExit2 debug $0 ("DNS entry for " . ($MacDash . "." . $Domain) . " does not need updating.") false; } else={ From c5c235246b82530135352eef954e5ce477455f93 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Mar 2023 09:16:16 +0100 Subject: [PATCH 1400/2612] dhcp-to-dns: add debug message on duplicate leases --- dhcp-to-dns.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 8f5b842..8166b0c 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -71,6 +71,7 @@ $ScriptLock $0 false 10; :local DupMacLeases [ /ip/dhcp-server/lease/find where mac-address=($LeaseVal->"mac-address") status=bound ]; :if ([ :len $DupMacLeases ] > 1) do={ + $LogPrintExit2 debug $0 ("Multiple bound leases found for mac-address " . ($LeaseVal->"mac-address") . ", using ip address of last one.") false; :set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; } From b13a53531bcd2b557b207810110b8987b93208b6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Mar 2023 09:18:06 +0100 Subject: [PATCH 1401/2612] dhcp-to-dns: just update the address The other values *should* be unchanged... --- dhcp-to-dns.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 8166b0c..aa71e4c 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -79,7 +79,7 @@ $ScriptLock $0 false 10; $LogPrintExit2 debug $0 ("DNS entry for " . ($MacDash . "." . $Domain) . " does not need updating.") false; } else={ $LogPrintExit2 info $0 ("Replacing DNS entry for " . ($MacDash . "." . $Domain) . ", new address is " . $LeaseVal->"address" . ".") false; - /ip/dns/static/set name=($MacDash . "." . $Domain) address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; + /ip/dns/static/set address=($LeaseVal->"address") $DnsRecord; } } else={ $LogPrintExit2 info $0 ("Adding new DNS entry for " . ($MacDash . "." . $Domain) . ", address is " . $LeaseVal->"address" . ".") false; From 295ccb570d98dd3f782da5e0272d62bf2698a836 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Mar 2023 10:21:31 +0100 Subject: [PATCH 1402/2612] dhcp-to-dns: update cname record on changed host name --- dhcp-to-dns.rsc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index aa71e4c..75b3fbf 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -81,6 +81,12 @@ $ScriptLock $0 false 10; $LogPrintExit2 info $0 ("Replacing DNS entry for " . ($MacDash . "." . $Domain) . ", new address is " . $LeaseVal->"address" . ".") false; /ip/dns/static/set address=($LeaseVal->"address") $DnsRecord; } + + :local Cname [ /ip/dns/static/find where type=CNAME cname=($MacDash . "." . $Domain) comment=$Comment ]; + :if ([ :len $Cname ] > 0 && [ /ip/dns/static/get $Cname name ] != ($HostName . "." . $Domain)) do={ + $LogPrintExit2 info $0 ("Host name changed, updating CNAME (pointing to " . ($MacDash . "." . $Domain) . ") to " . ($HostName . "." . $Domain) . ".") false; + /ip/dns/static/set name=($HostName . "." . $Domain) $Cname; + } } else={ $LogPrintExit2 info $0 ("Adding new DNS entry for " . ($MacDash . "." . $Domain) . ", address is " . $LeaseVal->"address" . ".") false; /ip/dns/static/add name=($MacDash . "." . $Domain) type=A address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; From eab87e4d60898e64efe44c49a07526906910816b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 23 Mar 2023 13:51:52 +0100 Subject: [PATCH 1403/2612] sms-forward: add workaround to fix removal of messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removal of messages is broken in RouterOS 7.8: [admin@MikroTik] > /tool/sms/inbox/remove [ find ] failure: Interface not running! Of course the interface is running. Toggling the auto-erase setting fixes this until next boot. So let's add a workaround... Reported to support (SUP-110828), but not (yet) acknowledged. 🤨 --- sms-forward.rsc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sms-forward.rsc b/sms-forward.rsc index 802da48..74b1b31 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -13,9 +13,11 @@ :global Identity; :global SmsForwardHooks; +:global SmsForwardWorkaround; :global IfThenElse; :global LogPrintExit2; +:global RequiredRouterOS; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -28,6 +30,14 @@ $ScriptLock $0; $LogPrintExit2 warning $0 ("Receiving of SMS is not enabled.") true; } +:if ($SmsForwardWorkaround != true && \ + [ $RequiredRouterOS $0 "7.8" false ] = true) do={ + :local AutoErase [ /tool/sms/get auto-erase ]; + /tool/sms/set auto-erase=(!$AutoErase); + /tool/sms/set auto-erase=$AutoErase; + :set SmsForwardWorkaround true; +} + $WaitFullyConnected; :local Settings [ /tool/sms/get ]; From 4f722bc2c9019dd687a0df450034b18aae81f782 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Mar 2023 18:43:03 +0100 Subject: [PATCH 1404/2612] sms-forward: disable workaround for ROS 7.9beta4 The issue has been acknowledged by Mikrotik, but the cause is still unknown as the sms code did not change since RouterOS 7.6... Well, looks like the behavior changes again with RouterOS 7.9beta4, and everything works as expected again. So disable the workaround there. --- sms-forward.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sms-forward.rsc b/sms-forward.rsc index 74b1b31..9259eae 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -31,7 +31,8 @@ $ScriptLock $0; } :if ($SmsForwardWorkaround != true && \ - [ $RequiredRouterOS $0 "7.8" false ] = true) do={ + [ $RequiredRouterOS $0 "7.8" false ] = true && \ + [ $RequiredRouterOS $0 "7.9beta4" false ] = false) do={ :local AutoErase [ /tool/sms/get auto-erase ]; /tool/sms/set auto-erase=(!$AutoErase); /tool/sms/set auto-erase=$AutoErase; From 742c239629ff7e894ccf1a45e708a0a993ef380d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 28 Mar 2023 10:03:39 +0200 Subject: [PATCH 1405/2612] sms-forward: check that the interface is running --- sms-forward.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sms-forward.rsc b/sms-forward.rsc index 9259eae..e6ac9aa 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -43,6 +43,10 @@ $WaitFullyConnected; :local Settings [ /tool/sms/get ]; +:if ([ /interface/lte/get ($Settings->"port") running ] != true) do={ + $LogPrintExit2 info $0 ("The LTE interface is not in running state, skipping.") true; +} + # forward SMS in a loop :while ([ :len [ /tool/sms/inbox/find ] ] > 0) do={ :local Phone [ /tool/sms/inbox/get ([ find ]->0) phone ]; From b22a84ed0fe876f75b70e918c68835a01d67025c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 25 Mar 2023 22:51:33 +0100 Subject: [PATCH 1406/2612] doc/dhcp-to-dns: mention A record and optional CNAME record --- doc/dhcp-to-dns.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 531a75b..7229c9a 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -9,7 +9,9 @@ Create DNS records for DHCP leases Description ----------- -This script adds (and removes) dns records based on dhcp server leases. +This script adds (and updates & removes) dns records based on dhcp server +leases. An A record based on mac address is created for all bound lease, +additionally a CNAME record is created from host name if available. Requirements and installation ----------------------------- From 40f0d54ea89b701afbbc1cfa2ade8913c4d137eb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 25 Mar 2023 22:31:56 +0100 Subject: [PATCH 1407/2612] dhcp-to-dns: add cname if host name appears for existing record --- dhcp-to-dns.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 75b3fbf..b925fdb 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -83,6 +83,10 @@ $ScriptLock $0 false 10; } :local Cname [ /ip/dns/static/find where type=CNAME cname=($MacDash . "." . $Domain) comment=$Comment ]; + :if ([ :len $Cname ] = 0 && [ :len $HostName ] > 0) do={ + $LogPrintExit2 info $0 ("Host name appeared, adding CNAME " . ($HostName . "." . $Domain) . " pointing to " . ($MacDash . "." . $Domain) . ".") false; + /ip/dns/static/add name=($HostName . "." . $Domain) type=CNAME cname=($MacDash . "." . $Domain) ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + } :if ([ :len $Cname ] > 0 && [ /ip/dns/static/get $Cname name ] != ($HostName . "." . $Domain)) do={ $LogPrintExit2 info $0 ("Host name changed, updating CNAME (pointing to " . ($MacDash . "." . $Domain) . ") to " . ($HostName . "." . $Domain) . ".") false; /ip/dns/static/set name=($HostName . "." . $Domain) $Cname; From 847f0a4564e6f2b6084d591a0e8539c080bb49bb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 25 Mar 2023 20:28:58 +0100 Subject: [PATCH 1408/2612] global-functions: $MkDir: drop unused function --- global-functions.rsc | 1 - 1 file changed, 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 2249fe9..416ea08 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -558,7 +558,6 @@ :global CleanFilePath; :global GetRandom20CharAlNum; :global LogPrintExit2; - :global RequiredRouterOS; :global WaitForFile; :set Path [ $CleanFilePath $Path ]; From 7293306f76b638f8ca94e9916e92389aed34b770 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 25 Mar 2023 21:49:12 +0100 Subject: [PATCH 1409/2612] global-functions: $MkDir: return false on error --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 416ea08..ffe9a4b 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -589,7 +589,7 @@ $WaitForFile "tmpfs"; } on-error={ $LogPrintExit2 warning $0 ("Creating disk of type tmpfs failed!") false; - :set Error true; + :return false; } } :set Continue true; From d3ca5063947f4350721cfe1828faae2cd771f133 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 25 Mar 2023 21:27:24 +0100 Subject: [PATCH 1410/2612] global-functions: $MkDir: create tmpfs in local function --- global-functions.rsc | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index ffe9a4b..2eb0416 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -560,6 +560,26 @@ :global LogPrintExit2; :global WaitForFile; + :local MkTmpfs do={ + :global LogPrintExit2; + :global WaitForFile; + + :if ([ :len [ /disk/find where slot=tmpfs type=tmpfs ] ] = 1) do={ + :return true; + } + + $LogPrintExit2 info $0 ("Creating disk of type tmpfs.") false; + /file/remove [ find where name="tmpfs" type="directory" ]; + :do { + /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/get total-memory ] / 3); + $WaitForFile "tmpfs"; + } on-error={ + $LogPrintExit2 warning $0 ("Creating disk of type tmpfs failed!") false; + :return false; + } + :return true; + } + :set Path [ $CleanFilePath $Path ]; :if ($Path = "") do={ @@ -581,16 +601,8 @@ } :if ($Continue = false && $PathNext = "tmpfs") do={ - :if ([ :len [ /disk/find where slot=tmpfs type=tmpfs ] ] = 0) do={ - $LogPrintExit2 info $0 ("Creating disk of type tmpfs.") false; - /file/remove [ find where name="tmpfs" type="directory" ]; - :do { - /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/get total-memory ] / 3); - $WaitForFile "tmpfs"; - } on-error={ - $LogPrintExit2 warning $0 ("Creating disk of type tmpfs failed!") false; - :return false; - } + :if ([ $MkTmpfs ] = false) do={ + :return false; } :set Continue true; } From d700dbc00e6e22ea9521d3b359f0d3635d9af682 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 25 Mar 2023 22:33:02 +0100 Subject: [PATCH 1411/2612] dhcp-to-dns: support host name from dhcp lease comment The lease comment is supposed to be a human readable string... But we could allow parsable information. --- dhcp-to-dns.rsc | 4 +++- doc/dhcp-to-dns.md | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index b925fdb..259a904 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -19,8 +19,10 @@ :global ServerNameInZone; :global CharacterReplace; +:global EitherOr; :global IfThenElse; :global LogPrintExit2; +:global ParseKeyValueStore; :global ScriptLock; $ScriptLock $0 false 10; @@ -62,7 +64,7 @@ $ScriptLock $0 false 10; :if ([ :len ($LeaseVal->"address") ] > 0) do={ :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); :local MacDash [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ]; - :local HostName [ $CharacterReplace ($LeaseVal->"host-name") " " "" ]; + :local HostName [ $CharacterReplace [ $EitherOr ([ $ParseKeyValueStore ($LeaseVal->"comment") ]->"hostname") ($LeaseVal->"host-name") ] " " "" ]; :local Domain ([ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); :local DnsRecord [ /ip/dns/static/find where name=($MacDash . "." . $Domain) ]; diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 7229c9a..a2caf0c 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -41,6 +41,19 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `PrefixInZone`: whether or not to add prefix `dhcp` * `ServerNameInZone`: whether or not to add DHCP server name +### Host name from DHCP lease comment + +Overwriting the host name from dhcp lease comment is supported, just add +something like `hostname=new-hostname` in comment, and separate it by comma +from other information if required: + + /ip/dhcp-server/lease/add address=10.0.0.50 comment="my device, hostname=new-hostname" mac-address=00:11:22:33:44:55 server=dhcp; + +Note this information can be configured in wireless access list with +[dhcp-lease-comment](dhcp-lease-comment.md), though it comes with a delay +then due to script execution order. Decrease the scheduler interval to +reduce the effect. + See also -------- From 7fdec1abed5be3c7dc651cdd6b878519c848f15f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 28 Mar 2023 11:07:45 +0200 Subject: [PATCH 1412/2612] global-functions: $MkDir: add extra block for indention... ... to make the next commit cleaner. No functional change. --- global-functions.rsc | 60 +++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 2eb0416..3f0aa6a 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -590,40 +590,42 @@ :return true; } - :local Error false; - :local PathNext ""; - :foreach Dir in=[ :toarray [ $CharacterReplace $Path "/" "," ] ] do={ - :local Continue false; - :set PathNext [ $CleanFilePath ($PathNext . "/" . $Dir) ]; + { + :local Error false; + :local PathNext ""; + :foreach Dir in=[ :toarray [ $CharacterReplace $Path "/" "," ] ] do={ + :local Continue false; + :set PathNext [ $CleanFilePath ($PathNext . "/" . $Dir) ]; - :if ([ :len [ /file/find where name=$PathNext !(name="tmpfs") type="directory" ] ] = 1) do={ - :set Continue true; - } + :if ([ :len [ /file/find where name=$PathNext !(name="tmpfs") type="directory" ] ] = 1) do={ + :set Continue true; + } - :if ($Continue = false && $PathNext = "tmpfs") do={ - :if ([ $MkTmpfs ] = false) do={ + :if ($Continue = false && $PathNext = "tmpfs") do={ + :if ([ $MkTmpfs ] = false) do={ + :return false; + } + :set Continue true; + } + + :if ($Continue = false && [ :len [ /file/find where name=$PathNext ] ] = 1) do={ + $LogPrintExit2 warning $0 ("The path '" . $PathNext . "' exists, but is not a directory.") false; :return false; } - :set Continue true; - } - :if ($Continue = false && [ :len [ /file/find where name=$PathNext ] ] = 1) do={ - $LogPrintExit2 warning $0 ("The path '" . $PathNext . "' exists, but is not a directory.") false; - :return false; - } - - :if ($Continue = false) do={ - :local Name ($PathNext . "-" . [ $GetRandom20CharAlNum 6 ]); - :do { - /ip/smb/share/add disabled=yes directory=$PathNext name=$Name; - $WaitForFile $PathNext; - } on-error={ - $LogPrintExit2 warning $0 ("Making directory '" . $PathNext . "' failed!") false; - :set Error true; - } - /ip/smb/share/remove [ find where name=$Name ]; - :if ($Error = true) do={ - :return false; + :if ($Continue = false) do={ + :local Name ($PathNext . "-" . [ $GetRandom20CharAlNum 6 ]); + :do { + /ip/smb/share/add disabled=yes directory=$PathNext name=$Name; + $WaitForFile $PathNext; + } on-error={ + $LogPrintExit2 warning $0 ("Making directory '" . $PathNext . "' failed!") false; + :set Error true; + } + /ip/smb/share/remove [ find where name=$Name ]; + :if ($Error = true) do={ + :return false; + } } } } From f2e811527206373d91ffa36f4a9662b1adb563d2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 25 Mar 2023 21:59:40 +0100 Subject: [PATCH 1413/2612] global-functions: $MkDir: make directory by adding file This is new functionality in RouterOS 7.9beta4, where new file can be added with `/file/add ...`. This also creates directories for the full path. --- global-functions.rsc | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 3f0aa6a..24b6223 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -558,6 +558,7 @@ :global CleanFilePath; :global GetRandom20CharAlNum; :global LogPrintExit2; + :global RequiredRouterOS; :global WaitForFile; :local MkTmpfs do={ @@ -590,7 +591,23 @@ :return true; } - { + :if ([ $RequiredRouterOS $0 "7.9beta4" false ] = true) do={ + :if ([ :pick $Path 0 5 ] = "tmpfs") do={ + :if ([ $MkTmpfs ] = false) do={ + :return false; + } + } + + :do { + :local File ($Path . "/file"); + /file/add name=$File; + $WaitForFile $File; + /file/remove $File; + } on-error={ + $LogPrintExit2 warning $0 ("Making directory '" . $Path . "' failed!") false; + :return false; + } + } else={ :local Error false; :local PathNext ""; :foreach Dir in=[ :toarray [ $CharacterReplace $Path "/" "," ] ] do={ From 9d823448f6f3bfe00a6c8a44d151e79fb9a41ff4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Mar 2023 15:22:13 +0200 Subject: [PATCH 1414/2612] contrib/notification.html: fix warnings and errors Checked with W3C validator: https://validator.w3.org/ --- contrib/notification.d/style.css | 3 ++- contrib/notification.html | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/contrib/notification.d/style.css b/contrib/notification.d/style.css index c07de89..f4b34df 100644 --- a/contrib/notification.d/style.css +++ b/contrib/notification.d/style.css @@ -34,6 +34,7 @@ pre { span.link { color: #863600; } -tt { +span.tag { + font-family: monospace; background-color: #e6e6e6; } diff --git a/contrib/notification.html b/contrib/notification.html index 56cb612..e71c71b 100644 --- a/contrib/notification.html +++ b/contrib/notification.html @@ -1,5 +1,5 @@ - + RouterOS-Scripts Notification Generator @@ -10,7 +10,7 @@

    RouterOS-Scripts Notification Generator

    - +

    [MikroTik] â„šī¸ Subject

    Message
    @@ -21,13 +21,13 @@

    Hostname:

    -

    Subject:

    +

    Subject:

    Message:

    Show link:

    Queued since

    Cut-off with percent

    -

    â„šī¸ Open the inspector, select the div element, right click and select "Screenshot Node"!

    +

    â„šī¸ Open the inspector, select the div element, right click and select "Screenshot Node"!

    From 3d0107ed2c0f03998b6ca59f3731d785f05df1e8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Mar 2023 15:35:07 +0200 Subject: [PATCH 1415/2612] contrib/notification.html: add and load the script --- contrib/notification.d/script.js | 6 ++++++ contrib/notification.html | 1 + 2 files changed, 7 insertions(+) create mode 100644 contrib/notification.d/script.js diff --git a/contrib/notification.d/script.js b/contrib/notification.d/script.js new file mode 100644 index 0000000..91741fd --- /dev/null +++ b/contrib/notification.d/script.js @@ -0,0 +1,6 @@ +function visible(cb, element) { + document.getElementById(element).style.display = cb.checked ? "block" : "none"; +} +function update(cb, element) { + document.getElementById(element).innerHTML = cb.value; +} diff --git a/contrib/notification.html b/contrib/notification.html index e71c71b..f483ab0 100644 --- a/contrib/notification.html +++ b/contrib/notification.html @@ -4,6 +4,7 @@ RouterOS-Scripts Notification Generator + From 779b3b8872b23b784c331d7a454c86439046f5d3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Mar 2023 15:49:41 +0200 Subject: [PATCH 1416/2612] dhcp-to-dns: use better condition The condition worked, but could match others (AAAA, NXDOMAIN, ...) as well (though these should not exist). The problem is that matching with `type=A` does not return any results. For historical reasons A records have no type, thus can be matched with `!type`. I opened an issue to fix this... (SUP-111312) So let's assum `!type` works and `type=A` could become valid... --- dhcp-to-dns.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 259a904..67ecacd 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -40,7 +40,7 @@ $ScriptLock $0 false 10; } :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) !(type=CNAME) ] do={ +:foreach DnsRecord in=[ /ip/dns/static/find where comment~("^" . $CommentPrefix) (!type or type=A) ] do={ :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; :if ([ :len [ /ip/dhcp-server/lease/find where mac-address=$MacAddress address=($DnsRecordVal->"address") status=bound ] ] > 0) do={ From 5f374c469a0bc49b2c9bf26cc3129e747867cc42 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 30 Mar 2023 20:50:55 +0200 Subject: [PATCH 1417/2612] global-functions: $RequiredRouterOS: accept "alpha" in version string --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 24b6223..82823fb 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -704,7 +704,7 @@ :global LogPrintExit2; :global VersionToNum; - :if (!($Required ~ "^\\d+\\.\\d+((beta|rc|\\.)\\d+|)\$")) do={ + :if (!($Required ~ "^\\d+\\.\\d+((alpha|beta|rc|\\.)\\d+|)\$")) do={ $LogPrintExit2 error $0 ("No valid RouterOS version: " . $Required) false; :return false; } From 415c4144f2e1ee32a0b588e2d66ec95d6d40e612 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 30 Mar 2023 20:58:19 +0200 Subject: [PATCH 1418/2612] global-functions: $VersionToNum: support "alpha" in version string --- global-functions.rsc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 82823fb..f75ed54 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1226,8 +1226,10 @@ :global CharacterReplace; - :set Input [ $CharacterReplace [ $CharacterReplace [ $CharacterReplace $Input \ - "." "," ] "beta" ",beta," ] "rc" ",rc," ]; + :set Input [ $CharacterReplace $Input "." "," ]; + :foreach I in={ "alpha"; "beta"; "rc" } do={ + :set Input [ $CharacterReplace $Input $I ("," . $I . ",") ]; + } :foreach Value in=([ :toarray $Input ], 0) do={ :local Num [ :tonum $Value ]; @@ -1236,7 +1238,8 @@ :set Return ($Return + 0xff00); :set Multi ($Multi / 0x100); } else={ - :if ($Value = "beta") do={ :set Return ($Return + 0x3f00); } + :if ($Value = "alpha") do={ :set Return ($Return + 0x3f00); } + :if ($Value = "beta") do={ :set Return ($Return + 0x5f00); } :if ($Value = "rc") do={ :set Return ($Return + 0x7f00); } } } From 68364d4a50552bbbb3fbfd8ecbc94329feae188e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 31 Mar 2023 17:45:55 +0200 Subject: [PATCH 1419/2612] doc/check-health: use an unusual interval --- doc/check-health.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/check-health.md b/doc/check-health.md index 58c1fba..f0e5c11 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -59,7 +59,11 @@ Requirements and installation Just install the script and create a scheduler: $ScriptInstallUpdate check-health; - /system/scheduler/add interval=1m name=check-health on-event="/system/script/run check-health;" start-time=startup; + /system/scheduler/add interval=53s name=check-health on-event="/system/script/run check-health;" start-time=startup; + +> â„šī¸ **Info**: Running lots of scripts simultaneously can tamper the +> precision of cpu utilization, escpecially on devices with limited +> resources. Thus an unusual interval is used here. Configuration ------------- From b6f9094c3d09360f06adda67b453bbfbf54dc7ec Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 4 Apr 2023 19:22:13 +0200 Subject: [PATCH 1420/2612] mod/inspectvar: link documentation --- mod/inspectvar.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mod/inspectvar.rsc b/mod/inspectvar.rsc index 8bb5c5f..e06d799 100644 --- a/mod/inspectvar.rsc +++ b/mod/inspectvar.rsc @@ -2,6 +2,9 @@ # RouterOS script: mod/inspectvar # Copyright (c) 2020-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# inspect variables +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/inspectvar.md :global InspectVar; :global InspectVarReturn; From 8edf694b54277404869a81cd7a01fb9abe0f4e0d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 4 Apr 2023 19:22:44 +0200 Subject: [PATCH 1421/2612] mod/ipcalc: link documentation --- mod/ipcalc.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc index 92e246f..ee78378 100644 --- a/mod/ipcalc.rsc +++ b/mod/ipcalc.rsc @@ -2,6 +2,9 @@ # RouterOS script: mod/ipcalc # Copyright (c) 2020-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# ip address calculation +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ipcalc.md :global IPCalc; :global IPCalcReturn; From 9136bf28bde80a7850a2013cd6a190a9f6fcccda Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 4 Apr 2023 19:23:03 +0200 Subject: [PATCH 1422/2612] mod/notification-email: link documentation --- mod/notification-email.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index b03e176..b1f3f7c 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -2,6 +2,9 @@ # RouterOS script: mod/notification-email # Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# send notifications via e-mail +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-email.md :global FlushEmailQueue; :global LogForwardFilterLogForwarding; From b7cb722b5cc58c03aa2ab5fd49dd3559498e4643 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 4 Apr 2023 19:23:23 +0200 Subject: [PATCH 1423/2612] mod/notification-matrix: link documentation --- mod/notification-matrix.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 6266b75..16b2370 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -3,6 +3,9 @@ # Copyright (c) 2013-2023 Michael Gisbers # Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# send notifications via Matrix +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-matrix.md :global FlushMatrixQueue; :global NotificationFunctions; From 61e0e052a6370bd099418554a7599848004c3459 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 4 Apr 2023 19:23:39 +0200 Subject: [PATCH 1424/2612] mod/notification-telegram: link documentation --- mod/notification-telegram.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index c90e3f0..e59dbb2 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -2,6 +2,9 @@ # RouterOS script: mod/notification-telegram # Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# send notifications via Telegram +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-telegram.md :global FlushTelegramQueue; :global NotificationFunctions; From a1f6bd532b43aead33cfbbce85e8a41e7d2ee1c3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 4 Apr 2023 19:24:00 +0200 Subject: [PATCH 1425/2612] mod/scriptrunonce: link documentation --- mod/scriptrunonce.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index 96c49c3..376e778 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -2,6 +2,9 @@ # RouterOS script: mod/scriptrunonece # Copyright (c) 2020-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# download script and run it once +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/scriptrunonce.md :global ScriptRunOnce; From a263fcdec2da2360cebea137085a60c7a67c4198 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Apr 2023 10:16:55 +0200 Subject: [PATCH 1426/2612] check-certificates: format information in a local function --- check-certificates.rsc | 44 +++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 8a06f8b..ed50eea 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -27,9 +27,25 @@ :global WaitForFile; :global WaitFullyConnected; -:local FormatExpire do={ - :global CharacterReplace; - :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; +:local FormatInfo do={ + :local CertVal $1; + + :global IfThenElse; + :global ParseKeyValueStore; + + :local FormatExpire do={ + :global CharacterReplace; + :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; + } + + :return ( \ + "Name: " . ($CertVal->"name") . "\n" . \ + "CommonName: " . ($CertVal->"common-name") . "\n" . \ + "Private key: " . [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] . "\n" . \ + "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ + "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ + "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ + "Expires in: " . [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ]); } $WaitFullyConnected; @@ -95,18 +111,13 @@ $WaitFullyConnected; /certificate/remove $Cert; /certificate/set $CertNew name=($CertVal->"name"); + :set CertNewVal; + :set CertVal [ /certificate/get $CertNew ];; } - $SendNotification2 ({ origin=$0; \ + $SendNotification2 ({ origin=$0; silent=true; \ subject=([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed"); \ - message=("A certificate on " . $Identity . " has been renewed.\n\n" . \ - "Name: " . ($CertVal->"name") . "\n" . \ - "CommonName: " . ($CertNewVal->"common-name") . "\n" . \ - "Private key: " . [ $IfThenElse (($CertNewVal->"private-key") = true) "available" "missing" ] . "\n" . \ - "Fingerprint: " . ($CertNewVal->"fingerprint") . "\n" . \ - "Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \ - "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ - "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]); silent=true }); + message=("A certificate on " . $Identity . " has been renewed.\n\n" . [ $FormatInfo $CertVal ]) }); $LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " has been renewed.") false; } on-error={ $LogPrintExit2 debug $0 ("Could not renew certificate " . ($CertVal->"name") . ".") false; @@ -124,14 +135,7 @@ $WaitFullyConnected; $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning!"); \ - message=("A certificate on " . $Identity . " " . $State . ".\n\n" . \ - "Name: " . ($CertVal->"name") . "\n" . \ - "CommonName: " . ($CertVal->"common-name") . "\n" . \ - "Private key: " . [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] . "\n" . \ - "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ - "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ - "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ - "Expires in: " . [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ]) }); + message=("A certificate on " . $Identity . " " . $State . ".\n\n" . [ $FormatInfo $CertVal ]) }); $LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " " . $State . \ ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; } From 706e4de6d1ed218ca689885621183ba42a9d62cf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Apr 2023 10:18:41 +0200 Subject: [PATCH 1427/2612] check-certificates: show CommonName only if available --- check-certificates.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index ed50eea..704ea15 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -40,7 +40,7 @@ :return ( \ "Name: " . ($CertVal->"name") . "\n" . \ - "CommonName: " . ($CertVal->"common-name") . "\n" . \ + [ $IfThenElse ([ :len ($CertVal->"common-name") ] > 0) ("CommonName: " . ($CertVal->"common-name") . "\n") ] . \ "Private key: " . [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] . "\n" . \ "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ From f585b6ee32a6c7a4e860f17e4f9d332021f856aa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Apr 2023 13:53:04 +0200 Subject: [PATCH 1428/2612] README: add badge to hint required RouterOS version --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2d6b41f..931d500 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ RouterOS Scripts [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) +![required RouterOS version](https://img.shields.io/badge/RouterOS-7.7-yellow?style=flat) ![RouterOS Scripts Logo](logo.svg) From 4073daa13990076c695a2d9c32208faf7415617b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Apr 2023 10:26:24 +0200 Subject: [PATCH 1429/2612] check-certificates: include SANs in information --- check-certificates.rsc | 11 +++++++++++ doc/check-certificates.d/notification.avif | Bin 13088 -> 25274 bytes 2 files changed, 11 insertions(+) diff --git a/check-certificates.rsc b/check-certificates.rsc index 704ea15..6b35cbf 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -38,9 +38,20 @@ :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; } + :local FormatSANs do={ + :local SANs $1; + :local Return ""; + + :foreach SAN in=$SANs do={ + :set Return ($Return . "\n " . $SAN); + } + :return $Return; + } + :return ( \ "Name: " . ($CertVal->"name") . "\n" . \ [ $IfThenElse ([ :len ($CertVal->"common-name") ] > 0) ("CommonName: " . ($CertVal->"common-name") . "\n") ] . \ + [ $IfThenElse ([ :len ($CertVal->"subject-alt-name") ] > 0) ("SubjectAltNames:" . [ $FormatSANs ($CertVal->"subject-alt-name") ] . "\n") ] . \ "Private key: " . [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] . "\n" . \ "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ diff --git a/doc/check-certificates.d/notification.avif b/doc/check-certificates.d/notification.avif index d7e9e84e8e14d8a3b3a12642fd92d8bb746470a4..7c250da192f5f0045edba36cc55e0e7246cd75b5 100644 GIT binary patch literal 25274 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 LpG`Ottk=MR`F=Nx delta 12990 zcmV;vGC|F{#Q~sZkRk#A@{uG#DIRHTZ({%e002Y)00962000010003R001%u0000e zX=!d|0000000EJl9g*xD1#$oY0OgYn0T}@xlP3W#e=-hjWMOm?0162>CFdSS5D?I5 zGWKH;kO77mVL;taN^cVJ=g`$*Ov;{-_?prwd(wEXs!3##ieZeb-YMlfLTAlm^93{V zR9k62NPpx%0$WzROQB%h;p_0fy*h01W`P_vDD;zn zl~GsMJbydQ&|XTFhhbEbFcdT0xGVEyCdoJov{{BVezvKL`vkOwmqJNQRVeJu$f54!e zVC9hi3g?`Td6mKxe`_%@be@S~()(N6_Ec`1J1nT$!?a>!b@*lnZSx+8clZFz6P2pO zJKyM%EUm7^HyDyYM#9SJn+NzY@#9E|D)508*>h5QDR;vI1HFfsSZ;om_XwZKA{u3> zO!aO+x)$G^PqP2D^{}(J*25a3f61OhS;1=mf5dfk@!$!yQrLew+hRgkXAuAy*w5H8mIIiiX?DCI&BC6Fa}bZlpm+xDhLA~XRc=_$ z@_!7LiwS+SF%IS9vMVe!9j}pTp~X9O_Hn)U(^6+jiM4RmRfZQQ^lup3Qe-JGe}(k;39miKZs{7wB3{{WU z_f4>D;kt^_^tS9V4ucOGar5|AGg_EIjfp9w*;`%l-V0<>!Ym3}X1reu)%RU;Wuxkr zFDF_>EzqtN?V3>me{+PH#hKNWT`sGuz|R5%O&v6Du<@z|L|?{3hW=qgOj=DN)!1ts zF;=$4ILAYS=bsz357J+0HdRdF__&*_(ENz-dohY|Nd`Q1CxDI|gfswLeD-3jy3Zf< zWJs=;GjzPFD)cjxZnIhFUsF&jDaq<&9}3(c{m;GjAWC(me*q2vN%EGd*ZWx?HgNNT zc}~xIwwQa7q8rRR^w5i_#xc!BjC+uZ? z3zW6LP$aw`l;rD-JrIzlfs3OpyaOT7yr2k{!K#^2Yj3yrzjoZt^wbuP+=WHPCg@`e z+?PsH#_+S+f4vC)tev%%I*^Y&WMB|Njp1udA#!_MEh^V9>t2g^24STy3rt-r);f7=3^Wu1sO)jI31_n)}FhJeM~h_CpK z34u3o`-mp@{3$^EnxTpb_^3I1B?h06O>kLCK(2*y6D^;>7apD&AJ=k03e`1Qd{pj^ zA^WbmhAhUVGn#No4of*R=&c_&M(p(!-bugoH*QOp_9CplGF~x*1*-QrQ$&Dp;J+eY zf3Gq=Lh_#Jy5_5ZvntIwjl@4T_@IP{S4C>(Oj(sORb+;ZL*27ee(J875DAiWzsk*h zP6ytuxq+N(LzvR>O2ccrhw`7ojxzlH^UQXPNfhPXHD(dyMq3ck{aG=y`OR3WC)4F= z({!&7Q`$&&r?}qVu0)V)@ILGMgxm=zf2Dd33Vs1J`26dYRLmjj>CB}6$pBDKqjU|V ziI*St4w%Q1Mh22+Vm`ul_}1`41=l8Z(_tY2N^iB^`6XUdBB1|wiTno?jOKC5F8i?qgh#s{fXlSSyEUtE?1vv9;@pKl`dP5g!$T>pjv(oC z3_q?=)B8KusxLvepbR>nKFozL{{5MbSj8mzmfENMCF+#>tm!~d>`+A}L8IPnmtq>tVd_tXzA^Xt2~!wp;FEbKf7V^6Vq@su?@~Onf0*XB%A%U4 z7p5E9b=o<8IKDUsaE$8PfA;R);?cs)fLkR4BSmmC{VfuQ=jAK z2KChV%O*6kybP`^-G+sy3dW@6g--#;>17sF|J%PUZK;Q_x|gstAoDWpGLv=rP8Ons z2S>{?VuPUaqRpffe!Bq4<_=7B8<`$D`=yb-bw{!(mL~8FSU%CBTV~08{xl^K zjDgRH8tHeDI(1_#D^s~M(yZB}B|z--h{nBdQz=n#gUm&p#1#i;cu#~?`X@t!LwbfD zE)1Dz@DK{`*xD(@e;ylyG@scOnI&8&eHu@;*f11?q_X;Mv(ia?hxp2lDKl!+`z`tV z9o{H*27x4{KG}TU#V{T5V{etsfyc->z-H?aq|U}iq&}hn8Xft-^Cqx!-<_NkiWw$f zJI~%%$CJSq{aX6(t`Ks&7aQUA881WVa;=_7e@Bw31(Dir`Pa{XP4vYo zGGP)tEi*@^|GCp(kZe2_^0fz;afZ-HOU`v(8gxHxm2e??dQqOnQ_m;Te*VI+|80y|6jZA)xJtl}1>i<4z_9*#EU!oP&)yY}5S1s$S674Xe|`a?*yyGr__zg2b5iXZLaF7i zYbWPYThoB1UhOW1eBe4$NNtS2?i&*mtSvmA5A>|EEPbRdcqhKFN$}8=D#YISni4k ztS5MS9E}*X_Tag}J>w)l=f5Zz9q{hJ1}7&0qME?&UDH*YW5|A8 zn0bNaPW69wRX(YS=Mv0BYItrk7&*+T8CaA-8y6mdfh~gdzMQr28^vaPq-)j0wA`Lo zkjcmQXzom5t%R`bh}hf%Bh+P%Vi}Y+e>RsbtH#pF(aI7|^v*>e>HREJf57xd1i%~y zg+Y5$nhR;2&Q5MAghiF>ur$e|nDUGcmwNZpu+#c8Unl_Y!RL{F^mV=87eTTQdg`BK zHBqpu7|Ww=kSV>n78*)!xc0t*YM2oyZth6Gjp~_A1KoEc_=J{&^XE3^oS9=Kf6Td< zP5%lUfLz~Jp&c=>NMfF{bs$$r1MT=tTyr?nSpC;wND_sQbd?VHF?-p!Q%>d@m9c&A7?OzFD*_Kc>Wvm_&JwS;HLdeJVukoLkm*X1zkR#FoT zlt3u(%~wK*2+Z*>XSSuXU>rKuf4Kim7&m66s?}iNuo8R-fx{G>s4^}x8Qhb#x}e>> z#NdX5fV81N&SryGdh}=md1jnEU$-Y}3+EyS<;>vxNg|F+hc^2bPHcOPkYMd=1jJPh z`zs5Iz(q2aFGRq&VcRfz`AfYFD@>Ggcl~EQy&upKL~(#aVjX%mLCqO}e@1;rf$G?& z?7EkZ(W5W!RaLmN+v>PNvMTJHhOyx{zfgUI!14F;^G7(;yZ|RdLKeq{=Sn%tYw0|# zfre!csyEEcm6LifJ2<3Y=ZsYqc)uxF**VGJ>Nu3%L@@m;YzqT?c^}8So-N8u1p}eL zi*Y&;AB&ISdWNfKLzgV@e{Kc~g6p8|x~V&ziNp7eXJl-kh}Cv+bxePBeG7Aoecu-D z9SSq4B*xgs_KRy28LDv#*2w8R($9*1Kkq(^zgl6Vq7S-_#>&@QzCLNnv)F(gIsl!H z6l`)!!L3BZ0^{;iLG9Y{2*SL0RvA>MIsZ_fRe-zo=78q_S535-*u*72a ziwcoc+r1Zp=-18-f59K$2=)^>BpS=1(N1R24OC8OKKT|fH^b-M`Y#ex{5?s;3!^cO z#-Fa0E)whS=OK(;^+%^&4(G_ScRy{Q*<$La zo;VuYGse+zlkT)H0@tV`R=6cf8%U4Df8Hm{&7u2Gs*Y!drjG*5|I$mUB?Ah{~s zu5Nd0^x}Bnphr#9x-)KI@*Qh62cGgM- zOJaFSUS$Z{+OJ105tQ(#Vi+=kQ1F9Kv&jpJ$PnBKe~6|ojX?aOlwrObVCutT%}HB4NpK6A~7F=snSYxKsGhGWOtDQIu-==Cs+DiYka)hXJPb&89$ z4TetQ;Ifk3v*Zh)-_}?Zdxu#hh^Mjv>zXt3TDu!qK_dD$K&aSneixDjTsX)#k{AB# z)djZae;Siuz>#T`R&hyZ$iDWAVAV~F0v?@c=ARBi7uEiOiuf=OZNZCULlFP}tCaOZ zK=p4+oQIdQX&*6G?P!#D*Mrlez?g6a{r36Z2-dB%XtpXyS=d@+CoXDOKgTwHCTNTh z7XBi*qz`=%ON2>AvLwddbCw5g>|0(vMwH&oWH5}zTq?k=ggR$jVAA|D&XYOB-PTaYs}C$diyEe*(G&(evG{?iPXIkSf^4If_y>N9f`|7EIVcsl48dNB4q3BI_=WQ5 ze>#EXjYmOPW*6>G9nX5Q<9mzRhq${Zh|iHOd@9iA4A?*U{VchoT~OfoBSL4xt<+&K zqeo%EMDl^{dFBi88@|4Jh>>A5TIo|yqrEox;cY;j4539iFQvYOe{3&nOTJ_^TU&c9 z<_&gEDDX^c_^}*MhgeOzAXGutf{)bZe_ptW)`dxb!ebMqR^>JFW>kf7_5E z0fF;ZI;TUHA1Yd3zU+$8tDBl(jJ#o(3XZv#56#9j2IJX`08MTX{BPuSe;+#dJV@xK}dvbA{96;TeeYGBgQ%Z-`1V_s? zMYf2Nx`v+XO(1>aV!oDIx?^60bIq5y2|Adi9F9@jQeylYeIifRr*Z^!p5_5No4XxBrV00Gk_Xs*k zV_Md(0MOeVeuGyP06rn`4r}hvT8G?=E$zYCV5?V_SigNbD4{jd&(TejfAeu-y@aYP z0LTA-T$-aXT~qerrY<-k(jp$-BxTA0&=gi{pvxQZQzb$)_#-!=2_v(JwA2kv(_2e~!PB?#>CoSm2+!u&?F381NLgTw4}2GhZUE9BL& z%LmJJYM(DKiiw~Mcdr&Vb(#@<`hMHS6rNIqp->3|DL=wy*%6q%f6UqA8kl!NZ!qdR zW|G@^imGHs__ngpu*A&x`11#g`A>d()I^-%eP`lQ&vPX-p=r!}U0vlpE&|KIN}5?_ z>oit2!Tm)1CAD>I5m+-k5nHM-+3h3D$M zs28abZ@&CgL%ZD=e{74>re^lT<1^QMOr*ubk|f`YN7Jgb0yGo@^3j zuw9wJ^vITdq8tDVc$3(hf}Lh=2El;EnS6N?lI+kfGrM^UEX zo=q;d7xXDQ0kTkF7jDt;EXAH^#kQbTC=vauLmD;<#SDmCN+A+B;Ta81#JCviclLN zk}lTye{H_z-mP|nSDWh79mXBVgWA_?ZF$+ z)r7=L*SwNc$Jx853cRdt_CeE!L?MkeNBoIr-N`Ky&f62Yi#Vp2gETTJl6bW3bsz|v zdg)9ZSc&6npSdp*qK;5#`wl$}I%@yPimgj}g*cdyW4jUX_Y^dl?6P zZgC1dFsaIgu}}MP@8^(tqHXCgpz>o%UihB*4~QQ5J=aMbBwe|AN%vDCDWotmbdxiK ze;f_mwgX1scIM31TAIr-@X(|_#~5_+%j4{kCD+J$O~lAqMqr+nfAhMcug6Z6nM+MH z=AmK7FAWC`(A^>7CwS%ML!8dc)6OI9UseRZTpL)QRp-_)qRWu1MYe-Q1~b3vU=6U2$m}T^iU9Te<5{p z=sZIOTC)OfM{F@RIWe8ou`q^+*^E9yQ+)B4@4MRI;N!BHaM^c+LheM!&TzJ!EdL>G zr50y2d~gemrldSEq7%M?%=)&!n6m>m#fJSD2!0|x@RD%n0#5$%JdRpy`~fgoHVZL_ zg58~EHrF+?mWd=ThH>yah@hk8e@#aATTdgi?(JO#z*QJv?<}8aOX*Z-i&z7m99;Tp zWVgMOL2`zsqEor7*1w+jQ-8#nl_@0Rxf zv7>z%MnOuYs!gcBp(r@RN`uOnVzg_7zR$)lMydLcVp9>QC+Xm7aKrqO3T9cQ3?MF+ zSF%!>5Ja*Dp``!202Vk8-%OR;TQ&^uE(wA{qDB~UwD{D2e@HIBLIFgl@J5}4 zZ`WGxSnT&IdDPfofttK;lN8_&6ETwk>YO321qV7EdC(V%2&R|KNR`#iHU+o)F<2C~D%5%* z#aB2FH^+S?CHE{UJ~rCE5&`7o#hQ480gu_SUHqs1oG0t@8KDa7mGNd46`%oT`&e1m z!~m1S^(JW1f7Q3uBXq4sY!?pvh>1bj@s?+8YGLqI8!xwD#S<;ix^PwE-)xy@KliJzN$>@G( z>P~%m9~9-b!WMa<<@0GXS;EVC2S+s%SR!LETkuRrX?AT@3<<|z2t^idtap} zG%LXZ-J12Wv}QOIJFRSa_S7rvzLbCe76)ub2|sWLHL`%eEEHI|5?{w>sT9B7RM0<{ z+q^O8wor&CHz-aEiY2;ru~)L?PVvw#?||_%t`|eNwBx;jhYhb2^0?I4tC= z?k>D+O?KjluxJXAOgi;_X%2mb!UE}M=-j9`NXDkfgbinwn{>|0Tx73U6JYI`A)y%J zfAFOi`7vPG+4h4KWhsl``ks+v21Gnd=lc#cKt^OCEG@0Zh}!{iTE@%M~|1w40dZG&xG$oRs5KKmYokS{RNeHM&| zuksQ19uSHpW$z|I3k}+$7i2w(97B58A(GKHmoJ zRRFU4`$ucayKXnq>HFq~J%wK@RvqpkRe{I5cdQJ6vwb0;J;iD9Rl zX&l(zR~vvcG>=ZU-VjcdV_oc2s5SfA)?TW!E(T zx$NTo?pNd7Gtm@+fL7g`$TSWgrv6JndEZq~Uca|u) zVSXo?v}Nv`p)Nn9wiZBFe_2cnolMMIB~%wbKf*4~8A+18|C188y;KWBh2XxK+R)JX z>}D~m5}*{%D9}pi!#*dExk;*a+kAI0KK*7_beBJ79B5SR;5O4RXOO-%N>HZ^-+TmE zimAj*RGWO21#VJeUFxW^r5&FZXd48Qt3}m=*e;|n_dOzqivs43s4g{loK7Z(n65#^iFYXH)ODlQ0|>~0jztn1ji5vFC%x;`%bYNmF`OSG=3!~kw`X@>N%bVkWST@7kMkjtH~jwswRY_dxGc}v5=3?&agGQ*1UtqZHzWb0 zvmzw7Xq2K_&i|OBFin{r%sr!zeZ^e?;H}-=9uS>(CL4VCXJhHCY@Y^3SvAe0rr?~= z3Q&Z(Sh+FIf06%!vp~!|q<|Fm+<#pmF&~Ze_Mokh+ScB`z%vqJq>Xy0{2XLcoD1(S z6Zs@u|3q-A#K!|VV2T?H&cJ}?sJrZ#sbBk{CJ(HWyiivlz0$mxIxUyS5iBXsW&v8B zOkmG8JHlRCF+SX?Z0Uqfao7joIyJq*suu8mqkw`Of5tWa=-kldd#F7rO{?v!qC(6) z3nrD4MOWDQ3r{kiVs*LtoM_F;kzzEqxTD7=kgrgXj;X!VSe~;wy!-$t;#}(FTwGnGJDWuYA#lEiLg&|CL$AAR>^%l{~@{#22r3&Ig#rY+Q z0L$675qdu2z%8uzg2oSQpNhR_>7U0yd7+1{Lah|_>^hCtHBpxXw_~Mg8p%{AoI%QS zL6nB`w#UIr{w$T9w-NFD@V|wmke?-c}RB z8Bj)^JlTd0q;gp3T#P^u4@@8ZI~W1f{bp{((pqENP)Nsv{6d+m=`T;3;>l;Y-a+c^ z$M1?YbB*wC9->+?QwX9P9f<&#UNWsjX7V6%$8_Lcm?IyOeYc09XME9<-Z&3`p%?&gNC1!EqGwjbkc@~sdfa5zgD4*8n{=Jk0-5@G{bPvBt2 z_l$VhkW+{`^Mt`q8~Q~PV;qEZlV67CWp*9|h;x|;91$Gc24?XW|1hmo-Zy%H(pixg z4_Wo}*?e5U*sar=AwYxeH`v){scQPnp$r*vvdx55)dr{^0>_=(>fAOin zXgcw^QwNu};{+5t%J=9ptbS*ICrcanBPiaqC(~Pu+N_)TmDn%`vfhGb6oQIJR&sS_ z3b3S>m>59yLM|E|X^-sq=WU@PDuWy{PSYU`u~8v>0MHo2uRtT;W%4vNWuITM2G#QG z$P{P}9_Wm0+$#LIbVI#i1Hnvqe-mO|4n_m=A3I+pvKp0vLP?S33*Cs80;psCaP&=_8jO8 zuZ80P1OWVC0L)(z1|YUf$b*ezgyL=rhs-21YV>^s_DRcy_uvn zT80Tzvb3cPn$Hw{`VvL%2dV2NsW=<2%Pn9omad7Wq>AJegTMz#=1`(}NjU}O`D^^R z&er->O%G^kkCE<3TFVYBwfCQm zPDowQzjBrBfcmulwK$9Up>li{;rF8H002Un>56-9Kj&mSe)+^cPJNk8jttX|hKA*0 zh5&CzFDYAce~s+vT1J)w#^WWUN}q}&&BA=Dw1H~MrxTHz76+oBX>}B+&Y3lk;Eft< zTJ@fs>$*8x`0t-iHc7rV=IQtU(?YXd-BEuClET(i*$Eu6T)TANDyoM&XH z2)w~j$SF2?KxAe!I$-_d{c^?n5m3@4x)Q4wF~C^*I5nAuWQ)BYKl8RYZY2UD#T(J` z<8W&m1}VF_K2Q<}0Y1NZYdzVAvq}#6E9=9+T}AO_tRa-VRxk+#j2=wX<<$MP=myeY zbyVNke{OTDX{b4xQl&&bgd=!`B9;Z3x!Ln0%N3ZpYB-i#$E6vPss6&-1CIZ$7{%wQ z?iJ}J(c8%b)0|e#)wV*3&ty)iEmBnUilPgzXp3wv$aI=nW&D^=E;Y@=)=!TlH`Sg* zWyc;Z@p}qj_{82PyN^U6J4a_%6`fbKExc8nf4^2b(Ty>F)#jM^Id@i%nTR?(BeJ}& zv99{G=yv@kE)Ss*PjA7cvv&>q2IJ3wfXf+|@+N^C1j`T4^Tr-+l#OIOceuT`nDA&EMOByq$BvV>4@{OXhHO$xyoQtlW<_U$FDWB1Lu}USb6nN ze@h`9It~!~P*n&Xt97X7%19U+vRM9!0GaW1$NW@NX@SuD7;&CH$J^ibw9vUhOD7h# zQ!7x4CoUuZ<_;~g@${Ymu949<%4m#s!9L@?OvH_?e3{ApLXA3vgknj}Mk}U4YIng^ ziEAbyl_QAI(H|_17~iTsprdsf)tmK^e-p&Iq#LzVS*V3f%U%UFU@v`jz=(h(sJ}Fo zYgF^)Yk|{xQ5NgRN7$J}A-Gl}2NV0T!BXoQYrs+iVqKJDClcy#euxF5+oY52A62&t zID6=(&bQ}tX3wrI0~Q^(-4$okFWql)u7UI zNmR1y3@;b2Pj&=%uCSQ9vagYu!4w7F?EJnH%WXdc$WBLfdQozk=TABj+0j;A4`fbD zyvim45=U%x*cZ!!Vwp1WJQn6zf2}Dz5U5M#Pi8~rJY)3YVvVXA;kkht8^RstW(7<< ztlZ?>a}>d$YV&R~Awj6o5EO1+GM>71ioA4+f<=kbyn+facLXwza#NJf4`RppXm+7R zCm-WOV86jarI|KuxX{34&Y7(@RM~Gf2A}tx&!K_oDoNjc6n+$~B0<-Ne`79n7X|(h zjh=6o5jY?ZY=8aC&JT=ix_USoss;Slzr3slWonq*=m?tSp+5F01ZE5Z^ z@bUkk&Ln&78-iKz5%fONWb!;8RsK&6)`UizgZtKDUB9t30PTw-B{yrDUj=@Vd z2z{rH&C7O@ariKU!2Fwse^3Wb$a>XWDf)30Ay-HQ5`e%t_9gb%sVs5A7>Icr?wK<~ zBrHFt|D(eb98#!PQ^jBPIG9A&v(Yr+O5lY1Fg>QUnq~_P-&;s&+sejnfkB#AaFEX00p+ z)0Z7FlF@z>&88r$@@6YBU9kH>rGZ`w{uv`&?l=Gcw@{Z_qQZa4?tToH1rN|KQN=wx AGynhq From 11093045f30eb289c17c9d08a80de69798ad942d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Apr 2023 14:56:36 +0200 Subject: [PATCH 1430/2612] check-certificates: download and import in a local function --- check-certificates.rsc | 72 ++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 6b35cbf..8250269 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -10,23 +10,59 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global CertRenewPass; :global CertRenewTime; :global CertRenewUrl; :global CertWarnTime; :global Identity; :global CertificateAvailable -:global CertificateNameByCN; :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; :global SendNotification2; :global SymbolForNotification; -:global UrlEncode; -:global WaitForFile; :global WaitFullyConnected; +:local CheckCertificatesDownloadImport do={ + :local Name [ :tostr $1 ]; + + :global CertRenewUrl; + :global CertRenewPass; + + :global CertificateNameByCN; + :global LogPrintExit2; + :global UrlEncode; + :global WaitForFile; + + :foreach Type in={ ".pem"; ".p12" } do={ + :local CertFileName ([ $UrlEncode $Name ] . $Type); + :do { + /tool/fetch check-certificate=yes-without-crl \ + ($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~("^" . $CertFileName . "_[0-9]+\$") common-name!=$Name ] do={ + $CertificateNameByCN [ /certificate/get $CertInChain common-name ]; + } + } on-error={ + $LogPrintExit2 debug $0 ("Could not download certificate file " . $CertFileName) false; + } + } +} + :local FormatInfo do={ :local CertVal $1; @@ -70,33 +106,7 @@ $WaitFullyConnected; } $LogPrintExit2 info $0 ("Attempting to renew certificate " . ($CertVal->"name") . ".") false; - :foreach Type in={ ".pem"; ".p12" } do={ - :local CertFileName ([ $UrlEncode ($CertVal->"common-name") ] . $Type); - :do { - /tool/fetch check-certificate=yes-without-crl \ - ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; - $WaitForFile $CertFileName; - - :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~("^" . $CertFileName . "_[0-9]+\$") common-name!=($CertVal->"common-name") ] do={ - $CertificateNameByCN [ /certificate/get $CertInChain common-name ]; - } - } on-error={ - $LogPrintExit2 debug $0 ("Could not download certificate file " . $CertFileName) false; - } - } + $CheckCertificatesDownloadImport ($CertVal->"common-name"); :local CertNew [ /certificate/find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ]; :local CertNewVal [ /certificate/get $CertNew ]; From 46110661e07095b3504cbef5e9a66317146c05ce Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Apr 2023 15:05:43 +0200 Subject: [PATCH 1431/2612] check-certificates: do not rename certificates without common-name --- check-certificates.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 8250269..fa0963f 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -54,7 +54,7 @@ $LogPrintExit2 warning $0 ("Decryption failed for certificate file " . $CertFileName) false; } - :foreach CertInChain in=[ /certificate/find where name~("^" . $CertFileName . "_[0-9]+\$") common-name!=$Name ] do={ + :foreach CertInChain in=[ /certificate/find where name~("^" . $CertFileName . "_[0-9]+\$") common-name!=$Name !(common-name=[]) ] do={ $CertificateNameByCN [ /certificate/get $CertInChain common-name ]; } } on-error={ From 922dde3ff0ebaab70df8a8bfa402c1d19b624f51 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Apr 2023 15:11:28 +0200 Subject: [PATCH 1432/2612] check-certificates: make the function return a status --- check-certificates.rsc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index fa0963f..db1127c 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -34,6 +34,8 @@ :global UrlEncode; :global WaitForFile; + :local Return false; + :foreach Type in={ ".pem"; ".p12" } do={ :local CertFileName ([ $UrlEncode $Name ] . $Type); :do { @@ -57,10 +59,14 @@ :foreach CertInChain in=[ /certificate/find where name~("^" . $CertFileName . "_[0-9]+\$") common-name!=$Name !(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={ @@ -106,7 +112,8 @@ $WaitFullyConnected; } $LogPrintExit2 info $0 ("Attempting to renew certificate " . ($CertVal->"name") . ".") false; - $CheckCertificatesDownloadImport ($CertVal->"common-name"); + :local ImportSuccess false; + :set ImportSuccess [ $CheckCertificatesDownloadImport ($CertVal->"common-name") ]; :local CertNew [ /certificate/find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ]; :local CertNewVal [ /certificate/get $CertNew ]; From 96170950222dd4e63b7bd01c3db3298b902c4c87 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Apr 2023 15:19:23 +0200 Subject: [PATCH 1433/2612] check-certificates: try all SANs for download --- check-certificates.rsc | 19 ++++++++++++++++--- doc/check-certificates.md | 5 +++-- global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index db1127c..1a984bc 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -16,11 +16,13 @@ :global Identity; :global CertificateAvailable +:global EscapeForRegEx; :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; :global SendNotification2; :global SymbolForNotification; +:global UrlEncode; :global WaitFullyConnected; :local CheckCertificatesDownloadImport do={ @@ -56,7 +58,8 @@ $LogPrintExit2 warning $0 ("Decryption failed for certificate file " . $CertFileName) false; } - :foreach CertInChain in=[ /certificate/find where name~("^" . $CertFileName . "_[0-9]+\$") common-name!=$Name !(common-name=[]) ] do={ + :foreach CertInChain in=[ /certificate/find where name~("^" . $CertFileName . "_[0-9]+\$") \ + common-name!=$Name !(subject-alt-name~("(^|\\W)(DNS|IP):" . [ $EscapeForRegEx $Name ] . "(\\W|\$)")) !(common-name=[]) ] do={ $CertificateNameByCN [ /certificate/get $CertInChain common-name ]; } @@ -105,6 +108,7 @@ $WaitFullyConnected; :foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ :local CertVal [ /certificate/get $Cert ]; + :local LastName; :do { :if ([ :len $CertRenewUrl ] = 0) do={ @@ -113,9 +117,18 @@ $WaitFullyConnected; $LogPrintExit2 info $0 ("Attempting to renew certificate " . ($CertVal->"name") . ".") false; :local ImportSuccess false; - :set ImportSuccess [ $CheckCertificatesDownloadImport ($CertVal->"common-name") ]; + :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 ]; + } + } - :local CertNew [ /certificate/find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ]; + :local 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={ diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 80f6aee..f295117 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -34,8 +34,9 @@ in `global-config-overlay`, these are the parameters: * `CertRenewUrl`: the url to download certificates from * `CertWarnTime`: on what remaining time to warn via notification -Certificates on the web server should be named `CN.pem` (`PEM` format) or -`CN.p12` (`PKCS#12` format). +Certificates on the web server should be named by their common name, like +`CN.pem` (`PEM` format) or`CN.p12` (`PKCS#12` format). Alternatively any +subject alternative name (aka *Subject Alt Name* or *SAN*) can be used. Also notification settings are required for [e-mail](mod/notification-email.md), diff --git a/global-functions.rsc b/global-functions.rsc index f75ed54..e682edc 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 97; +:global ExpectedConfigVersion 98; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index d21ea6b..08ff3fb 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -11,6 +11,7 @@ :global GlobalConfigChanges { 96="Added support for notes in 'netwatch-notify', these are included verbatim into the notification."; 97="Modified 'dhcp-to-dns' to always add A records for names with mac address, and optionally add CNAME records if the host name is available."; + 98="Extended 'check-certificates' to download new certificate by SubjectAltNames if download by CommonName fails."; }; # Migration steps to be applied on script updates From f14788a10444022ae0f7d0bea7839facf36128f1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Apr 2023 22:38:17 +0200 Subject: [PATCH 1434/2612] check-certificates: properly escape the name for regex --- check-certificates.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 1a984bc..98a6cab 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -32,6 +32,7 @@ :global CertRenewPass; :global CertificateNameByCN; + :global EscapeForRegEx; :global LogPrintExit2; :global UrlEncode; :global WaitForFile; @@ -58,7 +59,7 @@ $LogPrintExit2 warning $0 ("Decryption failed for certificate file " . $CertFileName) false; } - :foreach CertInChain in=[ /certificate/find where name~("^" . $CertFileName . "_[0-9]+\$") \ + :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 ]; } From f1c634b984c5ae25bab1abee296f59e9bb74c6c7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 16 Apr 2023 22:04:20 +0200 Subject: [PATCH 1435/2612] README: add badge to link Telegram group --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 931d500..dc5660c 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ RouterOS Scripts [![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.7-yellow?style=flat) +[![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) ![RouterOS Scripts Logo](logo.svg) From b4fbd65f55b041d0b68f1c077c2f6ce49f581e95 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 17 Apr 2023 10:52:40 +0200 Subject: [PATCH 1436/2612] README: note about breaking changes --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dc5660c..6179d5e 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,10 @@ Requirements ------------ Latest version of the scripts require recent RouterOS to function properly. -Make sure to install latest updates before you begin. +Make sure to install latest updates before you begin. If new functionality +or a breaking change in RouterOS `7.n` is used in my scripts I push my +change some time after `7.(n+1)` was released. At any time you should have +at least two minor and their bugfix releases to choose from. Specific scripts may require even newer RouterOS version. From 5324bffd840fd4201d231044f28e7f30e876d6d7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 18 Apr 2023 18:23:41 +0200 Subject: [PATCH 1437/2612] README: generate a donate buttom from shields.io --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6179d5e..9711834 100644 --- a/README.md +++ b/README.md @@ -324,7 +324,7 @@ for you. If you like the scripts and think this is of value for you or your business please consider to [donate with PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J). -[![donate with PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) +[![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=for-the-badge)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) Thanks a lot for your support! From f7eb123f3d35b0bad19e94ee74f6252865743b89 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 18 Apr 2023 21:59:47 +0200 Subject: [PATCH 1438/2612] README: add a donate button to badges --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9711834..5b0e312 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ RouterOS Scripts [![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.7-yellow?style=flat) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) +[![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) ![RouterOS Scripts Logo](logo.svg) From 69ea231efcbfcb967cbcbfecf802ca00b130a931 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 18 Apr 2023 22:00:39 +0200 Subject: [PATCH 1439/2612] README: make the Telegram QR code a link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b0e312..14a5680 100644 --- a/README.md +++ b/README.md @@ -301,7 +301,7 @@ Contact We have a Telegram Group [RouterOS-Scripts](https://t.me/routeros_scripts)! -![RouterOS Scripts Telegram Group](README.d/telegram-group.avif) +[![RouterOS Scripts Telegram Group](README.d/telegram-group.avif)](https://t.me/routeros_scripts) Get help, give feedback or just chat - but do not expect free professional support! From baf6b3ae178453975940d5002030b4df9e157e01 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 19 Apr 2023 08:28:04 +0200 Subject: [PATCH 1440/2612] README: make the screenshot match the example --- README.d/13-install-custom-script.avif | Bin 4746 -> 4589 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/README.d/13-install-custom-script.avif b/README.d/13-install-custom-script.avif index df9f734218565e449d969005bb32c7515246ffef..2f01c43c0317a0258b52b0efdfbf22110c897da1 100644 GIT binary patch delta 3552 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 Date: Wed, 19 Apr 2023 22:02:27 +0200 Subject: [PATCH 1441/2612] check-routeros-update: add version in notification subject --- check-routeros-update.rsc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index d1c82c5..4c1aaf9 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -64,7 +64,7 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; $LogPrintExit2 info $0 ("Installing ALL versions automatically, including " . \ $Update->"latest-version" . "...") false; $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + 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; @@ -73,7 +73,7 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ ", updating on " . $Identity . "..."); link=$Link; silent=true }); $DoUpdate; @@ -83,7 +83,7 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; version=($Update->"latest-version" . " (" . $Update->"channel" . ")") ] ] > 0) do={ $LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ message=("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \ ", updating on " . $Identity . "..."); link=$Link; silent=true }); $DoUpdate; @@ -101,7 +101,7 @@ $LogPrintExit2 debug $0 ("Checking for updates...") 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"); \ + 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; @@ -123,7 +123,7 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; } $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ + 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 }); @@ -137,7 +137,7 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; } $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "warning-sign" ] . "RouterOS version"); \ + 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 }); From fb9feea5950caec1c9bd7b9a3188cc312bf61956 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 19 Apr 2023 22:05:15 +0200 Subject: [PATCH 1442/2612] check-certificates: add certificate name in notification subject --- check-certificates.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 98a6cab..2b76873 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -158,7 +158,7 @@ $WaitFullyConnected; } $SendNotification2 ({ origin=$0; silent=true; \ - subject=([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed"); \ + subject=([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed: " . ($CertVal->"name")); \ message=("A certificate on " . $Identity . " has been renewed.\n\n" . [ $FormatInfo $CertVal ]) }); $LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " has been renewed.") false; } on-error={ @@ -176,7 +176,7 @@ $WaitFullyConnected; :local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ]; $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning!"); \ + subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning: " . ($CertVal->"name")); \ message=("A certificate on " . $Identity . " " . $State . ".\n\n" . [ $FormatInfo $CertVal ]) }); $LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " " . $State . \ ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; From cb338c76a8eb19a3ed1a73df330c3ddf638c7c39 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Apr 2023 23:15:04 +0200 Subject: [PATCH 1443/2612] global-functions: introduce $FormatLine --- global-functions.rsc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index e682edc..501ea92 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -29,6 +29,7 @@ :global DownloadPackage; :global EitherOr; :global EscapeForRegEx; +:global FormatLine; :global GetMacVendor; :global GetRandom20CharAlNum; :global GetRandom20CharHex; @@ -329,6 +330,32 @@ :return $Return; } +# format a line for output +:set FormatLine do={ + :local Key [ :tostr $1 ]; + :local Values [ :toarray $2 ]; + :local Indent [ :tonum $3 ]; + :local Spaces " "; + :local Return ""; + + :global EitherOr; + :global FormatLine; + + :set Indent [ $EitherOr $Indent 16 ]; + + :if ([ :len $Key ] > 0) do={ :set Return ($Key . ":"); } + :if ([ :len $Key ] > ($Indent - 2)) do={ + :set Return ($Return . "\n" . [ :pick $Spaces 0 $Indent ] . ($Values->0)); + } else={ + :set Return ($Return . [ :pick $Spaces 0 ($Indent - [ :len $Return ]) ] . ($Values->0)); + } + :foreach Value in=[ :pick $Values 1 [ :len $Values ] ] do={ + :set Return ($Return . "\n" . [ $FormatLine "" ({$Value}) $Indent ]); + } + + :return $Return; +} + # get MAC vendor :set GetMacVendor do={ :local Mac [ :tostr $1 ]; From fb12aabf3e8685aaa21185b145caf431ca44b0d4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Apr 2023 23:44:56 +0200 Subject: [PATCH 1444/2612] global-functions: $DeviceInfo: use $FormatLine --- global-functions.rsc | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 501ea92..45fda9f 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -195,6 +195,7 @@ :global Identity; :global IfThenElse; + :global FormatLine; :local Resource [ /system/resource/get ]; :local RouterBoard; @@ -205,27 +206,27 @@ :local Update [ /system/package/update/get ]; :return ( \ - "Hostname: " . $Identity . \ - "\nBoard name: " . $Resource->"board-name" . \ - "\nArchitecture: " . $Resource->"architecture-name" . \ + [ $FormatLine "Hostname" $Identity ] . "\n" . \ + [ $FormatLine "Board name" ($Resource->"board-name") ] . "\n" . \ + [ $FormatLine "Architecture" ($Resource->"architecture-name") ] . "\n" . \ [ $IfThenElse ($RouterBoard->"routerboard" = true) \ - ("\nModel: " . $RouterBoard->"model" . \ - [ $IfThenElse ([ :len ($RouterBoard->"revision") ] > 0) \ - (" " . $RouterBoard->"revision") ] . \ - "\nSerial number: " . $RouterBoard->"serial-number") ] . \ + ([ $FormatLine "Model" ($RouterBoard->"model") ] . \ + [ $IfThenElse ([ :len ($RouterBoard->"revision") ] > 0) \ + (" " . $RouterBoard->"revision") ] . "\n" . \ + [ $FormatLine "Serial number" ($RouterBoard->"serial-number") ] . "\n") ] . \ [ $IfThenElse ([ :len ($License->"level") ] > 0) \ - ("\nLicense: " . $License->"level") ] . \ - "\nRouterOS:" . \ - "\n Channel: " . $Update->"channel" . \ - "\n Installed: " . $Update->"installed-version" . \ + ([ $FormatLine "License" ($License->"level") ] . "\n") ] . \ + "RouterOS:\n" . \ + [ $FormatLine " Channel" ($Update->"channel") ] . "\n" . \ + [ $FormatLine " Installed" ($Update->"installed-version") ] . "\n" . \ [ $IfThenElse ([ :typeof ($Update->"latest-version") ] != "nothing" && \ $Update->"installed-version" != $Update->"latest-version") \ - ("\n Available: " . $Update->"latest-version") ] . \ + ([ $FormatLine " Available" ($Update->"latest-version") ] . "\n") ] . \ [ $IfThenElse ($RouterBoard->"routerboard" = true && \ $RouterBoard->"current-firmware" != $RouterBoard->"upgrade-firmware") \ - ("\n Firmware: " . $RouterBoard->"current-firmware") ] . \ - "\nRouterOS-Scripts:" . \ - "\n Version: " . $ExpectedConfigVersion); + ([ $FormatLine " Firmware" ($RouterBoard->"current-firmware") ] . "\n") ] . \ + "RouterOS-Scripts:\n" . \ + [ $FormatLine " Version" $ExpectedConfigVersion ]); } # convert line endings, DOS -> UNIX From 31553f86a6bbdf1ba8c46548763eb7ad6e6c74f5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Apr 2023 23:18:51 +0200 Subject: [PATCH 1445/2612] backup-cloud: use $FormatLine --- backup-cloud.rsc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index b75d5cb..b6f6025 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -17,6 +17,7 @@ :global Identity; :global DeviceInfo; +:global FormatLine; :global LogPrintExit2; :global RandomDelay; :global ScriptFromTerminal; @@ -47,9 +48,9 @@ $WaitFullyConnected; subject=([ $SymbolForNotification "floppy-disk,cloud" ] . "Cloud backup"); \ message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ - "Name: " . $Cloud->"name" . "\n" . \ - "Size: " . $Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)\n" . \ - "Download key: " . $Cloud->"secret-download-key"); silent=true }); + [ $FormatLine "Name" ($Cloud->"name") ] . "\n" . \ + [ $FormatLine "Size" ($Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)") ] . "\n" . \ + [ $FormatLine "Download key" ($Cloud->"secret-download-key") ]); silent=true }); } on-error={ $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Cloud backup failed"); \ From 637b5e21daa17b369c07667be993b1e125470e3f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Apr 2023 23:47:37 +0200 Subject: [PATCH 1446/2612] backup-email: use $FormatLine --- backup-email.rsc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backup-email.rsc b/backup-email.rsc index ba12494..e8837a0 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -22,6 +22,7 @@ :global CharacterReplace; :global DeviceInfo; +:global FormatLine; :global LogPrintExit2; :global MkDir; :global RandomDelay; @@ -91,9 +92,9 @@ $SendEMail2 ({ origin=$0; \ message=("See attached files for backup and config export for " . \ $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ - "Backup file: " . $BackupFile . "\n" . \ - "Export file: " . $ExportFile . "\n" . \ - "Config file: " . $ConfigFile); \ + [ $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 From bac6a72d519a6aead5a3920773da6365c260092a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Apr 2023 23:48:56 +0200 Subject: [PATCH 1447/2612] backup-upload: use $FormatLine --- backup-upload.rsc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 4c09d4a..9fb35d8 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -25,6 +25,7 @@ :global CharacterReplace; :global DeviceInfo; +:global FormatLine; :global IfThenElse; :global LogPrintExit2; :global MkDir; @@ -120,9 +121,9 @@ $SendNotification2 ({ origin=$0; \ ([ $SymbolForNotification "floppy-disk,up-arrow" ] . "Backup & Config upload") ]; \ message=("Backup and config export upload for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ - "Backup file: " . $BackupFile . "\n" . \ - "Export file: " . $ExportFile . "\n" . \ - "Config file: " . $ConfigFile); silent=true }); + [ $FormatLine "Backup file" $BackupFile ] . "\n" . \ + [ $FormatLine "Export file" $ExportFile ] . "\n" . \ + [ $FormatLine "Config file" $ConfigFile ]); silent=true }); :if ($Failed = 1) do={ :error "An error occured!"; From 7ed70bdb2631afe0b9a480ea7b1cc14438dea532 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Apr 2023 23:55:03 +0200 Subject: [PATCH 1448/2612] check-certificates: use $FormatLine --- check-certificates.rsc | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 2b76873..7e9fbe2 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -76,6 +76,7 @@ :local FormatInfo do={ :local CertVal $1; + :global FormatLine; :global IfThenElse; :global ParseKeyValueStore; @@ -84,25 +85,15 @@ :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; } - :local FormatSANs do={ - :local SANs $1; - :local Return ""; - - :foreach SAN in=$SANs do={ - :set Return ($Return . "\n " . $SAN); - } - :return $Return; - } - :return ( \ - "Name: " . ($CertVal->"name") . "\n" . \ - [ $IfThenElse ([ :len ($CertVal->"common-name") ] > 0) ("CommonName: " . ($CertVal->"common-name") . "\n") ] . \ - [ $IfThenElse ([ :len ($CertVal->"subject-alt-name") ] > 0) ("SubjectAltNames:" . [ $FormatSANs ($CertVal->"subject-alt-name") ] . "\n") ] . \ - "Private key: " . [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] . "\n" . \ - "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ - "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ - "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ - "Expires in: " . [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ]); + [ $FormatLine "Name" ($CertVal->"name") ] . "\n" . \ + [ $IfThenElse ([ :len ($CertVal->"common-name") ] > 0) ([ $FormatLine "CommonName" ($CertVal->"common-name") ] . "\n") ] . \ + [ $IfThenElse ([ :len ($CertVal->"subject-alt-name") ] > 0) ([ $FormatLine "SubjectAltNames" ($CertVal->"subject-alt-name") ] . "\n") ] . \ + [ $FormatLine "Private key" [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] ] . "\n" . \ + [ $FormatLine "Fingerprint" ($CertVal->"fingerprint") ] . "\n" . \ + [ $FormatLine "Issuer" ($CertVal->"ca" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN")) ] . "\n" . \ + [ $FormatLine "Validity" ($CertVal->"invalid-before" . " to " . $CertVal->"invalid-after") ] . "\n" . \ + [ $FormatLine "Expires in" [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ] ]); } $WaitFullyConnected; From f3876b0637140db2e242cddb5b38b128bcaa7473 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 12 Apr 2023 23:09:58 +0200 Subject: [PATCH 1449/2612] dhcp-to-dns: handle dns record by comment and type --- dhcp-to-dns.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 67ecacd..507bda6 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -67,7 +67,7 @@ $ScriptLock $0 false 10; :local HostName [ $CharacterReplace [ $EitherOr ([ $ParseKeyValueStore ($LeaseVal->"comment") ]->"hostname") ($LeaseVal->"host-name") ] " " "" ]; :local Domain ([ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); - :local DnsRecord [ /ip/dns/static/find where name=($MacDash . "." . $Domain) ]; + :local DnsRecord [ /ip/dns/static/find where comment=$Comment (!type or type=A) ]; :if ([ :len $DnsRecord ] > 0) do={ :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; From b1cb4cb10f74be294fd234459e864cbf2762bae0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Apr 2023 23:58:24 +0200 Subject: [PATCH 1450/2612] check-health: use $FormatLine --- check-health.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/check-health.rsc b/check-health.rsc index e208bac..af0d70b 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -21,6 +21,7 @@ :global CheckHealthVoltagePercent; :global Identity; +:global FormatLine; :global IfThenElse; :global LogPrintExit2; :global ScriptLock; @@ -93,8 +94,8 @@ $ScriptLock $0; subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \ $NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ - "old value: " . ($CheckHealthLast->$Name) . " V\n" . \ - "new value: " . $Value . " V") }); + [ $FormatLine "old value" ($CheckHealthLast->$Name . " V") ] . "\n" . \ + [ $FormatLine "new value" ($Value . " V") ]) }); } else={ :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ $SendNotification2 ({ origin=$0; \ From 4c416cb39eac3981ef2d5db727b45f3dcfdda4c4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 12 Apr 2023 23:13:26 +0200 Subject: [PATCH 1451/2612] dhcp-to-dns: handle duplicate leases earlier --- dhcp-to-dns.rsc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 507bda6..e6970ff 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -57,6 +57,11 @@ $ScriptLock $0 false 10; :local LeaseVal; :do { :set LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + :local DupMacLeases [ /ip/dhcp-server/lease/find where mac-address=($LeaseVal->"mac-address") status=bound ]; + :if ([ :len $DupMacLeases ] > 1) do={ + $LogPrintExit2 debug $0 ("Multiple bound leases found for mac-address " . ($LeaseVal->"mac-address") . ", using last one.") false; + :set LeaseVal [ /ip/dhcp-server/lease/get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) ]; + } } on-error={ $LogPrintExit2 debug $0 ("A lease just vanished, ignoring.") false; } @@ -71,12 +76,6 @@ $ScriptLock $0 false 10; :if ([ :len $DnsRecord ] > 0) do={ :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; - :local DupMacLeases [ /ip/dhcp-server/lease/find where mac-address=($LeaseVal->"mac-address") status=bound ]; - :if ([ :len $DupMacLeases ] > 1) do={ - $LogPrintExit2 debug $0 ("Multiple bound leases found for mac-address " . ($LeaseVal->"mac-address") . ", using ip address of last one.") false; - :set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; - } - :if ($DnsIp = $LeaseVal->"address") do={ $LogPrintExit2 debug $0 ("DNS entry for " . ($MacDash . "." . $Domain) . " does not need updating.") false; } else={ From 3f9480f9f2c89ab80cacdc7f8b850707d757ab43 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 21 Apr 2023 00:01:06 +0200 Subject: [PATCH 1452/2612] check-lte-firmware-upgrade: use $FormatLine --- check-lte-firmware-upgrade.rsc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index 02e864b..81bdf9b 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -23,6 +23,7 @@ :global SentLteFirmwareUpgradeNotification; :global CharacterReplace; + :global FormatLine; :global LogPrintExit2; :global ScriptFromTerminal; :global SendNotification2; @@ -71,9 +72,9 @@ subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \ message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \ "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ - "Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \ - "Installed: " . ($Firmware->"installed") . "\n" . \ - "Available: " . ($Firmware->"latest")); silent=true }); + [ $FormatLine "Interface" [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] ] . "\n" . \ + [ $FormatLine "Installed" ($Firmware->"installed") ] . "\n" . \ + [ $FormatLine "Available" ($Firmware->"latest") ]); silent=true }); :set ($SentLteFirmwareUpgradeNotification->$IntName) ($Firmware->"latest"); } From 517bb4ede8192b2e6bce765f56fa684581f998e3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 12 Apr 2023 23:21:51 +0200 Subject: [PATCH 1453/2612] dhcp-to-dns: get all values of dns record --- dhcp-to-dns.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index e6970ff..8a2cf0b 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -74,9 +74,9 @@ $ScriptLock $0 false 10; :local DnsRecord [ /ip/dns/static/find where comment=$Comment (!type or type=A) ]; :if ([ :len $DnsRecord ] > 0) do={ - :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; + :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; - :if ($DnsIp = $LeaseVal->"address") do={ + :if ($DnsRecordVal->"address" = $LeaseVal->"address") do={ $LogPrintExit2 debug $0 ("DNS entry for " . ($MacDash . "." . $Domain) . " does not need updating.") false; } else={ $LogPrintExit2 info $0 ("Replacing DNS entry for " . ($MacDash . "." . $Domain) . ", new address is " . $LeaseVal->"address" . ".") false; From b705ceae591205b5eba54ee2f6a1ffb9066f2779 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 21 Apr 2023 00:03:55 +0200 Subject: [PATCH 1454/2612] collect-wireless-mac: use $FormatLine --- collect-wireless-mac.capsman.rsc | 19 ++++++++++--------- collect-wireless-mac.local.rsc | 19 ++++++++++--------- collect-wireless-mac.template.rsc | 19 ++++++++++--------- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index e814fa9..094ffc0 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -17,6 +17,7 @@ :global Identity; :global EitherOr; +:global FormatLine; :global GetMacVendor; :global LogPrintExit2; :global ScriptLock; @@ -69,15 +70,15 @@ $ScriptLock $0 false 10; $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - "Controller: " . $Identity . "\n" . \ - "Interface: " . $RegVal->"interface" . "\n" . \ - "SSID: " . $RegVal->"ssid" . "\n" . \ - "MAC: " . $RegVal->"mac-address" . "\n" . \ - "Vendor: " . $Vendor . "\n" . \ - "Hostname: " . $HostName . "\n" . \ - "Address: " . $Address . "\n" . \ - "DNS name: " . $DnsName . "\n" . \ - "Date: " . $DateTime) }); + [ $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" . \ + [ $FormatLine "DNS name" $DnsName ] . "\n" . \ + [ $FormatLine "Date" $DateTime ]) }); } } else={ $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index ee07f54..23eb9fa 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -17,6 +17,7 @@ :global Identity; :global EitherOr; +:global FormatLine; :global GetMacVendor; :global LogPrintExit2; :global ScriptLock; @@ -70,15 +71,15 @@ $ScriptLock $0 false 10; $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - "Controller: " . $Identity . "\n" . \ - "Interface: " . $RegVal->"interface" . "\n" . \ - "SSID: " . $RegVal->"ssid" . "\n" . \ - "MAC: " . $RegVal->"mac-address" . "\n" . \ - "Vendor: " . $Vendor . "\n" . \ - "Hostname: " . $HostName . "\n" . \ - "Address: " . $Address . "\n" . \ - "DNS name: " . $DnsName . "\n" . \ - "Date: " . $DateTime) }); + [ $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" . \ + [ $FormatLine "DNS name" $DnsName ] . "\n" . \ + [ $FormatLine "Date" $DateTime ]) }); } } else={ $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index c315385..a8983d9 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -18,6 +18,7 @@ :global Identity; :global EitherOr; +:global FormatLine; :global GetMacVendor; :global LogPrintExit2; :global ScriptLock; @@ -71,15 +72,15 @@ $ScriptLock $0 false 10; $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - "Controller: " . $Identity . "\n" . \ - "Interface: " . $RegVal->"interface" . "\n" . \ - "SSID: " . $RegVal->"ssid" . "\n" . \ - "MAC: " . $RegVal->"mac-address" . "\n" . \ - "Vendor: " . $Vendor . "\n" . \ - "Hostname: " . $HostName . "\n" . \ - "Address: " . $Address . "\n" . \ - "DNS name: " . $DnsName . "\n" . \ - "Date: " . $DateTime) }); + [ $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" . \ + [ $FormatLine "DNS name" $DnsName ] . "\n" . \ + [ $FormatLine "Date" $DateTime ]) }); } } else={ $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; From 79cdefbd1e3c10f6ed87b705d1993eaf9d219d47 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 12 Apr 2023 23:43:45 +0200 Subject: [PATCH 1455/2612] dhcp-to-dns: handle change of domain --- dhcp-to-dns.rsc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 8a2cf0b..9d785d2 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -49,7 +49,7 @@ $ScriptLock $0 false 10; :local Found false; $LogPrintExit2 info $0 ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry.") false; /ip/dns/static/remove $DnsRecord; - /ip/dns/static/remove [ find where type=CNAME cname=($DnsRecordVal->"name") comment=($DnsRecordVal->"comment") ]; + /ip/dns/static/remove [ find where type=CNAME comment=($DnsRecordVal->"comment") ]; } } @@ -76,26 +76,27 @@ $ScriptLock $0 false 10; :if ([ :len $DnsRecord ] > 0) do={ :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; - :if ($DnsRecordVal->"address" = $LeaseVal->"address") do={ - $LogPrintExit2 debug $0 ("DNS entry for " . ($MacDash . "." . $Domain) . " does not need updating.") false; + :if ($DnsRecordVal->"address" = $LeaseVal->"address" && $DnsRecordVal->"name" = ($MacDash . "." . $Domain)) do={ + $LogPrintExit2 debug $0 ("DNS entry for " . $LeaseVal->"mac-address" . " does not need updating.") false; } else={ - $LogPrintExit2 info $0 ("Replacing DNS entry for " . ($MacDash . "." . $Domain) . ", new address is " . $LeaseVal->"address" . ".") false; - /ip/dns/static/set address=($LeaseVal->"address") $DnsRecord; + $LogPrintExit2 info $0 ("Replacing DNS entry for " . $LeaseVal->"mac-address" . " (" . ($MacDash . "." . $Domain) . " -> " . $LeaseVal->"address" . ").") false; + /ip/dns/static/set address=($LeaseVal->"address") name=($MacDash . "." . $Domain) $DnsRecord; } - :local Cname [ /ip/dns/static/find where type=CNAME cname=($MacDash . "." . $Domain) comment=$Comment ]; + :local Cname [ /ip/dns/static/find where comment=$Comment type=CNAME ]; :if ([ :len $Cname ] = 0 && [ :len $HostName ] > 0) do={ - $LogPrintExit2 info $0 ("Host name appeared, adding CNAME " . ($HostName . "." . $Domain) . " pointing to " . ($MacDash . "." . $Domain) . ".") false; + $LogPrintExit2 info $0 ("Host name appeared, adding CNAME (" . ($HostName . "." . $Domain) . " -> " . ($MacDash . "." . $Domain) . ").") false; /ip/dns/static/add name=($HostName . "." . $Domain) type=CNAME cname=($MacDash . "." . $Domain) ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } :if ([ :len $Cname ] > 0 && [ /ip/dns/static/get $Cname name ] != ($HostName . "." . $Domain)) do={ - $LogPrintExit2 info $0 ("Host name changed, updating CNAME (pointing to " . ($MacDash . "." . $Domain) . ") to " . ($HostName . "." . $Domain) . ".") false; - /ip/dns/static/set name=($HostName . "." . $Domain) $Cname; + $LogPrintExit2 info $0 ("Host name or domain changed, updating CNAME (" . ($HostName . "." . $Domain) . " -> " . ($MacDash . "." . $Domain) . ").") false; + /ip/dns/static/set name=($HostName . "." . $Domain) cname=($MacDash . "." . $Domain) $Cname; } } else={ - $LogPrintExit2 info $0 ("Adding new DNS entry for " . ($MacDash . "." . $Domain) . ", address is " . $LeaseVal->"address" . ".") false; + $LogPrintExit2 info $0 ("Adding new DNS entry for " . $LeaseVal->"mac-address" . " (" . ($MacDash . "." . $Domain) . " -> " . $LeaseVal->"address" . ").") false; /ip/dns/static/add name=($MacDash . "." . $Domain) type=A address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; :if ([ :len $HostName ] > 0) do={ + $LogPrintExit2 info $0 ("Adding new CNAME (" . ($HostName . "." . $Domain) . " -> " . ($MacDash . "." . $Domain) . ").") false; /ip/dns/static/add name=($HostName . "." . $Domain) type=CNAME cname=($MacDash . "." . $Domain) ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } From 944b2f58649835dbc6abe83bab6d4500dd046fd8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 21 Apr 2023 00:05:46 +0200 Subject: [PATCH 1456/2612] daily-psk: use $FormatLine --- daily-psk.capsman.rsc | 7 ++++--- daily-psk.local.rsc | 7 ++++--- daily-psk.template.rsc | 7 ++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index 17a09e1..e589991 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -17,6 +17,7 @@ :global DailyPskQrCodeUrl; :global Identity; +:global FormatLine; :global LogPrintExit2; :global SendNotification2; :global SymbolForNotification; @@ -86,9 +87,9 @@ $WaitFullyConnected; $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - "SSID: " . $Ssid . "\n" . \ - "PSK: " . $NewPsk . "\n" . \ - "Date: " . $Date . "\n\n" . \ + [ $FormatLine "SSID" $Ssid ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk ] . "\n" . \ + [ $FormatLine "Date" $Date ] . "\n\n" . \ "A client device specific rule must not exist!"); link=$Link }); } } diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 17a60f7..df17173 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -17,6 +17,7 @@ :global DailyPskQrCodeUrl; :global Identity; +:global FormatLine; :global LogPrintExit2; :global SendNotification2; :global SymbolForNotification; @@ -85,9 +86,9 @@ $WaitFullyConnected; $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - "SSID: " . $Ssid . "\n" . \ - "PSK: " . $NewPsk . "\n" . \ - "Date: " . $Date . "\n\n" . \ + [ $FormatLine "SSID" $Ssid ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk ] . "\n" . \ + [ $FormatLine "Date" $Date ] . "\n\n" . \ "A client device specific rule must not exist!"); link=$Link }); } } diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 7e41a1f..5f30ce3 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -18,6 +18,7 @@ :global DailyPskQrCodeUrl; :global Identity; +:global FormatLine; :global LogPrintExit2; :global SendNotification2; :global SymbolForNotification; @@ -93,9 +94,9 @@ $WaitFullyConnected; $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - "SSID: " . $Ssid . "\n" . \ - "PSK: " . $NewPsk . "\n" . \ - "Date: " . $Date . "\n\n" . \ + [ $FormatLine "SSID" $Ssid ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk ] . "\n" . \ + [ $FormatLine "Date" $Date ] . "\n\n" . \ "A client device specific rule must not exist!"); link=$Link }); } } From ac5d84173f0a5b019ed59051c142837f76b5549e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 13 Apr 2023 00:46:05 +0200 Subject: [PATCH 1457/2612] dhcp-to-dns: rename variable to not clash with global one --- dhcp-to-dns.rsc | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 9d785d2..d310a73 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -70,34 +70,34 @@ $ScriptLock $0 false 10; :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); :local MacDash [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ]; :local HostName [ $CharacterReplace [ $EitherOr ([ $ParseKeyValueStore ($LeaseVal->"comment") ]->"hostname") ($LeaseVal->"host-name") ] " " "" ]; - :local Domain ([ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); + :local NetDomain ([ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); :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->"address" && $DnsRecordVal->"name" = ($MacDash . "." . $Domain)) do={ + :if ($DnsRecordVal->"address" = $LeaseVal->"address" && $DnsRecordVal->"name" = ($MacDash . "." . $NetDomain)) do={ $LogPrintExit2 debug $0 ("DNS entry for " . $LeaseVal->"mac-address" . " does not need updating.") false; } else={ - $LogPrintExit2 info $0 ("Replacing DNS entry for " . $LeaseVal->"mac-address" . " (" . ($MacDash . "." . $Domain) . " -> " . $LeaseVal->"address" . ").") false; - /ip/dns/static/set address=($LeaseVal->"address") name=($MacDash . "." . $Domain) $DnsRecord; + $LogPrintExit2 info $0 ("Replacing DNS entry for " . $LeaseVal->"mac-address" . " (" . ($MacDash . "." . $NetDomain) . " -> " . $LeaseVal->"address" . ").") false; + /ip/dns/static/set address=($LeaseVal->"address") name=($MacDash . "." . $NetDomain) $DnsRecord; } :local Cname [ /ip/dns/static/find where comment=$Comment type=CNAME ]; :if ([ :len $Cname ] = 0 && [ :len $HostName ] > 0) do={ - $LogPrintExit2 info $0 ("Host name appeared, adding CNAME (" . ($HostName . "." . $Domain) . " -> " . ($MacDash . "." . $Domain) . ").") false; - /ip/dns/static/add name=($HostName . "." . $Domain) type=CNAME cname=($MacDash . "." . $Domain) ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + $LogPrintExit2 info $0 ("Host name appeared, adding CNAME (" . ($HostName . "." . $NetDomain) . " -> " . ($MacDash . "." . $NetDomain) . ").") false; + /ip/dns/static/add name=($HostName . "." . $NetDomain) type=CNAME cname=($MacDash . "." . $NetDomain) ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } - :if ([ :len $Cname ] > 0 && [ /ip/dns/static/get $Cname name ] != ($HostName . "." . $Domain)) do={ - $LogPrintExit2 info $0 ("Host name or domain changed, updating CNAME (" . ($HostName . "." . $Domain) . " -> " . ($MacDash . "." . $Domain) . ").") false; - /ip/dns/static/set name=($HostName . "." . $Domain) cname=($MacDash . "." . $Domain) $Cname; + :if ([ :len $Cname ] > 0 && [ /ip/dns/static/get $Cname name ] != ($HostName . "." . $NetDomain)) do={ + $LogPrintExit2 info $0 ("Host name or domain changed, updating CNAME (" . ($HostName . "." . $NetDomain) . " -> " . ($MacDash . "." . $NetDomain) . ").") false; + /ip/dns/static/set name=($HostName . "." . $NetDomain) cname=($MacDash . "." . $NetDomain) $Cname; } } else={ - $LogPrintExit2 info $0 ("Adding new DNS entry for " . $LeaseVal->"mac-address" . " (" . ($MacDash . "." . $Domain) . " -> " . $LeaseVal->"address" . ").") false; - /ip/dns/static/add name=($MacDash . "." . $Domain) type=A address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + $LogPrintExit2 info $0 ("Adding new DNS entry for " . $LeaseVal->"mac-address" . " (" . ($MacDash . "." . $NetDomain) . " -> " . $LeaseVal->"address" . ").") false; + /ip/dns/static/add name=($MacDash . "." . $NetDomain) type=A address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; :if ([ :len $HostName ] > 0) do={ - $LogPrintExit2 info $0 ("Adding new CNAME (" . ($HostName . "." . $Domain) . " -> " . ($MacDash . "." . $Domain) . ").") false; - /ip/dns/static/add name=($HostName . "." . $Domain) type=CNAME cname=($MacDash . "." . $Domain) ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + $LogPrintExit2 info $0 ("Adding new CNAME (" . ($HostName . "." . $NetDomain) . " -> " . ($MacDash . "." . $NetDomain) . ").") false; + /ip/dns/static/add name=($HostName . "." . $NetDomain) type=CNAME cname=($MacDash . "." . $NetDomain) ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } } else={ From 82b5ae174ac15bb6c2b7180980da12c1908de7df Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 21 Apr 2023 00:12:31 +0200 Subject: [PATCH 1458/2612] mod/ipcalc: use $FormatLine --- mod/ipcalc.rsc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc index ee78378..eaa5c97 100644 --- a/mod/ipcalc.rsc +++ b/mod/ipcalc.rsc @@ -13,18 +13,19 @@ :set IPCalc do={ :local Input [ :tostr $1 ]; + :global FormatLine; :global IPCalcReturn; :global PrettyPrint; :local Values [ $IPCalcReturn $1 ]; $PrettyPrint ( \ - "Address: " . $Values->"address" . "\n" . \ - "Netmask: " . $Values->"netmask" . "\n" . \ - "Network: " . $Values->"network" . "\n" . \ - "HostMin: " . $Values->"hostmin" . "\n" . \ - "HostMax: " . $Values->"hostmax" . "\n" . \ - "Broadcast: " . $Values->"broadcast"); + [ $FormatLine "Address" ($Values->"address") ] . "\n" . \ + [ $FormatLine "Netmask" ($Values->"netmask") ] . "\n" . \ + [ $FormatLine "Network" ($Values->"network") ] . "\n" . \ + [ $FormatLine "HostMin" ($Values->"hostmin") ] . "\n" . \ + [ $FormatLine "HostMax" ($Values->"hostmax") ] . "\n" . \ + [ $FormatLine "Broadcast" ($Values->"broadcast") ]); } # calculate and return netmask, network, min host, max host and broadcast From ee94024dcaa59333f03d90f342e550a5f3ab40f2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 13 Apr 2023 00:32:13 +0200 Subject: [PATCH 1459/2612] dhcp-to-dns: get domain from dhcp server's network definition --- dhcp-to-dns.rsc | 15 ++++++++------- doc/dhcp-to-dns.md | 23 +++++++++++++++++++---- global-config.rsc | 3 --- global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 5 files changed, 29 insertions(+), 15 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index d310a73..b15511e 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -13,10 +13,7 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global Domain; -:global HostNameInZone; :global Identity; -:global PrefixInZone; -:global ServerNameInZone; :global CharacterReplace; :global EitherOr; @@ -27,9 +24,6 @@ $ScriptLock $0 false 10; -:local Zone \ - ([ $IfThenElse ($PrefixInZone = true) "dhcp." ] . \ - [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); :local Ttl 5m; :local CommentPrefix ("managed by " . $0 . " for "); :local CommentString ("--- " . $0 . " above ---"); @@ -70,7 +64,14 @@ $ScriptLock $0 false 10; :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); :local MacDash [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ]; :local HostName [ $CharacterReplace [ $EitherOr ([ $ParseKeyValueStore ($LeaseVal->"comment") ]->"hostname") ($LeaseVal->"host-name") ] " " "" ]; - :local NetDomain ([ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); + :local Network [ /ip/dhcp-server/network/find where ($LeaseVal->"address") in address ]; + :local NetworkVal; + :if ([ :len $Network ] > 0) do={ + :set NetworkVal [ /ip/dhcp-server/network/get ($Network->0) ]; + } + :local NetworkInfo [ $ParseKeyValueStore ($NetworkVal->"comment") ]; + :local NetDomain ([ $IfThenElse ([ :len ($NetworkInfo->"name-extra") ] > 0) ($NetworkInfo->"name-extra" . ".") ] . \ + [ $EitherOr [ $EitherOr ($NetworkInfo->"domain") ($NetworkVal->"domain") ] $Domain ]); :local DnsRecord [ /ip/dns/static/find where comment=$Comment (!type or type=A) ]; :if ([ :len $DnsRecord ] > 0) do={ diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index a2caf0c..0c443a0 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -34,12 +34,27 @@ On first run a disabled static dns record acting as marker (with comment "`--- dhcp-to-dns above ---`") is added. Move this entry to define where new entries are to be added. -The configuration goes to `global-config-overlay`, these are the parameters: +The configuration goes to dhcp server's network definition. The domain is +used to form the dns name: + + /ip/dhcp-server/network/add address=10.0.0.0/24 domain=example.com; + +A bound lease for mac address `00:11:22:33:44:55` with ip address +`10.0.0.50` would result in an A record `00-11-22-33-44-55.example.com` +pointing to the given ip address. + +Additional options can be given from comment, to add an extra level in +dns name or define a different domain. + + /ip/dhcp-server/network/add address=10.0.0.0/24 domain=example.com comment="domain=another-domain.com, name-extra=dhcp"; + +This example would result in name `00-11-22-33-44-55.dhcp.another-domain.com` +for the same lease. + +If no domain is found in dhcp server's network definition a fallback from +`global-config-overlay` is used. This is the parameter: * `Domain`: the domain used for dns records -* `HostNameInZone`: whether or not to add the dhcp/dns server's hostname -* `PrefixInZone`: whether or not to add prefix `dhcp` -* `ServerNameInZone`: whether or not to add DHCP server name ### Host name from DHCP lease comment diff --git a/global-config.rsc b/global-config.rsc index 770efd0..71be3f2 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -14,9 +14,6 @@ # This is used for DNS and backup file. :global Domain "example.com"; -:global HostNameInZone true; -:global PrefixInZone true; -:global ServerNameInZone false; # You can send e-mail notifications. Configure the system's mail settings # (/tool/e-mail), then install the module: diff --git a/global-functions.rsc b/global-functions.rsc index 45fda9f..e6b1d36 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 98; +:global ExpectedConfigVersion 99; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 08ff3fb..7087c6c 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -12,6 +12,7 @@ 96="Added support for notes in 'netwatch-notify', these are included verbatim into the notification."; 97="Modified 'dhcp-to-dns' to always add A records for names with mac address, and optionally add CNAME records if the host name is available."; 98="Extended 'check-certificates' to download new certificate by SubjectAltNames if download by CommonName fails."; + 99="Modified 'dhcp-to-dns', which dropped global configuration. Settings moved to dhcp server's network definitions."; }; # Migration steps to be applied on script updates From 9dead9cc33f29166bb3c72ccd3e5444f215c1c6f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 25 Apr 2023 09:43:50 +0200 Subject: [PATCH 1460/2612] mod/bridge-port-vlan: increase the delay before re-enabling Looks like two seconds is way too short... NetworkManager act after five seconds - so let's delay that time at least. https://networkmanager.dev/docs/api/latest/NetworkManager.conf.html#carrier-wait-timeout --- mod/bridge-port-vlan.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/bridge-port-vlan.rsc b/mod/bridge-port-vlan.rsc index 8fb64e1..792a6c4 100644 --- a/mod/bridge-port-vlan.rsc +++ b/mod/bridge-port-vlan.rsc @@ -66,7 +66,7 @@ } } :if ([ :len $InterfaceReEnable ] > 0) do={ - :delay 2s; + :delay 5s; $LogPrintExit2 info $0 ("Re-enabling interfaces...") false; /interface/ethernet/enable $InterfaceReEnable; } From 575c77d1a68fd8af4a6fb25f1c6c41d26f563d0a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 25 Apr 2023 09:45:46 +0200 Subject: [PATCH 1461/2612] mod/bridge-port-to: increase the delay before re-enabling Looks like two seconds is way too short... NetworkManager act after five seconds - so let's delay that time at least. https://networkmanager.dev/docs/api/latest/NetworkManager.conf.html#carrier-wait-timeout --- mod/bridge-port-to.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/bridge-port-to.rsc b/mod/bridge-port-to.rsc index f752d30..86689c9 100644 --- a/mod/bridge-port-to.rsc +++ b/mod/bridge-port-to.rsc @@ -58,7 +58,7 @@ } } :if ([ :len $InterfaceReEnable ] > 0) do={ - :delay 2s; + :delay 5s; $LogPrintExit2 info $0 ("Re-enabling interfaces...") false; /interface/ethernet/enable $InterfaceReEnable; } From 5c7a7723f318a852c5dff087ef8ec12510846dcf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Apr 2023 10:25:38 +0200 Subject: [PATCH 1462/2612] global-config: be more verbose about domain --- global-config.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-config.rsc b/global-config.rsc index 71be3f2..3135b43 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -12,7 +12,8 @@ # Add extra text (or emojis) in notification tags. :global IdentityExtra ""; -# This is used for DNS and backup file. +# This is used in DNS scripts ('ipsec-to-dns' and fallback in 'dhcp-to-dns') +# and backup scripts for file names. :global Domain "example.com"; # You can send e-mail notifications. Configure the system's mail settings From a3a7e5be4b77a6f879dd318d67d40390d643d391 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Apr 2023 10:28:47 +0200 Subject: [PATCH 1463/2612] global-config: restore variables still used in ipsec-to-dns (for now) --- global-config.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/global-config.rsc b/global-config.rsc index 3135b43..6f2beed 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -139,6 +139,10 @@ "String"; "Whistle" } } +# Specify how to assemble DNS names in ipsec-to-dns. +:global HostNameInZone true; +:global PrefixInZone true; + # Run different commands with multiple mode-button presses. :global ModeButton { 1="/system/script/run leds-toggle-mode;"; From c8500dddd01ef10128eca0e4176050ef087a3918 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 4 Apr 2023 16:27:23 +0200 Subject: [PATCH 1464/2612] mod/ssh-keys-import: make ssh-keys-import a module --- README.md | 2 +- doc/mod/ssh-keys-import.md | 59 ++++++++++++++++++++++++++ doc/ssh-keys-import.md | 35 +--------------- global-functions.rsc | 2 +- mod/ssh-keys-import.rsc | 84 ++++++++++++++++++++++++++++++++++++++ news-and-changes.rsc | 2 + ssh-keys-import.rsc | 11 ----- 7 files changed, 149 insertions(+), 46 deletions(-) create mode 100644 doc/mod/ssh-keys-import.md create mode 100644 mod/ssh-keys-import.rsc delete mode 100644 ssh-keys-import.rsc diff --git a/README.md b/README.md index 14a5680..1d6bc9b 100644 --- a/README.md +++ b/README.md @@ -225,7 +225,6 @@ Available scripts * [Run scripts on ppp connection](doc/ppp-on-up.md) * [Act on received SMS](doc/sms-action.md) * [Forward received SMS](doc/sms-forward.md) -* [Import SSH keys](doc/ssh-keys-import.md) * [Play Super Mario theme](doc/super-mario-theme.md) * [Chat with your router and send commands via Telegram bot](doc/telegram-chat.md) * [Install LTE firmware upgrade](doc/unattended-lte-firmware-upgrade.md) @@ -243,6 +242,7 @@ Available modules * [Send notifications via Matrix](doc/mod/notification-matrix.md) * [Send notifications via Telegram](doc/mod/notification-telegram.md) * [Download script and run it once](doc/mod/scriptrunonce.md) +* [Import ssh keys for public key authentication](doc/mod/ssh-keys-import.md) Installing custom scripts & modules ----------------------------------- diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md new file mode 100644 index 0000000..2f631a7 --- /dev/null +++ b/doc/mod/ssh-keys-import.md @@ -0,0 +1,59 @@ +Import ssh keys for public key authentication +============================================= + +[âŦ…ī¸ Go back to main README](../../README.md) + +![required RouterOS version](https://img.shields.io/badge/RouterOS-7.9beta4-yellow?style=flat) + +> â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base +> installation. See [main README](../../README.md) for details. + +Description +----------- + +RouterOS supports ssh login with public key authentication. The functions +in this module help importing the keys. + +Requirements and installation +----------------------------- + +Just install the module: + + $ScriptInstallUpdate mod/ssh-keys-import; + +Usage and invocation +-------------------- + +### Import single key from terminal + +Call the function `$SSHKeysImport` with key and user as parameter to +import that key: + + $SSHKeysImport "ssh-rsa ssh-rsa AAAAB3Nza...QYZk8= user" admin; + +The third part of the key (`user` in this example) is inherited as +`key-owner` in RouterOS. + +### Import several keys from file + +The functions `$SSHKeysImportFile` can read an `authorized_keys`-style file +and import all the keys. The user given to the function can be overwritting +from comments in the file. Create a file `keys.pub` with this content: + +``` +ssh-rsa AAAAB3Nza...QYZk8= user@client +ssh-rsa AAAAB3Nza...ozyts= worker@station +# user=example +ssh-rsa AAAAB3Nza...GXQVk= person@host +``` + +Then import it with: + + $SSHKeysImportFile keys.pub admin; + +This will import the first two keys for user `admin` (as given to function) +and the third one for user `example` (as defined in comment). + +--- +[âŦ…ī¸ Go back to main README](../../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/ssh-keys-import.md b/doc/ssh-keys-import.md index 2dd6c42..d1325aa 100644 --- a/doc/ssh-keys-import.md +++ b/doc/ssh-keys-import.md @@ -1,33 +1,2 @@ -Import SSH keys -=============== - -[âŦ…ī¸ Go back to main README](../README.md) - -Description ------------ - -This script imports public SSH keys (files with extension "`pub`") into -local store for user authentication. - -Requirements and installation ------------------------------ - -Just install the script: - - $ScriptInstallUpdate ssh-keys-import; - -Usage and invocation --------------------- - -Copy files with extension "`pub`" containing public SSH keys for your device. -Then run the script: - - /system/script/run ssh-keys-import; - -Starting with an `authorized_keys` file you can split it on a shell: - - grep -E '^ssh-rsa' authorized_keys | nl -nrz | while read num type key name; do echo $type $key $name > $num-$name.pub; done - ---- -[âŦ…ī¸ Go back to main README](../README.md) -[âŦ†ī¸ Go back to top](#top) +This script has been replaced by a module. Please see +[Import ssh keys for public key authentication](mod/ssh-keys-import.md). diff --git a/global-functions.rsc b/global-functions.rsc index e6b1d36..4ec5857 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 99; +:global ExpectedConfigVersion 100; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc new file mode 100644 index 0000000..6f47314 --- /dev/null +++ b/mod/ssh-keys-import.rsc @@ -0,0 +1,84 @@ +#!rsc by RouterOS +# RouterOS script: mod/ssh-keys-import +# Copyright (c) 2020-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.9beta4 +# +# import ssh keys for public key authentication +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ssh-keys-import.md + +:global SSHKeysImport; +:global SSHKeysImportFile; + +# import single key passed as string +:set SSHKeysImport do={ + :local Key [ :tostr $1 ]; + :local User [ :tostr $2 ]; + + :global GetRandom20CharAlNum; + :global LogPrintExit2; + :global MkDir; + :global WaitForFile; + + :if ([ :len $Key ] = 0 || [ :len $User ] = 0) do={ + $LogPrintExit2 warning $0 ("Missing argument(s), please pass key and user!") true; + } + + :if ([ :len [ /user/find where name=$User ] ] = 0) do={ + $LogPrintExit2 warning $0 ("User '" . $User . "' does not exist.") true; + } + + :if ([ $MkDir "tmpfs/ssh-keys-import" ] = false) do={ + $LogPrintExit2 warning $0 ("Creating directory 'tmpfs/ssh-keys-import' failed!") true; + } + + :local FileName ("tmpfs/ssh-keys-import/key-" . [ $GetRandom20CharAlNum 6 ] . ".pub"); + /file/add name=$FileName contents=$Key; + $WaitForFile $FileName; + + :do { + /user/ssh-keys/import public-key-file=$FileName user=$User; + } on-error={ + $LogPrintExit2 warning $0 ("Failed importing key.") true; + } +} + +# import keys from a file +:set SSHKeysImportFile do={ + :local FileName [ :tostr $1 ]; + :local User [ :tostr $2 ]; + + :global EitherOr; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global SSHKeysImport; + + :if ([ :len $FileName ] = 0 || [ :len $User ] = 0) do={ + $LogPrintExit2 warning $0 ("Missing argument(s), please pass file name and user!") true; + } + + :local File [ /file/find where name=$FileName ]; + :if ([ :len $File ] = 0) do={ + $LogPrintExit2 warning $0 ("File '" . $FileName . "' does not exist.") true; + } + :local Keys ([ /file/get $FileName contents ] . "\n"); + + :do { + :local Continue false; + :local Line [ :pick $Keys 0 [ :find $Keys "\n" ] ]; + :set Keys [ :pick $Keys ([ :find $Keys "\n" ] + 1) [ :len $Keys ] ]; + :local Type [ :pick $Line 0 [ :find $Line " " ] ]; + :if ($Type = "ssh-rsa") do={ + $SSHKeysImport $Line $User; + :set Continue true; + } + :if ($Continue = false && $Type = "#") do={ + :set User [ $EitherOr ([ $ParseKeyValueStore [ :pick $Line 2 [ :len $Line ] ] ]->"user") $User ]; + :set Continue true; + } + :if ($Continue = false && [ :len $Type ] > 0) do={ + $LogPrintExit2 warning $0 ("SSH key of type '" . $Type . "' is not supported.") false; + } + } while=([ :len $Keys ] > 0); +} diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 7087c6c..1e43722 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -13,9 +13,11 @@ 97="Modified 'dhcp-to-dns' to always add A records for names with mac address, and optionally add CNAME records if the host name is available."; 98="Extended 'check-certificates' to download new certificate by SubjectAltNames if download by CommonName fails."; 99="Modified 'dhcp-to-dns', which dropped global configuration. Settings moved to dhcp server's network definitions."; + 100="The script 'ssh-keys-import' became a module 'mod/ssh-keys-import' with enhanced functionality."; }; # Migration steps to be applied on script updates :global GlobalConfigMigration { 97=":local Rec [ /ip/dns/static/find where comment~\"^managed by dhcp-to-dns for \" ]; :if ([ :len \$Rec ] > 0) do={ /ip/dns/static/remove \$Rec; /system/script/run dhcp-to-dns; }"; + 100=":global ScriptInstallUpdate; :if ([ :len [ /system/script/find where name=\"ssh-keys-import\" source~\"^#!rsc by RouterOS\\n\" ] ] > 0) do={ /system/script/set name=\"mod/ssh-keys-import\" ssh-keys-import; \$ScriptInstallUpdate; }"; }; diff --git a/ssh-keys-import.rsc b/ssh-keys-import.rsc deleted file mode 100644 index b40a997..0000000 --- a/ssh-keys-import.rsc +++ /dev/null @@ -1,11 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: ssh-keys-import -# Copyright (c) 2013-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# import ssh keys from file -# https://git.eworm.de/cgit/routeros-scripts/about/doc/ssh-keys-import.md - -:foreach Key in=[ /file/find where type="ssh key" ] do={ - /user/ssh-key/import user=admin public-key-file=[ /file/get $Key name ]; -} From 1f1e76b822689297faff56cfcbdd574da4a2bd9f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 28 Mar 2023 15:55:48 +0200 Subject: [PATCH 1465/2612] sms-forward: drop workaround, add required RouterOS --- doc/sms-forward.md | 2 ++ sms-forward.rsc | 13 ++----------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 9dccaf3..bfab38d 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -3,6 +3,8 @@ Forward received SMS [âŦ…ī¸ Go back to main README](../README.md) +![required RouterOS version](https://img.shields.io/badge/RouterOS-7.9beta4-yellow?style=flat) + > â„šī¸ **Info**: This script can not be used on its own but requires the base > installation. See [main README](../README.md) for details. diff --git a/sms-forward.rsc b/sms-forward.rsc index e6ac9aa..542fe0d 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -4,6 +4,8 @@ # Anatoly Bubenkov # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.9beta4 +# # forward SMS to e-mail # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md @@ -13,11 +15,9 @@ :global Identity; :global SmsForwardHooks; -:global SmsForwardWorkaround; :global IfThenElse; :global LogPrintExit2; -:global RequiredRouterOS; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -30,15 +30,6 @@ $ScriptLock $0; $LogPrintExit2 warning $0 ("Receiving of SMS is not enabled.") true; } -:if ($SmsForwardWorkaround != true && \ - [ $RequiredRouterOS $0 "7.8" false ] = true && \ - [ $RequiredRouterOS $0 "7.9beta4" false ] = false) do={ - :local AutoErase [ /tool/sms/get auto-erase ]; - /tool/sms/set auto-erase=(!$AutoErase); - /tool/sms/set auto-erase=$AutoErase; - :set SmsForwardWorkaround true; -} - $WaitFullyConnected; :local Settings [ /tool/sms/get ]; From 3fe66c841392c8cbfa6d6514fe0b2f685911364a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 2 May 2023 16:19:44 +0200 Subject: [PATCH 1466/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index efa418c..0213b45 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -28,6 +28,7 @@ Add yourself to the list, * Christoph Boss (@Kampfwurst) * Devin Dean (@dd2594gh) * Evaldo Gardenal +* Harold Schoemaker * Hugo BV * Klaus Michael RÃŧbsam * Linux-Schmie.de Michael Gisbers From d586a5ab1975e7f06a43f816e3809753d9606cba Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 May 2023 13:28:51 +0200 Subject: [PATCH 1467/2612] daily-psk: simplify calculation Use a named array, and drop the loop... --- daily-psk.capsman.rsc | 12 +++--------- daily-psk.local.rsc | 12 +++--------- daily-psk.template.rsc | 12 +++--------- 3 files changed, 9 insertions(+), 27 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index e589991..65a17d0 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -33,19 +33,13 @@ $WaitFullyConnected; :global DailyPskSecrets; - :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun"; - "jul"; "aug"; "sep"; "oct"; "nov"; "dec" }; + :local Months { "jan"=1; "feb"=2; "mar"=3; "apr"=4; "may"=5; "jun"=6; + "jul"=7; "aug"=8; "sep"=9; "oct"=10; "nov"=11; "dec"=12 }; - :local Month [ :pick $Date 0 3 ]; + :local Month ($Months->[ :pick $Date 0 3 ]); :local Day [ :tonum [ :pick $Date 4 6 ] ]; :local Year [ :pick $Date 7 11 ]; - :for MIndex from=0 to=[ :len $Months ] do={ - :if ($Months->$MIndex = $Month) do={ - :set Month ($MIndex + 1); - } - } - :local A ((14 - $Month) / 12); :local B ($Year - $A); :local C ($Month + 12 * $A - 2); diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index df17173..94991a7 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -33,19 +33,13 @@ $WaitFullyConnected; :global DailyPskSecrets; - :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun"; - "jul"; "aug"; "sep"; "oct"; "nov"; "dec" }; + :local Months { "jan"=1; "feb"=2; "mar"=3; "apr"=4; "may"=5; "jun"=6; + "jul"=7; "aug"=8; "sep"=9; "oct"=10; "nov"=11; "dec"=12 }; - :local Month [ :pick $Date 0 3 ]; + :local Month ($Months->[ :pick $Date 0 3 ]); :local Day [ :tonum [ :pick $Date 4 6 ] ]; :local Year [ :pick $Date 7 11 ]; - :for MIndex from=0 to=[ :len $Months ] do={ - :if ($Months->$MIndex = $Month) do={ - :set Month ($MIndex + 1); - } - } - :local A ((14 - $Month) / 12); :local B ($Year - $A); :local C ($Month + 12 * $A - 2); diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 5f30ce3..e2a3d59 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -34,19 +34,13 @@ $WaitFullyConnected; :global DailyPskSecrets; - :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun"; - "jul"; "aug"; "sep"; "oct"; "nov"; "dec" }; + :local Months { "jan"=1; "feb"=2; "mar"=3; "apr"=4; "may"=5; "jun"=6; + "jul"=7; "aug"=8; "sep"=9; "oct"=10; "nov"=11; "dec"=12 }; - :local Month [ :pick $Date 0 3 ]; + :local Month ($Months->[ :pick $Date 0 3 ]); :local Day [ :tonum [ :pick $Date 4 6 ] ]; :local Year [ :pick $Date 7 11 ]; - :for MIndex from=0 to=[ :len $Months ] do={ - :if ($Months->$MIndex = $Month) do={ - :set Month ($MIndex + 1); - } - } - :local A ((14 - $Month) / 12); :local B ($Year - $A); :local C ($Month + 12 * $A - 2); From e7927e0eee62ea331e97c3e572b12a594eca14fd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 May 2023 18:10:02 +0200 Subject: [PATCH 1468/2612] daily-psk: explicitly cast to num --- daily-psk.capsman.rsc | 2 +- daily-psk.local.rsc | 2 +- daily-psk.template.rsc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index 65a17d0..2bfb576 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -38,7 +38,7 @@ $WaitFullyConnected; :local Month ($Months->[ :pick $Date 0 3 ]); :local Day [ :tonum [ :pick $Date 4 6 ] ]; - :local Year [ :pick $Date 7 11 ]; + :local Year [ :tonum [ :pick $Date 7 11 ] ]; :local A ((14 - $Month) / 12); :local B ($Year - $A); diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 94991a7..5f4382f 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -38,7 +38,7 @@ $WaitFullyConnected; :local Month ($Months->[ :pick $Date 0 3 ]); :local Day [ :tonum [ :pick $Date 4 6 ] ]; - :local Year [ :pick $Date 7 11 ]; + :local Year [ :tonum [ :pick $Date 7 11 ] ]; :local A ((14 - $Month) / 12); :local B ($Year - $A); diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index e2a3d59..7dd5c7e 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -39,7 +39,7 @@ $WaitFullyConnected; :local Month ($Months->[ :pick $Date 0 3 ]); :local Day [ :tonum [ :pick $Date 4 6 ] ]; - :local Year [ :pick $Date 7 11 ]; + :local Year [ :tonum [ :pick $Date 7 11 ] ]; :local A ((14 - $Month) / 12); :local B ($Year - $A); From bafd71344d2d2c1523b0f3a34ac238a59fb46d27 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 May 2023 13:44:11 +0200 Subject: [PATCH 1469/2612] global-functions: introduce $ParseDate The extra indention is intended for a later change. --- global-functions.rsc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 4ec5857..fa8b767 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -45,6 +45,7 @@ :global LogPrintExit2; :global MkDir; :global NotificationFunctions; +:global ParseDate; :global ParseKeyValueStore; :global PrettyPrint; :global RandomDelay; @@ -682,6 +683,18 @@ :set NotificationFunctions ({}); } +# parse the date and return a named array +:set ParseDate do={ + :local Date [ :tostr $1 ]; + + :local Months { "jan"=1; "feb"=2; "mar"=3; "apr"=4; "may"=5; "jun"=6; + "jul"=7; "aug"=8; "sep"=9; "oct"=10; "nov"=11; "dec"=12 }; + + :return ({ "year"=[ :tonum [ :pick $Date 7 11 ] ]; + "month"=($Months->[ :pick $Date 0 3 ]); + "day"=[ :tonum [ :pick $Date 4 6 ] ] }); +} + # parse key value store :set ParseKeyValueStore do={ :local Source $1; From 60f863871ca4ebe450011bdd0e6998eab6820fcd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 May 2023 14:42:48 +0200 Subject: [PATCH 1470/2612] global-functions: $ParseDate: handle date in ISO standard format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was introduced with RouterOS 7.10beta5... https://xkcd.com/1179/ 😜 --- global-functions.rsc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index fa8b767..c2c01ea 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -687,12 +687,18 @@ :set ParseDate do={ :local Date [ :tostr $1 ]; + :if ([ :pick $Date 4 5 ] != "-") do={ :local Months { "jan"=1; "feb"=2; "mar"=3; "apr"=4; "may"=5; "jun"=6; "jul"=7; "aug"=8; "sep"=9; "oct"=10; "nov"=11; "dec"=12 }; :return ({ "year"=[ :tonum [ :pick $Date 7 11 ] ]; "month"=($Months->[ :pick $Date 0 3 ]); "day"=[ :tonum [ :pick $Date 4 6 ] ] }); + } + + :return ({ "year"=[ :tonum [ :pick $Date 0 4 ] ]; + "month"=[ :tonum [ :pick $Date 5 7 ] ]; + "day"=[ :tonum [ :pick $Date 8 10 ] ] }); } # parse key value store From 9069f71ee6168a651fd42f90b7aea309fefa260b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 May 2023 13:48:46 +0200 Subject: [PATCH 1471/2612] daily-psk: use $ParseDate --- daily-psk.capsman.rsc | 19 ++++++++----------- daily-psk.local.rsc | 19 ++++++++----------- daily-psk.template.rsc | 19 ++++++++----------- 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index 2bfb576..a24d761 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -33,21 +33,18 @@ $WaitFullyConnected; :global DailyPskSecrets; - :local Months { "jan"=1; "feb"=2; "mar"=3; "apr"=4; "may"=5; "jun"=6; - "jul"=7; "aug"=8; "sep"=9; "oct"=10; "nov"=11; "dec"=12 }; + :global ParseDate; - :local Month ($Months->[ :pick $Date 0 3 ]); - :local Day [ :tonum [ :pick $Date 4 6 ] ]; - :local Year [ :tonum [ :pick $Date 7 11 ] ]; + :set Date [ $ParseDate $Date ]; - :local A ((14 - $Month) / 12); - :local B ($Year - $A); - :local C ($Month + 12 * $A - 2); - :local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); + :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->($Day - 1)) . \ - ($DailyPskSecrets->1->($Month - 1)) . \ + :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ + ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ ($DailyPskSecrets->2->$WeekDay)); } diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 5f4382f..5e6e30f 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -33,21 +33,18 @@ $WaitFullyConnected; :global DailyPskSecrets; - :local Months { "jan"=1; "feb"=2; "mar"=3; "apr"=4; "may"=5; "jun"=6; - "jul"=7; "aug"=8; "sep"=9; "oct"=10; "nov"=11; "dec"=12 }; + :global ParseDate; - :local Month ($Months->[ :pick $Date 0 3 ]); - :local Day [ :tonum [ :pick $Date 4 6 ] ]; - :local Year [ :tonum [ :pick $Date 7 11 ] ]; + :set Date [ $ParseDate $Date ]; - :local A ((14 - $Month) / 12); - :local B ($Year - $A); - :local C ($Month + 12 * $A - 2); - :local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); + :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->($Day - 1)) . \ - ($DailyPskSecrets->1->($Month - 1)) . \ + :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ + ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ ($DailyPskSecrets->2->$WeekDay)); } diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 7dd5c7e..966a407 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -34,21 +34,18 @@ $WaitFullyConnected; :global DailyPskSecrets; - :local Months { "jan"=1; "feb"=2; "mar"=3; "apr"=4; "may"=5; "jun"=6; - "jul"=7; "aug"=8; "sep"=9; "oct"=10; "nov"=11; "dec"=12 }; + :global ParseDate; - :local Month ($Months->[ :pick $Date 0 3 ]); - :local Day [ :tonum [ :pick $Date 4 6 ] ]; - :local Year [ :tonum [ :pick $Date 7 11 ] ]; + :set Date [ $ParseDate $Date ]; - :local A ((14 - $Month) / 12); - :local B ($Year - $A); - :local C ($Month + 12 * $A - 2); - :local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); + :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->($Day - 1)) . \ - ($DailyPskSecrets->1->($Month - 1)) . \ + :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ + ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ ($DailyPskSecrets->2->$WeekDay)); } From 4254b01a32a965a1850c6dc5c669dca34a64a297 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 15 May 2023 21:43:18 +0200 Subject: [PATCH 1472/2612] mod/notification-telegram: fix copy-and-paste error --- mod/notification-telegram.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index e59dbb2..0ab1aa0 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -37,7 +37,7 @@ ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ http-data=("chat_id=" . ($Message->"chatid") . \ "&disable_notification=" . ($Message->"silent") . \ - "&reply_to_message_id=" . ($Notification->"replyto") . \ + "&reply_to_message_id=" . ($Message->"replyto") . \ "&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \ "&text=" . ($Message->"text")) as-value; :set ($TelegramQueue->$Id); From 8284035ad8e945f70859c3a9a270058546d11cb6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 22 May 2023 09:51:23 +0200 Subject: [PATCH 1473/2612] doc/mod/notification-email: describe how to declare functions... ... to use them in own scripts. --- doc/mod/notification-email.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/mod/notification-email.md b/doc/mod/notification-email.md index 61798e6..2186777 100644 --- a/doc/mod/notification-email.md +++ b/doc/mod/notification-email.md @@ -44,8 +44,8 @@ Usage and invocation There's nothing special to do. Every script or function sending a notification will now send it to your e-mail account. -But of course you can send notifications directly or use a function in your -own scripts. Give it a try: +But of course you can use the function to send notifications directly. Give +it a try: $SendEMail "Subject..." "Body..." @@ -54,6 +54,12 @@ methods: $SendNotification "Subject..." "Body..." +To use the functions in your own scripts you have to declare them first. +Place this before you call them: + + :global SendEMail; + :global SendNotification; + See also -------- From c0aeee3d3eb4abc006a3cfd4f57da7ab9f290e03 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 22 May 2023 09:52:18 +0200 Subject: [PATCH 1474/2612] doc/mod/notification-matrix: describe how to declare functions... ... to use them in own scripts. --- doc/mod/notification-matrix.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index 6bb04b6..639fa98 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -90,8 +90,8 @@ Usage and invocation There's nothing special to do. Every script or function sending a notification will now send it to your Matrix account. -But of course you can send notifications directly or use a function in your -own scripts. Give it a try: +But of course you can use the function to send notifications directly. Give +it a try: $SendMatrix "Subject..." "Body..." @@ -100,6 +100,12 @@ methods: $SendNotification "Subject..." "Body..." +To use the functions in your own scripts you have to declare them first. +Place this before you call them: + + :global SendMatrix; + :global SendNotification; + See also -------- From e9b7c7f7ed540e88006c626c205d9c60c50c1677 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 22 May 2023 09:52:34 +0200 Subject: [PATCH 1475/2612] doc/mod/notification-telegram: describe how to declare functions... ... to use them in own scripts. --- doc/mod/notification-telegram.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index 5e6c1a0..7141fe9 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -53,8 +53,8 @@ Usage and invocation There's nothing special to do. Every script or function sending a notification will now send it to your Telegram account. -But of course you can send notifications directly or use a function in your -own scripts. Give it a try: +But of course you can use the function to send notifications directly. Give +it a try: $SendTelegram "Subject..." "Body..." @@ -63,6 +63,12 @@ methods: $SendNotification "Subject..." "Body..." +To use the functions in your own scripts you have to declare them first. +Place this before you call them: + + :global SendTelegram; + :global SendNotification; + See also -------- From c2e7567c13bba80190ad5c2dd7c6ad7b025619e3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 May 2023 11:25:43 +0200 Subject: [PATCH 1476/2612] logo: rename SVG ids --- logo.svg | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/logo.svg b/logo.svg index 4812897..a30e04e 100644 --- a/logo.svg +++ b/logo.svg @@ -1,14 +1,14 @@ - - + + - - + + - - + + From 5ae3cb336fa80d8d5fe141d59a85148f8c4823df Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 May 2023 11:47:06 +0200 Subject: [PATCH 1477/2612] add a logo color changer Generate a colored logo for your notifications! --- contrib/logo-color.d/script.js | 5 +++++ contrib/logo-color.d/style.css | 5 +++++ contrib/logo-color.html | 27 +++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 contrib/logo-color.d/script.js create mode 100644 contrib/logo-color.d/style.css create mode 100644 contrib/logo-color.html diff --git a/contrib/logo-color.d/script.js b/contrib/logo-color.d/script.js new file mode 100644 index 0000000..ac89905 --- /dev/null +++ b/contrib/logo-color.d/script.js @@ -0,0 +1,5 @@ +function color() { + var svg = document.querySelector(".logo").getSVGDocument(); + svg.getElementById("dark-1").setAttribute("stop-color", document.getElementById("color1").value); + svg.getElementById("dark-2").setAttribute("stop-color", document.getElementById("color2").value); +} diff --git a/contrib/logo-color.d/style.css b/contrib/logo-color.d/style.css new file mode 100644 index 0000000..f0e3f49 --- /dev/null +++ b/contrib/logo-color.d/style.css @@ -0,0 +1,5 @@ +body { + font-family: fira-sans, sans; + font-size: 10pt; + background-color: transparent; +} diff --git a/contrib/logo-color.html b/contrib/logo-color.html new file mode 100644 index 0000000..2864fcb --- /dev/null +++ b/contrib/logo-color.html @@ -0,0 +1,27 @@ + + + + +RouterOS-Scripts Logo Color Changer + + + + + +

    RouterOS-Scripts Logo Color Changer

    + +

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

    + + + +

    Select the colors here: + +

    + +

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

    + + + From 6327348405a6fa4dec5c9df5b2cee3cc340a5a6d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 May 2023 22:40:54 +0200 Subject: [PATCH 1478/2612] check-certificates: split validity output --- check-certificates.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 7e9fbe2..a3b0a8f 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -92,7 +92,9 @@ [ $FormatLine "Private key" [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] ] . "\n" . \ [ $FormatLine "Fingerprint" ($CertVal->"fingerprint") ] . "\n" . \ [ $FormatLine "Issuer" ($CertVal->"ca" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN")) ] . "\n" . \ - [ $FormatLine "Validity" ($CertVal->"invalid-before" . " to " . $CertVal->"invalid-after") ] . "\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") ] ] ]); } From 44e483ecb7cf4cf812044f791fd11e383ee2e02d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 May 2023 09:06:02 +0200 Subject: [PATCH 1479/2612] contrib/logo-color: scale up... ... to make BotFather happy, why asks for images with at least 150x150 pixels. --- contrib/logo-color.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/logo-color.html b/contrib/logo-color.html index 2864fcb..5e74549 100644 --- a/contrib/logo-color.html +++ b/contrib/logo-color.html @@ -14,7 +14,7 @@ Telegram Group and want something that differentiates? Color it!

    - +

    Select the colors here: From 871f30ad8eba795c685b42bc7354b908040d1331 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 May 2023 09:08:43 +0200 Subject: [PATCH 1480/2612] contrib/logo-color: fix the font family --- contrib/logo-color.d/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/logo-color.d/style.css b/contrib/logo-color.d/style.css index f0e3f49..eb2ec6a 100644 --- a/contrib/logo-color.d/style.css +++ b/contrib/logo-color.d/style.css @@ -1,5 +1,5 @@ body { - font-family: fira-sans, sans; + font-family: fira-sans, sans-serif; font-size: 10pt; background-color: transparent; } From 5b869d51911d5a42a7a5d903953ebd30c1cd368e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 May 2023 09:09:15 +0200 Subject: [PATCH 1481/2612] contrib/notification: fix the font families --- contrib/notification.d/style.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/notification.d/style.css b/contrib/notification.d/style.css index f4b34df..f9c3404 100644 --- a/contrib/notification.d/style.css +++ b/contrib/notification.d/style.css @@ -1,5 +1,5 @@ body { - font-family: fira-sans, sans; + font-family: fira-sans, sans-serif; font-size: 10pt; background-color: transparent; } @@ -28,13 +28,13 @@ p.hint { display: none; } pre { - font-family: fira-mono, mono; + font-family: fira-mono, monospace; white-space: pre-wrap; } span.link { color: #863600; } span.tag { - font-family: monospace; + font-family: fira-mono, monospace; background-color: #e6e6e6; } From ccb0e468b4fae9a8aeddda04b81556b8debbf796 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 May 2023 09:40:11 +0200 Subject: [PATCH 1482/2612] contrib/logo-color: add screenshots from browser --- contrib/logo-color.d/browser-01.avif | Bin 0 -> 42058 bytes contrib/logo-color.d/browser-02.avif | Bin 0 -> 29025 bytes contrib/logo-color.d/browser-03.avif | Bin 0 -> 26034 bytes contrib/logo-color.html | 8 ++++++++ 4 files changed, 8 insertions(+) create mode 100644 contrib/logo-color.d/browser-01.avif create mode 100644 contrib/logo-color.d/browser-02.avif create mode 100644 contrib/logo-color.d/browser-03.avif diff --git a/contrib/logo-color.d/browser-01.avif b/contrib/logo-color.d/browser-01.avif new file mode 100644 index 0000000000000000000000000000000000000000..3dc0a1f90dfa11da1abb0586d042b5bcf02d61d3 GIT binary patch literal 42058 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 Q4WxnIKy=S%D8}L1*glp8KmY&$ literal 0 HcmV?d00001 diff --git a/contrib/logo-color.d/browser-02.avif b/contrib/logo-color.d/browser-02.avif new file mode 100644 index 0000000000000000000000000000000000000000..1867fbe3c876fe63aeb7404e98ff85c2631f7784 GIT binary patch literal 29025 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%0DyyEM$D&!T2Se(iRa1 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 literal 0 HcmV?d00001 diff --git a/contrib/logo-color.d/browser-03.avif b/contrib/logo-color.d/browser-03.avif new file mode 100644 index 0000000000000000000000000000000000000000..dc24bbbc7aa2623f396a914a8f2982ea12ce7bd0 GIT binary patch literal 26034 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 X8tE6LwK+csQ3S#qKmHdNM$X00i_C16 literal 0 HcmV?d00001 diff --git a/contrib/logo-color.html b/contrib/logo-color.html index 5e74549..b74615b 100644 --- a/contrib/logo-color.html +++ b/contrib/logo-color.html @@ -23,5 +23,13 @@ something that differentiates? Color it!

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

    +

    Screenshot Browser 01 +Screenshot Browser 02 +Screenshot Browser 03

    + +

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

    + From 80198dcfb52b050618547d85aeef55dc1a15a375 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 May 2023 10:21:24 +0200 Subject: [PATCH 1483/2612] doc/mod/notification-telegram: show how to set bot's profile photo --- doc/mod/notification-telegram.d/setuserpic.avif | Bin 0 -> 38522 bytes doc/mod/notification-telegram.md | 14 ++++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 doc/mod/notification-telegram.d/setuserpic.avif diff --git a/doc/mod/notification-telegram.d/setuserpic.avif b/doc/mod/notification-telegram.d/setuserpic.avif new file mode 100644 index 0000000000000000000000000000000000000000..2017d20dfa9530c87f885a4efc3a33ca78899abb GIT binary patch literal 38522 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 Date: Thu, 25 May 2023 10:26:14 +0200 Subject: [PATCH 1484/2612] contrib/logo-color: link to doc/mod/notification-telegram --- contrib/logo-color.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/logo-color.html b/contrib/logo-color.html index b74615b..2d812d1 100644 --- a/contrib/logo-color.html +++ b/contrib/logo-color.html @@ -31,5 +31,9 @@ logo and download it.

    Firefox. The workflow for other browsers may differ.)

    +

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

    + From 51a7453e6c8acd17b9cbdac7fda278d915501197 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 May 2023 10:07:37 +0200 Subject: [PATCH 1485/2612] contrib/notification: update the screenshot procedure --- contrib/notification.d/style.css | 4 ---- contrib/notification.html | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/contrib/notification.d/style.css b/contrib/notification.d/style.css index f9c3404..648ea23 100644 --- a/contrib/notification.d/style.css +++ b/contrib/notification.d/style.css @@ -34,7 +34,3 @@ pre { span.link { color: #863600; } -span.tag { - font-family: fira-mono, monospace; - background-color: #e6e6e6; -} diff --git a/contrib/notification.html b/contrib/notification.html index f483ab0..7875036 100644 --- a/contrib/notification.html +++ b/contrib/notification.html @@ -28,7 +28,8 @@

    Queued since

    Cut-off with percent

    -

    â„šī¸ Open the inspector, select the div element, right click and select "Screenshot Node"!

    +

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

    From 8dc047510824654cd236357b2eaedd21c06e96d1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 May 2023 11:55:08 +0200 Subject: [PATCH 1486/2612] contrib/logo-color: support settings the background --- contrib/logo-color.d/script.js | 7 +++++++ contrib/logo-color.html | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/contrib/logo-color.d/script.js b/contrib/logo-color.d/script.js index ac89905..82cc204 100644 --- a/contrib/logo-color.d/script.js +++ b/contrib/logo-color.d/script.js @@ -1,5 +1,12 @@ +function invertHex(hex) { + return (Number("0x1" + hex) ^ 0xffffff).toString(16).substr(1); +} + function color() { var svg = document.querySelector(".logo").getSVGDocument(); svg.getElementById("dark-1").setAttribute("stop-color", document.getElementById("color1").value); svg.getElementById("dark-2").setAttribute("stop-color", document.getElementById("color2").value); + var background = document.getElementById("color3").value; + svg.getElementById("background").setAttribute("fill", background); + svg.getElementById("hexagon").setAttribute("stroke", "#" + invertHex(background.substring(1))); } diff --git a/contrib/logo-color.html b/contrib/logo-color.html index 2d812d1..17942ce 100644 --- a/contrib/logo-color.html +++ b/contrib/logo-color.html @@ -18,7 +18,8 @@ something that differentiates? Color it!

    Select the colors here: -

    + +

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

    From 1568df3b4f16837427dc2b6018347f35caf55100 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 May 2023 11:41:12 +0200 Subject: [PATCH 1487/2612] global-config: end all (array) variables with a semicolon --- global-config.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/global-config.rsc b/global-config.rsc index 6f2beed..b17d25c 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -114,7 +114,7 @@ cpu-temperature=70; board-temperature1=50; board-temperature2=50; -} +}; # This is deviation on recovery threshold against notification flooding. :global CheckHealthTemperatureDeviation 3; :global CheckHealthVoltageLow 115; @@ -137,7 +137,7 @@ "Staking"; "Thundering"; "Ultra"; "Unreal" }; { "Belief"; "Button"; "Curtain"; "Edge"; "Jewel"; "String"; "Whistle" } -} +}; # Specify how to assemble DNS names in ipsec-to-dns. :global HostNameInZone true; @@ -206,12 +206,12 @@ :global CertRenewPass { "v3ry-s3cr3t"; "4n0th3r-s3cr3t"; -} +}; :global CertWarnTime 2w; :global CertIssuedExportPass { "cert1-cn"="v3ry-s3cr3t"; "cert2-cn"="4n0th3r-s3cr3t"; -} +}; # load custom settings from overlay # Warning: Do *NOT* copy this code to overlay! From f416b0e59dfebdd852bd7fba782eb9de54044ea6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 May 2023 15:11:26 +0200 Subject: [PATCH 1488/2612] netwatch-notify: ignore status 'unknown' --- netwatch-notify.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 3f47304..910fb73 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -62,7 +62,7 @@ $ScriptLock $0; :set NetwatchNotify ({}); } -:foreach Host in=[ /tool/netwatch/find where comment~"notify" !disabled ] do={ +:foreach Host in=[ /tool/netwatch/find where comment~"notify" !disabled status!="unknown" ] do={ :local HostVal [ /tool/netwatch/get $Host ]; :local Type [ $IfThenElse ($HostVal->"type" ~ "^(https?-get|tcp-conn)\$") "service" "host" ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; From 007d1ff7b8dbe78d39216ef501ddcb8a76e372bc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 May 2023 15:12:14 +0200 Subject: [PATCH 1489/2612] netwatch-dns: handle status 'up' only --- netwatch-dns.rsc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 4eb3285..eb6cb6c 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -26,11 +26,11 @@ $ScriptLock $0; :local DnsFallback ({}); :local DnsCurrent [ /ip/dns/get servers ]; -:foreach Host in=[ /tool/netwatch/find where comment~"dns" !disabled ] do={ +:foreach Host in=[ /tool/netwatch/find where comment~"dns" status="up" ] do={ :local HostVal [ /tool/netwatch/get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; - :if ($HostVal->"status" = "up" && $HostInfo->"disabled" != true) do={ + :if ($HostInfo->"disabled" != true) do={ :if ($HostInfo->"dns" = true) do={ :set DnsServers ($DnsServers, $HostVal->"host"); } @@ -61,12 +61,11 @@ $ScriptLock $0; :local DohCurrent [ /ip/dns/get use-doh-server ]; :local DohCert ""; -:foreach Host in=[ /tool/netwatch/find where comment~"doh" !disabled ] do={ +:foreach Host in=[ /tool/netwatch/find where comment~"doh" status="up" ] do={ :local HostVal [ /tool/netwatch/get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; - :if ($HostVal->"status" = "up" && $HostInfo->"doh" = true && \ - $HostInfo->"disabled" != true && $DohServer = "") do={ + :if ($HostInfo->"doh" = true && $HostInfo->"disabled" != true && $DohServer = "") do={ :set DohServer [ $EitherOr ($HostInfo->"doh-url") \ ("https://" . $HostVal->"host" . "/dns-query") ]; :set DohCert ($HostInfo->"doh-cert"); From 42c658e1d4072837936db09bdd0ca7ff563d9a6a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 1 Jun 2023 09:23:22 +0200 Subject: [PATCH 1490/2612] netwatch-dns: reorder variables --- netwatch-dns.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index eb6cb6c..c1d57b8 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -58,8 +58,8 @@ $ScriptLock $0; } :local DohServer ""; -:local DohCurrent [ /ip/dns/get use-doh-server ]; :local DohCert ""; +:local DohCurrent [ /ip/dns/get use-doh-server ]; :foreach Host in=[ /tool/netwatch/find where comment~"doh" status="up" ] do={ :local HostVal [ /tool/netwatch/get $Host ]; From cfeddde17372fbc574ca367644875549749332f3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 May 2023 15:58:54 +0200 Subject: [PATCH 1491/2612] doc/check-routeros-update: hint on schedule at startup --- doc/check-routeros-update.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 8e158e1..fefac5e 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -77,6 +77,14 @@ If an update is found you can install it right away. Installing script [packages-update](packages-update.md) gives extra options. +Tips & Tricks +------------- + +The script checks for full connectivity before acting, so scheduling at +startup is perfectly valid: + + /system/scheduler/add name=check-routeros-update@startup on-event="/system/script/run check-routeros-update;" start-time=startup; + See also -------- From 95181fbef97658acd3b3eaca8753eef716349011 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 May 2023 15:58:21 +0200 Subject: [PATCH 1492/2612] doc/check-certificates: move and rename schedule at startup --- doc/check-certificates.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/check-certificates.md b/doc/check-certificates.md index f295117..52f5e51 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -54,9 +54,14 @@ Just run the script: /system/scheduler/add interval=1d name=check-certificates on-event="/system/script/run check-certificates;" start-time=startup; -Alternatively running on startup may be desired: - /system/scheduler/add name=check-certificates-startup on-event="/system/script/run check-certificates;" start-time=startup; +Tips & Tricks +------------- + +The script checks for full connectivity before acting, so scheduling at +startup is perfectly valid: + + /system/scheduler/add name=check-certificates@startup on-event="/system/script/run check-certificates;" start-time=startup; See also -------- From de8c534d41dbb6dd46e8a6b89d53cf4b34f3953d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 May 2023 15:59:07 +0200 Subject: [PATCH 1493/2612] doc/daily-psk: rename schedulers... ... to match other scripts. --- doc/daily-psk.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 0552f0d..1510ab3 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -28,14 +28,14 @@ and add schedulers to run the script: For CAPsMAN: $ScriptInstallUpdate daily-psk.capsman; - /system/scheduler/add interval=1d name=daily-psk-nightly on-event="/system/script/run daily-psk.capsman;" start-time=03:00:00; - /system/scheduler/add name=daily-psk-startup on-event="/system/script/run daily-psk.capsman;" start-time=startup; + /system/scheduler/add interval=1d name=daily-psk on-event="/system/script/run daily-psk.capsman;" start-time=03:00:00; + /system/scheduler/add name=daily-psk@startup on-event="/system/script/run daily-psk.capsman;" start-time=startup; For local interface: $ScriptInstallUpdate daily-psk.local; - /system/scheduler/add interval=1d name=daily-psk-nightly on-event="/system/script/run daily-psk.local;" start-time=03:00:00; - /system/scheduler/add name=daily-psk-startup on-event="/system/script/run daily-psk.local;" start-time=startup; + /system/scheduler/add interval=1d name=daily-psk on-event="/system/script/run daily-psk.local;" start-time=03:00:00; + /system/scheduler/add name=daily-psk@startup on-event="/system/script/run daily-psk.local;" start-time=startup; These will update the passphrase on boot and nightly at 3:00. From 0b8979e5b53896e4f788fdaa771c853520a11f8c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 May 2023 23:55:12 +0200 Subject: [PATCH 1494/2612] global-functions: $ScriptInstallUpdate: handle scripts with DOS line endings If the script is converted to DOS line endings (\r\n) on the device it was no longer handled by $ScriptInstallUpdate. Let's change that... --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index c2c01ea..833a595 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -832,7 +832,7 @@ :local ReloadGlobalConfig false; :local UserAgent ("User-Agent: Mikrotik/" . [ /system/resource/get version ] . " Fetch"); - :foreach Script in=[ /system/script/find where source~"^#!rsc by RouterOS\n" ] do={ + :foreach Script in=[ /system/script/find where source~"^#!rsc by RouterOS\r?\n" ] do={ :local ScriptVal [ /system/script/get $Script ]; :local ScriptFile [ /file/find where name=("script-updates/" . $ScriptVal->"name") . ".rsc" ]; :local SourceNew; From d2883e6f436b6e70cabbbbad9a8399002f444afe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 1 Jun 2023 21:57:05 +0200 Subject: [PATCH 1495/2612] global-functions: $CertificateDownload: add a delay For any reason the imported certificate(s) is/are not available for fetch command immediately. Let's add a delay here... It should not hurt as certificates are not imported that often. --- global-functions.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/global-functions.rsc b/global-functions.rsc index 833a595..d15567d 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -137,6 +137,7 @@ "CommonName \"" . $CommonName . "\"!") false; :return false; } + :delay 1s; :return true; } From 0b04f173c8c8e1616fa1494cf080b857470bcd5b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 6 Jun 2023 22:51:53 +0200 Subject: [PATCH 1496/2612] check-lte-firmware-upgrade: update formatting of notification --- check-lte-firmware-upgrade.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index 81bdf9b..92ebe51 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -73,8 +73,9 @@ message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \ "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ [ $FormatLine "Interface" [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] ] . "\n" . \ - [ $FormatLine "Installed" ($Firmware->"installed") ] . "\n" . \ - [ $FormatLine "Available" ($Firmware->"latest") ]); silent=true }); + "Firmware version:\n" . \ + [ $FormatLine " Installed" ($Firmware->"installed") ] . "\n" . \ + [ $FormatLine " Available" ($Firmware->"latest") ]); silent=true }); :set ($SentLteFirmwareUpgradeNotification->$IntName) ($Firmware->"latest"); } From 9bfa303038e0ad75f819494f46d8378a7c1954ca Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Jun 2023 21:33:49 +0200 Subject: [PATCH 1497/2612] dhcp-to-dns: use 'active-' properties from lease Turns out that address for static leases can be an address pool. Of course that breaks the script as an ip address is expected. Use 'active-address' instead. Also let's do the same for 'active-mac-address'... Fixes GH-43 --- dhcp-to-dns.rsc | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index b15511e..d6a39e5 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -37,7 +37,7 @@ $ScriptLock $0 false 10; :foreach DnsRecord in=[ /ip/dns/static/find where comment~("^" . $CommentPrefix) (!type or type=A) ] do={ :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; - :if ([ :len [ /ip/dhcp-server/lease/find where mac-address=$MacAddress address=($DnsRecordVal->"address") status=bound ] ] > 0) do={ + :if ([ :len [ /ip/dhcp-server/lease/find where active-mac-address=$MacAddress active-address=($DnsRecordVal->"address") status=bound ] ] > 0) do={ $LogPrintExit2 debug $0 ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; } else={ :local Found false; @@ -51,20 +51,20 @@ $ScriptLock $0 false 10; :local LeaseVal; :do { :set LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local DupMacLeases [ /ip/dhcp-server/lease/find where mac-address=($LeaseVal->"mac-address") status=bound ]; + :local DupMacLeases [ /ip/dhcp-server/lease/find where active-mac-address=($LeaseVal->"active-mac-address") status=bound ]; :if ([ :len $DupMacLeases ] > 1) do={ - $LogPrintExit2 debug $0 ("Multiple bound leases found for mac-address " . ($LeaseVal->"mac-address") . ", using last one.") false; + $LogPrintExit2 debug $0 ("Multiple bound leases found for mac-address " . ($LeaseVal->"active-mac-address") . ", using last one.") false; :set LeaseVal [ /ip/dhcp-server/lease/get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) ]; } } on-error={ $LogPrintExit2 debug $0 ("A lease just vanished, ignoring.") false; } - :if ([ :len ($LeaseVal->"address") ] > 0) do={ - :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); - :local MacDash [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ]; + :if ([ :len ($LeaseVal->"active-address") ] > 0) do={ + :local Comment ($CommentPrefix . $LeaseVal->"active-mac-address"); + :local MacDash [ $CharacterReplace ($LeaseVal->"active-mac-address") ":" "-" ]; :local HostName [ $CharacterReplace [ $EitherOr ([ $ParseKeyValueStore ($LeaseVal->"comment") ]->"hostname") ($LeaseVal->"host-name") ] " " "" ]; - :local Network [ /ip/dhcp-server/network/find where ($LeaseVal->"address") in address ]; + :local Network [ /ip/dhcp-server/network/find where ($LeaseVal->"active-address") in address ]; :local NetworkVal; :if ([ :len $Network ] > 0) do={ :set NetworkVal [ /ip/dhcp-server/network/get ($Network->0) ]; @@ -77,11 +77,11 @@ $ScriptLock $0 false 10; :if ([ :len $DnsRecord ] > 0) do={ :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; - :if ($DnsRecordVal->"address" = $LeaseVal->"address" && $DnsRecordVal->"name" = ($MacDash . "." . $NetDomain)) do={ - $LogPrintExit2 debug $0 ("DNS entry for " . $LeaseVal->"mac-address" . " does not need updating.") false; + :if ($DnsRecordVal->"address" = $LeaseVal->"active-address" && $DnsRecordVal->"name" = ($MacDash . "." . $NetDomain)) do={ + $LogPrintExit2 debug $0 ("DNS entry for " . $LeaseVal->"active-mac-address" . " does not need updating.") false; } else={ - $LogPrintExit2 info $0 ("Replacing DNS entry for " . $LeaseVal->"mac-address" . " (" . ($MacDash . "." . $NetDomain) . " -> " . $LeaseVal->"address" . ").") false; - /ip/dns/static/set address=($LeaseVal->"address") name=($MacDash . "." . $NetDomain) $DnsRecord; + $LogPrintExit2 info $0 ("Replacing DNS entry for " . $LeaseVal->"active-mac-address" . " (" . ($MacDash . "." . $NetDomain) . " -> " . $LeaseVal->"active-address" . ").") false; + /ip/dns/static/set address=($LeaseVal->"active-address") name=($MacDash . "." . $NetDomain) $DnsRecord; } :local Cname [ /ip/dns/static/find where comment=$Comment type=CNAME ]; @@ -94,8 +94,8 @@ $ScriptLock $0 false 10; /ip/dns/static/set name=($HostName . "." . $NetDomain) cname=($MacDash . "." . $NetDomain) $Cname; } } else={ - $LogPrintExit2 info $0 ("Adding new DNS entry for " . $LeaseVal->"mac-address" . " (" . ($MacDash . "." . $NetDomain) . " -> " . $LeaseVal->"address" . ").") false; - /ip/dns/static/add name=($MacDash . "." . $NetDomain) type=A address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + $LogPrintExit2 info $0 ("Adding new DNS entry for " . $LeaseVal->"active-mac-address" . " (" . ($MacDash . "." . $NetDomain) . " -> " . $LeaseVal->"active-address" . ").") false; + /ip/dns/static/add name=($MacDash . "." . $NetDomain) type=A address=($LeaseVal->"active-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; :if ([ :len $HostName ] > 0) do={ $LogPrintExit2 info $0 ("Adding new CNAME (" . ($HostName . "." . $NetDomain) . " -> " . ($MacDash . "." . $NetDomain) . ").") false; /ip/dns/static/add name=($HostName . "." . $NetDomain) type=CNAME cname=($MacDash . "." . $NetDomain) ttl=$Ttl comment=$Comment place-before=$PlaceBefore; From 2593f6ba30bdd50272a7d5dad4f2e078c9d1bd6a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Jun 2023 21:57:26 +0200 Subject: [PATCH 1498/2612] dhcp-lease-comment: use 'active-' properties from lease --- dhcp-lease-comment.capsman.rsc | 4 ++-- dhcp-lease-comment.local.rsc | 4 ++-- dhcp-lease-comment.template.rsc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc index 55b76bf..d3b2dc5 100644 --- a/dhcp-lease-comment.capsman.rsc +++ b/dhcp-lease-comment.capsman.rsc @@ -19,12 +19,12 @@ :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; :local NewComment; - :local AccessList ([ /caps-man/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0); + :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->"mac-address" . ": " . $NewComment) false; + $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc index 3f4d6c5..0d1b2c0 100644 --- a/dhcp-lease-comment.local.rsc +++ b/dhcp-lease-comment.local.rsc @@ -19,12 +19,12 @@ :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; :local NewComment; - :local AccessList ([ /interface/wireless/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0); + :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->"mac-address" . ": " . $NewComment) false; + $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index 9de5f97..28581f4 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -20,12 +20,12 @@ :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; :local NewComment; - :local AccessList ([ /%PATH%/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0); + :local AccessList ([ /%PATH%/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ :set NewComment [ /%PATH%/access-list/get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; + $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } From 964ec39a68310a2ccd4c097dd486182f933ba8c8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Jun 2023 21:58:06 +0200 Subject: [PATCH 1499/2612] collect-wireless-mac: use 'active-' properties from lease --- collect-wireless-mac.capsman.rsc | 4 ++-- collect-wireless-mac.local.rsc | 4 ++-- collect-wireless-mac.template.rsc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index 094ffc0..c6cae9c 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -51,9 +51,9 @@ $ScriptLock $0 false 10; :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); + :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 address ]; + :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); diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index 23eb9fa..fa8fe8d 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -51,9 +51,9 @@ $ScriptLock $0 false 10; :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); + :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 address ]; + :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); diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index a8983d9..6f9efc5 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -52,9 +52,9 @@ $ScriptLock $0 false 10; :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); + :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 address ]; + :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); From 5f28e928a1748450907bef4adbd686a42ea6838d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:11:06 +0200 Subject: [PATCH 1500/2612] doc/backup-cloud: hint to copy from global-config --- doc/backup-cloud.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index 511fad3..b612fc4 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -36,6 +36,10 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupPassword`: password to encrypt the backup with * `BackupRandomDelay`: delay up to amount of seconds when run from scheduler +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + Also notification settings are required for [e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or From 083fa82b13ac955f12fdfe05cd2817777e4c6ad9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:11:15 +0200 Subject: [PATCH 1501/2612] doc/backup-email: hint to copy from global-config --- doc/backup-email.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/backup-email.md b/doc/backup-email.md index a8ec760..67564e7 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -33,6 +33,10 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupPassword`: password to encrypt the backup with * `BackupRandomDelay`: delay up to amount of seconds when run from scheduler +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + Usage and invocation -------------------- From a65ea3fc2675dc5f4376709d51b26a625edbe5f0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:11:25 +0200 Subject: [PATCH 1502/2612] doc/backup-upload: hint to copy from global-config --- doc/backup-upload.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/backup-upload.md b/doc/backup-upload.md index f2bf4de..f9aaa29 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -42,6 +42,10 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupUploadUser`: username for server authentication * `BackupUploadPass`: password for server authentication +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + Also notification settings are required for [e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or From e96b2e485344d3447367a31400de0dd856759861 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:11:40 +0200 Subject: [PATCH 1503/2612] doc/certificate-renew-issued: hint to copy from global-config --- doc/certificate-renew-issued.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/certificate-renew-issued.md b/doc/certificate-renew-issued.md index 72f7fc5..bb8e18c 100644 --- a/doc/certificate-renew-issued.md +++ b/doc/certificate-renew-issued.md @@ -28,6 +28,10 @@ parameter: * `CertRenewPass`: an array holding individual passphrases for certificates +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + Usage and invocation -------------------- From 2ba93f61ac5616325709855a5337eb8c53dc2a72 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 13:34:50 +0200 Subject: [PATCH 1504/2612] doc/check-certificates: hint to copy from global-config --- doc/check-certificates.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 52f5e51..58151f3 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -34,6 +34,10 @@ in `global-config-overlay`, these are the parameters: * `CertRenewUrl`: the url to download certificates from * `CertWarnTime`: on what remaining time to warn via notification +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + Certificates on the web server should be named by their common name, like `CN.pem` (`PEM` format) or`CN.p12` (`PKCS#12` format). Alternatively any subject alternative name (aka *Subject Alt Name* or *SAN*) can be used. From d4e225f1b70d3f8fd3abb4872e019ffdc3666b3e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:12:01 +0200 Subject: [PATCH 1505/2612] doc/check-health: hint to copy from global-config --- doc/check-health.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/check-health.md b/doc/check-health.md index f0e5c11..3f4c70f 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -74,6 +74,10 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `CheckHealthVoltageLow`: value (in volt*10) giving a hard lower limit * `CheckHealthVoltagePercent`: percentage value to trigger voltage jumps +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + Also notification settings are required for [e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or From dea07a7f0b79bd3d15aee7db8c4bbe423a1bc93f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:12:12 +0200 Subject: [PATCH 1506/2612] doc/check-routeros-update: hint to copy from global-config --- doc/check-routeros-update.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index fefac5e..186fb86 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -58,8 +58,9 @@ The configuration goes to `global-config-overlay`, these are the parameters: (`long-term`, `stable` or `testing`) is appended * `SafeUpdateAll`: install **all** updates automatically -> â„šī¸ **Info**: Installing **all** updates automatically requires extra -> confirmation. See `global-config` for details. +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. Also notification settings are required for [e-mail](mod/notification-email.md), From 87318fddde2cbe4897467c502748bad33d081f69 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:12:36 +0200 Subject: [PATCH 1507/2612] doc/daily-psk: hint to copy from global-config --- doc/daily-psk.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 1510ab3..9a5e558 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -47,6 +47,10 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `DailyPskMatchComment`: pattern to match the wireless access list comment * `DailyPskSecrets`: an array with pseudo random strings +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + Then add an access list entry. For CAPsMAN: /caps-man/access-list/add comment="Daily PSK" ssid-regexp="-guest\$" private-passphrase="ToBeChangedDaily"; From a77e0bf0d5c80a7c85cec0aad26590abb71041e3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:12:46 +0200 Subject: [PATCH 1508/2612] doc/dhcp-to-dns: hint to copy from global-config --- doc/dhcp-to-dns.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 0c443a0..772704e 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -56,6 +56,10 @@ If no domain is found in dhcp server's network definition a fallback from * `Domain`: the domain used for dns records +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + ### Host name from DHCP lease comment Overwriting the host name from dhcp lease comment is supported, just add From 8fa04fec15735ca3edb9ed8e782b0a5109628001 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:12:57 +0200 Subject: [PATCH 1509/2612] doc/gps-track: hint to copy from global-config --- doc/gps-track.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/gps-track.md b/doc/gps-track.md index f5d9901..721b075 100644 --- a/doc/gps-track.md +++ b/doc/gps-track.md @@ -32,6 +32,10 @@ The configuration goes to `global-config-overlay`, the only parameter is: * `GpsTrackUrl`: the url to send json data to +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + The configured coordinate format (see `/system/gps`) defines the format sent to the server. From 4ab1a88a92316fcb759cd0a4fcb97589d4316491 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:13:13 +0200 Subject: [PATCH 1510/2612] doc/ipsec-to-dns: hint to copy from global-config --- doc/ipsec-to-dns.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/ipsec-to-dns.md b/doc/ipsec-to-dns.md index 5825def..04500a3 100644 --- a/doc/ipsec-to-dns.md +++ b/doc/ipsec-to-dns.md @@ -36,6 +36,10 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `HostNameInZone`: whether or not to add the ipsec/dns server's hostname * `PrefixInZone`: whether or not to add prefix `ipsec` +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + See also -------- From 601404a5db29b7d2b25a1e8e8d27f65e909b6d1d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:13:25 +0200 Subject: [PATCH 1511/2612] doc/log-forward: hint to copy from global-config --- doc/log-forward.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/log-forward.md b/doc/log-forward.md index 6faa27e..43ae897 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -54,6 +54,10 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `LogForwardIncludeMessage`: define message text to be forwarded (even if filter matches) +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + These patterns are matched as [regular expressions](https://wiki.mikrotik.com/wiki/Manual:Regular_Expressions). To forward **all** (ignoring severity) log messages with topics `account` From 3fafed250e2895003e50eae6b80a1df0c441dfa9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:13:37 +0200 Subject: [PATCH 1512/2612] doc/mode-button: hint to copy from global-config --- doc/mode-button.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/mode-button.md b/doc/mode-button.md index 50b1722..6374b83 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -54,6 +54,10 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `ModeButton`: an array with defined actions * `ModeButtonLED`: led to give visual feedback +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + Usage and invocation -------------------- From b93126bc469ca8c285e693246015a721d0d78a3a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:13:46 +0200 Subject: [PATCH 1513/2612] doc/sms-action: hint to copy from global-config --- doc/sms-action.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/sms-action.md b/doc/sms-action.md index e72aa11..3391902 100644 --- a/doc/sms-action.md +++ b/doc/sms-action.md @@ -28,6 +28,10 @@ The configuration goes to `global-config-overlay`, this is the only parameter: * `SmsAction`: an array with pre-defined actions +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + Then enable SMS actions: /tool/sms/set allowed-number=+491234567890 receive-enabled=yes secret=s3cr3t; From 5c27024bc65dd47cf8d118bdf990be2e6ad584aa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:13:54 +0200 Subject: [PATCH 1514/2612] doc/sms-forward: hint to copy from global-config --- doc/sms-forward.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index bfab38d..74a08e6 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -44,6 +44,10 @@ The configuration goes to `global-config-overlay`, this is the only parameter: (which is matched against the sending phone number or name) and `command`. For `match` and `allowed-number` regular expressions are supported. +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + Notification settings are required for [e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or From c8497d05c5ae2ec3779000530eb937cd2a785cae Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:14:04 +0200 Subject: [PATCH 1515/2612] doc/telegram-chat: hint to copy from global-config --- doc/telegram-chat.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index c3ef7fc..391042d 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -39,6 +39,10 @@ parameters: * `TelegramChatIdsTrusted`: an array with trusted chat ids or user names * `TelegramChatGroups`: define the groups a device should belong to +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + Usage and invocation -------------------- From a0dc721ea324b9e09ee0c5d57c75b73b17e9e8e9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:15:44 +0200 Subject: [PATCH 1516/2612] doc/mod/scriptrunonce: hint to copy from global-config --- doc/mod/scriptrunonce.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/mod/scriptrunonce.md b/doc/mod/scriptrunonce.md index 20760fb..895c20c 100644 --- a/doc/mod/scriptrunonce.md +++ b/doc/mod/scriptrunonce.md @@ -27,6 +27,10 @@ The optional configuration goes to `global-config-overlay`. * `ScriptRunOnceBaseUrl`: base url, prepended to parameter * `ScriptRunOnceUrlSuffix`: url suffix, appended to parameter +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + If the parameter passed to the function is not a complete URL (starting with protocol `ftp://`, `http://`, `https://` or `sftp://`) the base-url is prepended, and file extension `.rsc` and url-suffix are appended. From 9ac7cf5fc02789f97eb57659dbcdc511cad41c9d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:15:55 +0200 Subject: [PATCH 1517/2612] doc/mod/notification-email: hint to copy from global-config --- doc/mod/notification-email.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/mod/notification-email.md b/doc/mod/notification-email.md index 2186777..e4ceda2 100644 --- a/doc/mod/notification-email.md +++ b/doc/mod/notification-email.md @@ -32,6 +32,10 @@ the ntp client. Then edit `global-config-overlay`, add `EmailGeneralTo` with a valid recipient address. Finally reload the configuration. +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + ### Sending to several recipients Sending notifications to several recipients is possible as well. Add From 9ebebcfa52fdd781ca4b4bcc4bb8e1402ee3d771 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:16:08 +0200 Subject: [PATCH 1518/2612] doc/mod/notification-matrix: hint to copy from global-config --- doc/mod/notification-matrix.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index 639fa98..070ed9f 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -31,6 +31,10 @@ Edit `global-config-overlay`, add `MatrixHomeServer`, `MatrixAccessToken` and `MatrixRoom` - see below on hints how to retrieve this information. Then reload the configuration. +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + ### Home server Matrix user accounts are identified by a unique user id in the form of From 43978692604e00d40202013004ac966e8944471b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 17:21:37 +0200 Subject: [PATCH 1519/2612] global-config-overlay: link 'editing-configuration' in README --- global-config-overlay.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config-overlay.rsc b/global-config-overlay.rsc index a95f9cc..7ed094c 100644 --- a/global-config-overlay.rsc +++ b/global-config-overlay.rsc @@ -3,7 +3,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global configuration, custom overlay -# https://git.eworm.de/cgit/routeros-scripts/about/ +# https://git.eworm.de/cgit/routeros-scripts/about/#editing-configuration # Copy relevant configuration from global-config, paste and modify it here. From 9a1f2deb57d0af76d8118035de91e313dfbe32e1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 14:16:19 +0200 Subject: [PATCH 1520/2612] doc/mod/notification-telegram: hint to copy from global-config --- doc/mod/notification-telegram.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index 482285a..40e6fb1 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -41,6 +41,10 @@ Finally edit `global-config-overlay`, add `TelegramTokenId` with the token from *BotFather* and `TelegramChatId` with your id from *GetIDs Bot*. Then reload the configuration. +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + ### Notifications to a group Sending notifications to a group is possible as well. Add your bot and the From 0b8588e6e812a270ac55bd82870e99a0fee01b07 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Jun 2023 17:12:13 +0200 Subject: [PATCH 1521/2612] global-config-overlay: link global-config --- global-config-overlay.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/global-config-overlay.rsc b/global-config-overlay.rsc index 7ed094c..af4b52c 100644 --- a/global-config-overlay.rsc +++ b/global-config-overlay.rsc @@ -6,6 +6,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/#editing-configuration # Copy relevant configuration from global-config, paste and modify it here. +# https://git.eworm.de/cgit/routeros-scripts/about/global-config.rsc # End of global-config-overlay From 2f399f2a48a063d3164e8b9428bb78b6375e2661 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 11 Jun 2023 22:52:10 +0200 Subject: [PATCH 1522/2612] hotspot-to-wpa: fail on missing context --- hotspot-to-wpa.rsc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hotspot-to-wpa.rsc b/hotspot-to-wpa.rsc index dbce9ff..e2de112 100644 --- a/hotspot-to-wpa.rsc +++ b/hotspot-to-wpa.rsc @@ -16,6 +16,11 @@ :local MacAddress $"mac-address"; :local UserName $username; + +:if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ + $LogPrintExit2 error $0 ("This script is supposed to run from hotspot on login.") true; +} + :local Date [ /system/clock/get date ]; :local UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; From 4aaa144472a1b880398b770b6b529f11e6c9917e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 12 Jun 2023 07:59:34 +0200 Subject: [PATCH 1523/2612] backup-cloud: lock the script --- backup-cloud.rsc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index b6f6025..859892b 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -21,10 +21,12 @@ :global LogPrintExit2; :global RandomDelay; :global ScriptFromTerminal; +:global ScriptLock; :global SendNotification2; :global SymbolForNotification; :global WaitFullyConnected; +$ScriptLock $0; $WaitFullyConnected; :if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ From 229e1169990d68090dd8f4b0dcd83c3f3afd1c46 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 12 Jun 2023 07:59:54 +0200 Subject: [PATCH 1524/2612] backup-email: lock the script --- backup-email.rsc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backup-email.rsc b/backup-email.rsc index e8837a0..5eb4fcc 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -27,6 +27,7 @@ :global MkDir; :global RandomDelay; :global ScriptFromTerminal; +:global ScriptLock; :global SendEMail2; :global SymbolForNotification; :global WaitForFile; @@ -41,6 +42,7 @@ $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; } +$ScriptLock $0; $WaitFullyConnected; :if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ From fa851a78387c4145dfa308fd6c767af71f7b79ca Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 12 Jun 2023 19:02:41 +0200 Subject: [PATCH 1525/2612] backup-partition: lock the script --- backup-partition.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backup-partition.rsc b/backup-partition.rsc index 824cb7e..364101c 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -13,6 +13,9 @@ :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; From 1167347ec099563c3129a844c0d02c806368cf6e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 12 Jun 2023 08:00:06 +0200 Subject: [PATCH 1526/2612] backup-upload: lock the script --- backup-upload.rsc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backup-upload.rsc b/backup-upload.rsc index 9fb35d8..1ec61a5 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -31,6 +31,7 @@ :global MkDir; :global RandomDelay; :global ScriptFromTerminal; +:global ScriptLock; :global SendNotification2; :global SymbolForNotification; :global WaitForFile; @@ -41,6 +42,7 @@ $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; } +$ScriptLock $0; $WaitFullyConnected; :if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ From 4420c79e0c98f05f45abfa7ad8da37ffa6aa6fb2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 08:51:01 +0200 Subject: [PATCH 1527/2612] certificate-renew-issued: lock the script --- certificate-renew-issued.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc index c297b15..2b18a76 100644 --- a/certificate-renew-issued.rsc +++ b/certificate-renew-issued.rsc @@ -14,6 +14,9 @@ :global LogPrintExit2; :global MkDir; +:global ScriptLock; + +$ScriptLock $0; :foreach Cert in=[ /certificate/find where issued expires-after<3w ] do={ :local CertVal [ /certificate/get $Cert ]; From e0714bdfff451c6fc653abbc7007b430d768273a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 12 Jun 2023 08:19:14 +0200 Subject: [PATCH 1528/2612] check-certificates: lock the script --- check-certificates.rsc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/check-certificates.rsc b/check-certificates.rsc index a3b0a8f..db9007a 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -20,6 +20,7 @@ :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; +:global ScriptLock; :global SendNotification2; :global SymbolForNotification; :global UrlEncode; @@ -98,6 +99,7 @@ [ $FormatLine "Expires in" [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ] ]); } +$ScriptLock $0; $WaitFullyConnected; :foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ From d2de9be4394b5a8dc8aa93f262440545a046a90c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 08:56:10 +0200 Subject: [PATCH 1529/2612] check-lte-firmware-upgrade: lock the script --- check-lte-firmware-upgrade.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index 92ebe51..a2aec01 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -12,6 +12,10 @@ :global SentLteFirmwareUpgradeNotification; +:global ScriptLock; + +$ScriptLock $0; + :if ([ :typeof $SentLteFirmwareUpgradeNotification ] != "array") do={ :global SentLteFirmwareUpgradeNotification ({}); } From 40f2953dde0b07b8868d38f1fee0c6a183e3c005 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 08:52:03 +0200 Subject: [PATCH 1530/2612] daily-psk: lock the script --- daily-psk.capsman.rsc | 2 ++ daily-psk.local.rsc | 2 ++ daily-psk.template.rsc | 2 ++ 3 files changed, 6 insertions(+) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index a24d761..0b5e666 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -19,12 +19,14 @@ :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 diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 5e6e30f..df6d962 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -19,12 +19,14 @@ :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 diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 966a407..777f6c0 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -20,12 +20,14 @@ :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 From 497915b4a2ea1fe0ef2f8659b9559f22c0aaa23b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 08:53:49 +0200 Subject: [PATCH 1531/2612] dhcp-lease-comment: lock the script --- dhcp-lease-comment.capsman.rsc | 3 +++ dhcp-lease-comment.local.rsc | 3 +++ dhcp-lease-comment.template.rsc | 3 +++ 3 files changed, 9 insertions(+) diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc index d3b2dc5..89d2c4e 100644 --- a/dhcp-lease-comment.capsman.rsc +++ b/dhcp-lease-comment.capsman.rsc @@ -15,6 +15,9 @@ :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 ]; diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc index 0d1b2c0..11e92cc 100644 --- a/dhcp-lease-comment.local.rsc +++ b/dhcp-lease-comment.local.rsc @@ -15,6 +15,9 @@ :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 ]; diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index 28581f4..be28cfd 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -16,6 +16,9 @@ :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 ]; From 51ebbd46d969d6d025270dcab9a746589e1b613b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 08:54:36 +0200 Subject: [PATCH 1532/2612] firmware-upgrade-reboot: lock the script --- firmware-upgrade-reboot.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc index cc45c38..ec2babc 100644 --- a/firmware-upgrade-reboot.rsc +++ b/firmware-upgrade-reboot.rsc @@ -11,8 +11,11 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global LogPrintExit2; +:global ScriptLock; :global VersionToNum; +$ScriptLock $0; + :local RouterBoard [ /system/routerboard/get ]; :if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ $LogPrintExit2 info $0 ("Current and upgrade firmware match with version " . \ From 4176fd058eecb5553b0bbd6c15577b298b4f4d04 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 08:57:13 +0200 Subject: [PATCH 1533/2612] hotspot-to-wpa: lock the script --- hotspot-to-wpa.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hotspot-to-wpa.rsc b/hotspot-to-wpa.rsc index e2de112..d7aeb65 100644 --- a/hotspot-to-wpa.rsc +++ b/hotspot-to-wpa.rsc @@ -13,6 +13,9 @@ :global EitherOr; :global LogPrintExit2; :global ParseKeyValueStore; +:global ScriptLock; + +$ScriptLock $0; :local MacAddress $"mac-address"; :local UserName $username; From f375b7fbf79660fd2b532c33469d6f2996986179 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 09:00:15 +0200 Subject: [PATCH 1534/2612] gps-track: lock the script --- gps-track.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gps-track.rsc b/gps-track.rsc index d0d1232..c601e04 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -14,6 +14,9 @@ :global Identity; :global LogPrintExit2; +:global ScriptLock; + +$ScriptLock $0; :local CoordinateFormat [ /system/gps/get coordinate-format ]; :local Gps [ /system/gps/monitor once as-value ]; From 878e1f66f263b8bdfe0a86fd8f2accecf5bd8a4d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 09:02:15 +0200 Subject: [PATCH 1535/2612] ipsec-to-dns: lock the script --- ipsec-to-dns.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index a476e74..d961865 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -19,6 +19,9 @@ :global EscapeForRegEx; :global IfThenElse; :global LogPrintExit2; +:global ScriptLock; + +$ScriptLock $0; :local Zone \ ([ $IfThenElse ($PrefixInZone = true) "ipsec." ] . \ From de750f055904f8c95aa2ed889ae6ec8ba9798f97 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 09:03:10 +0200 Subject: [PATCH 1536/2612] ipv6-update: lock the script --- ipv6-update.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ipv6-update.rsc b/ipv6-update.rsc index 2838feb..7e1d34f 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -14,6 +14,9 @@ :global LogPrintExit2; :global ParseKeyValueStore; +:global ScriptLock; + +$ScriptLock $0; :if ([ :typeof $PdPrefix ] = "nothing") do={ $LogPrintExit2 error $0 ("This script is supposed to run from ipv6 dhcp-client.") true; From cc3a017507d9228aad412287819ed428a4f1a922 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 09:04:14 +0200 Subject: [PATCH 1537/2612] ospf-to-leds: lock the script --- ospf-to-leds.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc index 12ec820..2dc8448 100644 --- a/ospf-to-leds.rsc +++ b/ospf-to-leds.rsc @@ -12,6 +12,9 @@ :global LogPrintExit2; :global ParseKeyValueStore; +:global ScriptLock; + +$ScriptLock $0; :foreach Instance in=[ /routing/ospf/instance/find where comment~"^ospf-to-leds," ] do={ :local InstanceVal [ /routing/ospf/instance/get $Instance ]; From 2861610e5a2ace7d1ce1b234db73d75295f7510f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 09:06:11 +0200 Subject: [PATCH 1538/2612] update-gre-address: lock the script --- update-gre-address.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/update-gre-address.rsc b/update-gre-address.rsc index 2958055..e38839c 100644 --- a/update-gre-address.rsc +++ b/update-gre-address.rsc @@ -13,6 +13,9 @@ :global CharacterReplace; :global LogPrintExit2; +:global ScriptLock; + +$ScriptLock $0; /interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; From befa739e11b04a1b9c5ae2a54f1b37fc920f538a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 09:06:25 +0200 Subject: [PATCH 1539/2612] update-tunnelbroker: lock the script --- update-tunnelbroker.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index 84d7430..a1d5e5e 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -16,6 +16,9 @@ :global CertificateAvailable; :global LogPrintExit2; :global ParseKeyValueStore; +:global ScriptLock; + +$ScriptLock $0; :if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; From 679c971ea6b6ffb3a64e48e74526d0f9a3357725 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 09:01:06 +0200 Subject: [PATCH 1540/2612] gps-track: wait to be fully connected --- gps-track.rsc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gps-track.rsc b/gps-track.rsc index c601e04..29d2572 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -15,8 +15,10 @@ :global LogPrintExit2; :global ScriptLock; +:global WaitFullyConnected; $ScriptLock $0; +$WaitFullyConnected; :local CoordinateFormat [ /system/gps/get coordinate-format ]; :local Gps [ /system/gps/monitor once as-value ]; From 1e29eeb388dff8f9cbb7e47e53146d4da87d3c81 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 09:28:32 +0200 Subject: [PATCH 1541/2612] gps-track: add error handling --- gps-track.rsc | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/gps-track.rsc b/gps-track.rsc index 29d2572..0d328d5 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -24,16 +24,20 @@ $WaitFullyConnected; :local Gps [ /system/gps/monitor once as-value ]; :if ($Gps->"valid" = true) do={ - /tool/fetch check-certificate=yes-without-crl $GpsTrackUrl output=none \ - http-method=post http-header-field="Content-Type: application/json" \ - http-data=("{" . \ - "\"lat\":\"" . ($Gps->"latitude") . "\"," . \ - "\"lon\":\"" . ($Gps->"longitude") . "\"," . \ - "\"identity\":\"" . $Identity . "\"" . \ - "}") as-value; - $LogPrintExit2 debug $0 ("Sending GPS data in " . $CoordinateFormat . " format: " . \ - "lat: " . ($Gps->"latitude") . " " . \ - "lon: " . ($Gps->"longitude")) false; + :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={ $LogPrintExit2 debug $0 ("GPS data not valid.") false; } From 196fe1b0109ff42c9df52a5f8b2314aeff65cd5f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Jun 2023 12:53:38 +0200 Subject: [PATCH 1542/2612] global-functions: $CertificateDownload: add proper version in user agent --- global-functions.rsc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index d15567d..030892b 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -116,14 +116,15 @@ :global UrlEncode; :global WaitForFile; + :local UserAgent ("User-Agent: Mikrotik/" . [ /system/resource/get version ] . " Fetch"); + $LogPrintExit2 info $0 ("Downloading and importing certificate with " . \ "CommonName \"" . $CommonName . "\".") false; :do { :local LocalFileName ($CommonName . ".pem"); :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); - /tool/fetch check-certificate=yes-without-crl \ - ($ScriptUpdatesBaseUrl . "certs/" . \ - $UrlFileName . $ScriptUpdatesUrlSuffix) \ + /tool/fetch check-certificate=yes-without-crl http-header-field=$UserAgent \ + ($ScriptUpdatesBaseUrl . "certs/" . $UrlFileName . $ScriptUpdatesUrlSuffix) \ dst-path=$LocalFileName as-value; $WaitForFile $LocalFileName; /certificate/import file-name=$LocalFileName passphrase="" as-value; From e19e33d0a80fe1b4520fe9dab05f6f8a96d6c574 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 May 2023 10:01:38 +0200 Subject: [PATCH 1543/2612] introduce fw-addr-lists --- README.md | 1 + doc/fw-addr-lists.md | 88 +++++++++++++++++++++++++++++++++++++++ fw-addr-lists.rsc | 99 ++++++++++++++++++++++++++++++++++++++++++++ global-config.rsc | 15 +++++++ global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 6 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 doc/fw-addr-lists.md create mode 100644 fw-addr-lists.rsc diff --git a/README.md b/README.md index 1d6bc9b..c03d244 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,7 @@ Available scripts * [Comment DHCP leases with info from access list](doc/dhcp-lease-comment.md) * [Create DNS records for DHCP leases](doc/dhcp-to-dns.md) * [Automatically upgrade firmware and reboot](doc/firmware-upgrade-reboot.md) +* [Download, import and update firewall address-lists](doc/fw-addr-lists.md) * [Wait for global functions und modules](doc/global-wait.md) * [Send GPS position to server](doc/gps-track.md) * [Use WPA2 network with hotspot credentials](doc/hotspot-to-wpa.md) diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md new file mode 100644 index 0000000..98aedcc --- /dev/null +++ b/doc/fw-addr-lists.md @@ -0,0 +1,88 @@ +Download, import and update firewall address-lists +================================================== + +[âŦ…ī¸ Go back to main README](../README.md) + +> â„šī¸ **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. + +Description +----------- + +This script downloads, imports and updates firewall address-lists. Its main +purpose is to block attacking ip addresses, spam hosts, command-and-control +servers and similar malicious entities. The default configuration contains +a list from [dshield.org](https://dshield.org/). + +The address-lists are updated in place, so after initial import you will not +see situation when the lists are not populated. + +To mitigate man-in-the-middle attacks with altered lists the server's +certificate is checked. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate fw-addr-lists; + +And add two schedulers, first one for initial import after startup, second +one for subsequent updates: + + /system/scheduler/add name="fw-addr-lists@startup" start-time=startup on-event="/system/script/run fw-addr-lists;"; + /system/scheduler/add name="fw-addr-lists" start-time=startup interval=2h on-event="/system/script/run fw-addr-lists;"; + +> â„šī¸ **Info**: Modify the interval to your needs, but it is recommended to +> use less than half of the configured timeout for expiration. + +Configuration +------------- + +The configuration goes to `global-config-overlay`, these are the parameters: + +* `FwAddrLists`: a list of firewall address-lists to download and import +* `FwAddrListTimeOut`: the timeout for expiration without renew + +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + +Naming a certificate for a list makes the script verify the server +certificate, so you should add that if possible. Some certificates are +available in my repository and downloaded automatically. Import it manually +(menu `/certificate/`) if missing. + +Create firewall rules to process the packets that are related to addresses +from address-lists. This rejects the packets from and to ip addresses listed +in address-list `block`. + + /ip/firewall/filter/add chain=input src-address-list=block action=reject reject-with=icmp-admin-prohibited; + /ip/firewall/filter/add chain=forward src-address-list=block action=reject reject-with=icmp-admin-prohibited; + /ip/firewall/filter/add chain=forward dst-address-list=block action=reject reject-with=icmp-admin-prohibited; + /ip/firewall/filter/add chain=output dst-address-list=block action=reject reject-with=icmp-admin-prohibited; + +You may want to have an address-list to allow specific addresses, as prepared +with a list `allow`. In fact you can use any list name, just change the +default ones or add your own - matching in configuration and firewall rules. + + /ip/firewall/filter/add chain=input src-address-list=allow action=accept; + /ip/firewall/filter/add chain=forward src-address-list=allow action=accept; + /ip/firewall/filter/add chain=forward dst-address-list=allow action=accept; + /ip/firewall/filter/add chain=output dst-address-list=allow action=accept; + +Modify these for your needs, but **most important**: Move the rules up in +chains and make sure they actually take effect as expected! + +Alternatively handle the packets in firewall's raw section if you prefer: + + /ip/firewall/raw/add chain=prerouting src-address-list=block action=drop; + /ip/firewall/raw/add chain=prerouting dst-address-list=block action=drop; + /ip/firewall/raw/add chain=output dst-address-list=block action=drop; + +> âš ī¸ **Warning**: Just again... The order of firewall rules is important. Make +> sure they actually take effect as expected! + +--- +[âŦ…ī¸ Go back to main README](../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc new file mode 100644 index 0000000..5117c3e --- /dev/null +++ b/fw-addr-lists.rsc @@ -0,0 +1,99 @@ +#!rsc by RouterOS +# RouterOS script: fw-addr-lists +# Copyright (c) 2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# download, import and update firewall address-lists +# https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md + +:local 0 "fw-addr-lists"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global FwAddrLists; +:global FwAddrListTimeOut; + +:global CertificateAvailable; +:global LogPrintExit2; +:global ScriptLock; +:global WaitFullyConnected; + +:local FindDelim do={ + :local ValidChars "0123456789./"; + :for I from=0 to=[ :len $1 ] do={ + :if ([ :typeof [ :find $ValidChars [ :pick ($1 . " ") $I ] ] ] != "num") do={ + :return $I; + } + } +} + +$ScriptLock $0; + +$WaitFullyConnected; + +:local ListComment ("managed by " . $0); + +:foreach FwListName,FwList in=$FwAddrLists do={ + :local Addresses ({}); + :local CntAdd 0; + :local CntRenew 0; + :local CntRemove 0; + :local Failure false; + + :foreach List in=$FwList do={ + :local Data; + :local CheckCertificate "no"; + + :if ([ :len ($List->"cert") ] > 0) do={ + :set CheckCertificate "yes-without-crl"; + :if ([ $CertificateAvailable ($List->"cert") ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading required certificate failed, trying anyway.") false; + } + } + + :do { + :set Data ([ /tool/fetch ($List->"url") check-certificate=$CheckCertificate output=user as-value ]->"data"); + } on-error={ + :set Failure true; + $LogPrintExit2 warning $0 ("Failed downloading list from: " . $List->"url") false; + } + + :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})?\$") do={ + :set ($Addresses->$Address) 1; + } + :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 (($Addresses->$Address) = 1) do={ + $LogPrintExit2 debug $0 ("Renewing: " . $Address) false; + /ip/firewall/address-list/set $Entry timeout=$FwAddrListTimeOut; + :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={ + $LogPrintExit2 debug $0 ("Adding: " . $Address) false; + :do { + /ip/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$FwAddrListTimeOut; + :set ($Addresses->$Address); + :set CntAdd ($CntAdd + 1); + } on-error={ + $LogPrintExit2 warning $0 ("Failed to add address " . $Address . " to list '" . $FwListName . "'.") false; + } + } + + $LogPrintExit2 info $0 ("List: " . $FwListName . " -- Added: " . $CntAdd . " - renewed: " . $CntRenew . " - removed: " . $CntRemove) false; +} diff --git a/global-config.rsc b/global-config.rsc index b17d25c..901c7b3 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -80,6 +80,21 @@ :global BackupUploadUser "mikrotik"; :global BackupUploadPass "v3ry-s3cr3t"; +# This defines the settings for firewall address-lists (fw-addr-lists). +:global FwAddrLists { +# "allow"={ +# { url="https://eworm.de/ros/fw-addr-lists/allow"; +# cert="R3" }; +# }; + "block"={ +# { url="https://eworm.de/ros/fw-addr-lists/block"; +# cert="R3" }; + { url="https://www.dshield.org/block.txt"; cidr="/24"; + cert="R3" }; + }; +}; +:global FwAddrListTimeOut 1d; + # This defines what log messages to filter or include by topic or message # text. Regular expressions are supported. Do *NOT* set an empty string, # that will filter or include everything! diff --git a/global-functions.rsc b/global-functions.rsc index 030892b..98f6978 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 100; +:global ExpectedConfigVersion 101; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 1e43722..e33a7db 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -14,6 +14,7 @@ 98="Extended 'check-certificates' to download new certificate by SubjectAltNames if download by CommonName fails."; 99="Modified 'dhcp-to-dns', which dropped global configuration. Settings moved to dhcp server's network definitions."; 100="The script 'ssh-keys-import' became a module 'mod/ssh-keys-import' with enhanced functionality."; + 101="Introduced new script 'fw-addr-lists' to download, import and update firewall address-lists."; }; # Migration steps to be applied on script updates From 589492621be60f736f4c66b0297f17a1d411b223 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 May 2023 11:44:55 +0200 Subject: [PATCH 1544/2612] certs: add GlobalSign certificates... ... for later use. --- .../GlobalSign Atlas R3 DV TLS CA 2022 Q3.pem | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 certs/GlobalSign Atlas R3 DV TLS CA 2022 Q3.pem diff --git a/certs/GlobalSign Atlas R3 DV TLS CA 2022 Q3.pem b/certs/GlobalSign Atlas R3 DV TLS CA 2022 Q3.pem new file mode 100644 index 0000000..b514c11 --- /dev/null +++ b/certs/GlobalSign Atlas R3 DV TLS CA 2022 Q3.pem @@ -0,0 +1,177 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 7c:2a:0c:21:3f:c6:55:53:45:c9:1f:19:1f:b8:4e:fa + Signature Algorithm: sha256WithRSAEncryption + Issuer: OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign + Validity + Not Before: Apr 20 12:00:00 2022 GMT + Not After : Apr 20 00:00:00 2025 GMT + Subject: C = BE, O = GlobalSign nv-sa, CN = GlobalSign Atlas R3 DV TLS CA 2022 Q3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b8:a8:7a:66:3c:4e:66:9c:ce:37:a5:54:35:4d: + 36:c7:99:d3:a8:27:36:f2:2f:c6:d5:18:3e:e9:09: + dd:05:d6:d7:2c:34:32:7c:08:63:49:d1:10:37:e5: + 78:5d:11:62:ce:6d:fb:2f:3f:37:94:db:8f:7b:30: + e9:5e:2c:d9:55:3f:b2:db:b9:a0:b5:60:37:8b:a4: + 06:32:35:50:a4:09:af:0a:45:ff:a8:1f:9b:65:8e: + dd:4a:e0:40:a1:e3:63:37:58:90:dd:75:3b:fc:0e: + 1c:82:40:98:bd:70:b1:c1:48:14:14:3c:04:4b:69: + dd:d4:9c:01:a6:e9:21:e3:82:0a:fe:e4:aa:bf:34: + a0:8c:cb:c9:79:6e:3e:5c:6a:52:9e:c4:ed:2b:c5: + 69:fe:50:3c:93:9d:b5:ff:2d:28:a8:6c:06:6c:9d: + c5:af:b2:59:fb:59:77:0d:74:7a:88:84:a4:d4:1d: + d4:ba:20:06:cc:b5:1e:48:4e:74:21:15:86:75:c0: + cc:5a:d1:05:cf:57:16:7a:13:17:ec:c2:4a:ae:d5: + 1e:72:aa:22:5a:8c:9c:82:32:c4:10:e6:42:6e:21: + 86:68:7c:80:23:30:35:d3:bd:b0:5e:0a:29:2b:f0: + 14:b1:18:37:d9:59:25:c3:e7:38:d9:e9:d4:2d:36: + 35:65 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + FA:91:39:63:9A:FB:AD:10:24:E5:BE:B5:B9:DA:AB:D9:C4:46:69:AB + X509v3 Authority Key Identifier: + 8F:F0:4B:7F:A8:2E:45:24:AE:4D:50:FA:63:9A:8B:DE:E2:DD:1B:BC + Authority Information Access: + OCSP - URI:http://ocsp2.globalsign.com/rootr3 + CA Issuers - URI:http://secure.globalsign.com/cacert/root-r3.crt + X509v3 CRL Distribution Points: + Full Name: + URI:http://crl.globalsign.com/root-r3.crl + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.1 + Policy: 1.3.6.1.4.1.4146.10.1.3 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 14:33:2c:79:e5:3f:82:c6:70:3f:da:59:38:a7:bb:a2:76:ac: + 61:18:05:68:57:d9:0d:fb:8a:46:bc:f1:a8:e8:0c:70:02:1d: + c6:2f:97:ed:36:3e:9e:52:86:2f:5c:62:d8:d5:47:43:9a:73: + d1:2b:25:87:9f:44:b4:14:eb:26:bc:21:47:74:20:bd:9f:a4: + bf:b3:80:1d:4d:35:7d:cd:b9:b5:da:55:f2:90:50:c8:b2:17: + 4e:0e:b4:61:88:29:5f:44:5d:03:7f:57:91:81:d0:eb:30:ae: + d5:2a:ec:82:20:ce:4e:d2:b0:8b:95:02:61:73:d8:69:34:f4: + ad:63:0e:5c:e4:20:1f:a9:7d:ed:8e:e5:1c:04:bb:22:9f:c7: + a9:22:ca:99:3d:02:a7:67:e8:06:2d:fa:04:6b:bb:49:d2:6c: + 99:57:63:6c:2d:c2:61:78:e1:20:b1:fb:f6:bf:e1:82:39:39: + 3c:7b:ef:7d:1a:95:4a:b2:72:da:55:90:ae:ed:dd:e2:70:90: + 7c:1a:ee:b5:32:5a:5d:cf:d6:fa:45:f2:9e:01:0c:31:2f:89: + 84:fe:31:60:0f:fd:ee:a6:5b:84:d5:c7:18:e6:a4:f9:40:30: + 29:18:1e:fe:fc:41:b5:b9:29:05:75:8b:62:1a:5b:22:2e:bf: + e4:59:6c:b0 +-----BEGIN CERTIFICATE----- +MIIEjzCCA3egAwIBAgIQfCoMIT/GVVNFyR8ZH7hO+jANBgkqhkiG9w0BAQsFADBM +MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv +YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMjA0MjAxMjAwMDBaFw0y +NTA0MjAwMDAwMDBaMFgxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu +IG52LXNhMS4wLAYDVQQDEyVHbG9iYWxTaWduIEF0bGFzIFIzIERWIFRMUyBDQSAy +MDIyIFEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKh6ZjxOZpzO +N6VUNU02x5nTqCc28i/G1Rg+6QndBdbXLDQyfAhjSdEQN+V4XRFizm37Lz83lNuP +ezDpXizZVT+y27mgtWA3i6QGMjVQpAmvCkX/qB+bZY7dSuBAoeNjN1iQ3XU7/A4c +gkCYvXCxwUgUFDwES2nd1JwBpukh44IK/uSqvzSgjMvJeW4+XGpSnsTtK8Vp/lA8 +k521/y0oqGwGbJ3Fr7JZ+1l3DXR6iISk1B3UuiAGzLUeSE50IRWGdcDMWtEFz1cW +ehMX7MJKrtUecqoiWoycgjLEEOZCbiGGaHyAIzA1072wXgopK/AUsRg32Vklw+c4 +2enULTY1ZQIDAQABo4IBXzCCAVswDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG +CCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW +BBT6kTljmvutECTlvrW52qvZxEZpqzAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpj +move4t0bvDB7BggrBgEFBQcBAQRvMG0wLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3Nw +Mi5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1 +cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0w +K6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwIQYD +VR0gBBowGDAIBgZngQwBAgEwDAYKKwYBBAGgMgoBAzANBgkqhkiG9w0BAQsFAAOC +AQEAFDMseeU/gsZwP9pZOKe7onasYRgFaFfZDfuKRrzxqOgMcAIdxi+X7TY+nlKG +L1xi2NVHQ5pz0Sslh59EtBTrJrwhR3QgvZ+kv7OAHU01fc25tdpV8pBQyLIXTg60 +YYgpX0RdA39XkYHQ6zCu1SrsgiDOTtKwi5UCYXPYaTT0rWMOXOQgH6l97Y7lHAS7 +Ip/HqSLKmT0Cp2foBi36BGu7SdJsmVdjbC3CYXjhILH79r/hgjk5PHvvfRqVSrJy +2lWQru3d4nCQfBrutTJaXc/W+kXyngEMMS+JhP4xYA/97qZbhNXHGOak+UAwKRge +/vxBtbkpBXWLYhpbIi6/5FlssA== +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:00:00:00:00:01:21:58:53:08:a2 + Signature Algorithm: sha256WithRSAEncryption + Issuer: OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign + Validity + Not Before: Mar 18 10:00:00 2009 GMT + Not After : Mar 18 10:00:00 2029 GMT + Subject: OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:cc:25:76:90:79:06:78:22:16:f5:c0:83:b6:84: + ca:28:9e:fd:05:76:11:c5:ad:88:72:fc:46:02:43: + c7:b2:8a:9d:04:5f:24:cb:2e:4b:e1:60:82:46:e1: + 52:ab:0c:81:47:70:6c:dd:64:d1:eb:f5:2c:a3:0f: + 82:3d:0c:2b:ae:97:d7:b6:14:86:10:79:bb:3b:13: + 80:77:8c:08:e1:49:d2:6a:62:2f:1f:5e:fa:96:68: + df:89:27:95:38:9f:06:d7:3e:c9:cb:26:59:0d:73: + de:b0:c8:e9:26:0e:83:15:c6:ef:5b:8b:d2:04:60: + ca:49:a6:28:f6:69:3b:f6:cb:c8:28:91:e5:9d:8a: + 61:57:37:ac:74:14:dc:74:e0:3a:ee:72:2f:2e:9c: + fb:d0:bb:bf:f5:3d:00:e1:06:33:e8:82:2b:ae:53: + a6:3a:16:73:8c:dd:41:0e:20:3a:c0:b4:a7:a1:e9: + b2:4f:90:2e:32:60:e9:57:cb:b9:04:92:68:68:e5: + 38:26:60:75:b2:9f:77:ff:91:14:ef:ae:20:49:fc: + ad:40:15:48:d1:02:31:61:19:5e:b8:97:ef:ad:77: + b7:64:9a:7a:bf:5f:c1:13:ef:9b:62:fb:0d:6c:e0: + 54:69:16:a9:03:da:6e:e9:83:93:71:76:c6:69:85: + 82:17 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 8F:F0:4B:7F:A8:2E:45:24:AE:4D:50:FA:63:9A:8B:DE:E2:DD:1B:BC + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 4b:40:db:c0:50:aa:fe:c8:0c:ef:f7:96:54:45:49:bb:96:00: + 09:41:ac:b3:13:86:86:28:07:33:ca:6b:e6:74:b9:ba:00:2d: + ae:a4:0a:d3:f5:f1:f1:0f:8a:bf:73:67:4a:83:c7:44:7b:78: + e0:af:6e:6c:6f:03:29:8e:33:39:45:c3:8e:e4:b9:57:6c:aa: + fc:12:96:ec:53:c6:2d:e4:24:6c:b9:94:63:fb:dc:53:68:67: + 56:3e:83:b8:cf:35:21:c3:c9:68:fe:ce:da:c2:53:aa:cc:90: + 8a:e9:f0:5d:46:8c:95:dd:7a:58:28:1a:2f:1d:de:cd:00:37: + 41:8f:ed:44:6d:d7:53:28:97:7e:f3:67:04:1e:15:d7:8a:96: + b4:d3:de:4c:27:a4:4c:1b:73:73:76:f4:17:99:c2:1f:7a:0e: + e3:2d:08:ad:0a:1c:2c:ff:3c:ab:55:0e:0f:91:7e:36:eb:c3: + 57:49:be:e1:2e:2d:7c:60:8b:c3:41:51:13:23:9d:ce:f7:32: + 6b:94:01:a8:99:e7:2c:33:1f:3a:3b:25:d2:86:40:ce:3b:2c: + 86:78:c9:61:2f:14:ba:ee:db:55:6f:df:84:ee:05:09:4d:bd: + 28:d8:72:ce:d3:62:50:65:1e:eb:92:97:83:31:d9:b3:b5:ca: + 47:58:3f:5f +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- From 53ad7b717d5e0dc4c9e40a9b24e64d5f933bf14c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 9 Jun 2023 16:03:36 +0200 Subject: [PATCH 1545/2612] fw-addr-lists: add lists from abuse.ch in config --- doc/fw-addr-lists.md | 3 ++- global-config.rsc | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md index 98aedcc..4328776 100644 --- a/doc/fw-addr-lists.md +++ b/doc/fw-addr-lists.md @@ -12,7 +12,8 @@ Description This script downloads, imports and updates firewall address-lists. Its main purpose is to block attacking ip addresses, spam hosts, command-and-control servers and similar malicious entities. The default configuration contains -a list from [dshield.org](https://dshield.org/). +lists from [abuse.ch](https://abuse.ch/) and +[dshield.org](https://dshield.org/). The address-lists are updated in place, so after initial import you will not see situation when the lists are not populated. diff --git a/global-config.rsc b/global-config.rsc index 901c7b3..8fe4761 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -89,6 +89,10 @@ "block"={ # { url="https://eworm.de/ros/fw-addr-lists/block"; # cert="R3" }; + { url="https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt"; + cert="GlobalSign Atlas R3 DV TLS CA 2022 Q3" }; + { url="https://sslbl.abuse.ch/blacklist/sslipblacklist.txt"; + cert="GlobalSign Atlas R3 DV TLS CA 2022 Q3" }; { url="https://www.dshield.org/block.txt"; cidr="/24"; cert="R3" }; }; From 3c61cf57c4ab5cef8e41185b4e8a85b788d60788 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 May 2023 22:43:49 +0200 Subject: [PATCH 1546/2612] certs: add Cloudflare certificates... ... for later use. --- certs/Cloudflare Inc ECC CA-3.pem | 163 ++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 certs/Cloudflare Inc ECC CA-3.pem diff --git a/certs/Cloudflare Inc ECC CA-3.pem b/certs/Cloudflare Inc ECC CA-3.pem new file mode 100644 index 0000000..fa91603 --- /dev/null +++ b/certs/Cloudflare Inc ECC CA-3.pem @@ -0,0 +1,163 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0a:37:87:64:5e:5f:b4:8c:22:4e:fd:1b:ed:14:0c:3c + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root + Validity + Not Before: Jan 27 12:48:08 2020 GMT + Not After : Dec 31 23:59:59 2024 GMT + Subject: C = US, O = "Cloudflare, Inc.", CN = Cloudflare Inc ECC CA-3 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:b9:ad:4d:66:99:14:0b:46:ec:1f:81:d1:2a:50: + 1e:9d:03:15:2f:34:12:7d:2d:96:b8:88:38:9b:85: + 5f:8f:bf:bb:4d:ef:61:46:c4:c9:73:d4:24:4f:e0: + ee:1c:ce:6c:b3:51:71:2f:6a:ee:4c:05:09:77:d3: + 72:62:a4:9b:d7 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Subject Key Identifier: + A5:CE:37:EA:EB:B0:75:0E:94:67:88:B4:45:FA:D9:24:10:87:96:1F + X509v3 Authority Key Identifier: + E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + X509v3 CRL Distribution Points: + Full Name: + URI:http://crl3.digicert.com/Omniroot2025.crl + X509v3 Certificate Policies: + Policy: 2.16.840.1.114412.1.1 + CPS: https://www.digicert.com/CPS + Policy: 2.16.840.1.114412.1.2 + Policy: 2.23.140.1.2.1 + Policy: 2.23.140.1.2.2 + Policy: 2.23.140.1.2.3 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 05:24:1d:dd:1b:b0:2a:eb:98:d6:85:e3:39:4d:5e:6b:57:9d: + 82:57:fc:eb:e8:31:a2:57:90:65:05:be:16:44:38:5a:77:02: + b9:cf:10:42:c6:e1:92:a4:e3:45:27:f8:00:47:2c:68:a8:56: + 99:53:54:8f:ad:9e:40:c1:d0:0f:b6:d7:0d:0b:38:48:6c:50: + 2c:49:90:06:5b:64:1d:8b:cc:48:30:2e:de:08:e2:9b:49:22: + c0:92:0c:11:5e:96:92:94:d5:fc:20:dc:56:6c:e5:92:93:bf: + 7a:1c:c0:37:e3:85:49:15:fa:2b:e1:74:39:18:0f:b7:da:f3: + a2:57:58:60:4f:cc:8e:94:00:fc:46:7b:34:31:3e:4d:47:82: + 81:3a:cb:f4:89:5d:0e:ef:4d:0d:6e:9c:1b:82:24:dd:32:25: + 5d:11:78:51:10:3d:a0:35:23:04:2f:65:6f:9c:c1:d1:43:d7: + d0:1e:f3:31:67:59:27:dd:6b:d2:75:09:93:11:24:24:14:cf: + 29:be:e6:23:c3:b8:8f:72:3f:e9:07:c8:24:44:53:7a:b3:b9: + 61:65:a1:4c:0e:c6:48:00:c9:75:63:05:87:70:45:52:83:d3: + 95:9d:45:ea:f0:e8:31:1d:7e:09:1f:0a:fe:3e:dd:aa:3c:5e: + 74:d2:ac:b1 +-----BEGIN CERTIFICATE----- +MIIDzTCCArWgAwIBAgIQCjeHZF5ftIwiTv0b7RQMPDANBgkqhkiG9w0BAQsFADBa +MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl +clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTIw +MDEyNzEyNDgwOFoXDTI0MTIzMTIzNTk1OVowSjELMAkGA1UEBhMCVVMxGTAXBgNV +BAoTEENsb3VkZmxhcmUsIEluYy4xIDAeBgNVBAMTF0Nsb3VkZmxhcmUgSW5jIEVD +QyBDQS0zMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEua1NZpkUC0bsH4HRKlAe +nQMVLzQSfS2WuIg4m4Vfj7+7Te9hRsTJc9QkT+DuHM5ss1FxL2ruTAUJd9NyYqSb +16OCAWgwggFkMB0GA1UdDgQWBBSlzjfq67B1DpRniLRF+tkkEIeWHzAfBgNVHSME +GDAWgBTlnVkwgkdYzKz6CFQ2hns6tQRN8DAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0l +BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYI +KwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j +b20wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL09t +bmlyb290MjAyNS5jcmwwbQYDVR0gBGYwZDA3BglghkgBhv1sAQEwKjAoBggrBgEF +BQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzALBglghkgBhv1sAQIw +CAYGZ4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggEB +AAUkHd0bsCrrmNaF4zlNXmtXnYJX/OvoMaJXkGUFvhZEOFp3ArnPEELG4ZKk40Un ++ABHLGioVplTVI+tnkDB0A+21w0LOEhsUCxJkAZbZB2LzEgwLt4I4ptJIsCSDBFe +lpKU1fwg3FZs5ZKTv3ocwDfjhUkV+ivhdDkYD7fa86JXWGBPzI6UAPxGezQxPk1H +goE6y/SJXQ7vTQ1unBuCJN0yJV0ReFEQPaA1IwQvZW+cwdFD19Ae8zFnWSfda9J1 +CZMRJCQUzym+5iPDuI9yP+kHyCREU3qzuWFloUwOxkgAyXVjBYdwRVKD05WdRerw +6DEdfgkfCv4+3ao8XnTSrLE= +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 33554617 (0x20000b9) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root + Validity + Not Before: May 12 18:46:00 2000 GMT + Not After : May 12 23:59:00 2025 GMT + Subject: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a3:04:bb:22:ab:98:3d:57:e8:26:72:9a:b5:79: + d4:29:e2:e1:e8:95:80:b1:b0:e3:5b:8e:2b:29:9a: + 64:df:a1:5d:ed:b0:09:05:6d:db:28:2e:ce:62:a2: + 62:fe:b4:88:da:12:eb:38:eb:21:9d:c0:41:2b:01: + 52:7b:88:77:d3:1c:8f:c7:ba:b9:88:b5:6a:09:e7: + 73:e8:11:40:a7:d1:cc:ca:62:8d:2d:e5:8f:0b:a6: + 50:d2:a8:50:c3:28:ea:f5:ab:25:87:8a:9a:96:1c: + a9:67:b8:3f:0c:d5:f7:f9:52:13:2f:c2:1b:d5:70: + 70:f0:8f:c0:12:ca:06:cb:9a:e1:d9:ca:33:7a:77: + d6:f8:ec:b9:f1:68:44:42:48:13:d2:c0:c2:a4:ae: + 5e:60:fe:b6:a6:05:fc:b4:dd:07:59:02:d4:59:18: + 98:63:f5:a5:63:e0:90:0c:7d:5d:b2:06:7a:f3:85: + ea:eb:d4:03:ae:5e:84:3e:5f:ff:15:ed:69:bc:f9: + 39:36:72:75:cf:77:52:4d:f3:c9:90:2c:b9:3d:e5: + c9:23:53:3f:1f:24:98:21:5c:07:99:29:bd:c6:3a: + ec:e7:6e:86:3a:6b:97:74:63:33:bd:68:18:31:f0: + 78:8d:76:bf:fc:9e:8e:5d:2a:86:a7:4d:90:dc:27: + 1a:39 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:3 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + Signature Value: + 85:0c:5d:8e:e4:6f:51:68:42:05:a0:dd:bb:4f:27:25:84:03: + bd:f7:64:fd:2d:d7:30:e3:a4:10:17:eb:da:29:29:b6:79:3f: + 76:f6:19:13:23:b8:10:0a:f9:58:a4:d4:61:70:bd:04:61:6a: + 12:8a:17:d5:0a:bd:c5:bc:30:7c:d6:e9:0c:25:8d:86:40:4f: + ec:cc:a3:7e:38:c6:37:11:4f:ed:dd:68:31:8e:4c:d2:b3:01: + 74:ee:be:75:5e:07:48:1a:7f:70:ff:16:5c:84:c0:79:85:b8: + 05:fd:7f:be:65:11:a3:0f:c0:02:b4:f8:52:37:39:04:d5:a9: + 31:7a:18:bf:a0:2a:f4:12:99:f7:a3:45:82:e3:3c:5e:f5:9d: + 9e:b5:c8:9e:7c:2e:c8:a4:9e:4e:08:14:4b:6d:fd:70:6d:6b: + 1a:63:bd:64:e6:1f:b7:ce:f0:f2:9f:2e:bb:1b:b7:f2:50:88: + 73:92:c2:e2:e3:16:8d:9a:32:02:ab:8e:18:dd:e9:10:11:ee: + 7e:35:ab:90:af:3e:30:94:7a:d0:33:3d:a7:65:0f:f5:fc:8e: + 9e:62:cf:47:44:2c:01:5d:bb:1d:b5:32:d2:47:d2:38:2e:d0: + fe:81:dc:32:6a:1e:b5:ee:3c:d5:fc:e7:81:1d:19:c3:24:42: + ea:63:39:a9 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- From 458fe7c08857afa841feb018ac29780b3e4496a9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 9 Jun 2023 16:03:45 +0200 Subject: [PATCH 1547/2612] fw-addr-lists: prepare lists from spamhaus.org in config --- doc/fw-addr-lists.md | 3 ++- global-config.rsc | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md index 4328776..5805905 100644 --- a/doc/fw-addr-lists.md +++ b/doc/fw-addr-lists.md @@ -13,7 +13,8 @@ This script downloads, imports and updates firewall address-lists. Its main purpose is to block attacking ip addresses, spam hosts, command-and-control servers and similar malicious entities. The default configuration contains lists from [abuse.ch](https://abuse.ch/) and -[dshield.org](https://dshield.org/). +[dshield.org](https://dshield.org/), and +lists from [spamhaus.org](https://spamhaus.org/) are prepared. The address-lists are updated in place, so after initial import you will not see situation when the lists are not populated. diff --git a/global-config.rsc b/global-config.rsc index 8fe4761..e82170c 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -95,6 +95,10 @@ cert="GlobalSign Atlas R3 DV TLS CA 2022 Q3" }; { url="https://www.dshield.org/block.txt"; cidr="/24"; cert="R3" }; +# { url="https://www.spamhaus.org/drop/drop.txt"; +# cert="Cloudflare Inc ECC CA-3" }; +# { url="https://www.spamhaus.org/drop/edrop.txt"; +# cert="Cloudflare Inc ECC CA-3" }; }; }; :global FwAddrListTimeOut 1d; From 94b07600baff987161e4f661ff14bddeef9a6174 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 12 Jun 2023 09:14:36 +0200 Subject: [PATCH 1548/2612] fw-addr-lists: support domain names in lists --- fw-addr-lists.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 5117c3e..b33638e 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -19,7 +19,7 @@ :global WaitFullyConnected; :local FindDelim do={ - :local ValidChars "0123456789./"; + :local ValidChars "0123456789./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"; :for I from=0 to=[ :len $1 ] do={ :if ([ :typeof [ :find $ValidChars [ :pick ($1 . " ") $I ] ] ] != "num") do={ :return $I; @@ -28,7 +28,6 @@ } $ScriptLock $0; - $WaitFullyConnected; :local ListComment ("managed by " . $0); @@ -61,7 +60,8 @@ $WaitFullyConnected; :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})?\$") do={ + :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) 1; } :set Data [ :pick $Data ([ :len $Line ] + 1) [ :len $Data ] ]; From e7d9a94ad8ec93cd67111a7c6b912124f95d8c00 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 14 Jun 2023 18:29:29 +0200 Subject: [PATCH 1549/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 0213b45..9024268 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -40,6 +40,7 @@ Add yourself to the list, * Richard Österreicher * Simon Hitzemann * Sunny Chu (@sunnychuchu) +* Ulrich Wessendorf * Zac Kornilakis --- From 64698253983f4ea608b31eb46fb4ac11fc9a156c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 22 Jun 2023 14:21:52 +0200 Subject: [PATCH 1550/2612] global-functions: $IsTimeSync: reset ntp client when "waiting" Every now and then the ntp client stays in status "waiting" forever... This happens if the server answers, but is not accurate enough. Unlike with connection failure the address is not rotated. (SUP-120012) Let's reset it... Should help with a pool address (like pool.ntp.org) at least. --- global-functions.rsc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 98f6978..bdab5a2 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -504,6 +504,7 @@ # check if system time is sync :set IsTimeSync do={ :global IsTimeSyncCached; + :global IsTimeSyncResetNtp; :global LogPrintExit2; @@ -516,6 +517,18 @@ :set IsTimeSyncCached true; :return true; } + + :if ([ /system/resource/get uptime ] < 3m || $IsTimeSyncResetNtp = true) do={ + :return false; + } + + :set IsTimeSyncResetNtp true; + /system/ntp/client/set enabled=no; + :delay 20ms; + /system/ntp/client/set enabled=yes; + /system/scheduler/add name="clear-IsTimeSyncResetNtp" interval=1m \ + on-event=("/system/scheduler/remove clear-IsTimeSyncResetNtp; " . \ + ":global IsTimeSyncResetNtp; :set IsTimeSyncResetNtp;"); :return false; } From 4a67155d059cc816a5b83443104eaf79a8cfe20c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 22 Jun 2023 14:28:17 +0200 Subject: [PATCH 1551/2612] packages-update: rename scheduler to match function name --- check-routeros-update.rsc | 2 +- packages-update.rsc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 4c1aaf9..1405d4e 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -39,7 +39,7 @@ $ScriptLock $0; $WaitFullyConnected; -:if ([ :len [ /system/scheduler/find where name="reboot-for-update" ] ] > 0) do={ +:if ([ :len [ /system/scheduler/find where name="\$RebootForUpdate" ] ] > 0) do={ :error "A reboot for update is already scheduled."; } diff --git a/packages-update.rsc b/packages-update.rsc index 5162103..74b1822 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -86,8 +86,8 @@ $ScriptLock $0; $RandomDelay 3600; /system/reboot; } - /system/scheduler/add name="reboot-for-update" start-time=03:00:00 interval=1d \ - on-event=("/system/scheduler/remove reboot-for-update; " . \ + /system/scheduler/add name="\$RebootForUpdate" start-time=03:00:00 interval=1d \ + on-event=("/system/scheduler/remove \"\\\$RebootForUpdate\"; " . \ ":global RebootForUpdate; \$RebootForUpdate;"); $LogPrintExit2 info $0 ("Scheduled reboot for update between 03:00 and 04:00.") true; } From 351c7d31ffd3ca88a3407e1b9744f8d2189e39e7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 22 Jun 2023 14:36:00 +0200 Subject: [PATCH 1552/2612] mode-button: add dollar sign in scheduler name --- mode-button.rsc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mode-button.rsc b/mode-button.rsc index 52ab00e..87e8740 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -16,10 +16,10 @@ :set ($ModeButton->"count") ($ModeButton->"count" + 1); -:local Scheduler [ /system/scheduler/find where name="ModeButtonScheduler" ]; +:local Scheduler [ /system/scheduler/find where name="\$ModeButtonScheduler" ]; :if ([ :len $Scheduler ] = 0) do={ - $LogPrintExit2 info $0 ("Creating scheduler ModeButtonScheduler, counting presses...") false; + $LogPrintExit2 info $0 ("Creating scheduler \$ModeButtonScheduler, counting presses...") false; :global ModeButtonScheduler do={ :global ModeButton; @@ -44,7 +44,7 @@ :set ($ModeButton->"count") 0; :set ModeButtonScheduler; - /system/scheduler/remove ModeButtonScheduler; + /system/scheduler/remove [ find where name=$0 ]; :if ([ :len $Code ] > 0) do={ :if ([ $ValidateSyntax $Code ] = true) do={ @@ -68,9 +68,9 @@ $LogPrintExit2 info $0 ("No action defined for " . $Count . " mode-button presses.") false; } } - /system/scheduler/add name="ModeButtonScheduler" \ + /system/scheduler/add name="\$ModeButtonScheduler" \ on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s; } else={ - $LogPrintExit2 debug $0 ("Updating scheduler ModeButtonScheduler...") false; + $LogPrintExit2 debug $0 ("Updating scheduler \$ModeButtonScheduler...") false; /system/scheduler/set $Scheduler start-time=[ /system/clock/get time ]; } From eb3b4d169ef57a60c95cb91105bbd9401cc6ae37 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Jun 2023 09:35:00 +0200 Subject: [PATCH 1553/2612] fw-addr-lists: retry to download on failure --- fw-addr-lists.rsc | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index b33638e..b09cf29 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -40,8 +40,8 @@ $WaitFullyConnected; :local Failure false; :foreach List in=$FwList do={ - :local Data; :local CheckCertificate "no"; + :local Data false; :if ([ :len ($List->"cert") ] > 0) do={ :set CheckCertificate "yes-without-crl"; @@ -50,9 +50,19 @@ $WaitFullyConnected; } } - :do { - :set Data ([ /tool/fetch ($List->"url") check-certificate=$CheckCertificate output=user as-value ]->"data"); - } on-error={ + :for I from=2 to=0 do={ + :if ($Data = false) do={ + :do { + :set Data ([ /tool/fetch ($List->"url") check-certificate=$CheckCertificate output=user as-value ]->"data"); + } on-error={ + $LogPrintExit2 debug $0 ("Failed downloading, " . $I . " retries pending: " . $List->"url") false; + :delay 2s; + } + } + } + + :if ($Data = false) do={ + :set Data ""; :set Failure true; $LogPrintExit2 warning $0 ("Failed downloading list from: " . $List->"url") false; } From ec7adcf78e2533a81c43145023aaeaf3740fe729 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Jun 2023 09:36:52 +0200 Subject: [PATCH 1554/2612] update-tunnelbroker: rework the retry-loop --- update-tunnelbroker.rsc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index a1d5e5e..d0a2d16 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -25,27 +25,28 @@ $ScriptLock $0; } :foreach Interface in=[ /interface/6to4/find where comment~"^tunnelbroker" !disabled ] do={ - :local I 0; - :local Response ""; + :local Data false; :local InterfaceVal [ /interface/6to4/get $Interface ]; :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; - :while ($I < 3 && $Response = "") do={ - :do { - :set Response ([ /tool/fetch check-certificate=yes-without-crl \ + :for I from=2 to=0 do={ + :if ($Data = false) do={ + :do { + :set Data ([ /tool/fetch check-certificate=yes-without-crl \ ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ user=($Comment->"user") password=($Comment->"pass") output=user as-value ]->"data"); - } on-error={ - :delay 10s; - :set I ($I + 1); + } on-error={ + $LogPrintExit2 debug $0 ("Failed downloading, " . $I . " retries pending.") false; + :delay 2s; + } } } - :if (!($Response~"^(good|nochg) ")) do={ + :if (!($Data ~ "^(good|nochg) ")) do={ $LogPrintExit2 error $0 ("Failed sending the local address to tunnelbroker or unexpected response!") true; } - :local PublicAddress [ :pick $Response ([ :find $Response " " ] + 1) [ :find $Response "\n" ] ]; + :local PublicAddress [ :pick $Data ([ :find $Data " " ] + 1) [ :find $Data "\n" ] ]; :if ($PublicAddress != $InterfaceVal->"local-address") do={ :if ([ :len [ /ip/address find where address~("^" . $PublicAddress . "/") ] ] < 1) do={ From 29f0a14b7e6675433840a814ecbebdc7bac5c30b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 26 Jun 2023 11:16:49 +0200 Subject: [PATCH 1555/2612] global-config: escaping question mark is no longer required --- global-config.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config.rsc b/global-config.rsc index e82170c..7988ce3 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -207,7 +207,7 @@ #:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/next/"; :global ScriptUpdatesUrlSuffix ""; # use next branch with default url (git.eworm.de) -#:global ScriptUpdatesUrlSuffix "\?h=next"; +#:global ScriptUpdatesUrlSuffix "?h=next"; # Use this for defaults with $ScriptRunOnce # Install module with: From 0af1fa40094ab591dd6a6cf40d0f73e3e9a5514f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 26 Jun 2023 11:14:55 +0200 Subject: [PATCH 1556/2612] global-functions: escaping question mark is no longer required --- global-functions | 2 +- global-functions.rsc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/global-functions b/global-functions index 366ef94..ce55b15 100644 --- a/global-functions +++ b/global-functions @@ -166,7 +166,7 @@ /system/script/run global-config; } on-error={ $LogPrintExit2 error $0 ("Reloading global configuration failed!" . \ - " Syntax error or missing overlay\?") false; + " Syntax error or missing overlay?") false; } } diff --git a/global-functions.rsc b/global-functions.rsc index b8da30b..1f1cfa1 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -321,7 +321,7 @@ } :local Return ""; - :local Chars ("^.[]\$()|*+\?{}\\"); + :local Chars ("^.[]\$()|*+?{}\\"); :for I from=0 to=([ :len $Input ] - 1) do={ :local Char [ :pick $Input $I ]; @@ -942,7 +942,7 @@ /system/script/run global-config; } on-error={ $LogPrintExit2 error $0 ("Reloading global configuration failed!" . \ - " Syntax error or missing overlay\?") false; + " Syntax error or missing overlay?") false; } } @@ -1251,7 +1251,7 @@ } :local Return ""; - :local Chars ("\n\r !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~"); + :local Chars ("\n\r !\"#\$%&'()*+,:;<=>?@[\\]^`{|}~"); :local Subs { "%0A"; "%0D"; "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27"; "%28"; "%29"; "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; "%3F"; "%40"; "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; "%7E" }; From a1b896a5d3174f888db7809c1950e79a533919b9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 26 Jun 2023 11:18:12 +0200 Subject: [PATCH 1557/2612] mod/notification-email: escaping question mark is no longer required --- mod/notification-email.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index b1f3f7c..7be3abe 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -189,7 +189,7 @@ :return $Input; } - :return ("=\?utf-8\?Q\?" . $Return . "\?="); + :return ("=?utf-8?Q?" . $Return . "?="); } # send notification via e-mail - expects at least two string arguments From 0502cf17c9ce5b32b35282ae599542801a9534a7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 26 Jun 2023 11:17:24 +0200 Subject: [PATCH 1558/2612] mod/scriptrunonce: escaping question mark is no longer required --- mod/scriptrunonce.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index 376e778..199d852 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -19,7 +19,7 @@ :global ValidateSyntax; :foreach Script in=$Scripts do={ - :if (!($Script ~ "^(ftp|https\?|sftp)://")) do={ + :if (!($Script ~ "^(ftp|https?|sftp)://")) do={ :if ([ :len $ScriptRunOnceBaseUrl ] = 0) do={ $LogPrintExit2 warning $0 ("Script '" . $Script . "' is not an url and base url is not available.") true; } From cc5820ed90a349a5a607dd93ea54d41e214308e0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 26 Jun 2023 11:16:19 +0200 Subject: [PATCH 1559/2612] update-tunnelbroker: escaping question mark is no longer required --- update-tunnelbroker.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index d0a2d16..60cb003 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -33,7 +33,7 @@ $ScriptLock $0; :if ($Data = false) do={ :do { :set Data ([ /tool/fetch check-certificate=yes-without-crl \ - ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ + ("https://ipv4.tunnelbroker.net/nic/update?hostname=" . $Comment->"id") \ user=($Comment->"user") password=($Comment->"pass") output=user as-value ]->"data"); } on-error={ $LogPrintExit2 debug $0 ("Failed downloading, " . $I . " retries pending.") false; From 640b8fd401eae8ff90bfcbb13f683326f522eabe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Jun 2023 21:32:00 +0200 Subject: [PATCH 1560/2612] global-functions: $IsTimeSync: calculate with uptime, drop scheduler --- global-functions.rsc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index bdab5a2..b8da30b 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -518,17 +518,18 @@ :return true; } - :if ([ /system/resource/get uptime ] < 3m || $IsTimeSyncResetNtp = true) do={ + :if ([ :typeof $IsTimeSyncResetNtp ] = "nothing") do={ + :set IsTimeSyncResetNtp 0s; + } + :local Uptime [ /system/resource/get uptime ]; + :if ($Uptime - $IsTimeSyncResetNtp < 3m) do={ :return false; } - :set IsTimeSyncResetNtp true; + :set IsTimeSyncResetNtp $Uptime; /system/ntp/client/set enabled=no; :delay 20ms; /system/ntp/client/set enabled=yes; - /system/scheduler/add name="clear-IsTimeSyncResetNtp" interval=1m \ - on-event=("/system/scheduler/remove clear-IsTimeSyncResetNtp; " . \ - ":global IsTimeSyncResetNtp; :set IsTimeSyncResetNtp;"); :return false; } From 4e411728e676050c4c53efafc3fdde1b2547f52e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Jun 2023 16:24:25 +0200 Subject: [PATCH 1561/2612] README: link the RouterOS button to changelog --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c03d244..e6119f5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ RouterOS Scripts [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -![required RouterOS version](https://img.shields.io/badge/RouterOS-7.7-yellow?style=flat) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.7-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) From edbb52d4e79748761670af35d935c4b340aa6fb9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Jun 2023 16:26:06 +0200 Subject: [PATCH 1562/2612] doc/mod/ssh-keys-import: link the RouterOS button to changelog --- doc/mod/ssh-keys-import.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md index 2f631a7..44131b8 100644 --- a/doc/mod/ssh-keys-import.md +++ b/doc/mod/ssh-keys-import.md @@ -3,7 +3,7 @@ Import ssh keys for public key authentication [âŦ…ī¸ Go back to main README](../../README.md) -![required RouterOS version](https://img.shields.io/badge/RouterOS-7.9beta4-yellow?style=flat) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.9beta4-yellow?style=flat)](https://mikrotik.com/download/changelogs/) > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base > installation. See [main README](../../README.md) for details. From 5ba34c819a93e27b0eb4c56e25435fe522e16ee3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Jun 2023 16:26:33 +0200 Subject: [PATCH 1563/2612] doc/sms-forward: link the RouterOS button to changelog --- doc/sms-forward.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 74a08e6..dfd91e7 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -3,7 +3,7 @@ Forward received SMS [âŦ…ī¸ Go back to main README](../README.md) -![required RouterOS version](https://img.shields.io/badge/RouterOS-7.9beta4-yellow?style=flat) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.9beta4-yellow?style=flat)](https://mikrotik.com/download/changelogs/) > â„šī¸ **Info**: This script can not be used on its own but requires the base > installation. See [main README](../README.md) for details. From f8a2b88692e21d46799738c13d4d12cfa95b4152 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Jun 2023 17:33:51 +0200 Subject: [PATCH 1564/2612] hotspot-to-wpa: support non-local users This has some limitations, though: The password is not known and additional configuration can not be given in user's comment. --- doc/hotspot-to-wpa.md | 3 +++ global-functions.rsc | 2 +- hotspot-to-wpa.rsc | 5 ++++- news-and-changes.rsc | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index 0abe18b..097cba4 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -54,6 +54,9 @@ Create hotspot login credentials: /ip/hotspot/user/add comment="Test User 1" name=user1 password=v3ry; /ip/hotspot/user/add comment="Test User 2" name=user2 password=s3cr3t; +This also works with authentication via radius, but is limited then: +Additional information is not available, including the password. + Additionally templates can be created to give more options for access list: * `action`: set to `reject` to ignore logins on that hotspot diff --git a/global-functions.rsc b/global-functions.rsc index 1f1cfa1..0378775 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 101; +:global ExpectedConfigVersion 102; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/hotspot-to-wpa.rsc b/hotspot-to-wpa.rsc index d7aeb65..ede4daf 100644 --- a/hotspot-to-wpa.rsc +++ b/hotspot-to-wpa.rsc @@ -25,7 +25,10 @@ $ScriptLock $0; } :local Date [ /system/clock/get date ]; -:local UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; +:local UserVal ({}); +:if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ + :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; +} :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index e33a7db..b062c5e 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -15,6 +15,7 @@ 99="Modified 'dhcp-to-dns', which dropped global configuration. Settings moved to dhcp server's network definitions."; 100="The script 'ssh-keys-import' became a module 'mod/ssh-keys-import' with enhanced functionality."; 101="Introduced new script 'fw-addr-lists' to download, import and update firewall address-lists."; + 102="Modified 'hotspot-to-wpa' to support non-local (radius) users."; }; # Migration steps to be applied on script updates From 0c8bc60648c2b5629273bf64bce81c664470506c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 26 Jun 2023 10:44:52 +0200 Subject: [PATCH 1565/2612] hotspot-to-wpa: reject for two seconds... ... to make the device send a new DHCP request after. --- hotspot-to-wpa.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hotspot-to-wpa.rsc b/hotspot-to-wpa.rsc index ede4daf..35d4fa5 100644 --- a/hotspot-to-wpa.rsc +++ b/hotspot-to-wpa.rsc @@ -57,7 +57,8 @@ $LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $ " (user " . $UserName . ").") false; /caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; /caps-man/access-list/add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - mac-address=$MacAddress private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" place-before=$PlaceBefore; + mac-address=$MacAddress private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + action=reject place-before=$PlaceBefore; :local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; @@ -81,3 +82,6 @@ $LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $ :if ([ :len $VlanMode] > 0) do={ /caps-man/access-list/set $Entry vlan-mode=$VlanMode; } + +:delay 2s; +/caps-man/access-list/set $Entry action=accept; From 16a551a0ee712b81dc267e50414ceee39d434edc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Jun 2023 22:30:34 +0200 Subject: [PATCH 1566/2612] hotspot-to-wpa-cleanup: drop hard-coded server name, find by comment --- doc/hotspot-to-wpa.md | 6 ++++-- global-functions.rsc | 2 +- hotspot-to-wpa-cleanup.rsc | 32 +++++++++++++++++++++----------- news-and-changes.rsc | 1 + 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index 097cba4..5cbe22c 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -38,9 +38,11 @@ Create a scheduler: /system/scheduler/add interval=1d name=hotspot-to-wpa-cleanup on-event="/system/script/run hotspot-to-wpa-cleanup;" start-time=startup; -And add the lease script to your wpa interfaces' dhcp server: +And add the lease script and matcher comment to your wpa interfaces' dhcp +server. You can add more information to the comment, separated by comma. In +this example the server is called `hotspot-to-wpa`. - /ip/dhcp-server/set lease-script=lease-script [ find where name~"wpa" ]; + /ip/dhcp-server/set lease-script=lease-script comment="hotspot-to-wpa=wpa" hotspot-to-wpa; Configuration ------------- diff --git a/global-functions.rsc b/global-functions.rsc index 0378775..205f67a 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 102; +:global ExpectedConfigVersion 103; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/hotspot-to-wpa-cleanup.rsc b/hotspot-to-wpa-cleanup.rsc index 15f63f9..b3aba11 100644 --- a/hotspot-to-wpa-cleanup.rsc +++ b/hotspot-to-wpa-cleanup.rsc @@ -13,26 +13,36 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global LogPrintExit2; +:global ParseKeyValueStore; :global ScriptLock; $ScriptLock $0 false 10; -:foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ - :local ClientVal [ /caps-man/registration-table/get $Client ]; - :local Lease [ /ip/dhcp-server/lease/find where server~"wpa" dynamic \ - mac-address=($ClientVal->"mac-address") ]; - :if ([ :len $Lease ] > 0) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static.") false; - /ip/dhcp-server/lease/make-static $Lease; - /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; +:local DHCPServers ({}); +:foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ + :local ServerVal [ /ip/dhcp-server/get $Server ] + :if (([ $ParseKeyValueStore ($ServerVal->"comment") ]->"hotspot-to-wpa") = "wpa") do={ + :set ($DHCPServers->($ServerVal->"name")) 1; } } -:foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" and \ +:foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ + :local ClientVal [ /caps-man/registration-table/get $Client ]; + :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ + mac-address=($ClientVal->"mac-address") ] do={ + :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) = 1) do={ + $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ + " connected to WPA, making lease static.") false; + /ip/dhcp-server/lease/make-static $Lease; + /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; + } + } +} + +:foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \ !(comment~[ /system/clock/get date ]) ] do={ :local ClientVal [ /caps-man/access-list/get $Client ]; - :if ([ :len [ /ip/dhcp-server/lease/find where server~"wpa" !dynamic \ + :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ mac-address=($ClientVal->"mac-address") ] ] = 0) do={ $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ " did not connect to WPA, removing from access list.") false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index b062c5e..fd7742e 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -16,6 +16,7 @@ 100="The script 'ssh-keys-import' became a module 'mod/ssh-keys-import' with enhanced functionality."; 101="Introduced new script 'fw-addr-lists' to download, import and update firewall address-lists."; 102="Modified 'hotspot-to-wpa' to support non-local (radius) users."; + 103="Dropped hard-coded name from 'hotspot-to-wpa-cleanup', instead a comment is required for dhcp server now."; }; # Migration steps to be applied on script updates From 64ab9eec6756a95df14471b0ebf0f3014c478e9a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Jun 2023 21:59:18 +0200 Subject: [PATCH 1567/2612] hotspot-to-wpa-cleanup: drop hard-coded timeout, get from comment This keeps the default of four weeks, though. --- doc/hotspot-to-wpa.md | 5 +++++ hotspot-to-wpa-cleanup.rsc | 27 ++++++++++++++++----------- news-and-changes.rsc | 2 +- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index 5cbe22c..2630694 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -44,6 +44,11 @@ this example the server is called `hotspot-to-wpa`. /ip/dhcp-server/set lease-script=lease-script comment="hotspot-to-wpa=wpa" hotspot-to-wpa; +You can specify the timeout after which a device is removed from leases and +access-list. The default is four weeks. + + /ip/dhcp-server/set lease-script=lease-script comment="hotspot-to-wpa=wpa, timeout=2w" hotspot-to-wpa; + Configuration ------------- diff --git a/hotspot-to-wpa-cleanup.rsc b/hotspot-to-wpa-cleanup.rsc index b3aba11..adb0abb 100644 --- a/hotspot-to-wpa-cleanup.rsc +++ b/hotspot-to-wpa-cleanup.rsc @@ -12,6 +12,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:global EitherOr; :global LogPrintExit2; :global ParseKeyValueStore; :global ScriptLock; @@ -21,8 +22,10 @@ $ScriptLock $0 false 10; :local DHCPServers ({}); :foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ :local ServerVal [ /ip/dhcp-server/get $Server ] - :if (([ $ParseKeyValueStore ($ServerVal->"comment") ]->"hotspot-to-wpa") = "wpa") do={ - :set ($DHCPServers->($ServerVal->"name")) 1; + :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; + :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ + :set ($DHCPServers->($ServerVal->"name")) \ + [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; } } @@ -30,7 +33,7 @@ $ScriptLock $0 false 10; :local ClientVal [ /caps-man/registration-table/get $Client ]; :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ mac-address=($ClientVal->"mac-address") ] do={ - :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) = 1) do={ + :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ " connected to WPA, making lease static.") false; /ip/dhcp-server/lease/make-static $Lease; @@ -50,12 +53,14 @@ $ScriptLock $0 false 10; } } -:foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status=waiting \ - last-seen>4w comment~"^hotspot-to-wpa:" ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for long time, removing.") false; - /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - mac-address=($LeaseVal->"mac-address") ]; - /ip/dhcp-server/lease/remove $Lease; +: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 ]; + $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ + " was not seen for " . $Timeout . ", removing.") false; + /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ + mac-address=($LeaseVal->"mac-address") ]; + /ip/dhcp-server/lease/remove $Lease; + } } diff --git a/news-and-changes.rsc b/news-and-changes.rsc index fd7742e..572f431 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -16,7 +16,7 @@ 100="The script 'ssh-keys-import' became a module 'mod/ssh-keys-import' with enhanced functionality."; 101="Introduced new script 'fw-addr-lists' to download, import and update firewall address-lists."; 102="Modified 'hotspot-to-wpa' to support non-local (radius) users."; - 103="Dropped hard-coded name from 'hotspot-to-wpa-cleanup', instead a comment is required for dhcp server now."; + 103="Dropped hard-coded name and timeout from 'hotspot-to-wpa-cleanup', instead a comment is required for dhcp server now."; }; # Migration steps to be applied on script updates From 5db9a71802230f8cbc0bf17d2a58c89c9c872dda Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 28 Mar 2023 15:57:06 +0200 Subject: [PATCH 1568/2612] global-functions: $MkDir: drop old code with smb workaround... ... and increase required RouterOS. --- README.md | 2 +- global-functions.rsc | 43 ++----------------------------------------- 2 files changed, 3 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index e6119f5..3988722 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ RouterOS Scripts [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.7-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.9beta4-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) diff --git a/global-functions.rsc b/global-functions.rsc index 205f67a..476db7c 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.7 +# requires RouterOS, version=7.9beta4 # # global functions # https://git.eworm.de/cgit/routeros-scripts/about/ @@ -603,7 +603,6 @@ :global CleanFilePath; :global GetRandom20CharAlNum; :global LogPrintExit2; - :global RequiredRouterOS; :global WaitForFile; :local MkTmpfs do={ @@ -636,7 +635,7 @@ :return true; } - :if ([ $RequiredRouterOS $0 "7.9beta4" false ] = true) do={ + { :if ([ :pick $Path 0 5 ] = "tmpfs") do={ :if ([ $MkTmpfs ] = false) do={ :return false; @@ -652,44 +651,6 @@ $LogPrintExit2 warning $0 ("Making directory '" . $Path . "' failed!") false; :return false; } - } else={ - :local Error false; - :local PathNext ""; - :foreach Dir in=[ :toarray [ $CharacterReplace $Path "/" "," ] ] do={ - :local Continue false; - :set PathNext [ $CleanFilePath ($PathNext . "/" . $Dir) ]; - - :if ([ :len [ /file/find where name=$PathNext !(name="tmpfs") type="directory" ] ] = 1) do={ - :set Continue true; - } - - :if ($Continue = false && $PathNext = "tmpfs") do={ - :if ([ $MkTmpfs ] = false) do={ - :return false; - } - :set Continue true; - } - - :if ($Continue = false && [ :len [ /file/find where name=$PathNext ] ] = 1) do={ - $LogPrintExit2 warning $0 ("The path '" . $PathNext . "' exists, but is not a directory.") false; - :return false; - } - - :if ($Continue = false) do={ - :local Name ($PathNext . "-" . [ $GetRandom20CharAlNum 6 ]); - :do { - /ip/smb/share/add disabled=yes directory=$PathNext name=$Name; - $WaitForFile $PathNext; - } on-error={ - $LogPrintExit2 warning $0 ("Making directory '" . $PathNext . "' failed!") false; - :set Error true; - } - /ip/smb/share/remove [ find where name=$Name ]; - :if ($Error = true) do={ - :return false; - } - } - } } :return true; } From 08e9634154b6a93367fae83ced3fe32c4c3c7f8b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 28 Mar 2023 15:59:23 +0200 Subject: [PATCH 1569/2612] global-functions: $MkDir: drop extra block, restore indention We had this to make the previous commit cleaner. No functional change. --- global-functions.rsc | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 476db7c..e317af9 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -635,23 +635,22 @@ :return true; } - { - :if ([ :pick $Path 0 5 ] = "tmpfs") do={ - :if ([ $MkTmpfs ] = false) do={ - :return false; - } - } - - :do { - :local File ($Path . "/file"); - /file/add name=$File; - $WaitForFile $File; - /file/remove $File; - } on-error={ - $LogPrintExit2 warning $0 ("Making directory '" . $Path . "' failed!") false; + :if ([ :pick $Path 0 5 ] = "tmpfs") do={ + :if ([ $MkTmpfs ] = false) do={ :return false; } } + + :do { + :local File ($Path . "/file"); + /file/add name=$File; + $WaitForFile $File; + /file/remove $File; + } on-error={ + $LogPrintExit2 warning $0 ("Making directory '" . $Path . "' failed!") false; + :return false; + } + :return true; } From 3ed124a013cdfa46f7f36713262f316803d469c4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 15 Jun 2023 22:49:00 +0200 Subject: [PATCH 1570/2612] README: reference stable version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3988722..de97c84 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ RouterOS Scripts [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.9beta4-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.9-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) From 6247b739a127c7c37dbcd50c1392c05e3a34a681 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 May 2023 15:24:16 +0200 Subject: [PATCH 1571/2612] netwatch-notify: drop the delay on startup... ... now that in RouterOS 7.9 netwatch itself comes with a startup-delay. Hosts in state 'unknown' are just ignored. --- doc/netwatch-notify.md | 2 ++ netwatch-notify.rsc | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 6df233b..efae5cf 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -3,6 +3,8 @@ Notify on host up and down [âŦ…ī¸ Go back to main README](../README.md) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.9beta4-yellow?style=flat)](https://mikrotik.com/download/changelogs/) + > â„šī¸ **Info**: This script can not be used on its own but requires the base > installation. See [main README](../README.md) for details. diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 910fb73..15a17b2 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2020-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.9beta4 +# # monitor netwatch and send notifications # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md @@ -54,10 +56,6 @@ $ScriptLock $0; :local ScriptFromTerminalCached [ $ScriptFromTerminal $0 ]; -:if ([ /system/resource/get uptime ] < 5m) do={ - $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; -} - :if ([ :typeof $NetwatchNotify ] = "nothing") do={ :set NetwatchNotify ({}); } From 313e026229932e4988d3ce96d69ddb8ab5f1b934 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 1 Jun 2023 09:37:54 +0200 Subject: [PATCH 1572/2612] netwatch-dns: increase startup delay In RouterOS 7.9 netwatch itself comes with a (default) startup-delay of five minutes. Increase our delay to make sure netwatch is active. --- netwatch-dns.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index c1d57b8..119a367 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -18,7 +18,7 @@ $ScriptLock $0; -:if ([ /system/resource/get uptime ] < 5m) do={ +:if ([ /system/resource/get uptime ] < 5m30s) do={ $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; } From fbf55292a4fa15cbd06490b66509884f62f78dbc Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Thu, 13 Jul 2023 09:38:20 +0800 Subject: [PATCH 1573/2612] check-routeros-update: match version with date suffix Neighbor version can have a date suffix. This changes to match only on the beginning. Closes: GH-45 Co-authored-by: Christian Hesse --- check-routeros-update.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 1405d4e..c46dc7d 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -18,6 +18,7 @@ :global SentRouterosUpdateNotification; :global DeviceInfo; +:global EscapeForRegEx; :global LogPrintExit2; :global ScriptFromTerminal; :global ScriptLock; @@ -80,7 +81,7 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; } :if ($SafeUpdateNeighbor = true && [ :len [ /ip/neighbor/find where \ - version=($Update->"latest-version" . " (" . $Update->"channel" . ")") ] ] > 0) do={ + version~("^" . [ $EscapeForRegEx ($Update->"latest-version" . " (" . $Update->"channel" . ")") ]) ] ] > 0) do={ $LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ From be97de3627f2fa098931d525945114f712ddae71 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 15 Jul 2023 22:05:47 +0200 Subject: [PATCH 1574/2612] check-routeros-update: also match platform for neighbors --- check-routeros-update.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index c46dc7d..b328d4c 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -80,7 +80,7 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; $DoUpdate; } - :if ($SafeUpdateNeighbor = true && [ :len [ /ip/neighbor/find where \ + :if ($SafeUpdateNeighbor = true && [ :len [ /ip/neighbor/find where platform="MikroTik" \ version~("^" . [ $EscapeForRegEx ($Update->"latest-version" . " (" . $Update->"channel" . ")") ]) ] ] > 0) do={ $LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; $SendNotification2 ({ origin=$0; \ From 5b789d298b8d6d48d91601b335e1feeeb1374f14 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 23 Jul 2023 22:01:43 +0200 Subject: [PATCH 1575/2612] check-certificates: properly handle in place updates This worked just kind of... The certification was updated, but script aborted before the notification was sent. --- check-certificates.rsc | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index db9007a..86e079a 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -122,18 +122,21 @@ $WaitFullyConnected; } } - :local 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={ - $LogPrintExit2 warning $0 ("The certificate chain is not available!") false; - } - - :if ($Cert != $CertNew) do={ + :if ($CertVal->"fingerprint" != [ /certificate/get $Cert fingerprint ]) do={ + $LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was updated in place.") false; + :set CertVal [ /certificate/get $Cert ]; + } else { $LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; + :local 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={ + $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; From 9a5d55da0dca37a8e921c411264b4187ba50e3e9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 6 Aug 2023 16:25:06 +0200 Subject: [PATCH 1576/2612] mod/notification-email: introduce $PurgeEmailQueue ... to purge the queue and remove the scheduler. --- doc/mod/notification-email.md | 5 +++++ mod/notification-email.rsc | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/doc/mod/notification-email.md b/doc/mod/notification-email.md index e4ceda2..8dc2ecf 100644 --- a/doc/mod/notification-email.md +++ b/doc/mod/notification-email.md @@ -64,6 +64,11 @@ Place this before you call them: :global SendEMail; :global SendNotification; +In case there is a situation when the queue needs to be purged there is a +function available: + + $PurgeEMailQueue; + See also -------- diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 7be3abe..e266201 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -10,6 +10,7 @@ :global LogForwardFilterLogForwarding; :global NotificationEMailSubject; :global NotificationFunctions; +:global PurgeEMailQueue; :global QuotedPrintable; :global SendEMail; :global SendEMail2; @@ -156,6 +157,14 @@ } } +# purge the e-mail queue +:set PurgeEMailQueue do={ + :global EmailQueue; + + /system/scheduler/remove [ find where name="\$FlushEmailQueue" ]; + :set EmailQueue; +} + # convert string to quoted-printable :global QuotedPrintable do={ :local Input [ :tostr $1 ]; From 0aeb34e5e9cb9ddaee7316b60e0e9eaeadb428d3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 6 Aug 2023 16:25:52 +0200 Subject: [PATCH 1577/2612] mod/notification-matrix: introduce $PurgeMatrixQueue ... to purge the queue and remove the scheduler. --- doc/mod/notification-matrix.md | 5 +++++ mod/notification-matrix.rsc | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index 070ed9f..ab8efc9 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -110,6 +110,11 @@ Place this before you call them: :global SendMatrix; :global SendNotification; +In case there is a situation when the queue needs to be purged there is a +function available: + + $PurgeMatrixQueue; + See also -------- diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 16b2370..03cfb13 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -9,6 +9,7 @@ :global FlushMatrixQueue; :global NotificationFunctions; +:global PurgeMatrixQueue; :global SendMatrix; :global SendMatrix2; @@ -151,6 +152,14 @@ } } +# purge the Matrix queue +:set PurgeMatrixQueue do={ + :global MatrixQueue; + + /system/scheduler/remove [ find where name="\$FlushMatrixQueue" ]; + :set MatrixQueue; +} + # send notification via Matrix - expects at least two string arguments :set SendMatrix do={ :global SendMatrix2; From c37739c2f6b050c965e0fa734309e1ecbed90add Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 6 Aug 2023 16:26:22 +0200 Subject: [PATCH 1578/2612] mod/notification-telegram: introduce $PurgeTelegramQueue ... to purge the queue and remove the scheduler. --- doc/mod/notification-telegram.md | 5 +++++ mod/notification-telegram.rsc | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index 40e6fb1..89659c8 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -73,6 +73,11 @@ Place this before you call them: :global SendTelegram; :global SendNotification; +In case there is a situation when the queue needs to be purged there is a +function available: + + $PurgeTelegramQueue; + Tips & Tricks ------------- diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 0ab1aa0..ea47b1a 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -8,6 +8,7 @@ :global FlushTelegramQueue; :global NotificationFunctions; +:global PurgeTelegramQueue; :global SendTelegram; :global SendTelegram2; @@ -162,6 +163,14 @@ } } +# purge the Telegram queue +:set PurgeTelegramQueue do={ + :global TelegramQueue; + + /system/scheduler/remove [ find where name="\$FlushTelegramQueue" ]; + :set TelegramQueue; +} + # send notification via telegram - expects at least two string arguments :set SendTelegram do={ :global SendTelegram2; From 1b947f445bfffb099b0f0fdc2011672ae716aa51 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Aug 2023 14:37:52 +0200 Subject: [PATCH 1579/2612] Makefile: drop path rewriting, use pattern to filter --- Makefile | 4 ++-- accesslist-duplicates.template.rsc | 16 ++++++++++------ collect-wireless-mac.template.rsc | 28 ++++++++++++++++++---------- daily-psk.template.rsc | 19 ++++++++++--------- dhcp-lease-comment.template.rsc | 10 ++++++---- 5 files changed, 46 insertions(+), 31 deletions(-) diff --git a/Makefile b/Makefile index 8c9bcf5..0179c6f 100644 --- a/Makefile +++ b/Makefile @@ -15,12 +15,12 @@ all: $(CAPSMAN) $(LOCAL) $(HTML) markdown $< | sed 's/href="\([-_\./[:alnum:]]*\)\.md"/href="\1.html"/g' > $@ %.local.rsc: %.template.rsc Makefile - sed -e '/\/caps-man/d' -e 's|%PATH%|interface\/wireless|' -e 's|%TEMPL%|.local|' \ + sed -e '/\/caps-man/d' -e 's|%TEMPL%|.local|' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ %.capsman.rsc: %.template.rsc Makefile - sed -e '/\/interface\/wireless/d' -e 's|%PATH%|caps-man|' -e 's|%TEMPL%|.capsman|' \ + sed -e '/\/interface\/wireless/d' -e 's|%TEMPL%|.capsman|' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index 80c47a9..b01c90d 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -6,8 +6,8 @@ # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md # -# !! This is just a template! Replace '%PATH%' with 'caps-man' -# !! or 'interface wireless'! +# !! This is just a template to generate the real script! +# !! Pattern '%TEMPL%' is replaced, paths are filtered. :local 0 "accesslist-duplicates%TEMPL%"; :global GlobalFunctionsReady; @@ -18,8 +18,10 @@ :local Seen ({}); :local Shown ({}); -:foreach AccList in=[ /%PATH%/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ - :local Mac [ /%PATH%/access-list/get $AccList mac-address ]; +:foreach AccList in=[ /caps-man/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/wireless/access-list/get $AccList mac-address ]; :foreach SeenMac in=$Seen do={ :if ($SeenMac = $Mac) do={ :local Skip 0; @@ -27,14 +29,16 @@ :if ($ShownMac = $Mac) do={ :set Skip 1; } } :if ($Skip = 0) do={ - /%PATH%/access-list/print where mac-address=$Mac; + /caps-man/access-list/print where mac-address=$Mac; + /interface/wireless/access-list/print where mac-address=$Mac; :set Shown ($Shown, $Mac); :put "\nNumeric id to remove, any key to skip!"; :local Remove [ :tonum [ $Read ] ]; :if ([ :typeof $Remove ] = "num") do={ :put ("Removing numeric id " . $Remove . "...\n"); - /%PATH%/access-list/remove $Remove; + /caps-man/access-list/remove $Remove; + /interface/wireless/access-list/remove $Remove; } } } diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index 6f9efc5..eb92270 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -8,8 +8,8 @@ # # provides: lease-script, order=40 # -# !! This is just a template! Replace '%PATH%' with 'caps-man' -# !! or 'interface wireless'! +# !! This is just a template to generate the real script! +# !! Pattern '%TEMPL%' is replaced, paths are filtered. :local 0 "collect-wireless-mac%TEMPL%"; :global GlobalFunctionsReady; @@ -27,25 +27,32 @@ $ScriptLock $0 false 10; -:if ([ :len [ /%PATH%/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - /%PATH%/access-list/add comment="--- collected above ---" disabled=yes; +:if ([ :len [ /caps-man/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/wireless/access-list/add comment="--- collected above ---" disabled=yes; $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false; } -:local PlaceBefore ([ /%PATH%/access-list/find where comment="--- collected above ---" disabled ]->0); +:local PlaceBefore ([ /caps-man/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=[ /%PATH%/registration-table/find ] do={ +:foreach Reg in=[ /caps-man/registration-table/find ] do={ +:foreach Reg in=[ /interface/wireless/registration-table/find ] do={ :local RegVal; :do { - :set RegVal [ /%PATH%/registration-table/get $Reg ]; + :set RegVal [ /caps-man/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={ - :local AccessList ([ /%PATH%/access-list/find where mac-address=($RegVal->"mac-address") ]->0); + :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); + :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /%PATH%/access-list/get $AccessList comment ]) false; + [ /caps-man/access-list/get $AccessList comment ]) false; + [ /interface/wireless/access-list/get $AccessList comment ]) false; } :if ([ :len $AccessList ] = 0) do={ @@ -68,7 +75,8 @@ $ScriptLock $0 false 10; :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); $LogPrintExit2 info $0 $Message false; - /%PATH%/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; + /caps-man/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" . \ diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 777f6c0..ea0fb46 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -7,8 +7,8 @@ # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md # -# !! This is just a template! Replace '%PATH%' with 'caps-man' -# !! or 'interface wireless'! +# !! This is just a template to generate the real script! +# !! Pattern '%TEMPL%' is replaced, paths are filtered. :local 0 "daily-psk%TEMPL%"; :global GlobalFunctionsReady; @@ -55,24 +55,25 @@ $WaitFullyConnected; :local Date [ /system/clock/get date ]; :local NewPsk [ $GeneratePSK $Date ]; -:foreach AccList in=[ /%PATH%/access-list/find where comment~$DailyPskMatchComment ] do={ - :local IntName [ /interface/wireless/access-list/get $AccList interface ]; - :local Ssid [ /interface/wireless/get $IntName ssid ]; - :local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ]; - # /interface/wireless above - /caps-man below +:foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ +:foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; :local 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 ]; + # /caps-man 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={ $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; - /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; /caps-man/access-list/set $AccList private-passphrase=$NewPsk; + /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; - :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ + :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index be28cfd..3fe9b64 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -8,8 +8,8 @@ # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md # -# !! This is just a template! Replace '%PATH%' with 'caps-man' -# !! or 'interface wireless'! +# !! This is just a template to generate the real script! +# !! Pattern '%TEMPL%' is replaced, paths are filtered. :local 0 "dhcp-lease-comment%TEMPL%"; :global GlobalFunctionsReady; @@ -23,9 +23,11 @@ $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 ([ /%PATH%/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); + :local AccessList ([ /caps-man/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 [ /%PATH%/access-list/get $AccessList comment ]; + :set NewComment [ /caps-man/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; From b014eb76c6fa6a07951374eb3cf6f43999d4ab38 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Aug 2023 14:58:49 +0200 Subject: [PATCH 1580/2612] collect-wireless-mac: move comment up --- collect-wireless-mac.capsman.rsc | 4 ++-- collect-wireless-mac.local.rsc | 4 ++-- collect-wireless-mac.template.rsc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index c6cae9c..f21fc46 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -3,11 +3,11 @@ # Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# provides: lease-script, order=40 +# # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # -# provides: lease-script, order=40 -# # !! Do not edit this file, it is generated from template! :local 0 "collect-wireless-mac.capsman"; diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index fa8fe8d..6bc8f45 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -3,11 +3,11 @@ # Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# provides: lease-script, order=40 +# # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # -# provides: lease-script, order=40 -# # !! Do not edit this file, it is generated from template! :local 0 "collect-wireless-mac.local"; diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index eb92270..b3618ee 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -3,11 +3,11 @@ # Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# provides: lease-script, order=40 +# # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md # -# provides: lease-script, order=40 -# # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. From 14dcea23b27a6cc43c01311535cc657c44e1179d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Aug 2023 10:00:43 +0200 Subject: [PATCH 1581/2612] Makefile: support wifiwave2 in templates --- Makefile | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 0179c6f..2539788 100644 --- a/Makefile +++ b/Makefile @@ -5,22 +5,28 @@ TEMPLATE = $(wildcard *.template.rsc) CAPSMAN = $(TEMPLATE:.template.rsc=.capsman.rsc) LOCAL = $(TEMPLATE:.template.rsc=.local.rsc) +WIFIWAVE2 = $(TEMPLATE:.template.rsc=.wifiwave2.rsc) MARKDOWN = $(wildcard *.md doc/*.md doc/mod/*.md) HTML = $(MARKDOWN:.md=.html) -all: $(CAPSMAN) $(LOCAL) $(HTML) +all: $(CAPSMAN) $(LOCAL) $(WIFIWAVE2) $(HTML) %.html: %.md Makefile markdown $< | sed 's/href="\([-_\./[:alnum:]]*\)\.md"/href="\1.html"/g' > $@ %.local.rsc: %.template.rsc Makefile - sed -e '/\/caps-man/d' -e 's|%TEMPL%|.local|' \ + sed -e '/\/caps-man/d' -e '/\/interface\/wifiwave2/d' -e 's|%TEMPL%|.local|' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ %.capsman.rsc: %.template.rsc Makefile - sed -e '/\/interface\/wireless/d' -e 's|%TEMPL%|.capsman|' \ + sed -e '/\/interface\/wifiwave2/d' -e '/\/interface\/wireless/d' -e 's|%TEMPL%|.capsman|' \ + -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ + < $< > $@ + +%.wifiwave2.rsc: %.template.rsc Makefile + sed -e '/\/caps-man/d' -e '/\/interface\/wireless/d' -e 's|%TEMPL%|.wifiwave2|' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ From 0f787f9b030408fd2500bb036ff5816df27012b0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Aug 2023 12:19:18 +0200 Subject: [PATCH 1582/2612] Makefile: only regenerate existing scripts from templates --- Makefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 2539788..547fe10 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,9 @@ # template scripts -> final scripts # markdown files -> html files -TEMPLATE = $(wildcard *.template.rsc) -CAPSMAN = $(TEMPLATE:.template.rsc=.capsman.rsc) -LOCAL = $(TEMPLATE:.template.rsc=.local.rsc) -WIFIWAVE2 = $(TEMPLATE:.template.rsc=.wifiwave2.rsc) +CAPSMAN = $(wildcard *.capsman.rsc) +LOCAL = $(wildcard *.local.rsc) +WIFIWAVE2 = $(wildcard *.wifiwave2.rsc) MARKDOWN = $(wildcard *.md doc/*.md doc/mod/*.md) HTML = $(MARKDOWN:.md=.html) From 5ea74968d942140aea79b7e001c8174f32b77e46 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Aug 2023 13:02:58 +0200 Subject: [PATCH 1583/2612] capsman-download-packages: find script by code comment --- capsman-download-packages.rsc | 5 +++-- capsman-rolling-upgrade.rsc | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/capsman-download-packages.rsc b/capsman-download-packages.rsc index 08edd59..2dd3bcd 100644 --- a/capsman-download-packages.rsc +++ b/capsman-download-packages.rsc @@ -78,8 +78,9 @@ $WaitFullyConnected; } :if ($Updated = true) do={ - :if ([ :len [ /system/script/find where name="capsman-rolling-upgrade" ] ] > 0) do={ - /system/script/run capsman-rolling-upgrade; + :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); + :if ([ :len $Script ] > 0) do={ + /system/script/run $Script; } else={ /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; } diff --git a/capsman-rolling-upgrade.rsc b/capsman-rolling-upgrade.rsc index 1f4a51c..91a6400 100644 --- a/capsman-rolling-upgrade.rsc +++ b/capsman-rolling-upgrade.rsc @@ -4,6 +4,8 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# provides: capsman-rolling-upgrade +# # upgrade CAPs one after another # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md From 5e3d9d746040a05ee94b5858f0d1a7cd9dd136ec Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Aug 2023 12:18:47 +0200 Subject: [PATCH 1584/2612] capsman-download-packages: convert to template, split capsman & wifiwave2 --- capsman-download-packages.capsman.rsc | 89 ++++++++++++++++++++++++ capsman-download-packages.rsc | 86 +---------------------- capsman-download-packages.template.rsc | 92 +++++++++++++++++++++++++ capsman-download-packages.wifiwave2.rsc | 89 ++++++++++++++++++++++++ doc/capsman-download-packages.md | 22 ++++-- 5 files changed, 288 insertions(+), 90 deletions(-) create mode 100644 capsman-download-packages.capsman.rsc create mode 100644 capsman-download-packages.template.rsc create mode 100644 capsman-download-packages.wifiwave2.rsc diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc new file mode 100644 index 0000000..99ff052 --- /dev/null +++ b/capsman-download-packages.capsman.rsc @@ -0,0 +1,89 @@ +#!rsc by RouterOS +# RouterOS script: capsman-download-packages.capsman +# Copyright (c) 2018-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# download and cleanup packages for CAP installation from CAPsMAN +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "capsman-download-packages.capsman"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global CleanFilePath; +:global DownloadPackage; +:global LogPrintExit2; +:global MkDir; +:global ScriptLock; +:global WaitFullyConnected; + +$ScriptLock $0; +$WaitFullyConnected; + +:local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; +:local InstalledVersion [ /system/package/update/get installed-version ]; +:local Updated false; + +:if ([ :len $PackagePath ] = 0) do={ + $LogPrintExit2 warning $0 ("The CAPsMAN package path is not defined, can not download packages.") true; +} + +:if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ + :if ([ $MkDir $PackagePath ] = false) do={ + $LogPrintExit2 warning $0 ("Creating directory at CAPsMAN package path (" . \ + $PackagePath . ") failed!") true; + } + $LogPrintExit2 info $0 ("Created directory at CAPsMAN package path (" . $PackagePath . \ + "). Please place your packages!") false; +} + +:foreach Package in=[ /file/find where type=package \ + package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ + :local File [ /file/get $Package ]; + :if ($File->"package-architecture" = "mips") do={ + :set ($File->"package-architecture") "mipsbe"; + } + :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ + ($File->"package-architecture") $PackagePath ] = true) do={ + :set Updated true; + /file/remove $Package; + } +} + +:if ([ :len [ /system/logging/find where topics~"error" !(topics~"!error") \ + !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ + $LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \ + "Probably can not download packages automatically.") false; +} else={ + :if ($Updated = false && [ /system/resource/get uptime ] < 2m) do={ + $LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false; + :delay 2m; + } +} + +:foreach Log in=[ /log/find where topics=({"caps"; "error"}) \ + message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \ + "-.*\\.npk', no such file") ] do={ + :local Message [ /log/get $Log message ]; + :local Package [ :pick $Message \ + ([ :find $Message "'" ] + 1) \ + [ :find $Message ("-" . $InstalledVersion . "-") ] ]; + :local Arch [ :pick $Message \ + ([ :find $Message ("-" . $InstalledVersion . "-") ] + 2 + [ :len $InstalledVersion ]) \ + [ :find $Message ".npk" ] ]; + :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ + :set Updated true; + } +} + +:if ($Updated = true) do={ + :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); + :if ([ :len $Script ] > 0) do={ + /system/script/run $Script; + } else={ + /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; + } +} diff --git a/capsman-download-packages.rsc b/capsman-download-packages.rsc index 2dd3bcd..2da00ca 100644 --- a/capsman-download-packages.rsc +++ b/capsman-download-packages.rsc @@ -1,87 +1,3 @@ #!rsc by RouterOS -# RouterOS script: capsman-download-packages -# Copyright (c) 2018-2023 Christian Hesse -# Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# download and cleanup packages for CAP installation from CAPsMAN -# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md - -:local 0 "capsman-download-packages"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global CleanFilePath; -:global DownloadPackage; -:global LogPrintExit2; -:global MkDir; -:global ScriptLock; -:global WaitFullyConnected; - -$ScriptLock $0; -$WaitFullyConnected; - -:local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; -:local InstalledVersion [ /system/package/update/get installed-version ]; -:local Updated false; - -:if ([ :len $PackagePath ] = 0) do={ - $LogPrintExit2 warning $0 ("The CAPsMAN package path is not defined, can not download packages.") true; -} - -:if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ - :if ([ $MkDir $PackagePath ] = false) do={ - $LogPrintExit2 warning $0 ("Creating directory at CAPsMAN package path (" . \ - $PackagePath . ") failed!") true; - } - $LogPrintExit2 info $0 ("Created directory at CAPsMAN package path (" . $PackagePath . \ - "). Please place your packages!") false; -} - -:foreach Package in=[ /file/find where type=package \ - package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ - :local File [ /file/get $Package ]; - :if ($File->"package-architecture" = "mips") do={ - :set ($File->"package-architecture") "mipsbe"; - } - :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ - ($File->"package-architecture") $PackagePath ] = true) do={ - :set Updated true; - /file/remove $Package; - } -} - -:if ([ :len [ /system/logging/find where topics~"error" !(topics~"!error") \ - !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ - $LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \ - "Probably can not download packages automatically.") false; -} else={ - :if ($Updated = false && [ /system/resource/get uptime ] < 2m) do={ - $LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false; - :delay 2m; - } -} - -:foreach Log in=[ /log/find where topics=({"caps"; "error"}) \ - message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \ - "-.*\\.npk', no such file") ] do={ - :local Message [ /log/get $Log message ]; - :local Package [ :pick $Message \ - ([ :find $Message "'" ] + 1) \ - [ :find $Message ("-" . $InstalledVersion . "-") ] ]; - :local Arch [ :pick $Message \ - ([ :find $Message ("-" . $InstalledVersion . "-") ] + 2 + [ :len $InstalledVersion ]) \ - [ :find $Message ".npk" ] ]; - :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ - :set Updated true; - } -} - -:if ($Updated = true) do={ - :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); - :if ([ :len $Script ] > 0) do={ - /system/script/run $Script; - } else={ - /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; - } -} +# dummy for migration diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc new file mode 100644 index 0000000..baa8fc4 --- /dev/null +++ b/capsman-download-packages.template.rsc @@ -0,0 +1,92 @@ +#!rsc by RouterOS +# RouterOS script: capsman-download-packages%TEMPL% +# Copyright (c) 2018-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# download and cleanup packages for CAP installation from CAPsMAN +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md +# +# !! This is just a template! Replace '%PATH%' with 'caps-man', +# !! 'interface/wireless' or 'interface/wifiwave2'! + +:local 0 "capsman-download-packages%TEMPL%"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global CleanFilePath; +:global DownloadPackage; +:global LogPrintExit2; +:global MkDir; +:global ScriptLock; +:global WaitFullyConnected; + +$ScriptLock $0; +$WaitFullyConnected; + +:local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; +:local 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 [ /system/logging/find where topics~"error" !(topics~"!error") \ + !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ + $LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \ + "Probably can not download packages automatically.") false; +} else={ + :if ($Updated = false && [ /system/resource/get uptime ] < 2m) do={ + $LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false; + :delay 2m; + } +} + +:foreach Log in=[ /log/find where topics=({"caps"; "error"}) \ + message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \ + "-.*\\.npk', no such file") ] do={ + :local Message [ /log/get $Log message ]; + :local Package [ :pick $Message \ + ([ :find $Message "'" ] + 1) \ + [ :find $Message ("-" . $InstalledVersion . "-") ] ]; + :local Arch [ :pick $Message \ + ([ :find $Message ("-" . $InstalledVersion . "-") ] + 2 + [ :len $InstalledVersion ]) \ + [ :find $Message ".npk" ] ]; + :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ + :set Updated true; + } +} + +:if ($Updated = true) do={ + :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); + :if ([ :len $Script ] > 0) do={ + /system/script/run $Script; + } else={ + /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; + /interface/wifiwave2/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; + } +} diff --git a/capsman-download-packages.wifiwave2.rsc b/capsman-download-packages.wifiwave2.rsc new file mode 100644 index 0000000..817f7d9 --- /dev/null +++ b/capsman-download-packages.wifiwave2.rsc @@ -0,0 +1,89 @@ +#!rsc by RouterOS +# RouterOS script: capsman-download-packages.wifiwave2 +# Copyright (c) 2018-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# download and cleanup packages for CAP installation from CAPsMAN +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "capsman-download-packages.wifiwave2"; +: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 [ /system/logging/find where topics~"error" !(topics~"!error") \ + !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ + $LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \ + "Probably can not download packages automatically.") false; +} else={ + :if ($Updated = false && [ /system/resource/get uptime ] < 2m) do={ + $LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false; + :delay 2m; + } +} + +:foreach Log in=[ /log/find where topics=({"caps"; "error"}) \ + message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \ + "-.*\\.npk', no such file") ] do={ + :local Message [ /log/get $Log message ]; + :local Package [ :pick $Message \ + ([ :find $Message "'" ] + 1) \ + [ :find $Message ("-" . $InstalledVersion . "-") ] ]; + :local Arch [ :pick $Message \ + ([ :find $Message ("-" . $InstalledVersion . "-") ] + 2 + [ :len $InstalledVersion ]) \ + [ :find $Message ".npk" ] ]; + :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ + :set Updated true; + } +} + +:if ($Updated = true) do={ + :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 ]; + } +} diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index 58f84e8..ccf0f34 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -18,13 +18,25 @@ This script automatically downloads these packages. Requirements and installation ----------------------------- -Just install the script on CAPsMAN device: +Just install the script on CAPsMAN device. Depending on whether you use +`wifiwave2` package (`/interface/wifiwave2`) or legacy wifi with CAPsMAN +(`/caps-man`) you need to install a different script. - $ScriptInstallUpdate capsman-download-packages; +For `wifiwave2`: -Optionally add a scheduler to run after startup: + $ScriptInstallUpdate capsman-download-packages.wifiwave2; - /system/scheduler/add name=capsman-download-packages on-event="/system/script/run capsman-download-packages;" start-time=startup; +For legacy CAPsMAN: + + $ScriptInstallUpdate capsman-download-packages.capsman; + +Optionally add a scheduler to run after startup. For `wifiwave2`: + + /system/scheduler/add name=capsman-download-packages on-event="/system/script/run capsman-download-packages.wifiwave2;" start-time=startup; + +For legacy CAPsMAN: + + /system/scheduler/add name=capsman-download-packages on-event="/system/script/run capsman-download-packages.capsman;" start-time=startup; Packages available in local storage in older version are downloaded unconditionally. The script tries to download missing packages by guessing @@ -35,7 +47,7 @@ Usage and invocation Run the script manually: - /system/script/run capsman-download-packages; + /system/script/run capsman-download-packages.wifiwave2; ... or from scheduler. From e6964b4348aca7556ac9c16cffe89d5a2b78b4bf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Aug 2023 13:11:14 +0200 Subject: [PATCH 1585/2612] capsman-rolling-upgrade: convert to template, split capsman & wifiwave2 --- capsman-rolling-upgrade.capsman.rsc | 40 ++++++++++++++++++++++ capsman-rolling-upgrade.rsc | 37 +-------------------- capsman-rolling-upgrade.template.rsc | 48 +++++++++++++++++++++++++++ capsman-rolling-upgrade.wifiwave2.rsc | 41 +++++++++++++++++++++++ doc/capsman-rolling-upgrade.md | 14 ++++++-- 5 files changed, 141 insertions(+), 39 deletions(-) create mode 100644 capsman-rolling-upgrade.capsman.rsc create mode 100644 capsman-rolling-upgrade.template.rsc create mode 100644 capsman-rolling-upgrade.wifiwave2.rsc diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc new file mode 100644 index 0000000..7f83b6c --- /dev/null +++ b/capsman-rolling-upgrade.capsman.rsc @@ -0,0 +1,40 @@ +#!rsc by RouterOS +# RouterOS script: capsman-rolling-upgrade.capsman +# Copyright (c) 2018-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: capsman-rolling-upgrade +# +# 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 "capsman-rolling-upgrade.capsman"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global LogPrintExit2; +:global ScriptLock; + +$ScriptLock $0; + +:local InstalledVersion [ /system/package/update/get installed-version ]; + +:local RemoteCapCount [ :len [ /caps-man/remote-cap/find ] ]; +:if ($RemoteCapCount > 0) do={ + :local Delay (600 / $RemoteCapCount); + :if ($Delay > 120) do={ :set Delay 120; } + :foreach RemoteCap in=[ /caps-man/remote-cap/find where version!=$InstalledVersion ] do={ + :local RemoteCapVal [ /caps-man/remote-cap/get $RemoteCap ]; + :if ([ :len $RemoteCapVal ] > 1) do={ + $LogPrintExit2 info $0 ("Starting upgrade for " . $RemoteCapVal->"name" . \ + " (" . $RemoteCapVal->"identity" . ")...") false; + /caps-man/remote-cap/upgrade $RemoteCap; + } else={ + $LogPrintExit2 warning $0 ("Remote CAP vanished, skipping upgrade.") false; + } + :delay ($Delay . "s"); + } +} diff --git a/capsman-rolling-upgrade.rsc b/capsman-rolling-upgrade.rsc index 91a6400..2da00ca 100644 --- a/capsman-rolling-upgrade.rsc +++ b/capsman-rolling-upgrade.rsc @@ -1,38 +1,3 @@ #!rsc by RouterOS -# RouterOS script: capsman-rolling-upgrade -# Copyright (c) 2018-2023 Christian Hesse -# Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: capsman-rolling-upgrade -# -# upgrade CAPs one after another -# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md - -:local 0 "capsman-rolling-upgrade"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; -:global ScriptLock; - -$ScriptLock $0; - -:local InstalledVersion [ /system/package/update/get installed-version ]; - -:local RemoteCapCount [ :len [ /caps-man/remote-cap/find ] ]; -:if ($RemoteCapCount > 0) do={ - :local Delay (600 / $RemoteCapCount); - :if ($Delay > 120) do={ :set Delay 120; } - :foreach RemoteCap in=[ /caps-man/remote-cap/find where version!=$InstalledVersion ] do={ - :local RemoteCapVal [ /caps-man/remote-cap/get $RemoteCap ]; - :if ([ :len $RemoteCapVal ] > 1) do={ - $LogPrintExit2 info $0 ("Starting upgrade for " . $RemoteCapVal->"name" . \ - " (" . $RemoteCapVal->"identity" . ")...") false; - /caps-man/remote-cap/upgrade $RemoteCap; - } else={ - $LogPrintExit2 warning $0 ("Remote CAP vanished, skipping upgrade.") false; - } - :delay ($Delay . "s"); - } -} +# dummy for migration diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc new file mode 100644 index 0000000..0890ad2 --- /dev/null +++ b/capsman-rolling-upgrade.template.rsc @@ -0,0 +1,48 @@ +#!rsc by RouterOS +# RouterOS script: capsman-rolling-upgrade%TEMPL% +# Copyright (c) 2018-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: capsman-rolling-upgrade +# +# upgrade CAPs one after another +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md +# +# !! This is just a template! Replace '%PATH%' with 'caps-man', +# !! 'interface/wireless' or 'interface/wifiwave2'! + +:local 0 "capsman-rolling-upgrade%TEMPL%"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global LogPrintExit2; +:global ScriptLock; + +$ScriptLock $0; + +:local InstalledVersion [ /system/package/update/get installed-version ]; + +:local RemoteCapCount [ :len [ /caps-man/remote-cap/find ] ]; +: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/wifiwave2/capsman/remote-cap/find where version!=$InstalledVersion ] do={ + :local RemoteCapVal [ /caps-man/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/wifiwave2/capsman/remote-cap/upgrade $RemoteCap; + } else={ + $LogPrintExit2 warning $0 ("Remote CAP vanished, skipping upgrade.") false; + } + :delay ($Delay . "s"); + } +} diff --git a/capsman-rolling-upgrade.wifiwave2.rsc b/capsman-rolling-upgrade.wifiwave2.rsc new file mode 100644 index 0000000..c0c08e7 --- /dev/null +++ b/capsman-rolling-upgrade.wifiwave2.rsc @@ -0,0 +1,41 @@ +#!rsc by RouterOS +# RouterOS script: capsman-rolling-upgrade.wifiwave2 +# Copyright (c) 2018-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: capsman-rolling-upgrade +# +# 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 "capsman-rolling-upgrade.wifiwave2"; +: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"); + } +} diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index d146adf..5c038e9 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -20,9 +20,17 @@ parallel. Requirements and installation ----------------------------- -Just install the script: +Just install the script on CAPsMAN device. Depending on whether you use +`wifiwave2` package (`/interface/wifiwave2`) or legacy wifi with CAPsMAN +(`/caps-man`) you need to install a different script. - $ScriptInstallUpdate capsman-rolling-upgrade; +For `wifiwave2`: + + $ScriptInstallUpdate capsman-rolling-upgrade.wifiwave2; + +For legacy CAPsMAN: + + $ScriptInstallUpdate capsman-rolling-upgrade.capsman; Usage and invocation -------------------- @@ -33,7 +41,7 @@ that script when required. Alternatively run it manually: - /system/script/run capsman-rolling-upgrade; + /system/script/run capsman-rolling-upgrade.wifiwave2; See also -------- From 8428ba890da07417bf5ee58deaa0a04a8fb18f30 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Aug 2023 16:40:05 +0200 Subject: [PATCH 1586/2612] Makefile: support excluding blocks from templates --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 547fe10..100aa78 100644 --- a/Makefile +++ b/Makefile @@ -16,16 +16,19 @@ all: $(CAPSMAN) $(LOCAL) $(WIFIWAVE2) $(HTML) %.local.rsc: %.template.rsc Makefile sed -e '/\/caps-man/d' -e '/\/interface\/wifiwave2/d' -e 's|%TEMPL%|.local|' \ + -e '/^# NOT \/interface\/wireless #$$/,/^# NOT \/interface\/wireless #$$/d' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ %.capsman.rsc: %.template.rsc Makefile sed -e '/\/interface\/wifiwave2/d' -e '/\/interface\/wireless/d' -e 's|%TEMPL%|.capsman|' \ + -e '/^# NOT \/caps-man #$$/,/^# NOT \/caps-man #$$/d' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ %.wifiwave2.rsc: %.template.rsc Makefile sed -e '/\/caps-man/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!' \ < $< > $@ From 3cab917a61cb84b08f99bd7b4a7b59b1a41024ac Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Aug 2023 16:44:26 +0200 Subject: [PATCH 1587/2612] capsman-download-packages: no download of missing package for wifiwave2 Sadly the log messages from wifiwave2 do not contain any hint what is missing... So it's not possible to download missing files. --- capsman-download-packages.template.rsc | 2 ++ capsman-download-packages.wifiwave2.rsc | 26 ------------------------- doc/capsman-download-packages.md | 6 ++++-- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index baa8fc4..4b52569 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -55,6 +55,7 @@ $WaitFullyConnected; } } +# NOT /interface/wifiwave2 # :if ([ :len [ /system/logging/find where topics~"error" !(topics~"!error") \ !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ $LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \ @@ -81,6 +82,7 @@ $WaitFullyConnected; } } +# NOT /interface/wifiwave2 # :if ($Updated = true) do={ :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); :if ([ :len $Script ] > 0) do={ diff --git a/capsman-download-packages.wifiwave2.rsc b/capsman-download-packages.wifiwave2.rsc index 817f7d9..af8b8e5 100644 --- a/capsman-download-packages.wifiwave2.rsc +++ b/capsman-download-packages.wifiwave2.rsc @@ -53,32 +53,6 @@ $WaitFullyConnected; } } -:if ([ :len [ /system/logging/find where topics~"error" !(topics~"!error") \ - !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ - $LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \ - "Probably can not download packages automatically.") false; -} else={ - :if ($Updated = false && [ /system/resource/get uptime ] < 2m) do={ - $LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false; - :delay 2m; - } -} - -:foreach Log in=[ /log/find where topics=({"caps"; "error"}) \ - message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \ - "-.*\\.npk', no such file") ] do={ - :local Message [ /log/get $Log message ]; - :local Package [ :pick $Message \ - ([ :find $Message "'" ] + 1) \ - [ :find $Message ("-" . $InstalledVersion . "-") ] ]; - :local Arch [ :pick $Message \ - ([ :find $Message ("-" . $InstalledVersion . "-") ] + 2 + [ :len $InstalledVersion ]) \ - [ :find $Message ".npk" ] ]; - :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ - :set Updated true; - } -} - :if ($Updated = true) do={ :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); :if ([ :len $Script ] > 0) do={ diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index ccf0f34..d9c76c0 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -39,8 +39,10 @@ For legacy CAPsMAN: /system/scheduler/add name=capsman-download-packages on-event="/system/script/run capsman-download-packages.capsman;" start-time=startup; Packages available in local storage in older version are downloaded -unconditionally. The script tries to download missing packages by guessing -from system log. +unconditionally. + +If no packages are found the script tries to download missing packages for +legacy CAPsMAN by guessing from system log. Usage and invocation -------------------- From d0ab951e3fbc2b4a82671e6844389068ef377549 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Aug 2023 17:16:03 +0200 Subject: [PATCH 1588/2612] capsman-download-packages: download a default set for wifiwave2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Well, AX devices can be arm or arm64... So let's just download packages 'routeros' and 'wifiwave2' - crossing fingers... 🤞 --- capsman-download-packages.template.rsc | 14 +++++++++++++- capsman-download-packages.wifiwave2.rsc | 11 +++++++++++ doc/capsman-download-packages.md | 3 ++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 4b52569..71bced0 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -81,8 +81,20 @@ $WaitFullyConnected; :set Updated true; } } - # NOT /interface/wifiwave2 # +# NOT /caps-man # +: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; + } + } + } +} +# NOT /caps-man # + :if ($Updated = true) do={ :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); :if ([ :len $Script ] > 0) do={ diff --git a/capsman-download-packages.wifiwave2.rsc b/capsman-download-packages.wifiwave2.rsc index af8b8e5..6a12b2d 100644 --- a/capsman-download-packages.wifiwave2.rsc +++ b/capsman-download-packages.wifiwave2.rsc @@ -53,6 +53,17 @@ $WaitFullyConnected; } } +: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={ diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index d9c76c0..8174c13 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -42,7 +42,8 @@ Packages available in local storage in older version are downloaded unconditionally. If no packages are found the script tries to download missing packages for -legacy CAPsMAN by guessing from system log. +legacy CAPsMAN by guessing from system log. For `wifiwave2` a default set +of packages (`routeros` and `wifiwave2` for *arm* and *arm64*) is downloaded. Usage and invocation -------------------- From d086e4a05f1a766d849955f375b4b4a9cf1c2b39 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Aug 2023 22:13:34 +0200 Subject: [PATCH 1589/2612] accesslist-duplicates: add support for wifiwave2 --- accesslist-duplicates.template.rsc | 4 +++ accesslist-duplicates.wifiwave2.rsc | 42 +++++++++++++++++++++++++++++ doc/accesslist-duplicates.md | 13 ++++++--- 3 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 accesslist-duplicates.wifiwave2.rsc diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index b01c90d..85d444e 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -19,8 +19,10 @@ :local Shown ({}); :foreach AccList in=[ /caps-man/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/wifiwave2/access-list/get $AccList mac-address ]; :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; :foreach SeenMac in=$Seen do={ :if ($SeenMac = $Mac) do={ @@ -30,6 +32,7 @@ } :if ($Skip = 0) do={ /caps-man/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; :set Shown ($Shown, $Mac); @@ -38,6 +41,7 @@ :if ([ :typeof $Remove ] = "num") do={ :put ("Removing numeric id " . $Remove . "...\n"); /caps-man/access-list/remove $Remove; + /interface/wifiwave2/access-list/remove $Remove; /interface/wireless/access-list/remove $Remove; } } diff --git a/accesslist-duplicates.wifiwave2.rsc b/accesslist-duplicates.wifiwave2.rsc new file mode 100644 index 0000000..7c0ecf4 --- /dev/null +++ b/accesslist-duplicates.wifiwave2.rsc @@ -0,0 +1,42 @@ +#!rsc by RouterOS +# RouterOS script: accesslist-duplicates.wifiwave2 +# Copyright (c) 2018-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# print duplicate antries in wireless access list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "accesslist-duplicates.wifiwave2"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Read; + +:local Seen ({}); +:local Shown ({}); + +: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 ]; + :foreach SeenMac in=$Seen do={ + :if ($SeenMac = $Mac) do={ + :local Skip 0; + :foreach ShownMac in=$Shown do={ + :if ($ShownMac = $Mac) do={ :set Skip 1; } + } + :if ($Skip = 0) do={ + /interface/wifiwave2/access-list/print where mac-address=$Mac; + :set Shown ($Shown, $Mac); + + :put "\nNumeric id to remove, any key to skip!"; + :local Remove [ :tonum [ $Read ] ]; + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /interface/wifiwave2/access-list/remove $Remove; + } + } + } + } + :set Seen ($Seen, $Mac); +} diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index c59aebf..e3767e7 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -15,14 +15,19 @@ entries in wireless access list. Requirements and installation ----------------------------- -Depending on whether you use CAPsMAN (`/caps-man`) or local wireless -interface (`/interface/wireless`) you need to install a different script. +Depending on whether you use `wifiwave2` package (`/interface/wifiwave2`) +or legacy wifi with CAPsMAN (`/caps-man`) or local wireless interface +(`/interface/wireless`) you need to install a different script. -For CAPsMAN: +For `wifiwave2`: + + $ScriptInstallUpdate accesslist-duplicates.wifiwave2; + +For legacy CAPsMAN: $ScriptInstallUpdate accesslist-duplicates.capsman; -For local interface: +For legacy local interface: $ScriptInstallUpdate accesslist-duplicates.local; From bac4a460f076b1c2a045e4aefbe3f7ff2eaec44a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Aug 2023 22:17:30 +0200 Subject: [PATCH 1590/2612] collect-wireless-mac: add support for wifiwave2 --- collect-wireless-mac.template.rsc | 8 +++ collect-wireless-mac.wifiwave2.rsc | 86 ++++++++++++++++++++++++++++++ doc/collect-wireless-mac.md | 13 +++-- 3 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 collect-wireless-mac.wifiwave2.rsc diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index b3618ee..df6b831 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -28,19 +28,24 @@ $ScriptLock $0 false 10; :if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ +: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/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/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/wifiwave2/registration-table/find ] do={ :foreach Reg in=[ /interface/wireless/registration-table/find ] do={ :local RegVal; :do { :set RegVal [ /caps-man/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; @@ -48,10 +53,12 @@ $ScriptLock $0 false 10; :if ([ :len ($RegVal->"mac-address") ] > 0) do={ :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); + :local AccessList ([ /interface/wifiwave2/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ [ /caps-man/access-list/get $AccessList comment ]) false; + [ /interface/wifiwave2/access-list/get $AccessList comment ]) false; [ /interface/wireless/access-list/get $AccessList comment ]) false; } @@ -76,6 +83,7 @@ $ScriptLock $0 false 10; "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/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"); \ diff --git a/collect-wireless-mac.wifiwave2.rsc b/collect-wireless-mac.wifiwave2.rsc new file mode 100644 index 0000000..42713a6 --- /dev/null +++ b/collect-wireless-mac.wifiwave2.rsc @@ -0,0 +1,86 @@ +#!rsc by RouterOS +# RouterOS script: collect-wireless-mac.wifiwave2 +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=40 +# +# 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 "collect-wireless-mac.wifiwave2"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global Identity; + +:global EitherOr; +:global FormatLine; +: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 ]; + } + } + :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" . \ + [ $FormatLine "DNS name" $DnsName ] . "\n" . \ + [ $FormatLine "Date" $DateTime ]) }); + } + } else={ + $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; + } +} diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index dd3743f..9ba1e3a 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -22,14 +22,19 @@ and modify it to your needs. Requirements and installation ----------------------------- -Depending on whether you use CAPsMAN (`/caps-man`) or local wireless -interface (`/interface/wireless`) you need to install a different script. +Depending on whether you use `wifiwave2` package (`/interface/wifiwave2`) +or legacy wifi with CAPsMAN (`/caps-man`) or local wireless interface +(`/interface/wireless`) you need to install a different script. -For CAPsMAN: +For `wifiwave2`: + + $ScriptInstallUpdate collect-wireless-mac.capsman.wifiwave2; + +For legacy CAPsMAN: $ScriptInstallUpdate collect-wireless-mac.capsman; -For local interface: +For legacy local interface: $ScriptInstallUpdate collect-wireless-mac.local; From 6d76704a97b7662aec51a45616a63f47e66c5b8f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Aug 2023 22:20:31 +0200 Subject: [PATCH 1591/2612] dhcp-lease-comment: add support for wifiwave2 --- dhcp-lease-comment.template.rsc | 2 ++ dhcp-lease-comment.wifiwave2.rsc | 33 ++++++++++++++++++++++++++++++++ doc/dhcp-lease-comment.md | 13 +++++++++---- 3 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 dhcp-lease-comment.wifiwave2.rsc diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index 3fe9b64..0f16285 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -24,9 +24,11 @@ $ScriptLock $0; :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/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/wifiwave2/access-list/get $AccessList comment ]; :set NewComment [ /interface/wireless/access-list/get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ diff --git a/dhcp-lease-comment.wifiwave2.rsc b/dhcp-lease-comment.wifiwave2.rsc new file mode 100644 index 0000000..200c53b --- /dev/null +++ b/dhcp-lease-comment.wifiwave2.rsc @@ -0,0 +1,33 @@ +#!rsc by RouterOS +# RouterOS script: dhcp-lease-comment.wifiwave2 +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=60 +# +# update dhcp-server lease comment with infos from access-list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "dhcp-lease-comment.wifiwave2"; +: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; + } +} diff --git a/doc/dhcp-lease-comment.md b/doc/dhcp-lease-comment.md index 4add0b8..cd29641 100644 --- a/doc/dhcp-lease-comment.md +++ b/doc/dhcp-lease-comment.md @@ -15,14 +15,19 @@ from wireless access list. Requirements and installation ----------------------------- -Depending on whether you use CAPsMAN (`/caps-man`) or local wireless -interface (`/interface/wireless`) you need to install a different script. +Depending on whether you use `wifiwave2` package (`/interface/wifiwave2`) +or legacy wifi with CAPsMAN (`/caps-man`) or local wireless interface +(`/interface/wireless`) you need to install a different script. -For CAPsMAN: +For `wifiwave2`: + + $ScriptInstallUpdate dhcp-lease-comment.wifiwave2; + +For legacy CAPsMAN: $ScriptInstallUpdate dhcp-lease-comment.capsman; -For local interface: +For legacy local interface: $ScriptInstallUpdate dhcp-lease-comment.local; From 8ce1683733ab08b8a83b8837e6880f972f6aa324 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 8 Aug 2023 23:49:02 +0200 Subject: [PATCH 1592/2612] daily-psk: add support for wifiwave2 --- daily-psk.template.rsc | 9 ++++- daily-psk.wifiwave2.rsc | 90 +++++++++++++++++++++++++++++++++++++++++ doc/daily-psk.md | 25 ++++++++---- 3 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 daily-psk.wifiwave2.rsc diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index ea0fb46..125e6c5 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -56,12 +56,17 @@ $WaitFullyConnected; :local NewPsk [ $GeneratePSK $Date ]; :foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ +:foreach AccList in=[ /interface/wifiwave2/access-list/find where comment~$DailyPskMatchComment ] do={ :foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; + :local SsidRegExp [ /interface/wifiwave2/access-list/get $AccList ssid-regexp ]; :local Configuration ([ /caps-man/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/wifiwave2/configuration/get $Configuration ssid ]; :local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ]; - # /caps-man above - /interface/wireless below + :local OldPsk [ /interface/wifiwave2/access-list/get $AccList passphrase ]; + # /caps-man /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 ]; @@ -70,9 +75,11 @@ $WaitFullyConnected; :if ($NewPsk != $OldPsk) do={ $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; /caps-man/access-list/set $AccList private-passphrase=$NewPsk; + /interface/wifiwave2/access-list/set $AccList passphrase=$NewPsk; /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ + :if ([ :len [ /interface/wifiwave2/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ diff --git a/daily-psk.wifiwave2.rsc b/daily-psk.wifiwave2.rsc new file mode 100644 index 0000000..40c79cd --- /dev/null +++ b/daily-psk.wifiwave2.rsc @@ -0,0 +1,90 @@ +#!rsc by RouterOS +# RouterOS script: daily-psk.wifiwave2 +# Copyright (c) 2013-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update daily PSK (pre shared key) +# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "daily-psk.wifiwave2"; +: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={ + :foreach SeenSsid in=$Seen do={ + :if ($SeenSsid = $Ssid) do={ + $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; + :set Skip 1; + } + } + + :if ($Skip = 0) do={ + :set Seen ($Seen, $Ssid); + :local Link ($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 }); + } + } + } +} diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 9a5e558..60a645f 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -21,17 +21,24 @@ Requirements and installation Just install this script. -Depending on whether you use CAPsMAN (`/caps-man`) or local wireless -interface (`/interface/wireless`) you need to install a different script -and add schedulers to run the script: +Depending on whether you use `wifiwave2` package (`/interface/wifiwave2`) +or legacy wifi with CAPsMAN (`/caps-man`) or local wireless interface +(`/interface/wireless`) you need to install a different script and add +schedulers to run the script: -For CAPsMAN: +For `wifiwave2`: + + $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: $ScriptInstallUpdate daily-psk.capsman; /system/scheduler/add interval=1d name=daily-psk on-event="/system/script/run daily-psk.capsman;" start-time=03:00:00; /system/scheduler/add name=daily-psk@startup on-event="/system/script/run daily-psk.capsman;" start-time=startup; -For local interface: +For legacy local interface: $ScriptInstallUpdate daily-psk.local; /system/scheduler/add interval=1d name=daily-psk on-event="/system/script/run daily-psk.local;" start-time=03:00:00; @@ -51,11 +58,15 @@ The configuration goes to `global-config-overlay`, these are the parameters: > [`global-config`](../global-config.rsc) (the one without `-overlay`) to > your local `global-config-overlay` and modify it to your specific needs. -Then add an access list entry. For CAPsMAN: +Then add an access list entry. For `wifiwave2`: + + /interface/wifiwave2/access-list/add comment="Daily PSK" ssid-regexp="-guest\$" passphrase="ToBeChangedDaily"; + +For legacy CAPsMAN: /caps-man/access-list/add comment="Daily PSK" ssid-regexp="-guest\$" private-passphrase="ToBeChangedDaily"; -For local interface: +For legacy local interface: /interface/wireless/access-list/add comment="Daily PSK" interface=wl-daily private-pre-shared-key="ToBeChangedDaily"; From 6552b0c02d23b39e4364be3cda5e0a2eb6a306c9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 9 Aug 2023 00:55:30 +0200 Subject: [PATCH 1593/2612] hotspot-to-wpa: convert to template, split capsman & wifiwave2 --- doc/hotspot-to-wpa.md | 34 ++++++--- hotspot-to-wpa-cleanup.capsman.rsc | 68 +++++++++++++++++ hotspot-to-wpa-cleanup.rsc | 65 +--------------- hotspot-to-wpa-cleanup.template.rsc | 75 ++++++++++++++++++ hotspot-to-wpa-cleanup.wifiwave2.rsc | 68 +++++++++++++++++ hotspot-to-wpa.capsman.rsc | 89 ++++++++++++++++++++++ hotspot-to-wpa.rsc | 86 +-------------------- hotspot-to-wpa.template.rsc | 110 +++++++++++++++++++++++++++ hotspot-to-wpa.wifiwave2.rsc | 86 +++++++++++++++++++++ 9 files changed, 523 insertions(+), 158 deletions(-) create mode 100644 hotspot-to-wpa-cleanup.capsman.rsc create mode 100644 hotspot-to-wpa-cleanup.template.rsc create mode 100644 hotspot-to-wpa-cleanup.wifiwave2.rsc create mode 100644 hotspot-to-wpa.capsman.rsc create mode 100644 hotspot-to-wpa.template.rsc create mode 100644 hotspot-to-wpa.wifiwave2.rsc diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index 2630694..4909eef 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -19,24 +19,35 @@ Requirements and installation You need a properly configured hotspot on one (open) SSID and a WP2 enabled SSID with suffix "`-wpa`". -Then install the script: +Then install the script. Depending on whether you use `wifiwave2` package +(`/interface/wifiwave2`) or legacy wifi with CAPsMAN (`/caps-man`) you need +to install a different script and set it as `on-login` script in hotspot. - $ScriptInstallUpdate hotspot-to-wpa; +For `wifiwave2`: -Configure your hotspot to use this script as `on-login` script: + $ScriptInstallUpdate hotspot-to-wpa.wifiwave2; + /ip/hotspot/user/profile/set on-login="hotspot-to-wpa.wifiwave2" [ find ]; - /ip/hotspot/user/profile/set on-login=hotspot-to-wpa [ find ]; +For legacy CAPsMAN: + + $ScriptInstallUpdate hotspot-to-wpa.capsman; + /ip/hotspot/user/profile/set on-login="hotspot-to-wpa.capsman" [ find ]; ### Automatic cleanup With just `hotspot-to-wpa` installed the mac addresses will last in the -access list forever. Install the optional script for automatic cleanup: +access list forever. Install the optional script for automatic cleanup +and add a scheduler. - $ScriptInstallUpdate hotspot-to-wpa-cleanup,lease-script; +For `wifiwave2`: -Create a scheduler: + $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; - /system/scheduler/add interval=1d name=hotspot-to-wpa-cleanup on-event="/system/script/run hotspot-to-wpa-cleanup;" start-time=startup; +For legacy CAPsMAN: + + $ScriptInstallUpdate hotspot-to-wpa-cleanup.capsman,lease-script; + /system/scheduler/add interval=1d name=hotspot-to-wpa-cleanup on-event="/system/script/run hotspot-to-wpa-cleanup.capsman;" start-time=startup; And add the lease script and matcher comment to your wpa interfaces' dhcp server. You can add more information to the comment, separated by comma. In @@ -74,7 +85,12 @@ Additionally templates can be created to give more options for access list: * `vlan-id`: connect device to specific VLAN * `vlan-mode`: set the VLAN mode for device -For a hotspot called `example` the template could look like this: +For a hotspot called `example` the template could look like this. For +`wifiwave2`: + + /interface/wifiwave2/access-list/add comment="hotspot-to-wpa template example" disabled=yes private-passphrase="ignore" ssid-regexp="^example\$" vlan-id=10; + +For legacy CAPsMAN: /caps-man/access-list/add comment="hotspot-to-wpa template example" disabled=yes private-passphrase="ignore" ssid-regexp="^example\$" vlan-id=10 vlan-mode=use-tag; diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc new file mode 100644 index 0000000..5bded2c --- /dev/null +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -0,0 +1,68 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa-cleanup.capsman +# Copyright (c) 2021-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=80 +# +# manage and clean up private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "hotspot-to-wpa-cleanup.capsman"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global EitherOr; +:global LogPrintExit2; +:global ParseKeyValueStore; +:global ScriptLock; + +$ScriptLock $0 false 10; + +:local DHCPServers ({}); +:foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ + :local ServerVal [ /ip/dhcp-server/get $Server ] + :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; + :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ + :set ($DHCPServers->($ServerVal->"name")) \ + [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; + } +} + +:foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ + :local ClientVal [ /caps-man/registration-table/get $Client ]; + :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ + mac-address=($ClientVal->"mac-address") ] do={ + :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ + $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ + " connected to WPA, making lease static.") false; + /ip/dhcp-server/lease/make-static $Lease; + /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; + } + } +} + +:foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \ + !(comment~[ /system/clock/get date ]) ] do={ + :local ClientVal [ /caps-man/access-list/get $Client ]; + :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ + mac-address=($ClientVal->"mac-address") ] ] = 0) do={ + $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ + " did not connect to WPA, removing from access list.") false; + /caps-man/access-list/remove $Client; + } +} + +:foreach 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 ]; + $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ + " was not seen for " . $Timeout . ", removing.") false; + /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ + mac-address=($LeaseVal->"mac-address") ]; + /ip/dhcp-server/lease/remove $Lease; + } +} diff --git a/hotspot-to-wpa-cleanup.rsc b/hotspot-to-wpa-cleanup.rsc index adb0abb..2da00ca 100644 --- a/hotspot-to-wpa-cleanup.rsc +++ b/hotspot-to-wpa-cleanup.rsc @@ -1,66 +1,3 @@ #!rsc by RouterOS -# RouterOS script: hotspot-to-wpa-cleanup -# Copyright (c) 2021-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: lease-script, order=80 -# -# manage and clean up private WPA passphrase after hotspot login -# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md - -:local 0 "hotspot-to-wpa-cleanup"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; - -$ScriptLock $0 false 10; - -:local DHCPServers ({}); -:foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ - :local ServerVal [ /ip/dhcp-server/get $Server ] - :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; - :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ - :set ($DHCPServers->($ServerVal->"name")) \ - [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; - } -} - -:foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ - :local ClientVal [ /caps-man/registration-table/get $Client ]; - :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ - mac-address=($ClientVal->"mac-address") ] do={ - :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static.") false; - /ip/dhcp-server/lease/make-static $Lease; - /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; - } - } -} - -:foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \ - !(comment~[ /system/clock/get date ]) ] do={ - :local ClientVal [ /caps-man/access-list/get $Client ]; - :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ - mac-address=($ClientVal->"mac-address") ] ] = 0) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " did not connect to WPA, removing from access list.") false; - /caps-man/access-list/remove $Client; - } -} - -:foreach 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 ]; - $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . $Timeout . ", removing.") false; - /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - mac-address=($LeaseVal->"mac-address") ]; - /ip/dhcp-server/lease/remove $Lease; - } -} +# dummy for migration diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc new file mode 100644 index 0000000..38313d9 --- /dev/null +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -0,0 +1,75 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa-cleanup%TEMPL% +# Copyright (c) 2021-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=80 +# +# manage and clean up private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# +# !! This is just a template to generate the real script! +# !! Pattern '%TEMPL%' is replaced, paths are filtered. + +:local 0 "hotspot-to-wpa-cleanup%TEMPL%"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global EitherOr; +:global LogPrintExit2; +:global ParseKeyValueStore; +:global ScriptLock; + +$ScriptLock $0 false 10; + +:local DHCPServers ({}); +:foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ + :local ServerVal [ /ip/dhcp-server/get $Server ] + :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; + :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ + :set ($DHCPServers->($ServerVal->"name")) \ + [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; + } +} + +:foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ +:foreach Client in=[ /interface/wifiwave2/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ + :local ClientVal [ /caps-man/registration-table/get $Client ]; + :local ClientVal [ /interface/wifiwave2/registration-table/get $Client ]; + :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ + mac-address=($ClientVal->"mac-address") ] do={ + :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ + $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ + " connected to WPA, making lease static.") false; + /ip/dhcp-server/lease/make-static $Lease; + /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; + } + } +} + +:foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \ +:foreach Client in=[ /interface/wifiwave2/access-list/find where comment~"^hotspot-to-wpa:" \ + !(comment~[ /system/clock/get date ]) ] do={ + :local ClientVal [ /caps-man/access-list/get $Client ]; + :local ClientVal [ /interface/wifiwave2/access-list/get $Client ]; + :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ + mac-address=($ClientVal->"mac-address") ] ] = 0) do={ + $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ + " did not connect to WPA, removing from access list.") false; + /caps-man/access-list/remove $Client; + /interface/wifiwave2/access-list/remove $Client; + } +} + +:foreach Server,Timeout in=$DHCPServers do={ + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ + server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ + " was not seen for " . $Timeout . ", removing.") false; + /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ + /interface/wifiwave2/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ + mac-address=($LeaseVal->"mac-address") ]; + /ip/dhcp-server/lease/remove $Lease; + } +} diff --git a/hotspot-to-wpa-cleanup.wifiwave2.rsc b/hotspot-to-wpa-cleanup.wifiwave2.rsc new file mode 100644 index 0000000..a8ba34c --- /dev/null +++ b/hotspot-to-wpa-cleanup.wifiwave2.rsc @@ -0,0 +1,68 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa-cleanup.wifiwave2 +# Copyright (c) 2021-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=80 +# +# manage and clean up private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "hotspot-to-wpa-cleanup.wifiwave2"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global EitherOr; +:global LogPrintExit2; +:global ParseKeyValueStore; +:global ScriptLock; + +$ScriptLock $0 false 10; + +:local DHCPServers ({}); +:foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ + :local ServerVal [ /ip/dhcp-server/get $Server ] + :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; + :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ + :set ($DHCPServers->($ServerVal->"name")) \ + [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; + } +} + +:foreach Client in=[ /interface/wifiwave2/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ + :local ClientVal [ /interface/wifiwave2/registration-table/get $Client ]; + :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ + mac-address=($ClientVal->"mac-address") ] do={ + :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ + $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ + " connected to WPA, making lease static.") false; + /ip/dhcp-server/lease/make-static $Lease; + /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; + } + } +} + +:foreach Client in=[ /interface/wifiwave2/access-list/find where comment~"^hotspot-to-wpa:" \ + !(comment~[ /system/clock/get date ]) ] do={ + :local ClientVal [ /interface/wifiwave2/access-list/get $Client ]; + :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ + mac-address=($ClientVal->"mac-address") ] ] = 0) do={ + $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ + " did not connect to WPA, removing from access list.") false; + /interface/wifiwave2/access-list/remove $Client; + } +} + +:foreach Server,Timeout in=$DHCPServers do={ + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ + server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ + " was not seen for " . $Timeout . ", removing.") false; + /interface/wifiwave2/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ + mac-address=($LeaseVal->"mac-address") ]; + /ip/dhcp-server/lease/remove $Lease; + } +} diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc new file mode 100644 index 0000000..a7ebafb --- /dev/null +++ b/hotspot-to-wpa.capsman.rsc @@ -0,0 +1,89 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa.capsman +# Copyright (c) 2019-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# add private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "hotspot-to-wpa.capsman"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global EitherOr; +:global LogPrintExit2; +:global ParseKeyValueStore; +:global ScriptLock; + +$ScriptLock $0; + +:local MacAddress $"mac-address"; +:local UserName $username; + +:if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ + $LogPrintExit2 error $0 ("This script is supposed to run from hotspot on login.") true; +} + +:local Date [ /system/clock/get date ]; +:local UserVal ({}); +:if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ + :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; +} +:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; +:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; + +:if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; +} +:local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + +:if ([ :len [ /caps-man/access-list/find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ + /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; +} +:local Template [ /caps-man/access-list/get ([ find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; + +:if ($Template->"action" = "reject") do={ + $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; +} + +# allow login page to load +:delay 1s; + +$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ").") false; +/caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; +/caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + action=reject place-before=$PlaceBefore; + +:local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ + comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; +:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; +:if ([ :len $PrivatePassphrase ] > 0) do={ + :if ($PrivatePassphrase = "ignore") do={ + /caps-man/access-list/set $Entry !private-passphrase; + } else={ + /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; + } +} +:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; +:if ([ :len $SsidRegexp ] > 0) do={ + /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; +} +:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; +:if ([ :len $VlanId ] > 0) do={ + /caps-man/access-list/set $Entry vlan-id=$VlanId; +} +:local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; +:if ([ :len $VlanMode] > 0) do={ + /caps-man/access-list/set $Entry vlan-mode=$VlanMode; +} + +:delay 2s; +/caps-man/access-list/set $Entry action=accept; diff --git a/hotspot-to-wpa.rsc b/hotspot-to-wpa.rsc index 35d4fa5..2da00ca 100644 --- a/hotspot-to-wpa.rsc +++ b/hotspot-to-wpa.rsc @@ -1,87 +1,3 @@ #!rsc by RouterOS -# RouterOS script: hotspot-to-wpa -# Copyright (c) 2019-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# add private WPA passphrase after hotspot login -# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md - -:local 0 "hotspot-to-wpa"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; - -$ScriptLock $0; - -:local MacAddress $"mac-address"; -:local UserName $username; - -:if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from hotspot on login.") true; -} - -:local Date [ /system/clock/get date ]; -:local UserVal ({}); -:if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ - :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; -} -:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; -:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; - -:if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; -} -:local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - -:if ([ :len [ /caps-man/access-list/find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; -} -:local Template [ /caps-man/access-list/get ([ find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; - -:if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; -} - -# allow login page to load -:delay 1s; - -$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ").") false; -/caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; -/caps-man/access-list/add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - mac-address=$MacAddress private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - action=reject place-before=$PlaceBefore; - -:local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ - comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; -:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; -:if ([ :len $PrivatePassphrase ] > 0) do={ - :if ($PrivatePassphrase = "ignore") do={ - /caps-man/access-list/set $Entry !private-passphrase; - } else={ - /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; - } -} -:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; -:if ([ :len $SsidRegexp ] > 0) do={ - /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; -} -:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; -:if ([ :len $VlanId ] > 0) do={ - /caps-man/access-list/set $Entry vlan-id=$VlanId; -} -:local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; -:if ([ :len $VlanMode] > 0) do={ - /caps-man/access-list/set $Entry vlan-mode=$VlanMode; -} - -:delay 2s; -/caps-man/access-list/set $Entry action=accept; +# dummy for migration diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc new file mode 100644 index 0000000..f465722 --- /dev/null +++ b/hotspot-to-wpa.template.rsc @@ -0,0 +1,110 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa%TEMPL% +# Copyright (c) 2019-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# add private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# +# !! This is just a template to generate the real script! +# !! Pattern '%TEMPL%' is replaced, paths are filtered. + +:local 0 "hotspot-to-wpa%TEMPL%"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global EitherOr; +:global LogPrintExit2; +:global ParseKeyValueStore; +:global ScriptLock; + +$ScriptLock $0; + +:local MacAddress $"mac-address"; +:local UserName $username; + +:if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ + $LogPrintExit2 error $0 ("This script is supposed to run from hotspot on login.") true; +} + +:local Date [ /system/clock/get date ]; +:local UserVal ({}); +:if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ + :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; +} +:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; +:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; + +:if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ +:if ([ :len [ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + /interface/wifiwave2/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; +} +:local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); +:local PlaceBefore ([ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + +:if ([ :len [ /caps-man/access-list/find where \ +:if ([ :len [ /interface/wifiwave2/access-list/find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ + /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + /interface/wifiwave2/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; +} +:local Template [ /caps-man/access-list/get ([ find where \ +:local Template [ /interface/wifiwave2/access-list/get ([ find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; + +:if ($Template->"action" = "reject") do={ + $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; +} + +# allow login page to load +:delay 1s; + +$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ").") false; +/caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; +/interface/wifiwave2/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; +/caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ +/interface/wifiwave2/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + action=reject place-before=$PlaceBefore; + +:local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ +:local Entry [ /interface/wifiwave2/access-list/find where mac-address=$MacAddress \ + comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; +# NOT /caps-man # +:set ($Template->"private-passphrase") ($Template->"passphrase"); +# NOT /caps-man # +:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; +:if ([ :len $PrivatePassphrase ] > 0) do={ + :if ($PrivatePassphrase = "ignore") do={ + /caps-man/access-list/set $Entry !private-passphrase; + /interface/wifiwave2/access-list/set $Entry !passphrase; + } else={ + /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; + /interface/wifiwave2/access-list/set $Entry passphrase=$PrivatePassphrase; + } +} +:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; +:if ([ :len $SsidRegexp ] > 0) do={ + /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; + /interface/wifiwave2/access-list/set $Entry ssid-regexp=$SsidRegexp; +} +:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; +:if ([ :len $VlanId ] > 0) do={ + /caps-man/access-list/set $Entry vlan-id=$VlanId; + /interface/wifiwave2/access-list/set $Entry vlan-id=$VlanId; +} +# NOT /interface/wifiwave2 # +:local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; +:if ([ :len $VlanMode] > 0) do={ + /caps-man/access-list/set $Entry vlan-mode=$VlanMode; + /interface/wifiwave2/access-list/set $Entry vlan-mode=$VlanMode; +} +# NOT /interface/wifiwave2 # + +:delay 2s; +/caps-man/access-list/set $Entry action=accept; +/interface/wifiwave2/access-list/set $Entry action=accept; diff --git a/hotspot-to-wpa.wifiwave2.rsc b/hotspot-to-wpa.wifiwave2.rsc new file mode 100644 index 0000000..ea44a9d --- /dev/null +++ b/hotspot-to-wpa.wifiwave2.rsc @@ -0,0 +1,86 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa.wifiwave2 +# Copyright (c) 2019-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# add private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "hotspot-to-wpa.wifiwave2"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global EitherOr; +:global LogPrintExit2; +:global ParseKeyValueStore; +:global ScriptLock; + +$ScriptLock $0; + +:local MacAddress $"mac-address"; +:local UserName $username; + +:if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ + $LogPrintExit2 error $0 ("This script is supposed to run from hotspot on login.") true; +} + +:local Date [ /system/clock/get date ]; +:local UserVal ({}); +:if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ + :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; +} +:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; +:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; + +:if ([ :len [ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + /interface/wifiwave2/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; +} +:local PlaceBefore ([ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + +:if ([ :len [ /interface/wifiwave2/access-list/find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ + /interface/wifiwave2/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; +} +:local Template [ /interface/wifiwave2/access-list/get ([ find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; + +:if ($Template->"action" = "reject") do={ + $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; +} + +# allow login page to load +:delay 1s; + +$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ").") false; +/interface/wifiwave2/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; +/interface/wifiwave2/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + action=reject place-before=$PlaceBefore; + +:local Entry [ /interface/wifiwave2/access-list/find where mac-address=$MacAddress \ + comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; +:set ($Template->"private-passphrase") ($Template->"passphrase"); +:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; +:if ([ :len $PrivatePassphrase ] > 0) do={ + :if ($PrivatePassphrase = "ignore") do={ + /interface/wifiwave2/access-list/set $Entry !passphrase; + } else={ + /interface/wifiwave2/access-list/set $Entry passphrase=$PrivatePassphrase; + } +} +:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; +:if ([ :len $SsidRegexp ] > 0) do={ + /interface/wifiwave2/access-list/set $Entry ssid-regexp=$SsidRegexp; +} +:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; +:if ([ :len $VlanId ] > 0) do={ + /interface/wifiwave2/access-list/set $Entry vlan-id=$VlanId; +} + +:delay 2s; +/interface/wifiwave2/access-list/set $Entry action=accept; From 92aca1aac05ba943fa41c9c6640265991a906e30 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 9 Aug 2023 11:12:21 +0200 Subject: [PATCH 1594/2612] news and migration for wifiwave2 --- global-functions.rsc | 2 +- news-and-changes.rsc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index e317af9..b9b20ee 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 103; +:global ExpectedConfigVersion 104; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 572f431..7ac56f8 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -17,10 +17,12 @@ 101="Introduced new script 'fw-addr-lists' to download, import and update firewall address-lists."; 102="Modified 'hotspot-to-wpa' to support non-local (radius) users."; 103="Dropped hard-coded name and timeout from 'hotspot-to-wpa-cleanup', instead a comment is required for dhcp server now."; + 104="All relevant scripts were ported to new wifiwave2 and are available for AX devices now!"; }; # Migration steps to be applied on script updates :global GlobalConfigMigration { 97=":local Rec [ /ip/dns/static/find where comment~\"^managed by dhcp-to-dns for \" ]; :if ([ :len \$Rec ] > 0) do={ /ip/dns/static/remove \$Rec; /system/script/run dhcp-to-dns; }"; 100=":global ScriptInstallUpdate; :if ([ :len [ /system/script/find where name=\"ssh-keys-import\" source~\"^#!rsc by RouterOS\\n\" ] ] > 0) do={ /system/script/set name=\"mod/ssh-keys-import\" ssh-keys-import; \$ScriptInstallUpdate; }"; + 104=":global CharacterReplace; :global ScriptInstallUpdate; :foreach Script in={ \"capsman-download-packages\"; \"capsman-rolling-upgrade\"; \"hotspot-to-wpa\"; \"hotspot-to-wpa-cleanup\" } do={ /system/script/set name=(\$Script . \".capsman\") [ find where name=\$Script ]; :foreach Scheduler in=[ /system/scheduler/find where on-event~(\$Script . \"([^-.]|\\\$)\") ] do={ /system/scheduler/set \$Scheduler on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Script (\$Script . \".capsman\") ]; }; }; /ip/hotspot/user/profile/set on-login=\"hotspot-to-wpa.capsman\" [ find where on-login=\"hotspot-to-wpa\" ]; \$ScriptInstallUpdate;"; }; From ddd5608b3816da123de0cfa8f83be32aca8e2901 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Aug 2023 09:02:32 +0200 Subject: [PATCH 1595/2612] mod/ssh-keys-import: drop RouterOS version dependency ... as global-functions depend on RouterOS 7.9beta already. --- doc/mod/ssh-keys-import.md | 2 -- mod/ssh-keys-import.rsc | 2 -- 2 files changed, 4 deletions(-) diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md index 44131b8..1adb75c 100644 --- a/doc/mod/ssh-keys-import.md +++ b/doc/mod/ssh-keys-import.md @@ -3,8 +3,6 @@ Import ssh keys for public key authentication [âŦ…ī¸ Go back to main README](../../README.md) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.9beta4-yellow?style=flat)](https://mikrotik.com/download/changelogs/) - > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base > installation. See [main README](../../README.md) for details. diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 6f47314..dd02d16 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -3,8 +3,6 @@ # Copyright (c) 2020-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.9beta4 -# # import ssh keys for public key authentication # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ssh-keys-import.md From c04bf2c9b787e6aa8543d507814575487694062d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Aug 2023 09:03:36 +0200 Subject: [PATCH 1596/2612] netwatch-notify: drop RouterOS version dependency ... as global-functions depend on RouterOS 7.9beta already. --- doc/netwatch-notify.md | 2 -- netwatch-notify.rsc | 2 -- 2 files changed, 4 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index efae5cf..6df233b 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -3,8 +3,6 @@ Notify on host up and down [âŦ…ī¸ Go back to main README](../README.md) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.9beta4-yellow?style=flat)](https://mikrotik.com/download/changelogs/) - > â„šī¸ **Info**: This script can not be used on its own but requires the base > installation. See [main README](../README.md) for details. diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 15a17b2..e1d489a 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -3,8 +3,6 @@ # Copyright (c) 2020-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.9beta4 -# # monitor netwatch and send notifications # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md From 25d40688f7633b87d285c0ce1c8f211e89416463 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Aug 2023 09:04:36 +0200 Subject: [PATCH 1597/2612] sms-forward: drop RouterOS version dependency ... as global-functions depend on RouterOS 7.9beta already. --- doc/sms-forward.md | 2 -- sms-forward.rsc | 2 -- 2 files changed, 4 deletions(-) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index dfd91e7..a323157 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -3,8 +3,6 @@ Forward received SMS [âŦ…ī¸ Go back to main README](../README.md) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.9beta4-yellow?style=flat)](https://mikrotik.com/download/changelogs/) - > â„šī¸ **Info**: This script can not be used on its own but requires the base > installation. See [main README](../README.md) for details. diff --git a/sms-forward.rsc b/sms-forward.rsc index 542fe0d..7c6a609 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -4,8 +4,6 @@ # Anatoly Bubenkov # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.9beta4 -# # forward SMS to e-mail # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md From 413be6f504b926e5e271001a00bd9e0d2aad5f43 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Aug 2023 09:05:45 +0200 Subject: [PATCH 1598/2612] doc/mod/ssh-keys-import: drop duplicate key type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stupid copy'n'paste error... đŸĢŖ --- doc/mod/ssh-keys-import.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md index 1adb75c..410bb5a 100644 --- a/doc/mod/ssh-keys-import.md +++ b/doc/mod/ssh-keys-import.md @@ -27,7 +27,7 @@ Usage and invocation Call the function `$SSHKeysImport` with key and user as parameter to import that key: - $SSHKeysImport "ssh-rsa ssh-rsa AAAAB3Nza...QYZk8= user" admin; + $SSHKeysImport "ssh-rsa AAAAB3Nza...QYZk8= user" admin; The third part of the key (`user` in this example) is inherited as `key-owner` in RouterOS. From ad6825571dba2d3f0654f5822c00b2e7f898db09 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Aug 2023 09:00:54 +0200 Subject: [PATCH 1599/2612] mod/ssh-keys-import: support ed25519 keys... ... with RouterOS 7.12beta1 --- doc/mod/ssh-keys-import.md | 7 ++++++- mod/ssh-keys-import.rsc | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md index 410bb5a..cf28ee2 100644 --- a/doc/mod/ssh-keys-import.md +++ b/doc/mod/ssh-keys-import.md @@ -29,6 +29,11 @@ import that key: $SSHKeysImport "ssh-rsa AAAAB3Nza...QYZk8= user" admin; +Starting with RouterOS *7.12beta1* support for keys of type `ed25519` has +been added: + + $SSHKeysImport "ssh-ed25519 AAAAC3Nza...ZVugJT user" admin; + The third part of the key (`user` in this example) is inherited as `key-owner` in RouterOS. @@ -39,7 +44,7 @@ and import all the keys. The user given to the function can be overwritting from comments in the file. Create a file `keys.pub` with this content: ``` -ssh-rsa AAAAB3Nza...QYZk8= user@client +ssh-ed25519 AAAAC3Nza...3OcN8A user@client ssh-rsa AAAAB3Nza...ozyts= worker@station # user=example ssh-rsa AAAAB3Nza...GXQVk= person@host diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index dd02d16..170139d 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -50,6 +50,7 @@ :global EitherOr; :global LogPrintExit2; :global ParseKeyValueStore; + :global RequiredRouterOS; :global SSHKeysImport; :if ([ :len $FileName ] = 0 || [ :len $User ] = 0) do={ @@ -67,7 +68,7 @@ :local Line [ :pick $Keys 0 [ :find $Keys "\n" ] ]; :set Keys [ :pick $Keys ([ :find $Keys "\n" ] + 1) [ :len $Keys ] ]; :local Type [ :pick $Line 0 [ :find $Line " " ] ]; - :if ($Type = "ssh-rsa") do={ + :if (([ $RequiredRouterOS $0 "7.12beta1" ] = true && $Type = "ssh-ed25519") || $Type = "ssh-rsa") do={ $SSHKeysImport $Line $User; :set Continue true; } From 53a80c81b18a01dadaef967fd52e2fc2474714fa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Aug 2023 09:15:44 +0200 Subject: [PATCH 1600/2612] mod/ssh-keys-import: $SSHKeysImport: add check for key type --- mod/ssh-keys-import.rsc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 170139d..31bb3e6 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -17,6 +17,7 @@ :global GetRandom20CharAlNum; :global LogPrintExit2; :global MkDir; + :global RequiredRouterOS; :global WaitForFile; :if ([ :len $Key ] = 0 || [ :len $User ] = 0) do={ @@ -27,6 +28,11 @@ $LogPrintExit2 warning $0 ("User '" . $User . "' does not exist.") true; } + :local Type [ :pick $Key 0 [ :find $Key " " ] ]; + :if (!(([ $RequiredRouterOS $0 "7.12beta1" ] = true && $Type = "ssh-ed25519") || $Type = "ssh-rsa")) do={ + $LogPrintExit2 warning $0 ("SSH key of type '" . $Type . "' is not supported.") true; + } + :if ([ $MkDir "tmpfs/ssh-keys-import" ] = false) do={ $LogPrintExit2 warning $0 ("Creating directory 'tmpfs/ssh-keys-import' failed!") true; } From 047c74a4b3feb40528c1fc72b371f3599dab4c2b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Aug 2023 09:29:22 +0200 Subject: [PATCH 1601/2612] global-functions: prepare user-agent for fetch in global variable --- global-functions.rsc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index b9b20ee..8a9b384 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -16,6 +16,7 @@ # global variables not to be changed by user :global GlobalFunctionsReady false; +:global FetchUserAgent ("User-Agent: Mikrotik/" . [ /system/resource/get version ] . " Fetch"); :global Identity [ /system/identity/get name ]; # global functions @@ -108,6 +109,7 @@ :set CertificateDownload do={ :local CommonName [ :tostr $1 ]; + :global FetchUserAgent; :global ScriptUpdatesBaseUrl; :global ScriptUpdatesUrlSuffix; @@ -116,14 +118,12 @@ :global UrlEncode; :global WaitForFile; - :local UserAgent ("User-Agent: Mikrotik/" . [ /system/resource/get version ] . " Fetch"); - $LogPrintExit2 info $0 ("Downloading and importing certificate with " . \ "CommonName \"" . $CommonName . "\".") false; :do { :local LocalFileName ($CommonName . ".pem"); :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); - /tool/fetch check-certificate=yes-without-crl http-header-field=$UserAgent \ + /tool/fetch check-certificate=yes-without-crl http-header-field=$FetchUserAgent \ ($ScriptUpdatesBaseUrl . "certs/" . $UrlFileName . $ScriptUpdatesUrlSuffix) \ dst-path=$LocalFileName as-value; $WaitForFile $LocalFileName; @@ -769,6 +769,7 @@ :local NewComment [ :tostr $2 ]; :global ExpectedConfigVersion; + :global FetchUserAgent; :global Identity; :global IDonate; :global NoNewsAndChangesNotification; @@ -806,7 +807,6 @@ :local ExpectedConfigVersionBefore $ExpectedConfigVersion; :local ReloadGlobalFunctions false; :local ReloadGlobalConfig false; - :local UserAgent ("User-Agent: Mikrotik/" . [ /system/resource/get version ] . " Fetch"); :foreach Script in=[ /system/script/find where source~"^#!rsc by RouterOS\r?\n" ] do={ :local ScriptVal [ /system/script/get $Script ]; @@ -836,7 +836,7 @@ :local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix); $LogPrintExit2 debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url) false; - :local Result [ /tool/fetch check-certificate=yes-without-crl http-header-field=$UserAgent \ + :local Result [ /tool/fetch check-certificate=yes-without-crl http-header-field=$FetchUserAgent \ $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set SourceNew ($Result->"data"); @@ -920,7 +920,7 @@ :do { :local Url ($ScriptUpdatesBaseUrl . "news-and-changes.rsc" . $ScriptUpdatesUrlSuffix); $LogPrintExit2 debug $0 ("Fetching news, changes and migration: " . $Url) false; - :local Result [ /tool/fetch check-certificate=yes-without-crl http-header-field=$UserAgent \ + :local Result [ /tool/fetch check-certificate=yes-without-crl http-header-field=$FetchUserAgent \ $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set ChangeLogCode ($Result->"data"); From 5b5c91da840d01f54dcb788dbd8098e47e9f2a69 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Aug 2023 16:31:06 +0200 Subject: [PATCH 1602/2612] hotspot-to-wpa-cleanup: require RouterOS for wifiwave2 RouterOS before version 7.12beta3 had a bug where getting comment from registration-table is not possible. Require that version at least. This was fixed in SUP-124500. --- hotspot-to-wpa-cleanup.template.rsc | 3 +++ hotspot-to-wpa-cleanup.wifiwave2.rsc | 1 + 2 files changed, 4 insertions(+) diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 38313d9..1c49091 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -4,6 +4,9 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 +# NOT /caps-man # +# requires RouterOS, version=7.12beta3 +# NOT /caps-man # # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa-cleanup.wifiwave2.rsc b/hotspot-to-wpa-cleanup.wifiwave2.rsc index a8ba34c..0433305 100644 --- a/hotspot-to-wpa-cleanup.wifiwave2.rsc +++ b/hotspot-to-wpa-cleanup.wifiwave2.rsc @@ -4,6 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 +# requires RouterOS, version=7.12beta3 # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md From 16844b935af98eaabf6db1db96a88ff39819a3df Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 29 Aug 2023 08:54:53 +0200 Subject: [PATCH 1603/2612] hotspot-to-wpa-cleanup: show last-seen, not timeout --- hotspot-to-wpa-cleanup.capsman.rsc | 2 +- hotspot-to-wpa-cleanup.template.rsc | 2 +- hotspot-to-wpa-cleanup.wifiwave2.rsc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index 5bded2c..b9a6620 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -60,7 +60,7 @@ $ScriptLock $0 false 10; server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . $Timeout . ", removing.") false; + " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ mac-address=($LeaseVal->"mac-address") ]; /ip/dhcp-server/lease/remove $Lease; diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 1c49091..8cc732b 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -69,7 +69,7 @@ $ScriptLock $0 false 10; server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . $Timeout . ", removing.") false; + " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ /interface/wifiwave2/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ mac-address=($LeaseVal->"mac-address") ]; diff --git a/hotspot-to-wpa-cleanup.wifiwave2.rsc b/hotspot-to-wpa-cleanup.wifiwave2.rsc index 0433305..e316c17 100644 --- a/hotspot-to-wpa-cleanup.wifiwave2.rsc +++ b/hotspot-to-wpa-cleanup.wifiwave2.rsc @@ -61,7 +61,7 @@ $ScriptLock $0 false 10; server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . $Timeout . ", removing.") false; + " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; /interface/wifiwave2/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ mac-address=($LeaseVal->"mac-address") ]; /ip/dhcp-server/lease/remove $Lease; From 1dd1c5b03c73034aec739c7ca54c6372107969f6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 24 Aug 2023 15:49:41 +0200 Subject: [PATCH 1604/2612] backup-upload: write config file directly This functionality was added in RouterOS 7.9beta4... --- backup-upload.rsc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 1ec61a5..35b9b53 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -100,13 +100,13 @@ $WaitFullyConnected; # global-config-overlay :if ($BackupSendGlobalConfig = true) do={ - :execute script={ :put [ /system/script/get global-config-overlay source ]; } \ - file=($FilePath . ".conf"); - $WaitForFile ($FilePath . ".conf.txt"); + :local Config [ /system/script/get global-config-overlay source ]; + /file/add name=($FilePath . ".conf") contents=$Config; + $WaitForFile ($FilePath . ".conf"); :do { /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \ - user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf.txt"); + user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf"); :set ConfigFile ($FileName . ".conf"); } on-error={ $LogPrintExit2 error $0 ("Uploading global-config-overlay failed!") false; @@ -114,7 +114,7 @@ $WaitFullyConnected; :set Failed 1; } - /file/remove ($FilePath . ".conf.txt"); + /file/remove ($FilePath . ".conf"); } $SendNotification2 ({ origin=$0; \ From 3c96db58246ce85b9796f4322a7ace7687531b55 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 24 Aug 2023 15:51:53 +0200 Subject: [PATCH 1605/2612] backup-email: write config file directly This functionality was added in RouterOS 7.9beta4... --- backup-email.rsc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backup-email.rsc b/backup-email.rsc index 5eb4fcc..4dd9fcc 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -80,11 +80,11 @@ $WaitFullyConnected; # global-config-overlay :if ($BackupSendGlobalConfig = true) do={ - :execute script={ :put [ /system/script/get global-config-overlay source ]; } \ - file=($FilePath . ".conf"); - $WaitForFile ($FilePath . ".conf.txt"); - :set ConfigFile ($FileName . ".conf.txt"); - :set Attach ($Attach, ($FilePath . ".conf.txt")); + :local Config [ /system/script/get global-config-overlay source ]; + /file/add name=($FilePath . ".conf") contents=$Config; + $WaitForFile ($FilePath . ".conf"); + :set ConfigFile ($FileName . ".conf"); + :set Attach ($Attach, ($FilePath . ".conf")); } # send email with status and files From ffc7521a350e613c23507a1cdbc5a9b028beced1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 24 Aug 2023 19:38:56 +0200 Subject: [PATCH 1606/2612] backup-email: support indication of failure --- backup-email.rsc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/backup-email.rsc b/backup-email.rsc index 4dd9fcc..8567a65 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -23,6 +23,7 @@ :global CharacterReplace; :global DeviceInfo; :global FormatLine; +:global IfThenElse; :global LogPrintExit2; :global MkDir; :global RandomDelay; @@ -57,6 +58,7 @@ $WaitFullyConnected; :local ExportFile "none"; :local ConfigFile "none"; :local Attach ({}); +:local Failed 0; :if ([ $MkDir $DirName ] = false) do={ $LogPrintExit2 error $0 ("Failed creating directory!") true; @@ -89,8 +91,9 @@ $WaitFullyConnected; # send email with status and files $SendEMail2 ({ origin=$0; \ - subject=([ $SymbolForNotification "floppy-disk,incoming-envelope" ] . \ - "Backup & Config"); \ + subject=[ $IfThenElse ($Failed > 0) \ + ([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Backup & Config with failure") \ + ([ $SymbolForNotification "floppy-disk,incoming-envelope" ] . "Backup & Config") ]; \ message=("See attached files for backup and config export for " . \ $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ @@ -108,3 +111,7 @@ $SendEMail2 ({ origin=$0; \ :delay 1s; :set I ($I + 1); } + +:if ($Failed = 1) do={ + :error "An error occured!"; +} From 07c6f5836a7e56d310890cf4bdaba1854205420f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 24 Aug 2023 19:39:38 +0200 Subject: [PATCH 1607/2612] backup-email: detect failure creating config file --- backup-email.rsc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/backup-email.rsc b/backup-email.rsc index 8567a65..3dce2ca 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -85,8 +85,16 @@ $WaitFullyConnected; :local Config [ /system/script/get global-config-overlay source ]; /file/add name=($FilePath . ".conf") contents=$Config; $WaitForFile ($FilePath . ".conf"); - :set ConfigFile ($FileName . ".conf"); - :set Attach ($Attach, ($FilePath . ".conf")); + + :local Size [ :len $Config ]; + :if ([ /file/get ($FilePath . ".conf") size ] = $Size) do={ + :set ConfigFile ($FileName . ".conf"); + :set Attach ($Attach, ($FilePath . ".conf")); + } else={ + $LogPrintExit2 warning $0 ("Creating config file failed. Size should be " . $Size . " bytes, but is not.") false; + :set ConfigFile "failed"; + :set Failed 1; + } } # send email with status and files From f86cf27aa3cbfccf67d47f640b4ad0df64be09ae Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 24 Aug 2023 19:39:59 +0200 Subject: [PATCH 1608/2612] backup-upload: detect failure creating config file --- backup-upload.rsc | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 35b9b53..29bdfff 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -104,12 +104,19 @@ $WaitFullyConnected; /file/add name=($FilePath . ".conf") contents=$Config; $WaitForFile ($FilePath . ".conf"); - :do { - /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \ - user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf"); - :set ConfigFile ($FileName . ".conf"); - } on-error={ - $LogPrintExit2 error $0 ("Uploading global-config-overlay failed!") false; + :local Size [ :len $Config ]; + :if ([ /file/get ($FilePath . ".conf") size ] = $Size) do={ + :do { + /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \ + user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf"); + :set ConfigFile ($FileName . ".conf"); + } on-error={ + $LogPrintExit2 error $0 ("Uploading global-config-overlay failed!") false; + :set ConfigFile "failed"; + :set Failed 1; + } + } else={ + $LogPrintExit2 warning $0 ("Creating config file failed. Size should be " . $Size . " bytes, but is not.") false; :set ConfigFile "failed"; :set Failed 1; } From 1e247542a51749175bcd73bb0ea07513848c6442 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 30 Aug 2023 09:01:46 +0200 Subject: [PATCH 1609/2612] backup-email: check configuration size before writing file --- backup-email.rsc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/backup-email.rsc b/backup-email.rsc index 3dce2ca..3beb730 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -83,15 +83,16 @@ $WaitFullyConnected; # global-config-overlay :if ($BackupSendGlobalConfig = true) do={ :local Config [ /system/script/get global-config-overlay source ]; - /file/add name=($FilePath . ".conf") contents=$Config; - $WaitForFile ($FilePath . ".conf"); - :local Size [ :len $Config ]; - :if ([ /file/get ($FilePath . ".conf") size ] = $Size) do={ + + :if ($Size <= 4095) { + /file/add name=($FilePath . ".conf") contents=$Config; + $WaitForFile ($FilePath . ".conf"); :set ConfigFile ($FileName . ".conf"); :set Attach ($Attach, ($FilePath . ".conf")); } else={ - $LogPrintExit2 warning $0 ("Creating config file failed. Size should be " . $Size . " bytes, but is not.") false; + $LogPrintExit2 warning $0 ("Creating config file not possible. Limit is 4kB, configuration has " . \ + $Size . " bytes.") false; :set ConfigFile "failed"; :set Failed 1; } From f099c2c9ea0a09e7802246b726f6abbc95c2f8ed Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 30 Aug 2023 08:59:04 +0200 Subject: [PATCH 1610/2612] backup-upload: check configuration size before writing file --- backup-upload.rsc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 29bdfff..ec76385 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -101,11 +101,12 @@ $WaitFullyConnected; # global-config-overlay :if ($BackupSendGlobalConfig = true) do={ :local Config [ /system/script/get global-config-overlay source ]; - /file/add name=($FilePath . ".conf") contents=$Config; - $WaitForFile ($FilePath . ".conf"); - :local Size [ :len $Config ]; - :if ([ /file/get ($FilePath . ".conf") size ] = $Size) do={ + + :if ($Size <= 4095) { + /file/add name=($FilePath . ".conf") contents=$Config; + $WaitForFile ($FilePath . ".conf"); + :do { /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \ user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf"); @@ -115,13 +116,14 @@ $WaitFullyConnected; :set ConfigFile "failed"; :set Failed 1; } + + /file/remove ($FilePath . ".conf"); } else={ - $LogPrintExit2 warning $0 ("Creating config file failed. Size should be " . $Size . " bytes, but is not.") false; + $LogPrintExit2 warning $0 ("Creating config file not possible. Limit is 4kB, configuration has " . \ + $Size . " bytes.") false; :set ConfigFile "failed"; :set Failed 1; } - - /file/remove ($FilePath . ".conf"); } $SendNotification2 ({ origin=$0; \ From ce822a0276da8ec50c6f7d58d8f0e04971f45a0b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 30 Aug 2023 09:13:13 +0200 Subject: [PATCH 1611/2612] backup-email: revert changes, add comment with warning Turned out that using `/file/add ...` introduced a regression. Accessing (reading and writing) file contents is limited to 4095 bytes. This limitation does not exist for `:execute script=... file=...`, so keep the old code. Also add a comment with warning. --- backup-email.rsc | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/backup-email.rsc b/backup-email.rsc index 3beb730..e4cd504 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -23,7 +23,6 @@ :global CharacterReplace; :global DeviceInfo; :global FormatLine; -:global IfThenElse; :global LogPrintExit2; :global MkDir; :global RandomDelay; @@ -58,7 +57,6 @@ $WaitFullyConnected; :local ExportFile "none"; :local ConfigFile "none"; :local Attach ({}); -:local Failed 0; :if ([ $MkDir $DirName ] = false) do={ $LogPrintExit2 error $0 ("Failed creating directory!") true; @@ -82,27 +80,18 @@ $WaitFullyConnected; # global-config-overlay :if ($BackupSendGlobalConfig = true) do={ - :local Config [ /system/script/get global-config-overlay source ]; - :local Size [ :len $Config ]; - - :if ($Size <= 4095) { - /file/add name=($FilePath . ".conf") contents=$Config; - $WaitForFile ($FilePath . ".conf"); - :set ConfigFile ($FileName . ".conf"); - :set Attach ($Attach, ($FilePath . ".conf")); - } else={ - $LogPrintExit2 warning $0 ("Creating config file not possible. Limit is 4kB, configuration has " . \ - $Size . " bytes.") false; - :set ConfigFile "failed"; - :set Failed 1; - } + # 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"); + $WaitForFile ($FilePath . ".conf.txt"); + :set ConfigFile ($FileName . ".conf.txt"); + :set Attach ($Attach, ($FilePath . ".conf.txt")); } # send email with status and files $SendEMail2 ({ origin=$0; \ - subject=[ $IfThenElse ($Failed > 0) \ - ([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Backup & Config with failure") \ - ([ $SymbolForNotification "floppy-disk,incoming-envelope" ] . "Backup & Config") ]; \ + subject=([ $SymbolForNotification "floppy-disk,incoming-envelope" ] . \ + "Backup & Config"); \ message=("See attached files for backup and config export for " . \ $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ @@ -120,7 +109,3 @@ $SendEMail2 ({ origin=$0; \ :delay 1s; :set I ($I + 1); } - -:if ($Failed = 1) do={ - :error "An error occured!"; -} From 49d85c6def6426a64b2ae516af80609cd17af317 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 30 Aug 2023 09:17:28 +0200 Subject: [PATCH 1612/2612] backup-upload: revert changes, add comment with warning Turned out that using `/file/add ...` introduced a regression. Accessing (reading and writing) file contents is limited to 4095 bytes. This limitation does not exist for `:execute script=... file=...`, so keep the old code. Also add a comment with warning. --- backup-upload.rsc | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index ec76385..7d4b1d1 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -100,30 +100,22 @@ $WaitFullyConnected; # global-config-overlay :if ($BackupSendGlobalConfig = true) do={ - :local Config [ /system/script/get global-config-overlay source ]; - :local Size [ :len $Config ]; + # 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"); + $WaitForFile ($FilePath . ".conf.txt"); - :if ($Size <= 4095) { - /file/add name=($FilePath . ".conf") contents=$Config; - $WaitForFile ($FilePath . ".conf"); - - :do { - /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \ - user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf"); - :set ConfigFile ($FileName . ".conf"); - } on-error={ - $LogPrintExit2 error $0 ("Uploading global-config-overlay failed!") false; - :set ConfigFile "failed"; - :set Failed 1; - } - - /file/remove ($FilePath . ".conf"); - } else={ - $LogPrintExit2 warning $0 ("Creating config file not possible. Limit is 4kB, configuration has " . \ - $Size . " bytes.") false; + :do { + /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \ + user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf.txt"); + :set ConfigFile ($FileName . ".conf"); + } on-error={ + $LogPrintExit2 error $0 ("Uploading global-config-overlay failed!") false; :set ConfigFile "failed"; :set Failed 1; } + + /file/remove ($FilePath . ".conf.txt"); } $SendNotification2 ({ origin=$0; \ From 7b47ed7ea5a937edef9699c1b8be3b6364c9c0c9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 17 Aug 2023 09:06:44 +0200 Subject: [PATCH 1613/2612] check-routeros-update: support update from specific neighbor(s) ... by matching the identity property. --- check-routeros-update.rsc | 4 +++- doc/check-routeros-update.md | 2 ++ global-config.rsc | 1 + global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index b328d4c..0625ebd 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -13,6 +13,7 @@ :global Identity; :global SafeUpdateAll; :global SafeUpdateNeighbor; +:global SafeUpdateNeighborIdentity; :global SafeUpdatePatch; :global SafeUpdateUrl; :global SentRouterosUpdateNotification; @@ -81,7 +82,8 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; } :if ($SafeUpdateNeighbor = true && [ :len [ /ip/neighbor/find where platform="MikroTik" \ - version~("^" . [ $EscapeForRegEx ($Update->"latest-version" . " (" . $Update->"channel" . ")") ]) ] ] > 0) do={ + version~("^" . [ $EscapeForRegEx ($Update->"latest-version" . " (" . $Update->"channel" . ")") ]) \ + identity~$SafeUpdateNeighborIdentity ] ] > 0) do={ $LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 186fb86..3b5c2bd 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -52,6 +52,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `SafeUpdateNeighbor`: install updates automatically if at least one other device is seen in neighbor list with new version +* `SafeUpdateNeighborIdentity`: regular expression to match identity for + trusted devices, leave empty to match all * `SafeUpdatePatch`: install patch updates (where just last digit changes) automatically * `SafeUpdateUrl`: url on webserver to check for safe update, the channel diff --git a/global-config.rsc b/global-config.rsc index 7988ce3..7d3ef7c 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -126,6 +126,7 @@ :global SafeUpdatePatch false; # Allow to install updates automatically if seen in neighbor list. :global SafeUpdateNeighbor false; +:global SafeUpdateNeighborIdentity ""; # Install *ALL* updates automatically! # Set to all upper-case "Yes, please!" to enable. :global SafeUpdateAll "no"; diff --git a/global-functions.rsc b/global-functions.rsc index 8a9b384..55f8af6 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 104; +:global ExpectedConfigVersion 105; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 7ac56f8..b027fb6 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -18,6 +18,7 @@ 102="Modified 'hotspot-to-wpa' to support non-local (radius) users."; 103="Dropped hard-coded name and timeout from 'hotspot-to-wpa-cleanup', instead a comment is required for dhcp server now."; 104="All relevant scripts were ported to new wifiwave2 and are available for AX devices now!"; + 105="Extended 'check-routeros-update' to support automatic update from specific neighbor(s)."; }; # Migration steps to be applied on script updates From 57027ceb26427ff34f4d022734f5196d4d3f0a04 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 24 Aug 2023 11:16:23 +0200 Subject: [PATCH 1614/2612] check-routeros-update: show neighbor's identity in message and notification --- check-routeros-update.rsc | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 0625ebd..73ce7d8 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -81,15 +81,19 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; $DoUpdate; } - :if ($SafeUpdateNeighbor = true && [ :len [ /ip/neighbor/find where platform="MikroTik" \ - version~("^" . [ $EscapeForRegEx ($Update->"latest-version" . " (" . $Update->"channel" . ")") ]) \ - identity~$SafeUpdateNeighborIdentity ] ] > 0) do={ - $LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ - message=("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \ - ", updating on " . $Identity . "..."); link=$Link; silent=true }); - $DoUpdate; + :if ($SafeUpdateNeighbor = true) do={ + :local Neighbors [ /ip/neighbor/find where platform="MikroTik" identity~$SafeUpdateNeighborIdentity \ + version~("^" . [ $EscapeForRegEx ($Update->"latest-version" . " (" . $Update->"channel" . ")") ]) ]; + :if ([ :len $Neighbors ] > 0) do={ + :local Neighbor [ /ip/neighbor/get ($Neighbors->0) identity ]; + $LogPrintExit2 info $0 ("Seen a neighbor (" . $Neighbor . ") running version " . \ + $Update->"latest-version" . " from " . $Update->"channel" . ", updating...") false; + $SendNotification2 ({ origin=$0; \ + 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={ From 50429a0ad8ce02f26f40a69d027ea709480aeb36 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Sep 2023 11:35:02 +0200 Subject: [PATCH 1615/2612] fw-addr-lists: no (mixed) capitalization in message --- fw-addr-lists.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index b09cf29..38fdd96 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -105,5 +105,5 @@ $WaitFullyConnected; } } - $LogPrintExit2 info $0 ("List: " . $FwListName . " -- Added: " . $CntAdd . " - renewed: " . $CntRenew . " - removed: " . $CntRemove) false; + $LogPrintExit2 info $0 ("list: " . $FwListName . " -- added: " . $CntAdd . " - renewed: " . $CntRenew . " - removed: " . $CntRemove) false; } From c3f9ad1df7422fb2c508ea4960bd95b4a2ef25b2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Sep 2023 01:01:34 +0200 Subject: [PATCH 1616/2612] packages-update: implement backup script order --- backup-cloud.rsc | 2 +- backup-email.rsc | 2 +- backup-partition.rsc | 2 +- backup-upload.rsc | 2 +- packages-update.rsc | 18 ++++++++++++++---- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 859892b..934edb9 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: backup-script +# provides: backup-script, order=40 # # upload backup to MikroTik cloud # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md diff --git a/backup-email.rsc b/backup-email.rsc index e4cd504..95e9015 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: backup-script +# provides: backup-script, order=20 # # create and email backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md diff --git a/backup-partition.rsc b/backup-partition.rsc index 364101c..b03ad7e 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2022-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: backup-script +# provides: backup-script, order=70 # # save configuration to fallback partition # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md diff --git a/backup-upload.rsc b/backup-upload.rsc index 7d4b1d1..4c8af4a 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: backup-script +# provides: backup-script, order=50 # # create and upload backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md diff --git a/packages-update.rsc b/packages-update.rsc index 74b1822..ebcbaae 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -11,7 +11,9 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global DownloadPackage; +:global Grep; :global LogPrintExit2; +:global ParseKeyValueStore; :global ScriptFromTerminal; :global ScriptLock; :global VersionToNum; @@ -52,13 +54,21 @@ $ScriptLock $0; } } -:foreach Script in=[ /system/script/find where source~"\n# provides: backup-script\n" ] do={ - :local ScriptName [ /system/script/get $Script name ]; +:local RunOrder ({}); + +:foreach Script in=[ /system/script/find where source~("\n# provides: backup-script, ") ] do={ + :local ScriptVal [ /system/script/get $Script ]; + :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") ("\23 provides: backup-script, ") ] ]; + + :set ($RunOrder->($Store->"order" . "-" . $ScriptVal->"name")) ($ScriptVal->"name"); +} + +:foreach Order,Script in=$RunOrder do={ :do { - $LogPrintExit2 info $0 ("Running backup script " . $ScriptName . " before update.") false; + $LogPrintExit2 info $0 ("Running backup script " . $Script . " (order " . $Order . ") before update.") false; /system/script/run $Script; } on-error={ - $LogPrintExit2 warning $0 ("Running backup script " . $ScriptName . " before update failed!") false; + $LogPrintExit2 warning $0 ("Running backup script " . $Script . " before update failed!") false; :if ([ $ScriptFromTerminal $0 ] = true) do={ :put "Do you want to continue anyway? [y/N]"; :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ From 66813d83a0927f528f37e280107400c794efc4c3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Sep 2023 16:08:04 +0200 Subject: [PATCH 1617/2612] packages-update: drop order from message --- packages-update.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages-update.rsc b/packages-update.rsc index ebcbaae..8923eb7 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -65,7 +65,7 @@ $ScriptLock $0; :foreach Order,Script in=$RunOrder do={ :do { - $LogPrintExit2 info $0 ("Running backup script " . $Script . " (order " . $Order . ") before update.") false; + $LogPrintExit2 info $0 ("Running backup script " . $Script . " before update.") false; /system/script/run $Script; } on-error={ $LogPrintExit2 warning $0 ("Running backup script " . $Script . " before update failed!") false; From 5d80b63f36c6254caafc858e59a4194cb8edcde3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Sep 2023 10:59:22 +0200 Subject: [PATCH 1618/2612] doc/packages-update: mention and link all backup scripts --- doc/packages-update.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/packages-update.md b/doc/packages-update.md index 4604bae..653d233 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -16,8 +16,12 @@ verification. But it provides some extra functionality: +* upload backup to Mikrotik cloud if [backup-cloud](backup-cloud.md) is + installed * send backup via e-mail if [backup-email](backup-email.md) is installed -* upload backup if [backup-upload](backup-upload.md) is installed +* save configuration to fallback partition if + [backup-partition](backup-partition.md) is installed +* upload backup to server if [backup-upload](backup-upload.md) is installed * schedule reboot at night Requirements and installation @@ -40,11 +44,11 @@ Alternatively run it manually: See also -------- -* [Notify on RouterOS update](check-routeros-update.md) * [Upload backup to Mikrotik cloud](backup-cloud.md) * [Send backup via e-mail](backup-email.md) -* [Save configuration to fallback partition](doc/backup-partition.md) +* [Save configuration to fallback partition](backup-partition.md) * [Upload backup to server](backup-upload.md) +* [Notify on RouterOS update](check-routeros-update.md) * [Automatically upgrade firmware and reboot](firmware-upgrade-reboot.md) --- From 8b8bc7cf2db33aa53ad905e8f0a6b01754ff9c39 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Sep 2023 12:18:55 +0200 Subject: [PATCH 1619/2612] packages-update: match on word boundary --- packages-update.rsc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index 8923eb7..caaac6a 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -55,8 +55,7 @@ $ScriptLock $0; } :local RunOrder ({}); - -:foreach Script in=[ /system/script/find where source~("\n# provides: backup-script, ") ] do={ +:foreach Script in=[ /system/script/find where source~("\n# provides: backup-script\\b") ] do={ :local ScriptVal [ /system/script/get $Script ]; :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") ("\23 provides: backup-script, ") ] ]; From 46e48497d5e9ca0627ad325b8d13d9b6d70c061a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Sep 2023 12:17:54 +0200 Subject: [PATCH 1620/2612] lease-script: match on word boundary --- lease-script.rsc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lease-script.rsc b/lease-script.rsc index 9b43e18..f8bc129 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -33,8 +33,7 @@ $ScriptLock $0 false 10; } :local RunOrder ({}); - -:foreach Script in=[ /system/script/find where source~("\n# provides: lease-script, ") ] do={ +:foreach Script in=[ /system/script/find where source~("\n# provides: lease-script\\b") ] do={ :local ScriptVal [ /system/script/get $Script ]; :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") ("\23 provides: lease-script, ") ] ]; From 110bb793b66b1f195eddd0480416b688b8af1a48 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Sep 2023 15:38:31 +0200 Subject: [PATCH 1621/2612] check-routeros-update: do not match the channel on neighbor update While this works for stable, it does not for testing: The testing channel can have "testing" in the string for rc releases, but also "development" for beta releases... and possibly more. Instead match on version string only, with word boundary. --- check-routeros-update.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 73ce7d8..d77164d 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -83,7 +83,7 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; :if ($SafeUpdateNeighbor = true) do={ :local Neighbors [ /ip/neighbor/find where platform="MikroTik" identity~$SafeUpdateNeighborIdentity \ - version~("^" . [ $EscapeForRegEx ($Update->"latest-version" . " (" . $Update->"channel" . ")") ]) ]; + version~("^" . [ $EscapeForRegEx ($Update->"latest-version") ] . "\\b") ]; :if ([ :len $Neighbors ] > 0) do={ :local Neighbor [ /ip/neighbor/get ($Neighbors->0) identity ]; $LogPrintExit2 info $0 ("Seen a neighbor (" . $Neighbor . ") running version " . \ From 2a10f43acc781359f05e59fc2305144f5027a31a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 10 Aug 2023 10:40:40 +0200 Subject: [PATCH 1622/2612] drop dummy scripts used for wifiwave2 migration This now causes expected warnings on first run of $ScriptInstallUpdate. --- capsman-download-packages.rsc | 3 --- capsman-rolling-upgrade.rsc | 3 --- hotspot-to-wpa-cleanup.rsc | 3 --- hotspot-to-wpa.rsc | 3 --- 4 files changed, 12 deletions(-) delete mode 100644 capsman-download-packages.rsc delete mode 100644 capsman-rolling-upgrade.rsc delete mode 100644 hotspot-to-wpa-cleanup.rsc delete mode 100644 hotspot-to-wpa.rsc diff --git a/capsman-download-packages.rsc b/capsman-download-packages.rsc deleted file mode 100644 index 2da00ca..0000000 --- a/capsman-download-packages.rsc +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/capsman-rolling-upgrade.rsc b/capsman-rolling-upgrade.rsc deleted file mode 100644 index 2da00ca..0000000 --- a/capsman-rolling-upgrade.rsc +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/hotspot-to-wpa-cleanup.rsc b/hotspot-to-wpa-cleanup.rsc deleted file mode 100644 index 2da00ca..0000000 --- a/hotspot-to-wpa-cleanup.rsc +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration diff --git a/hotspot-to-wpa.rsc b/hotspot-to-wpa.rsc deleted file mode 100644 index 2da00ca..0000000 --- a/hotspot-to-wpa.rsc +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS -# -# dummy for migration From 5349c9b52e48a1cc5245c8b76492cbbf2bd45ac4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 Sep 2023 09:46:28 +0200 Subject: [PATCH 1623/2612] global-functions: $EitherOr: properly handle time values --- global-functions.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 55f8af6..3d35a8d 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -309,6 +309,9 @@ :if ([ :typeof $1 ] = "num") do={ :return [ $IfThenElse ($1 != 0) $1 $2 ]; } + :if ([ :typeof $1 ] = "time") do={ + :return [ $IfThenElse ($1 > 0s) $1 $2 ]; + } :return [ $IfThenElse ([ :len [ :tostr $1 ] ] > 0) $1 $2 ]; } From 66ebcf2bbdb2a53328cb8603885da4d2da781b1c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 Sep 2023 09:37:20 +0200 Subject: [PATCH 1624/2612] telegram-chat: use the full command name :execute --- telegram-chat.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index ba2a3ff..a367b78 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -106,7 +106,7 @@ $WaitFullyConnected; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); $MkDir "tmpfs/telegram-chat"; $LogPrintExit2 info $0 ("Running command from update " . $UpdateID . ": " . $Text) false; - :exec script=(":do {\n" . $Text . "\n} on-error={ :execute script=\"/\" file=" . $File . ".failed };" . \ + :execute script=(":do {\n" . $Text . "\n} on-error={ :execute script=\"/\" file=" . $File . ".failed };" . \ ":execute script=\"/\" file=" . $File . ".done") file=$File; :if ([ $WaitForFile ($File . ".done.txt") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ :set State "The command did not finish, still running in background.\n\n"; From 557823c5c1c364d2d662069d4690640654fa1267 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 Sep 2023 09:54:03 +0200 Subject: [PATCH 1625/2612] telegram-chat: create status files with /file/add We have no content, thus no issues with file size. --- telegram-chat.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index a367b78..62a6ccc 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -106,12 +106,12 @@ $WaitFullyConnected; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); $MkDir "tmpfs/telegram-chat"; $LogPrintExit2 info $0 ("Running command from update " . $UpdateID . ": " . $Text) false; - :execute script=(":do {\n" . $Text . "\n} on-error={ :execute script=\"/\" file=" . $File . ".failed };" . \ - ":execute script=\"/\" file=" . $File . ".done") file=$File; - :if ([ $WaitForFile ($File . ".done.txt") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ + :execute script=(":do {\n" . $Text . "\n} on-error={ /file/add name=\"" . $File . ".failed\" };" . \ + "/file/add name=\"" . $File . ".done\"") file=$File; + :if ([ $WaitForFile ($File . ".done") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ :set State "The command did not finish, still running in background.\n\n"; } - :if ([ :len [ /file/find where name=($File . ".failed.txt") ] ] > 0) do={ + :if ([ :len [ /file/find where name=($File . ".failed") ] ] > 0) do={ :set State "The command failed with an error!\n\n"; } :local Content [ /file/get ($File . ".txt") contents ]; From 4ddc6be5859210e6a4c47699884f3fb67c3ed777 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 Sep 2023 22:50:32 +0200 Subject: [PATCH 1626/2612] global-functions: split off $FormatMultiLines ... ... to format multiple lines from an array. --- check-certificates.rsc | 3 ++- global-functions.rsc | 28 +++++++++++++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 86e079a..3410d4d 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -78,6 +78,7 @@ :local CertVal $1; :global FormatLine; + :global FormatMultiLines; :global IfThenElse; :global ParseKeyValueStore; @@ -89,7 +90,7 @@ :return ( \ [ $FormatLine "Name" ($CertVal->"name") ] . "\n" . \ [ $IfThenElse ([ :len ($CertVal->"common-name") ] > 0) ([ $FormatLine "CommonName" ($CertVal->"common-name") ] . "\n") ] . \ - [ $IfThenElse ([ :len ($CertVal->"subject-alt-name") ] > 0) ([ $FormatLine "SubjectAltNames" ($CertVal->"subject-alt-name") ] . "\n") ] . \ + [ $IfThenElse ([ :len ($CertVal->"subject-alt-name") ] > 0) ([ $FormatMultiLines "SubjectAltNames" ($CertVal->"subject-alt-name") ] . "\n") ] . \ [ $FormatLine "Private key" [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] ] . "\n" . \ [ $FormatLine "Fingerprint" ($CertVal->"fingerprint") ] . "\n" . \ [ $FormatLine "Issuer" ($CertVal->"ca" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN")) ] . "\n" . \ diff --git a/global-functions.rsc b/global-functions.rsc index 3d35a8d..8c96c72 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -31,6 +31,7 @@ :global EitherOr; :global EscapeForRegEx; :global FormatLine; +:global FormatMultiLines; :global GetMacVendor; :global GetRandom20CharAlNum; :global GetRandom20CharHex; @@ -339,25 +340,38 @@ # format a line for output :set FormatLine do={ - :local Key [ :tostr $1 ]; - :local Values [ :toarray $2 ]; - :local Indent [ :tonum $3 ]; + :local Key [ :tostr $1 ]; + :local Value [ :tostr $2 ]; + :local Indent [ :tonum $3 ]; :local Spaces " "; :local Return ""; :global EitherOr; - :global FormatLine; :set Indent [ $EitherOr $Indent 16 ]; :if ([ :len $Key ] > 0) do={ :set Return ($Key . ":"); } :if ([ :len $Key ] > ($Indent - 2)) do={ - :set Return ($Return . "\n" . [ :pick $Spaces 0 $Indent ] . ($Values->0)); + :set Return ($Return . "\n" . [ :pick $Spaces 0 $Indent ] . $Value); } else={ - :set Return ($Return . [ :pick $Spaces 0 ($Indent - [ :len $Return ]) ] . ($Values->0)); + :set Return ($Return . [ :pick $Spaces 0 ($Indent - [ :len $Return ]) ] . $Value); } + + :return $Return; +} + +# format multiple lines for output +:set FormatMultiLines do={ + :local Key [ :tostr $1 ]; + :local Values [ :toarray $2 ]; + :local Indent [ :tonum $3 ]; + :local Return; + + :global FormatLine; + + :set Return [ $FormatLine $Key ($Values->0) $Indent ]; :foreach Value in=[ :pick $Values 1 [ :len $Values ] ] do={ - :set Return ($Return . "\n" . [ $FormatLine "" ({$Value}) $Indent ]); + :set Return ($Return . "\n" . [ $FormatLine "" $Value $Indent ]); } :return $Return; From 57c5c3f7049c0d60340c7fa66cb85cc2d5b65e78 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 20 Sep 2023 12:26:49 +0200 Subject: [PATCH 1627/2612] collect-wireless-mac: add CNAME(s) in notification --- collect-wireless-mac.capsman.rsc | 8 ++++++-- collect-wireless-mac.local.rsc | 8 ++++++-- collect-wireless-mac.template.rsc | 8 ++++++-- collect-wireless-mac.wifiwave2.rsc | 8 ++++++-- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index f21fc46..f421a53 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -18,6 +18,7 @@ :global EitherOr; :global FormatLine; +:global FormatMultiLines; :global GetMacVendor; :global LogPrintExit2; :global ScriptLock; @@ -58,7 +59,10 @@ $ScriptLock $0 false 10; :set DnsName "no dns name"; :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ /ip/dns/static/get $DnsRec name ]; + :set DnsName ({ [ /ip/dns/static/get $DnsRec name ] }); + :foreach CName in=[ /ip/dns/static/find where cname=($DnsName->0) ] do={ + :set DnsName ($DnsName, [ /ip/dns/static/get $CName name ]); + } } } :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); @@ -77,7 +81,7 @@ $ScriptLock $0 false 10; [ $FormatLine "Vendor" $Vendor ] . "\n" . \ [ $FormatLine "Hostname" $HostName ] . "\n" . \ [ $FormatLine "Address" $Address ] . "\n" . \ - [ $FormatLine "DNS name" $DnsName ] . "\n" . \ + [ $FormatMultiLines "DNS name" $DnsName ] . "\n" . \ [ $FormatLine "Date" $DateTime ]) }); } } else={ diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index 6bc8f45..99f8d3b 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -18,6 +18,7 @@ :global EitherOr; :global FormatLine; +:global FormatMultiLines; :global GetMacVendor; :global LogPrintExit2; :global ScriptLock; @@ -58,7 +59,10 @@ $ScriptLock $0 false 10; :set DnsName "no dns name"; :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ /ip/dns/static/get $DnsRec name ]; + :set DnsName ({ [ /ip/dns/static/get $DnsRec name ] }); + :foreach CName in=[ /ip/dns/static/find where 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 ]; @@ -78,7 +82,7 @@ $ScriptLock $0 false 10; [ $FormatLine "Vendor" $Vendor ] . "\n" . \ [ $FormatLine "Hostname" $HostName ] . "\n" . \ [ $FormatLine "Address" $Address ] . "\n" . \ - [ $FormatLine "DNS name" $DnsName ] . "\n" . \ + [ $FormatMultiLines "DNS name" $DnsName ] . "\n" . \ [ $FormatLine "Date" $DateTime ]) }); } } else={ diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index df6b831..a584c79 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -19,6 +19,7 @@ :global EitherOr; :global FormatLine; +:global FormatMultiLines; :global GetMacVendor; :global LogPrintExit2; :global ScriptLock; @@ -73,7 +74,10 @@ $ScriptLock $0 false 10; :set DnsName "no dns name"; :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ /ip/dns/static/get $DnsRec name ]; + :set DnsName ({ [ /ip/dns/static/get $DnsRec name ] }); + :foreach CName in=[ /ip/dns/static/find where 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 ]; @@ -95,7 +99,7 @@ $ScriptLock $0 false 10; [ $FormatLine "Vendor" $Vendor ] . "\n" . \ [ $FormatLine "Hostname" $HostName ] . "\n" . \ [ $FormatLine "Address" $Address ] . "\n" . \ - [ $FormatLine "DNS name" $DnsName ] . "\n" . \ + [ $FormatMultiLines "DNS name" $DnsName ] . "\n" . \ [ $FormatLine "Date" $DateTime ]) }); } } else={ diff --git a/collect-wireless-mac.wifiwave2.rsc b/collect-wireless-mac.wifiwave2.rsc index 42713a6..04e65e8 100644 --- a/collect-wireless-mac.wifiwave2.rsc +++ b/collect-wireless-mac.wifiwave2.rsc @@ -18,6 +18,7 @@ :global EitherOr; :global FormatLine; +:global FormatMultiLines; :global GetMacVendor; :global LogPrintExit2; :global ScriptLock; @@ -58,7 +59,10 @@ $ScriptLock $0 false 10; :set DnsName "no dns name"; :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ /ip/dns/static/get $DnsRec name ]; + :set DnsName ({ [ /ip/dns/static/get $DnsRec name ] }); + :foreach CName in=[ /ip/dns/static/find where cname=($DnsName->0) ] do={ + :set DnsName ($DnsName, [ /ip/dns/static/get $CName name ]); + } } } :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); @@ -77,7 +81,7 @@ $ScriptLock $0 false 10; [ $FormatLine "Vendor" $Vendor ] . "\n" . \ [ $FormatLine "Hostname" $HostName ] . "\n" . \ [ $FormatLine "Address" $Address ] . "\n" . \ - [ $FormatLine "DNS name" $DnsName ] . "\n" . \ + [ $FormatMultiLines "DNS name" $DnsName ] . "\n" . \ [ $FormatLine "Date" $DateTime ]) }); } } else={ From 4c6c30550fe509267b599bc46a020d1639089744 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 22 Sep 2023 12:29:15 +0200 Subject: [PATCH 1628/2612] collect-wireless-mac: filter on dns type --- collect-wireless-mac.capsman.rsc | 2 +- collect-wireless-mac.local.rsc | 2 +- collect-wireless-mac.template.rsc | 2 +- collect-wireless-mac.wifiwave2.rsc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index f421a53..65effa8 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -60,7 +60,7 @@ $ScriptLock $0 false 10; :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 cname=($DnsName->0) ] do={ + :foreach CName in=[ /ip/dns/static/find where type=CNAME cname=($DnsName->0) ] do={ :set DnsName ($DnsName, [ /ip/dns/static/get $CName name ]); } } diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index 99f8d3b..3b97b52 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -60,7 +60,7 @@ $ScriptLock $0 false 10; :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 cname=($DnsName->0) ] do={ + :foreach CName in=[ /ip/dns/static/find where type=CNAME cname=($DnsName->0) ] do={ :set DnsName ($DnsName, [ /ip/dns/static/get $CName name ]); } } diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index a584c79..bba151a 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -75,7 +75,7 @@ $ScriptLock $0 false 10; :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 cname=($DnsName->0) ] do={ + :foreach CName in=[ /ip/dns/static/find where type=CNAME cname=($DnsName->0) ] do={ :set DnsName ($DnsName, [ /ip/dns/static/get $CName name ]); } } diff --git a/collect-wireless-mac.wifiwave2.rsc b/collect-wireless-mac.wifiwave2.rsc index 04e65e8..86cfd64 100644 --- a/collect-wireless-mac.wifiwave2.rsc +++ b/collect-wireless-mac.wifiwave2.rsc @@ -60,7 +60,7 @@ $ScriptLock $0 false 10; :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 cname=($DnsName->0) ] do={ + :foreach CName in=[ /ip/dns/static/find where type=CNAME cname=($DnsName->0) ] do={ :set DnsName ($DnsName, [ /ip/dns/static/get $CName name ]); } } From eef0662aa7c6213855044ae9bdc84e8326512913 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 29 Sep 2023 14:08:27 +0200 Subject: [PATCH 1629/2612] netwatch-notify: allow to give different origin for hosts... ... to use differing notification settings. Add an origin name in netwatch configuration: /tool/netwatch/add comment="notify, name=dns-google, origin=netwatch-notify-google" address=8.8.8.8; /tool/netwatch/add comment="notify, name=dns-cloudflare, origin=netwatch-notify-cloudflare" address=1.1.1.1; Then configure the notification settings in `global-config-overlay`: :global EmailGeneralToOverride { "netwatch-notify-google"="google@example.com"; "netwatch-notify-cloudflare"="cloudflare@example.com"; } I think it is best to handle this as a hidden setting... Handle with care! --- netwatch-notify.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index e1d489a..5482ea3 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -115,9 +115,8 @@ $ScriptLock $0; :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "up" \ ($HostInfo->"up-hook") ]); } - $SendNotification2 ({ origin=$0; silent=($HostInfo->"silent"); \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . \ - $Name . " up"); \ + $SendNotification2 ({ origin=[ $EitherOr ($HostInfo->"origin") $0 ]; silent=($HostInfo->"silent"); \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $Name . " up"); \ message=$Message }); } :set ($Metric->"notified") false; @@ -169,9 +168,8 @@ $ScriptLock $0; ($HostInfo->"down-hook") ]); } :if ($HostInfo->"no-down-notification" != true) do={ - $SendNotification2 ({ origin=$0; silent=($HostInfo->"silent"); \ - subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . \ - $Name . " down"); \ + $SendNotification2 ({ origin=[ $EitherOr ($HostInfo->"origin") $0 ]; silent=($HostInfo->"silent"); \ + subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $Name . " down"); \ message=$Message }); } :set ($Metric->"notified") true; From fedda2a946a336fd9204488b179d30ce1f0a5730 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Oct 2023 22:08:26 +0200 Subject: [PATCH 1630/2612] collect-wireless-mac: ignore remote aps... ... which are listed here in station mode. --- collect-wireless-mac.local.rsc | 2 +- collect-wireless-mac.template.rsc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index 3b97b52..0594ceb 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -33,7 +33,7 @@ $ScriptLock $0 false 10; } :local PlaceBefore ([ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ]->0); -:foreach Reg in=[ /interface/wireless/registration-table/find ] do={ +:foreach Reg in=[ /interface/wireless/registration-table/find where ap=no ] do={ :local RegVal; :do { :set RegVal [ /interface/wireless/registration-table/get $Reg ]; diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index bba151a..75073a4 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -42,7 +42,7 @@ $ScriptLock $0 false 10; :foreach Reg in=[ /caps-man/registration-table/find ] do={ :foreach Reg in=[ /interface/wifiwave2/registration-table/find ] do={ -:foreach Reg in=[ /interface/wireless/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 ]; From 702abd2a5d84dc95312bac3f43aebaaa5f159754 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Oct 2023 22:20:32 +0200 Subject: [PATCH 1631/2612] log-forward: add 'raw' in default filter... ... which is used when logging raw packets or commands. --- global-config.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config.rsc b/global-config.rsc index 7d3ef7c..172c4cd 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -107,7 +107,7 @@ # text. Regular expressions are supported. Do *NOT* set an empty string, # that will filter or include everything! # These are filters, so excluding messages from forwarding. -:global LogForwardFilter "(debug|info)"; +:global LogForwardFilter "(debug|info|raw)"; :global LogForwardFilterMessage []; #:global LogForwardFilterMessage "message text"; #:global LogForwardFilterMessage "(message text|another text|...)"; From 87b136f3a9c6b389f6cf95d37a4f0b638555c796 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Oct 2023 19:48:30 +0200 Subject: [PATCH 1632/2612] mod/notification-email: handle new property name... ... which changed in RouterOS 7.12rc1. --- mod/notification-email.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index e266201..a505a50 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -42,7 +42,8 @@ :return false; } - :if ([ :typeof [ :toip [ /tool/e-mail/get address ] ] ] != "ip" && [ $IsDNSResolving ] = false) do={ + :local EMailSettings [ /tool/e-mail/get ]; + :if ([ :typeof [ :toip [ $EitherOr ($EMailSettings->"server") ($EMailSettings->"address") ] ] ] != "ip" && [ $IsDNSResolving ] = false) do={ $LogPrintExit2 debug $0 ("Server address is a DNS name and resolving fails, not flushing.") false; :return false; } @@ -136,7 +137,7 @@ :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; :local EMailSettings [ /tool/e-mail/get ]; - :if ([ :len $To ] = 0 || ($EMailSettings->"address") = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={ + :if ([ :len $To ] = 0 || [ $EitherOr ($EMailSettings->"server") ($EMailSettings->"address") ] = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={ :return false; } From 65d05a757b60fda68547b0f4df9ab397fcfd71c6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 Oct 2023 08:57:24 +0200 Subject: [PATCH 1633/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 9024268..39fc8a9 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -28,6 +28,7 @@ Add yourself to the list, * Christoph Boss (@Kampfwurst) * Devin Dean (@dd2594gh) * Evaldo Gardenal +* Giorgio Bikos * Harold Schoemaker * Hugo BV * Klaus Michael RÃŧbsam From 4c51b2fe52d8972dd8e84586a1eb700d56c00013 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Oct 2023 10:29:28 +0200 Subject: [PATCH 1634/2612] telegram-chat: do not cover existing variable --- telegram-chat.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 62a6ccc..075161e 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -130,16 +130,16 @@ $WaitFullyConnected; } } } else={ - :local Message ("Received a message from untrusted contact " . \ + :local MessageText ("Received a message from untrusted contact " . \ [ $IfThenElse ($FromUserName = false) "without username" ("'" . $FromUserName . "'") ] . \ " (ID " . $FromID . ") in update " . $UpdateID . "!"); :if ($Text ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ - $LogPrintExit2 warning $0 $Message false; + $LogPrintExit2 warning $0 $MessageText false; $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; replyto=$MessageId; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("You are not trusted.") }); } else={ - $LogPrintExit2 info $0 $Message false; + $LogPrintExit2 info $0 $MessageText false; } } } else={ From 8e9734347e365f9a801096664c27bf0f76d0bc4e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Oct 2023 10:58:19 +0200 Subject: [PATCH 1635/2612] telegram-chat: parse (one level of) JSON into array --- telegram-chat.rsc | 74 ++++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 075161e..73fe6fe 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -45,20 +45,30 @@ $WaitFullyConnected; $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; } -:local JsonGetKey do={ - :local Array [ :toarray $1 ]; - :local Key [ :tostr $2 ]; +:local ParseJson do={ + :local Input [ :toarray $1 ]; - :for I from=0 to=([ :len $Array ] - 1) do={ - :if (($Array->$I) = $Key) do={ - :if ($Array->($I + 1) = ":") do={ - :return ($Array->($I + 2)); + :local Return ({}); + :local Skip 0; + + :for I from=0 to=([ :len $Input ] - 1) do={ + :if ($Skip > 0 || $Input->$I = "\n" || $Input->$I = "\r\n") do={ + :if ($Skip > 0) do={ + :set $Skip ($Skip - 1); + } + } else={ + :local Key ($Input->$I); + :if ($Input->($I + 1) = ":") do={ + :set ($Return->$Key) ($Input->($I + 2)); + :set Skip 2; + } else={ + :set ($Return->$Key) [ :pick ($Input->($I + 1)) 1 [ :len ($Input->($I + 1)) ] ]; + :set Skip 1; } - :return [ :pick ($Array->($I + 1)) 1 [ :len ($Array->($I + 1)) ] ]; } } - :return false; + :return $Return; } :local Data; @@ -73,26 +83,24 @@ $WaitFullyConnected; :local UpdateID 0; :local Uptime [ /system/resource/get uptime ]; -:foreach Update in=[ :toarray $Data ] do={ - :set UpdateID [ $JsonGetKey $Update "update_id" ]; +:foreach UpdateArray in=[ :toarray $Data ] do={ + :local Update [ $ParseJson $UpdateArray ]; + :set UpdateID ($Update->"update_id"); :if (($TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={ :local Trusted false; - :local Message [ $JsonGetKey $Update "message" ]; - :local MessageId [ $JsonGetKey $Message "message_id" ]; - :local From [ $JsonGetKey $Message "from" ]; - :local FromID [ $JsonGetKey $From "id" ]; - :local FromUserName [ $JsonGetKey $From "username" ]; - :local ChatID [ $JsonGetKey [ $JsonGetKey $Message "chat" ] "id" ]; - :local Text [ $JsonGetKey $Message "text" ]; + :local Message [ $ParseJson ($Update->"message") ]; + :local Chat [ $ParseJson ($Message->"chat") ]; + :local From [ $ParseJson ($Message->"from") ]; + :foreach IdsTrusted in=($TelegramChatId, $TelegramChatIdsTrusted) do={ - :if ($FromID = $IdsTrusted || $FromUserName = $IdsTrusted) do={ + :if ($From->"id" = $IdsTrusted || $From->"username" = $IdsTrusted) do={ :set Trusted true; } } :if ($Trusted = true) do={ - :if ([ :pick $Text 0 1 ] = "!") do={ - :if ($Text ~ ("^! *(" . [ $EscapeForRegEx $Identity ] . "|@" . $TelegramChatGroups . ")\$")) do={ + :if ([ :pick ($Message->"text") 0 1 ] = "!") do={ + :if ($Message->"text" ~ ("^! *(" . [ $EscapeForRegEx $Identity ] . "|@" . $TelegramChatGroups . ")\$")) do={ :set TelegramChatActive true; } else={ :set TelegramChatActive false; @@ -100,13 +108,13 @@ $WaitFullyConnected; $LogPrintExit2 info $0 ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . \ " from update " . $UpdateID . "!") false; } else={ - :if ($TelegramChatActive = true && $Text != false && [ :len $Text ] > 0) do={ - :if ([ $ValidateSyntax $Text ] = true) do={ + :if ($TelegramChatActive = true && [ :len ($Message->"text") ] > 0) do={ + :if ([ $ValidateSyntax ($Message->"text") ] = true) do={ :local State ""; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); $MkDir "tmpfs/telegram-chat"; - $LogPrintExit2 info $0 ("Running command from update " . $UpdateID . ": " . $Text) false; - :execute script=(":do {\n" . $Text . "\n} on-error={ /file/add name=\"" . $File . ".failed\" };" . \ + $LogPrintExit2 info $0 ("Running command from update " . $UpdateID . ": " . $Message->"text") false; + :execute script=(":do {\n" . $Message->"text" . "\n} on-error={ /file/add name=\"" . $File . ".failed\" };" . \ "/file/add name=\"" . $File . ".done\"") file=$File; :if ([ $WaitForFile ($File . ".done") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ :set State "The command did not finish, still running in background.\n\n"; @@ -115,27 +123,27 @@ $WaitFullyConnected; :set State "The command failed with an error!\n\n"; } :local Content [ /file/get ($File . ".txt") contents ]; - $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; replyto=$MessageId; \ + $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Command:\n" . $Text . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ + message=("Command:\n" . $Message->"text" . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ ("Output:\n" . $Content) [ $IfThenElse ([ /file/get ($File . ".txt") size ] > 0) \ ("Output exceeds file read size.") ("No output.") ] ]) }); /file/remove "tmpfs/telegram-chat"; } else={ $LogPrintExit2 info $0 ("The command from update " . $UpdateID . " failed syntax validation!") false; - $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; replyto=$MessageId; \ + $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Command:\n" . $Text . "\n\nThe command failed syntax validation!") }); + message=("Command:\n" . $Message->"text" . "\n\nThe command failed syntax validation!") }); } } } } else={ :local MessageText ("Received a message from untrusted contact " . \ - [ $IfThenElse ($FromUserName = false) "without username" ("'" . $FromUserName . "'") ] . \ - " (ID " . $FromID . ") in update " . $UpdateID . "!"); - :if ($Text ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ + [ $IfThenElse ([ :len ($From->"username") ] = 0) "without username" ("'" . $From->"username" . "'") ] . \ + " (ID " . $From->"id" . ") in update " . $UpdateID . "!"); + :if ($Message->"text" ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ $LogPrintExit2 warning $0 $MessageText false; - $SendTelegram2 ({ origin=$0; chatid=$ChatID; silent=false; replyto=$MessageId; \ + $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("You are not trusted.") }); } else={ From 080b3cbf9d8ff6cde9aeb08650ead5c3eeb9e7b7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Oct 2023 12:08:17 +0200 Subject: [PATCH 1636/2612] global-functions: make $ParseJson global --- global-functions.rsc | 29 +++++++++++++++++++++++++++++ telegram-chat.rsc | 27 +-------------------------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 8c96c72..80f1f78 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -48,6 +48,7 @@ :global MkDir; :global NotificationFunctions; :global ParseDate; +:global ParseJson; :global ParseKeyValueStore; :global PrettyPrint; :global RandomDelay; @@ -694,6 +695,34 @@ "day"=[ :tonum [ :pick $Date 8 10 ] ] }); } +# parse JSON into array +# Warning: This is not a complete parser! +:set ParseJson do={ + :local Input [ :toarray $1 ]; + + :local Return ({}); + :local Skip 0; + + :for I from=0 to=([ :len $Input ] - 1) do={ + :if ($Skip > 0 || $Input->$I = "\n" || $Input->$I = "\r\n") do={ + :if ($Skip > 0) do={ + :set $Skip ($Skip - 1); + } + } else={ + :local Key ($Input->$I); + :if ($Input->($I + 1) = ":") do={ + :set ($Return->$Key) ($Input->($I + 2)); + :set Skip 2; + } else={ + :set ($Return->$Key) [ :pick ($Input->($I + 1)) 1 [ :len ($Input->($I + 1)) ] ]; + :set Skip 1; + } + } + } + + :return $Return; +} + # parse key value store :set ParseKeyValueStore do={ :local Source $1; diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 73fe6fe..6083fee 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -26,6 +26,7 @@ :global IfThenElse; :global LogPrintExit2; :global MkDir; +:global ParseJson; :global ScriptLock; :global SendTelegram2; :global SymbolForNotification; @@ -45,32 +46,6 @@ $WaitFullyConnected; $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; } -:local ParseJson do={ - :local Input [ :toarray $1 ]; - - :local Return ({}); - :local Skip 0; - - :for I from=0 to=([ :len $Input ] - 1) do={ - :if ($Skip > 0 || $Input->$I = "\n" || $Input->$I = "\r\n") do={ - :if ($Skip > 0) do={ - :set $Skip ($Skip - 1); - } - } else={ - :local Key ($Input->$I); - :if ($Input->($I + 1) = ":") do={ - :set ($Return->$Key) ($Input->($I + 2)); - :set Skip 2; - } else={ - :set ($Return->$Key) [ :pick ($Input->($I + 1)) 1 [ :len ($Input->($I + 1)) ] ]; - :set Skip 1; - } - } - } - - :return $Return; -} - :local Data; :do { :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ From bb899b1fb0b20d481fafc7d67193ab003c33a652 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Oct 2023 12:49:10 +0200 Subject: [PATCH 1637/2612] global-functions: $ParseJson: drop superfluous substraction --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 80f1f78..12d510b 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -703,7 +703,7 @@ :local Return ({}); :local Skip 0; - :for I from=0 to=([ :len $Input ] - 1) do={ + :for I from=0 to=[ :len $Input ] do={ :if ($Skip > 0 || $Input->$I = "\n" || $Input->$I = "\r\n") do={ :if ($Skip > 0) do={ :set $Skip ($Skip - 1); From 7df4f9e78c9213dfb1bb9e423e1d55d2bc01dd6d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Oct 2023 12:54:59 +0200 Subject: [PATCH 1638/2612] global-functions: $ParseJson: handle outher curly brackets --- global-functions.rsc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 12d510b..df374b8 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -698,11 +698,16 @@ # parse JSON into array # Warning: This is not a complete parser! :set ParseJson do={ - :local Input [ :toarray $1 ]; + :local Input [ :tostr $1 ]; :local Return ({}); :local Skip 0; + :if ([ :pick $Input 0 ] = "{") do={ + :set Input [ :pick $Input 1 ([ :len $Input ] - 1) ]; + } + :set Input [ :toarray $Input ]; + :for I from=0 to=[ :len $Input ] do={ :if ($Skip > 0 || $Input->$I = "\n" || $Input->$I = "\r\n") do={ :if ($Skip > 0) do={ From 8ecde47a7836de8ec0e42ab2d95e80aff43151a8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Oct 2023 13:07:21 +0200 Subject: [PATCH 1639/2612] mod/notification-telegram: remember ids of sent messages --- mod/notification-telegram.rsc | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index ea47b1a..641c6f0 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -15,9 +15,11 @@ # flush telegram queue :set FlushTelegramQueue do={ :global TelegramQueue; + :global TelegramMessageIDs; :global IsFullyConnected; :global LogPrintExit2; + :global ParseJson; :if ([ $IsFullyConnected ] = false) do={ $LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false; @@ -34,14 +36,13 @@ :foreach Id,Message in=$TelegramQueue do={ :if ([ :typeof $Message ] = "array" ) do={ :do { - /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \ ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ - http-data=("chat_id=" . ($Message->"chatid") . \ - "&disable_notification=" . ($Message->"silent") . \ - "&reply_to_message_id=" . ($Message->"replyto") . \ - "&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \ - "&text=" . ($Message->"text")) as-value; + http-data=("chat_id=" . ($Message->"chatid") . "&disable_notification=" . ($Message->"silent") . \ + "&reply_to_message_id=" . ($Message->"replyto") . "&disable_web_page_preview=true" . \ + "&parse_mode=" . ($Message->"parsemode") . "&text=" . ($Message->"text")) as-value ]->"data"); :set ($TelegramQueue->$Id); + :set ($TelegramMessageIDs->([ $ParseJson ([ $ParseJson $Data ]->"result") ]->"message_id")) 1; } on-error={ $LogPrintExit2 debug $0 ("Sending queued Telegram message failed.") false; :set AllDone false; @@ -64,6 +65,7 @@ :global TelegramChatId; :global TelegramChatIdOverride; :global TelegramFixedWidthFont; + :global TelegramMessageIDs; :global TelegramQueue; :global TelegramTokenId; :global TelegramTokenIdOverride; @@ -73,6 +75,7 @@ :global EitherOr; :global IfThenElse; :global LogPrintExit2; + :global ParseJson; :global SymbolForNotification; :global UrlEncode; @@ -111,6 +114,10 @@ :return false; } + :if ([ :typeof $TelegramMessageIDs ] = "nothing") do={ + :set TelegramMessageIDs ({}); + } + :local Truncated false; :local Text ("*__" . [ $EscapeMD ("[" . $IdentityExtra . $Identity . "] " . \ ($Notification->"subject")) "plain" ] . "__*\n\n"); @@ -139,11 +146,12 @@ :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; } - /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \ ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ - "&reply_to_message_id=" . ($Notification->"replyto") . \ - "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; + "&reply_to_message_id=" . ($Notification->"replyto") . "&disable_web_page_preview=true" . \ + "&parse_mode=" . $ParseMode . "&text=" . $Text) as-value ]->"data"); + :set ($TelegramMessageIDs->([ $ParseJson ([ $ParseJson $Data ]->"result") ]->"message_id")) 1; } on-error={ $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; From fd1263324dbbb0e80bc99e30d317eca9fd7b264b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Oct 2023 11:48:49 +0200 Subject: [PATCH 1640/2612] doc/telegram-chat: update screenshots --- doc/telegram-chat.d/01-chat-specific.avif | Bin 31869 -> 38468 bytes doc/telegram-chat.d/02-chat-all.avif | Bin 48099 -> 54713 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/telegram-chat.d/01-chat-specific.avif b/doc/telegram-chat.d/01-chat-specific.avif index 387dc3aa207d4205622e44e403dec4449f522268..ab75f782ea9bf41499fe92349387c418489c8a6b 100644 GIT binary patch delta 37680 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 delta 47351 zcmaI6Wl$Ym(=NQR;32pKcXzi91PSi03GVKJ!3l1`2^!qp-Q67mL4v#MKHT?H&-;Gg zk8`T_sy(Y}bx+IHJw4siTne*&2OaB$MJogXB@}?5K_C#++fNq+qTY&&_Jxv3K!y4Y z-4dIi3B?Gtkq`u>3av?=oRenB9^H0XaE_5M9l*xiR_vo|zrV#5V)c8ZrS+ zt1(JW*7KZ2TfqBes;yEoWxp4JlNZ`AVydkwOcmuuBU*adJ*TASA_G7or!~JPJ`a7z z7=n<N`%#4fcoeL3k>57ACDaIJ59AlNf%?!WR+QE9gfWIGO2XNQ0PV5l6uS;qy z7BCfNhCyFP)PE!dAgm5OqNt}ZeQ99+BA-8@wG*$nErO{mfd%^S0{(mP@4xmP9s4Ln z8S_r8io}=8Xx;(ePMwZl>;e457El%?HE8!KJ)RJd#(GSnZ=#hS>62~Y^K&l*1i+El z)NFYmRp|N3y{JnRUOla!r@hkWoIY|_!?9i9w zTv2vL5ZxMks%h@@ILq4Za+43mXL#_k;?GW&#Db*2z_(Q zrEt78?D-m(o`Fr&onoKPf9_*w8Tjfw_|IwKS@`GMnAb<_-8hjFb_tzu0CkWOZ6s$8 zSbHPD8)XRp*HSYb)Bib#<&#VDa68Guy<YHBgr5Ak#dd7(fbVc-f4xkvr`Btz}3*=&1h0@Mnf{J6a6m}r_n!8qz=R?Qcs_r z=?r@p>=&dvp}{@nYQ@i;Vd;5_51lZDPx77rDuwmGPTJA!NkU!Fjd?l%dg8uO6c$gW zI{21#{!uFgn0sznU+ue&I_B;8*ChV+(XuTB1pe@5!mmxGS#V3^A8neNFpPKC)FPiE zH8a}2cnVowRjFYvXN+Wv&Qi`*i_dbyf0}!IQjx+>Y;Vmnw3-cIcBAH4d(<4~_8ExN z_*A~R_w^qnuQW7%HXi;XrK+qeQcbOh#Gj=Dq~QGQ@ed|~&;MvOM#F52(|dXM9$ON$ zFGO$d+Nj7Ztarm1d1RMPvHOO_U&;8O-59S46*6Xf(TRH@r-3X2cOfg@A2(c1v{%s# znNFNu!>2+%WD}|yeW!(;zyHGMWc_nAXH+Ho6QXf~CWfF|tQdi~f?pMOjg74_ zpjXvJH2SsGp@}|m)^Xo+z8Z-|^&M!3SHR$2F$V%b~7mZvZxR3DP;1|X5gwxB*c6HE__e9+3`tmJmJNj1(N7Us( zWb>w`_Qo9sGNaK)G?Ey1sJZZ4~p^whGE^sWiM1Ly11|palc5 z=+1|A%Z=qE<>IfcB8RdX7o&&FMHAXV#EaDEo(puuj){cx_%5kgN=XNH+OjCjcozfU z$v-;itCSYlL_N`gt_Hl<&_Q03JQ^ChN=P_?|eGM+h50$&I^ z)=(Vy=d#Ssv zTpU>?YD;oPbxAl^gu=0wF|ha5SZFfeYE`VdKoNo?Eoa zdf!&pbC~h?k_7?P6!7$#nUY%F(-c4PKtQG%=UOql&zcVz8!Nn;Kp}T#%yaZR%bw>F zr@`WafwrBSGyRcgX40J_eDKW)1hlL+dcGz#JRbr++IVADmhabh9kbOrHv6QA{Jaqe z0Z~MS2*&9+h+~;7s^a=3@>_{OK&vFLBV~mFx0&{DX0ZXD==YLzBM#8|fz%&Yi~=i$ z|B(F*U>c+b>L^6u>}Y~-fzgfEw=8xv7ucHu0VP*HheAM$xqJq6K3Q*6gMzknK9yrb zja`}S3ZO3u_Y3vwCBG$hTUiafd=N;IobOd*LY)U!njoMG;Kd94ha{o?Ddrv#0wTC( zb*bicnJx5wsJ!B{n$K4*9KUA|*dH8qxMOLK0F3-tn}s~jqQRK*{II5}QGG#GN={G{ zJivuvzJV~|n=E4zgU_%K(1qH@y<`Cdl%0`vHw*!7l{T(^1@=atwqMOGm0yAG#DNGr zpHWBJrzS!|W0F6QX~z56x!FzMP$D-?MJE+~rG)1#?#*m~AqB;!oqyP&p^Sn50yJcA zxi;&SzF55vm@K@@t|!@h#z(sq)P^5V2tb<)nLL_3kfx3x41l@~i~AyyuC&QYocFuD zGSr0R>O(99)TMYo7byA$S(XX_=9NpvwR3M{E9fQp>J?>DAA`!3+|!K~MD4Ma=@P^p zvNlNuH@dTVJHQ~psnTwz^$HI>Tk1*~zfn^HZ=B|x)n66+(Y=5%lm0y0$kV2TG0H!o zyhNbARhSK|tR=ROZjozp+R65*1DmYy*Du!6*Z6pjUcIl-z(BR#$!>L%$Ij1HA_U{1 zTy-jJPw^S_p!GZoot4$&-45HXotk8kZ`nB zbEe~D7R$@6g}VLJ;^B!af3wO(7F#Rr>IPvZ`0?heF@K+6qGUqOZwKM}F1?M3z=$xZ zXOso5fntyB##LtcY>dYHg}Aw7nU&09Q|ulx>r{6E0Aas=)2j?~*-+NjA($#EJXY#q ztB%?Ar#NQBQ_e9pV1H4jJ6c>pdBsc}uX)fS$>?~)Rc8EEcVW-)&n>%0f^1h$L{k-b z^J{yAzU%?1zm0*o(^+$ZAR1H89#JE9CF%Js#l^d%yd)k+VE=3TOxttopSbDt)(PQI zF7(Asq}COYy!(VRmmAox;5cR#PerdUog%DJ^aX zMwV>XV@A)kF=)QSREN7gI8m(QI3OC1Z4$R173cc#d0S_Fkml-2o>Z4Rei=3R5=Gmr*km-1PDD z_U?AfM7brrx^;-HXu72WE(nhA5#`0&EF46e`~P1IQ5O_(CG2nMf}y5@qtE!2`s}FM zng9YqoDX`X8S1BKK2m3@g`m;LTYr!Se?Qi*TGM9?kAd+uES$A#4G>iH-^}L=?#>J`t z;LTTur}(Dm4|XD&qo96w6k>M1qriL3@l5Qmzgeck1YbH(vYssJugm*v0d__szsL>n zQ%B&@OxqZAor$Yi^i@nw7E?pjAlvVf=XLJl?aM-@j?(GMcieGJ^m}}p*VkJ=cMci& zZQ{g@S_$I<<5|&&Q*&hnrhkNNGWr^@tu;E&9_jC;2>(W&|CwnSXbuAdGNx$|>NhMK zDyxha(b?aoe-Ccq7*x!s2Xqc)@z6Y*8>(nPPExRrM{<&h*y&8|7s1*l?;PttLBr#J zjG>r)Q0*A^uEP}GyMo&B0}amjRp&^kg#13B4%=yBE~&uxf{ADKa_fFRL{1lyv~I>{ zffntK61yxUn)G!R(VEMxomqKHWTWfx9bfD~cm}GhKr1L34zurNZ$suht;ibRqkRdM*<%9#;lP$^k zUPEZEFX2eTt^lBXS}>Ww!tk06Qb-*u6|fx^vgVf?a@P1Y7L}m37t5@!IJa;>cq*a2 z2KwjHWpeep6chYquwFTKUTb)0<2+fIc^Wu+L_zze8C?dCZ+tQf~tkbtYm{@e(vls3zo9fTm;%`p&R&^6(!ccNj+4hJ6b* z;~La9>U8YZ>X^9fWuaX91N5_zt|gNS19p;&LDAm~|IzOGU+p4V4eLEAJeA_@c|kiy zk88wphF9z}%OOyob~B%& zeuyFc+yxaKn8{GL$@E*NeKN7W=h!A5C~ViJmn}uagPNCQ1?1+nY^kFq&70ieer#56 z!(>80`BFuemj+D?tRmRM5@L>7}@Zph66i?;>b&a!n zh#lHmY*8UnP*T^~x@mJ7LJL7O>EAfgzm2x{8Gj4`bw9`K$=f2P#4~f7y8Xe0@)>*> zm-u8)7)O(|i&O;V7Bf-1Gd-5fHr}p88NI9S;n1&u_HreMYQ;cSC))V+b5Q|y z1Q|Rmh7%Ogm5htq$|^H=wTaCMFu`5o$1!)wF`Ug9WyQcx#Mv*%Zue<-kH(%UbLVj( z3L1$v*AMBklNjaxt%q?GuUVp*@GO#GA4aL%eVIU=p}u4=Nax55r4Clro@t=(D~~Bx zbxiwBKfqq3>6oCz+pqn_UrAcin1($gt6bA`T-S75WLt=CN$+oAkTie`?6-O-1MuM6 zY3l=hvC)%hDUvi}WK!eE=U!Ojo66K@2KLH`Itf^M7DBzJL^=avD$vY5~`KHKhu z1#~W|yg7c43DZ8}9C4q?@@UEn$TZPo8Z&EJ>}3sd3Eql%57{AujPVX8l{|!6RP?mU z`zB6mt^0SY7~&4+dZmI^nC7}FjNUns*UkYtlWz%dV!Nw zOX^R$s0i9mrw)AO zh?Qd5{Z>CQi_mlkXN}D*G)S(<_o!%&sx3#qgU5RT_(8Tep{rDl31hTh9M;@-2z?V} zU(xU7e<(pmP&x)_D}%lSya!}vn;Nfv`PXFkJw4zbOWhQa%?4qV4k*i%zQ-g?$aoPd zh8v;iE#1xKd;sWIBe3y}0~fEhXXaJ7p}HixZ>1oB^L=|16wf6r)o9R!}!GEtM17Ah4YvI+Z7+FS0~IN;&`qKf8LM z`ja7EWlNmT2`M42Dd7c>d7mW5@=;;3g@w_cD%7B968vJNLG(NjMPqY9lTwl2`(Wc& zAwueSO>tSO!5uKMI{Z;_OhIJ8S(SS?XcNb%9XB#-pm@NZ$t8yVvzRgA-Lt~|m?pWf* z-B20OQhSDq^}&h1Xel$*lrICW8hP;#6|=c6Apj_FLzru-2KY&LC-c=% z2_NN{$BQ-LJs0BS>JAB;aWDl9TgJ`FZsn%D76cSz*_iZXuQkGY*<^FNS814XeLLX@ z=)3VUkLC*T`I8?+PbWNGbv?iI%PhDZ_B*ptRGul`FPQwskC)#4Y2Pq(sQHdu4Z5VA z2dF{Y(}~wnxU#>>L()VMY}Ylg@28#HnK$v+C7N*4<8KvmDg58t8 zBw2Ua<0IiI7a(nA9>o699qA6&kiktY=$K{bsKWHKHL!k%mzOv8rYs^0dDJBVcsI9B zY=09k^+Ch_2TKJ%)JpyJ6HAqDouna$bM2lTf5sH9aYrxi-7g5JGbH&~8Sqkky0_}b zf*XN=zD7LF02^j8)ezhqS80t#Xi$lc)1UPW4Ee>^{fG+?&k8fFzh;Kc_{r<{w zyX~krlelHUg0-@C(QcB3HZP>%Ea?dMcq$HY{-MBESlX-Hfp2{S9Cx8IqqZap8CMh- zlW|udY2plJ;-7^jxK|rriyyQHKuj6iN4gmelG$k-WRd*Ic$DS^UaCjjE68|M!s>%G z)?dDF^HCI?C1?WAOAydruKU@+LQ3eg^2hH#{7m$)*WP;!F8rAMVASz-=VueV;1ui+ zwXa*4>@|v3H>;N!`M!%l8RoS`0y`DtPUn}dw7$8j3FC0?(bG9jY%xf zAw5-7@U*_EeEHN~Ib9~HgQ;9XOdBn<3|$1LO-c763J(g9Vd6Er56TUv{b#`l7(zg? za1hXoqy4S{o`iR1I|M|EeD=7tG1A5xxllLBL3})oiSj~Ey;WdGUsk!Kv47QE@rl6= zTSl@JgG((TZJK;blx$qXmwxn|zLiz3GC#wHMbCq^?sLfrd;_B&iJX98gY^ayk&WDa4uzhE3v-oo$1q=sFMr$ zHD|U6H7K0)Ir?X&sDN*crEa+@GpMK~9d^4}GB7}|0d=(5%p=x?;^ATf0mkS%o97(S zzyDT1`G?c~PsRVv_a8rf{Ewf6s^GjsTK{)XFIiqpENSwxA2+fdtQuFM{gF$1!n%O= zY8p9X4nR|7D{8>77S}O>bFxJ8S4|w0u~eR$rxZ5E?3Q|Es6+#nWL6;{$#Ng(Z%pA* zw;7uqxUf6%XoTKo9a85?5K#F4*Khi351<}1e6lM%2*?`#(X7pbf#Q%}peDPanvJMz z`jipMjP$zu=o(AHvJm}J*jE8?Bs<9L)VuqYhRW}Wg(3TGSBtMFlVbyGiDK5)&#;az z4)cq^P}fnUIRsRxChEBxG8b?vl_D}ce4>g2^7}lzPhS^d>88d3f4LgTM)>Hs@YB)N z-ll7;i+iRw+JS$TlCq;QT$L~$?#m*0Z_U@GyLdS+OUU=!a4-}6N!<*{l4W6xkJnB% zHpy^>!8@6t=MI%j({PLA5U{0TTEySZMC;V~RP80CFr$u2*!^SgFHAIB)?fOWDpwSa zz(Y1QrZSfYa?QpV^h=P25nq>}`I72Hj=9~LovFYUnHGjLJ}6poP8Ch;1Y7z>mp7xV z=D~z}Bg2@c0uElIMl}RTw|l1`$ttvu%zlD3=SU835M-imHdh|69+eSlW~wChn*x9E zFD<%Vc>YVN)jQd^OGG}r2We80so9WxE9t(UNEMFjeiYZ_{!5J#8oK+$pQp7FsNEbF ziTbtwg~vO$&VNGqE%5${VH~MrhTq>rAt3UXw;*@0-vtbyZ>B}?d35D=SV^vUR&A~Urz{uu|n)pY)Lzo2pm==$s80)K*5nNs~_ zDQT6vm|}hQlmCyOwJS}9W~asw>zmb z6@N%u_&G};D`$|%@p)XWC8TTZ^JSNgQKm6}!29Vz)WO})pTil-nQ2fz^0KpnPVLhP zQJiP%DK8H+N2pTWUr)Z<#ESV(An*|qWFpJL196E=BQ;;DmhpyZC}uNezv$u<@G6^r zM27pgfh5v>*8SH%CPuz0jg2(asR{nC8{eLAN4AfZ;_<3&t0VRLYW1El$HPpoP@Vg` z0g5ne_miUmPjESdp;$b^u+e}bOI);L=5>G3emQyYj{!Z~^=>C81wOu`nY;wKx+J%s zxqz@WVX~&FP&-;x;m7^tq&2K0sOs(kpld$J)kRYUscML#9jZ8v!V)*3$OU7Bnin4Y z&GG1UT&hz7rMjgmu0yFptJZDMz{~iuR3?dSjWe#7G+|!VGahkJI9rW% zr0=uwK{(t#g=Ise=l8fONy*!8C23IP<_(v^ zu1iy6uQM(_Y|`-Xs-JUalR?Mt`aD}_>@{RgrWWoAw5hG)wSsiUiG&z-DN_x-TEKbL ze^EeBX49Jt?jYh|dOPn|R*Dsv%fAFoWJ+&}{-t@LjrKtwPr6$zQ(@Gc(&? zAzX<6L{6Gu^kb2)D18@UbQ`fHY65qjU8}Hhs3Sp!!yxRYuVlHpdR2pbj`9x*J0(gZ zsBS`(M@)?xx_Gnuz*mW*w~*M}07g0hw@Tmw?Kz?)^q+t*6uum2sd`Z);k?h~fK3w< z!TL)k2`8?*&=N1$x`udDaydMQM42#CT0O2GWsF|ttjr~Nq0CljoJ(7Ke%Q0JJ%EGj zzIdCY(V$8-I_$_l7+*+_OB4T@MD$*Bde)<`Cm9Jx-&@+Kkb)Wx7UTy1 zr6>h9h9IE(aQA20%J;yOl=@r675CPt#@-dy@b0)2pt%4CnBTO}lgm2x(7t^4aJ2+c@eU31{l0Z&NCF3_aU% zYI8r~eZFC!QeIN%+*bZ6C2~cq2sAE*I^m}%WXJOp*GCHzTN=L_RD#dms_iWc@cZkx zl8D7U>&;FVoMpi$Y`{>*mF~$a(fi8VBhYA*8$4lw*sUV5X22?wkwF z=lS}d0*JGBM+Y%FqhOS}gf|hAH~tl&_qH(Y|Jq_piMo6wyRPPjO_Bw_$2vXcVBQ0+$-nt=$`xs3k`(;zr&%^SBLw^ zPYTiuo|%G^YjYUVX9gp_7#5+ghV>**C*b?=$Y=S?K*4<3Z=VF*=D!US--iBus*mFw>H#Gl353o{0%q+) z&jeG7Z_I#ynE{;7I8$i72A}#aWw+u|;t-w->}9xI z?>jE0&AVu$#|@~5AQbe&Is{e`X6C08yFD6h9+m9w}3Kb5p3TD1;An`;l0cI5Y22y+y2K zX$YQ(Lj=8_H4chiEwfLp?*GyBRBv-5R)Gn2BWoUTKpgNk$F@qlDEqEF$DTRhN858q z9oYk2$~}`42ERMZdlIOFjioUyCQB+1^HC%s5`EUkQj6b&N|TX z+kuHR%eB@ra81oqCEa&aRf2~sgD^lyNPOhLr6K}?1*aeTkHUl@3VFb*3Ga@e7^Ay( zibr{~eln=@wY4&0+04cD2o}Dd)0~CLbS{@hn=Z&*+L0-ss^`{eTfdi+W0m{x`?_z4 zVr+SI$admL{TOA=75ep%?0QARKC!CkMCjdyk1Z#%-;`hYp!QzUZ_Qj=mboH)ZMAAD zqW-Y$D`u+v@#1xgi8~;9e217(T}6OkmqY3r1qkL?@$zvF+_O;*;K!}Gtoztvecg)K z7HiN*jXd8_G>b_l>6pvRq>EkK8qa55@Ey+XFQ-$hank%*G~N%GLV7b04$0rOc%C@2 zujh274KkLoSh?q_>5Elzqj4`bzs{Q6_-GK58r-K=JbbGp0&D>8yttD%^qHn8Oy)ku zsHKEZi37h=&R8{^>x`mn3w^mvMNP4(v<`122LFt%oIi8w@7ALU80hhZQj(@h2d(qh zzTRhZnMKF(vAC?wE`P@v@P``Gt!IXkHmz?`-0B2R&MBCNz;kw@5Ih)JF4d7;FmwQ z?L@nSBc$RrRDzoQ!P`C&Hxn~33z@R!58c}MBL3}rTuiqIc@bWT`BY@&b;5bOQ5~x; z^R89Mj!(TnwlaK7`r;^kd3^( z8fsi!jA|5Sy}&{D-qATe*}11S2CG}4#@Ie`4zmtyLf-a_~aS=Hn+`>SeLQfzxAjWy%LTdp&y=!Ys>Xw@u1T znGO2H-DSPT;NJRoRwn7KxqKeFD%ONN5>fic`eq-*6BVHT*$OWKE-Ct zJ&j)4$8uurv!Sjc4uxXrThv4;Z$Imj@4$}Ef5a-j{gC(Szk33Sq?;x|t0!2j?xbQ| zf8UVxZ4mytx&~1WmH%Dv=kn5IR2+9|zLyBab940a$poWa zlL|HEp*DNEEW>^%^^xHAesg9z!~idFf|OY ztfe)5LYT;q;!`lez7Ys|{w*#vKs8@!Lh=x(r{HSHx(V4q^;~dsvlHXK;mMQUO1tb5R!hTVng0WCit0i0K6CLH6EU_Lrw)AujcB{|+jWdI7 zM7>l(v`GMusq;77VKA>tzG-d{hwe=Ix{U5PrAa%`ub30$G= zV&Wm9;g-TL`5L7Kgq24xU|P8ff>1n5?bp2eY_SE;IXeguzvOBiKMarg2b&nL4#Y=@ z{{arJLgA3+l@do29UkZ5{DR7qRW*;_JzyApE)wU(-d@Z*LdX8*OrDki=s1(O8>Cy} zstrljbmIr#69nXt_L5_fv}W*3OLvml4vz%Y2a92g%+=PSA0FXz8hWu`O1W_KikN|^ zy?Y$s?vL%o5;;`i*xN<}Vu-f?ss;Th6e0*G96b;|86V6bsB47(X?3!6N+U+N`JLY1 zC(#*{GpM%Hxw%aa)9|niV9h!~lD{;NSbWmtrO{2fcKTp)xp}l4S#nOi2NwIpN2e{J zM>mkK_bIDKm6Nj{5|PCWai=fgzrZ{GoYbFCQ%=_TiY*pP;B`s;Bdi-0DMIS`Cl1zF z1cW*WV~|m6)?>>0H(2#ddUzgegS;jo!G471d`GS}eI~jexbV{g2!%zp7hUq+cr6b4 z)-%IkT>mX0I+tbkTW{OidaE0{MYw8M#bV#{Gq{yFFK=fu+RXYZ23p;5huIm@*Hc&h zY)OTu1Ka)v4u`!$+OL8AYoS(HM{9bTkg(o$a~WcIE7ln=rKCb<+cVh*95DwAzVjH zEti>_=;0Ui(v>-rR75+XRit%B`A*Bt1nksHaGI$!@Wu_q_ogA-An%Y8ifQ^ z{H;vo#!JrixDMgU8R_iz6+srCD7(~?SSybxFHV_!4|bRRW5D`CjM3WNV6xM3!;B-; z9i;35vs1cVY27ybGv|XjY9^l^vfCrMcO6m^Ivy-QLMid*Szn#L&+uX}{zRrhY%4t}8#r8oP^wEJu@|bEJz0CCTrRggO#d1BGb%KXK!M8I zdfZR3&;ppGL>uQxM*H&*DuAPQb5zOer<_+xOd2=U7_}N*Lv@ppxuf(THc0JF{ zCdbx?+V^1gTpp%h{!SOOe1%G`IcpC?Ae?E0IwsrR&b4)wCFap(CSRU!_-n+%X(;aa{QA>LwJ6G{Dmo4O&ATF8^L zhnfE3{L6s=Exf%IwS_Yz#Byv}Qg8T9quzD2>CT+UTqXnE=TrLn5SM(r)a##!W@tN< zFLt@BC<+;pxO&e;#1GRhRp!?jyx{ddX1t%88_jeS(MGT#@ve^MQ28tA2yZ)%;l%tcTq=bw_XDS<8r#-VWjng6 zX7}%u6!d0?^VNm$p{>S=E4)bhLq0jH=L}D6BEqRx$YE<=hDz_RPeym_)JZto2_Y@( z8aNHmi=7u5oiJl}JRghi>!5}6lP#yYwj?&SF2A47|x2L%o5dK6}FT?{MjFRIfZ7?ikuNsbA`#Iq- zAH81mc{QH>yA@7s+9;80C!4*DT}B}_mUG`%el;1#j%keD@Nf@%KPBaI`;_nHH;3EN z9J4VUDl6pGFt)P|Sql%YlSa0JvE(|t$ zaoCGDCY`+yDOq1=tP}Dqd?e6fMMUF?f2T$v4-2Cwy`r>2#tSFjE&xHo*ND08#P`5K zM+wl#t+_gVm%=U5M9pivx7&I?6cxcr)(|XyBextko2OojS9i@_bgJ6xlEDsm6s(7h zgr&TnOf!oLs&ekaL^qCe>!q%KK^(p%Cn+Vy*JvBIj6f z2?x4Lh?VW~G$j$a9m(u%BGVAg#6_n_IP(ugOABB^*o)aE%S^C%K#)aTK8=}~>YNJ< zsyn><@(|g0l(Ko2PBE<6@>ve}5PPUFy3}W_Y&-P0k@|}qo~v%%Gl7lMG}_iebscCN}*$GWpmXwhJ}H+sw2#YGYfX< zlfI-q%&FNG9~xMw^gU}<77piDSbbK<5tugvUV1A2<>U>e%2e+TkC8|7 z_H$MPVwfFee`ziDKwAXHi&NT`H)hJ0ip`5zOV`KP2fO=aCL4#ccPPoAxd9>~Kfs}y;(xP%Q__QW9NklDZ&ccZRRk|h*Zd2IjvIpxmI*(AwgFfuTt>U}KU+ zy96~HhZru};zu|;*u*M&46!M*$M?_E%-~$d^ykfKHBe_$P8ZE@S4?Q04U6~KEh+?N z%j_qOPDvf=@AAe=91<;Y6uoPN2~;H9Mov6M(8Anil@1(itQ$PxxcktPQHB(!J|t4? znEMFikLC@G0DN)OUo|r8YxPHTz23EnjV>r#*xK+gG4a;c|JO2anAI^pYN&|qL#%v%_hF?KqVt< zhHSY=ZWe)jsKBi>^!BZMH&5x~JVIi>+HQa2C?C#tP}-wrgm<!P%sjTQxb`@=aEh(M#}#y^^~hmX3ecQ;R-gey6f)oRoU?H(xdZs`rWAobAxf5 zq}HN-L~JjYQK><|b0=Btd@at+cFuK&S?2ohsPHaF;PLn**1%c8T)1B)6uAr2xFz_qA6kvC zM5rHJ^T+Aj8(Y`KnU9-Ylo}R&oa6L_zSCRDXv2j+<1bHI97Z<93KB>V!*X^!FOPLD z0tx)>%)#S$auV9U!BBqKW3(l{XizIqH<_)gFmARM-thT6Klg7DHn+UfyvHn`Nq!j< z3r^dB>+Kp0wie8T7XEgz3q{z~ud8m~n%PDsN9m9BDE>_}QF0WAu2>0qfAZn{4%ycMX2FTQ; ze%!#BgqUL7S7lg?7_ImIymnHasmnX`_rMH7pof3-;6#u_+-#fx(>_T5ab0(dVY9NE z1~K0{$YK` zu1ZSE+l=Z6<^rXyLKc?QB>~^~0kHxGRPU6@aI&uwdo28)r3w8J!R?F~sn_mMI>rZD zj8%A;`yVx;BoQPCHHi43W!P3e<{3rzo+6F{-ty*aK(KyqmA33Bqdhpbq#EtmVWU2eU zSAfr{af!5^D+TGp$g)k{fc$5vWSVo;Q|^T$@z-cN@@iY1Ps=M{S^HTk+vSAaY&S)T z3XSCX&kT9>&t&&dpZHXzgT(jn!3Ooq?YvJIuiXoiS5-;K6fqCOI6H*md+L;7CJZpX z9)}-|d5@<|$0{xDzolMj#kYSiM$*H8$4qj<8Vn7~g|l@re-+u90djE^m0JAR>6nmI zy^c6WKE=A-smeS$#}XCFnf6#!8%;!~^LMVOHl(WSYr04DCkBsNZ{wIE$wz^Is3UE z9{>62MnY#RPFj(4oiE|Ad;N22`9L%{sUVF=`!}*v9mS+?41*ZrltE3p8A6Ck9~TFb z<~wH+BQb8z0s}0IXA%F)g_HR=alJ--bZlYyn(a-wv~qv%bW&gPN) z?wqwDrL8(#YD=p8S>fGGN@}(>gp0rQoFRL`KB<4T>tEV(jNKe}0WuQdt1=>^PM)ynhl{vm(Ua++-@ zGN9(|q7WuwHXNps$I)2~jSKKGt~8N5RQ8ApeJVQZ z3Le^+BYToTDoYLiD^PdrZPZ}o6s~Te5$+v#<&g7nv{qy1Z3Sy!LEtnT;JUkg8k%- zGxdVS#mz6vXeT47%k~5$+@eKD7n734HJ|R3~$$qDoFDzr}R%u(e zheHPlJ$Z6gSW#7cHa55w*$JXs))@FB?{*b~v)}dN$o2czdjw4|i zt}B&R65gvuERDiwk}LP;kDekz77Ct+70xYD=APa}x89D~Y+erkrFno_fQ)eMB}1OG zu4sTO!%9^g^25$9r^{0IPhSn&xm6bS1a&2_deJt#>!>tXR^)rUtu?-0C|JImy=O%j zKxo*Af_A#*jjcVSX-;~W`a@`!q0Kxu$p|xouBjL?;C=2^BPUx9S*riAyZo$q7y0^e zw@X_e*LNZvdoFsGT1mOTP{~af>uc-;(HY4Ci3R{&MaR z`GrY zFl*F#Yv^`P1r+a;(tgyiust4`gqV|3UOsyo(GZi5N^{K+heUpmr7YyaXc*P*sh+9 z{e5Qaq;~@fZNp{8Nu|cQxYq6Miu;*1TqGMY=XKA=DzcQaCdbzB`|Ufuhsl=Q6b&-& zUSLKB%h~nrms-HiG=kSE>xIcHS8OL9r@<MfhW?VlrzL9<(buQRWYP;DpVeHDVZ&5x(}y$2i96o^*E!(_PBX%bilkKQ)X;ZW zlDd_uw(3lzrdX}3nObaktrXS zX!f)Uv8R@0QlXA3I|OK;O(ME$4|@uk?>ow8W7|ZTAUd}RhZbAZ$&Dg#{qydrB3+k; zJe>;cFP){oOG+`lX1jqDvV>*lB%ucdI`M@dBdB5WF<#cT=7_Qny0Du#Skw>7-d~wp z8U5pMVshE}w6!cP5r5<)W<<|mh!mx85t75&OAj~Ed2bcez5FrDTw+7bv%KRCj94+G_E zk65z*2R}f-zjr69t>r!a1AkKIW0t=1F}T97)KW$a)24Z}j~ zY_MjH&T(2*?F%|l!CyR%cYl?k20`$uc=h~|;>Snf)q zG)bjzKuqjJu7%!!*$HlUoV=Kj-nM%X1Pz7w(Lw6ltlYxL%_2@~)_pXg2Eg*R(xQlUSsDdlt665I&@Vv|v)MSXbFu&qV8(pV zqy7+Wt5nI8sVhEbXMfQ$dTt<7#WDT~hcmAH%>(!7{lF0m5L>_2j|e)&{olS4H%K9M za0TtD1s%n%DB(YA`t3YJL?6UFz~edvV0CUKJrhjel}|85crTR|Nxs2a2av zb_*lycZMcE?@Fu85(OKuhI;*FE9;c5&ONd!#z_09biZBY<2+_-kOdn}M?Cxm4&J&B zyp|sU^kv#O?u<0ek%?Hj5?Q>h`1KJgZF#F}vAlj3FDRtZY*DLW15cJ)^lbeFs?Nw0 z?S^4$eM3|bXn*qHCEo6)Ls`8n3a7T!)E7nuzMPK8%qaH@;=q#sCog1J;+JfCg4h=H z@*T4D13eUydE6m8E&Dzhlrw#A+q_yR{#{7OR`U2+q*ZU*{(b*Ejs17BC?J@htV{^2 z$~zjOmRIFa5x!~KU+30t!Me~O^R|ZG;)abrpI11Z)PLNt6~UdJQ4$hP7)`oKu&BNa z3`hi*)gf=K6ZryE;Wf=gJsL zWO#Q(r{^rt)>t-{A>))`GT_WsR|ZqqxD&|9@s}3@yq`D_GyaA%C};}{k9J`Ka;o+B zr)xg{UVkZ2C7g5M<{_W5dsGwgO>9rSFxRM^#`Jnun)9Jg z-wFcFI6Mg71{bvo(F)mwsQ-eJx(6s8|9ioX<^GB7!nbP}k%2Muv{J(6P}H6@FZn7| zZRbMI@Rp5D`v?$qa@Ca$hi#)E#4x&8xNeAmx0DascJ0coa7EQ{AQ%P+(aAt_UiI!s zsOTl}53;>QErK0HqT zN`JwsnlVMUJ@71!oqra)FW4JSsSjyj09(Fw_;*@!kF2}=?S89IaptXllg17DqhP-U zfsLez!1bu1NWt=GVk)}N`Ms+jj<7T);7hLf0vyVGo2$gFv!Kyq{nkydM4^v*G_=n4 zXja(?R|)iAXH~N=82?Agavk_jSXI|het!{r%>b53+S<*pbc&2x$cW-2k)YnN!KuJB+nwR2_q ze%)O|aAh!?gNH3N*lCw8bQUfm;D;R2h?bo1D#B+IDFzA%P8kpSQKH0~rBiIdpnu-~ zn1&I|Skv6sVvEk4Qk^nK77UUdDW4>@N1B+-f>Unf2Q1&0eQWbkbgAp0G3IV z;`ZL4mz*{8Tp3%bQR0pAb+g99?R@%yc+wD4 zCP){z$H3%$ag-4}BT-muYik2Do1pk4#vAAW{CxbZRT&9CFvMB=rGHdP{j5JWtmtbH zl#R5Zd$^pYD_qKn;%t>!6lPx5oA4~l)tmBas665pUJ}Kz_Lb08+j?>#H_aHLi6A*| zgP8VA;}1F~W%Ii+fYA8?h-VYj);Oe_!E2H7+d7o;Y5vKUtrvE#wY zG;?e8CtJY@%g~jT1-;P+qBvXTJQM0X#4%A}i-X>ujNw)@Cx6Bh(R0A8VEf1kg3zaP z3z(U&9K=zHzg6F_=?bsETmWmvD|qyP_0RVAa}p2Cf0~H>ZC0|q0Sz>Un@a^* zLH^M}zJM@+lehd_pPCWbOc@fm3x{WHcQ3^@kS}m`>aJiF5_~oiX`}z*s#;8V$_%wXf!L+@>VN8v;wmleny4(x8&$(OdNrt<4xD>H z*buON?G{!&d2c@jr$ARGb@b+Ij@qwW6UkR`Hb$Y)bHMw3MI6e}tH|sKIn)pnSs#mK z*Cx}K%#{OAB8jaF5xwF)uv&q^BYKap4-!A;CjgTW)-5=<9W15eQTsgveVY)*L9)?e zWPh(iqv|){Kpa@7|FhyWBXS7Kv=JD=Bts|K(KZnTJH(zoddQfx{%B1G}Dcy`R>;&Bee|WZWjbirfX(KE~IVm5Y zIJM3$5ytFCh{i0II=DUf|I{vbLlD=DLA1qm;Srl{&MBfoKzoItvAI5oki$GP6(@xv zM2Xux^byV!GF>k zuZ>a7eTWxKrf)zmH|eywT!ThJIXJnyT$1 z)D;q$psD#Lm~A-s$roOwkN2YlkfSP$rU^*#RPihD%?b; zBi8kp2*QW|MuJznCa$tLQ;7Ow^{S;zR(h>Uz>vtw3tItZ!hbrFXMU1K zQ`=Bp2jVUAP26`@tWE)lT><9);p}_+SLI>;EdD}m28GxvD4@}xLh6QBl@cuW{z`(g z?xcRWg-?X%qQiqeF68zEh|kTOHad5-6^CZ#O`aoGh82OV6vkhs-@y~%zDhBBEHj)l__&jn}eiOKFbCz_p{c-tnULSTZ9CYd6&;CbfSqr6r-BO@vKYT5uL2;UBMV?jT15T3CDLRAOgL-#}v^ z5st2guQZr*2Qfbml8S{vs0X}J;-37n-`v&&I7Ft{$DS^ z`|NxA@|9?qIlG6mUu?XKu#!4gGDq|PVUS8|!iNiqfHx{OPJb0T&jW?~UcNp}e{7hu z=kU<#xrMrv|C@4w!TF+qM{t{gD*Ah70Mt_!=@)Fr3G@ScUt19`YYnqn*Gll9!S2Fi z5kQDPV1zPaJA^R7xj+aYREjbadbdeAk5*3lJ5fP2om-_Sowpl#H6cTEK79-%@3I2? z)BXf*Ha*GHjDJJ`K2&2$KbZ$ml=|xM^(^mr2bEe|yr;R#xfo=Bs#K!=$7w2+8VrNR zY3v7(SqhymB!bM5KS#Jk-5sT%jIcjFa0#Noih7~ODqhEbT%9P1V|08l7&*Ib_#S9j zS2nuqfK;x=5j~2wsb_sQYVFkck==-EbLw}0xdW<^n3tztkSHoLkb~-1ox*eFAR#ZE8_Ck z;wIx@qJIAzw#Gp;UdIi4hv(W>)5&je@9Habo76Avdb`|ADsHRxL!oI zG(~oCT_%;}{9aJH?(5tXV*HC&cYN>?Xs~B&uwT~_ zHHV-y$K=|oi6_5OdDbKcxOJt`_uLcN z7|svcaw?u+a>R=%U!386vEL5HWm3fi`v42?GB@;@(l*d>|fo*)qUIHc^VPHZb zY$dmW*GL&LAhVFyMRD9fqoJvu38o(d7_9U5PA~#GkRA3td2><)$i3(YhHmqvJd5v% zlJxm6@Bhd;a`a6_aeG#SLmHpdKa^#2nO=xWhqz>z>yGve(2Kc&ixxX&^7&%XYDRo| z@qb)#tn$4f6ap8#SHl(L?&ilD;n+->BR}2oS~M(C9?NPC8@} zz_&2pp4Z6l9a#j!&gArT8T|y6aX-yZB7cT9LMH9j6rmZ8g|m_SghYQF6#uX9$PE_W zl=}eb-sdP?vGdCz9>;-Ws>H}r>lD5ywv?nJ|9_H|Kb_vHv>Z=9tnJ8|ilag{s@+a* z3{Ca&!&>Q;aPwpPv=%RBc7NqR#qC3YcP1MHEj>|$=LoZqqdd0*_+Gk=;eIC^kALke z7|`x)tE8>00D4@_+TF+GMjT**XivzOA^w%jI?h#!Y{oAs-5oCZp#s^__fxYj#26k$ z_FVCS>p6IL-Bp;{I4hb}9qD;Q>AsoOei((ipK)f-+MM2JvGobYR2>-ig2{-p571`BU0Yu#=-3qmlTW-kAH=kK#0Cr_3|d)d$Ll3rd~YV(^|`KO6QcXQ3c*U zKOkK-Ew}TuPw&?35m#F=k{zR7AL@c(pt?WsgRmeo(O_Fkjx(veA%DZxho0IgC~J<@ zdPRlhwq-%0D@L5oH+F}5(;WA|tYAsqoK}^;OHYLR3pRe6MG>tN84nTX(0|RyT#C@A zs6)}A^vH**f;-|e4Xqyi7S}DVwyKooq+m;)*6_%+n{j^rTEsBO^@1^>>bLA0&WHAN6hwVyuXU4Nkc!H z{dfl#=+Is47^ZKozIe&1M1Nr?<5#XeO{)kXgb|bQ{Km4k)Ac7rt#u}eBObA!i#fd{ z(7Kfwr5S?yxAN;uPgVuA(2dn-3b)w(VAK*;%tLVWGzUaI6JW@9tgOx(@g0rU53EWV zwX56&MjM>qcf-qm$$nDSlQXa{D^b?vU(4SkH}(+%zqfz!2IKot@yvS z1!T10(kVQsIy3mcs@pze{T3nDXpM8>ZM>n3;0XZ3F)PQt%nJTw?MN=sLrngkZI28) zaoI#_a&3S1Tz`mAZ)GIvyCDcY>2bINhORQQZ>3eU|DtLv6~gK@xyvN+diCa5Us`}_ z%geD=E01o`SGpy^SAXD31K>ZXGIh@;WsY?dSYq*BGrP;N&H9&eOqUxA8O7gTJ3TorwYFU z2k8G!<|_#j`%f>m%hGnn)SY699-%h&{6LJ)hy zUL{+_sj8@m+^WX{NLh z>T5--N1T5_iUiG*^D=`l*#oZOz-nyY-18GdFG`f;(C{9ptBpg4gGi&?W4bv`H&VNN z6LL8`sLTAC%3}sY(S1XV8r=#!l{Uru&0=48j6MCl-ha%YaivDLoznCmK=HgyO%+ia zBtA8wmIhi0m;oYJ*l`cfGumtO*(<%KNmJ;V;*m<5Mt2+IL(EQ-WGAp1_Z@hJXuf(< zk@WlC^X_ayP2g-YSf{ssD&HFK`~m-PuB?_xarUmMu5 z89}*ZiGTH%Xex1CM~pPjll*q`t}$)i4Dq?6OWb0jktsz}hhdSIr;{mjIq$j6ThEet zjK^XegABJgG7;eT^$oFO0T+Q#HjAyV%3;eVj`9X z`la`KEXCWyUSqDFMdpz{j{}k)HNaB5GcoFld4GL6!)4|aVbF^wezpeMuTyjNc4umw z9s^L4^>ry}5Uj9ecZMxQ!hY$QyX@mvW*64slM6#O`;jjD=?6~2>)JiBi&FzJX6X<@ zqD2S0;(4`(EuIZDPUHubiydAa^}e1~_%NaOSxWtD(CS=1jc#iE^o4&db)FSyi!Q(! zT7S)A&#sC%p{|bIjzM(JFuk4>9Lb{*@Z6f33(_4URFj9#hHO3NYDKQ3y z?or#i0qu-K_mUJ%9sG`M{n{i`y*5eLNAf|^WCOamN2SXCNSMRr7bb|GeWFNL7-$4P z?ezXzJE+|TANu?%fr&*OgvV>{xtL$7D1Qa;IX3C8nEqPaqIfEe1iHU<{sbJOwc1$% zEL_n8<)}pl6b@IAmuXMDN(xUOpbErANSD!k7+8a?$`cu?+@s+RQ@#+{d%t5I2D9zI5(%^nLUK3pMcJGDLZq%Ex9MEy>{KIk7=M?5 zdn&lYT=!XV4>{Q=ZQZmGN16(*@PhXfjqMe}ZuSL5{YB@RdAK@v-<9K=|vv z`7n~_)_N>mhSYqRXIxU69iL24Qk8$) zxARYfMPLien$>&LNM+hv8B&gDYJcndn=Tq6j4RBDOgn&LxIZeLVq@|`_j9rN#5NC5 ztGUd+=GUv=H55>S=)>ksP$^vbP@OlEaYXw+&CKV=@jr_@ZAkr8@Pt0@d`eH9CJSQf z7!_^MWi9ti(3uw^aBZ-zDmFwMlt1@#_jeP{Mjy+afoywg$4W`I3eHdmrGK83^w zR9`kvHPBfMwVrL~D7Y>P@MksGw)87c90aA8fkP8ZuWB4k*j^1;yf_6ki8Ht0qj1<- zVL`B=1w}y<0Fu~IfV&EJGj!{Ov(O})!~Tt@7T8}AiS*^|`9Od#L}3H7T;0j34m;ph z|KyGZ6da#&j+t`*WZ_VT1%HP*aUa}gF9DscbH#Y-958M!fMiRK&T)2YABN6c+hqU& z24-uxc;D^w0`kBkgEXrz)Qb;a(DPoip63-=Oj4Xow2kQ=lT2^FhSrv4fVyMLO0yHxeVWOe0Q z&n7rC@$J0AR)DinG%}K-P?8tYlv41XL|K`RjJ*j1zssv0NRfsbuih~px}mRKy=KXG zH*J=UAafPWr^Rn0Fz4|x02%`yxs@k=*G`@YCMW_r=@s4rDajI*X4*80;2%%Cs$)vA z^I=?+}~gMYE`BG;H9rT_0&$sv%z-!IOW6MRW003+YA*=!}85`gf49;Qp!ll)pl-c zw?8jNF4yi*+S3(sm16v)I9!klNc_1b(0>BH2?zJ{yvF^KY7 zN#KFyBtY1GRq&N$X?*SyWPjO<&APGL;i>Zc`tJZ%?0~|x$UaRxXb=F7VL*sN47j6x zQ-S23tV#ak_a1etqSZDLKnZZw0vH-;8!7Vfv z4P=U(&_bzOyT1(}Mm{MNrnbG`XPiWczP^LXc`yH%UU?cui|7uan26Y=Yo{@O7?(Ojc=UCVaG( z65Rh3@csS;N)7y_q5pSdjy#6;R>+wB&`9$Z&ZI~X(&YKL>UmgmyRZd$ro2QMWDMZ$ zg*Jw4E`Oky8yIxb-;PtUd^+K`>FViakA~6(U~$>V<=5i!@x=KgJ$}nbZGNyB%7p)* zgPAKyP!?`R#yW8g-mJ&i6H$&`sThb2-n2BCb|5VPbF_J6vv#s0sq+?Be9xtaND=OL zFFpE^76^Vd)*v;Mi_Zo&9D=Rh#DChaAs0vM5j%H~c^yz7hEBUTVCqIF zHOU$0Kw3T?U3CX5aTz z6hzYLao~G9HV3@3y5Nlvz^^K^w2nnrs_=)n4V&n=vR`HgUj_pB>;rx&kmXFt8gB@? zvkj?2*4941KS({c5y1S7vxcPonIyHuE`Llvvt8-QuQor(AHLG8u_Tvm-F~MWhp_B3 z+7+6`L}S!0n@TYH<=W+iz$T=L4-a2bz&8O~L`yR?IEf31TTvmTWieFJ0Wc_v zJ5U5l67X)o1=H`ERkF4i*}m`sSihmIU2X}ajvETea;VvUpqcWK4^2ddsb5|^j)R+OGiyO=e`&3{l7|sjCHh?vy z_vmQcl(jhaEFVOypUodmg?OYUJ*Px$N2mCqt^?3FJOP_ugJ`Rdv)h|9++)j@(Cc-R z)TlY>O1EWQmoqj!p~Q+cytuTd@PB+qb|ZQG`eGX-6o|saAJVq--*VdaDayED)i2Ju zgZ`HTE5(x2I)x+OzW(iZ23NC7y=RCR`khx=jW|VC`kOSBN5*9Yg1`=x`9+g20eA;H zv)d(hrE*f=016(U7>90}2QrK>Y0Li;$ep(Q@d6xCjtJ_76|ayxp@s)a+kYJBtjPI( z;L=*?DF_z(rH0Y?7G;fHMWrCau4Nn_21Oku?zC;6`Wx3T*2_M+;eB|}hhMJ6c?e+l zzZ-Q%0`OLMn@wn3maX-7)Jz**N74Y_Hn zecu4f7SED?DUxFOt4LZs?>$U!r8DEV_}&|d1Vs*XH7IY{*EH&41b-m`5*(EfDJ}W z?r(|Z<}NY}BzyAWFoCo58bCqI@C^p~(vCl2G%q;yZk0)*SXUG9i<0S>X;E0(a&^dl zxDR_2Sbt^Dhfx!zdW4)(?*G|47^Xr)zE*aE-R-m$@BJ57Jze=u9KgCI zc9H)JTsv9;;MhkBYa-ntYGv`~4ODxkrpMJvD>ljs&H;t$qFq;Z4E_ec;Y68w7uMSk zvUsu*y(`L~aXDR+@Vx~XpxFFo&e{h*fsBg{M&#tr*#31-Sbxe(0XI%W!9$hcflAG0 zfV}{M#R@tORLhb#bJL9z-YYib8>rVmt1z|04X^LXQmfd)vBEF)I($ zBozUqzkl*S^3(RbjjiubPZ#I!D32aRManDWn&=m~5jT`4gvGR>QT}BP+BT)m>=Ac{ zZHB%@o1PK^Mt`pOC&tF@JvbE1QlMm~f11#Q6o{d@1v+fHZZ}$4@|^`f)PNjRg9!V)XFXo?*a3BYR-E8E01d zbd?BJj!Ci_PsW*8Te~;Dk~ZVNISsY+&JQNVCVw6A~*)5vN5h%i z)%w3U@73u*C9_DfxB@_N>AMgR4`otm0 zUw^%S(DZW=qUCj4o>9|e^6s)i6OwgRNK^C-xjE_nd^~?J550d%4M09-&B=hA>E|!= zjCoK%=(koq^9reb!fJ%dDf=dnAPXw0YG9v)dO>;@0P`76hjNM@Q{DALB4tchjKXis zQ^%L`Qw+G&l;Fn_@KlVI^aKAHz-+8~wSV)O5jGFao8VOFNK0bhyshHkK3TH zo4CgsIJ4?EOh`LO_vyy1VqF~PHGj=(lE#RO-yuOW)E zRKHh_<-n!SWDLzY#|5iU4)Ug1n;w~`MY`YwJBO4re`PtUjyK%v?}dqHW^y;3!GAB6 zQ1iPaOtL&GJ<55N`RP9G`?yq()@Sut&_HsV<3lyDRM=JQZ^~dgMSJSWXk;vsv99{FY47e06cRaSNAla>-L2zK~IR{ z!uOU*BsfHpPs704WW;aoPorccPz!DtHEbE^VnX}HrD{VAd}{GwXq6KXK-98|ds;sg z;DsFM*5+kKfVy*SgLVawp=@F`1LR~sQaS9ZFE=$@Q5nN-pjf#er!h}i(|^KY(7di} z%(7U-;hrj!s>>uRh`t+S0>(i495$&i!tk`5bxO(lWpYlvr6MT=Vi`$O)=1L&=M=X+ z(wf0hFRZ$SKfSPz$VAG~R~UyVpFg`!+k~M-=>7fQN5>+Yc!*SxsZpzLCc3{`HID~~ zF!xo^4;0y0p!UOPQ^yNf)qiD#Qe<8ks*R7RoUk36%h`7^v9%1EfwAc#*XKGti3-N1 z6Lcp;+lFvR6jYzPg*;{eMGg!MD!6H~h>gVANsk9pv%*lIcOR=4H2->{=tO-chJ)dx z+EOGzx@}5F3|19{7X%P(Tv70ysA9(V8t!KH2__g^M^kL?3u!&8Lw_T*ol%I(vlY9o zGRI1Y1}Gy}1mslgmrU#bVIV1SN7`|tQc8>zGOpEw5C{fINAFi>KZ|>hfwTKD#Hal} zH7G72(uu^(^kQLSWFlq@KzBFZGB-eVP?HgsARs3MQ+%Sucn`-x0d~j|b-g5nV~Zi( zvm8tae5_#GnkgkQ_J0aYrUAqp)`flxe;N;tca9U-Zmb7ASS%X z4DX<7eC^YSoID9pC{JkKq$F{>#m1g`)+uk~6sWDoS5E-97deMZQzP@?yMIuJtRSEP!a8sBHKW!kmvj8#v^(4t&Gq|Z^i8v6GCl1XdJ7$;g=e{uP30f7Enj0dT>=XmVfMS&V`x(o;8DtDZrU@4g$NT zUWPZGb|uirIwiE6xV#m3kt|uSBWcRERNi-^gD7 zwS~reX1-qvpEi?S9$~$fcCX0a1DkPO#W1kGj{qh1nb1Q_RSq)D=NT8*Jc0(*JYt|F zzH+R4fq#1JwAbQIsbcbUUSGo5uaXD&5;zQlCB*w~V0DpxUZOzJo5M+MOrv>w(NH(d z6eQt=5f7*1TUkv&xvA8d0Q?#r;+Ga|149Wh!zr0tFV9IcbuQshp}nf4#5%0#@}cKw z)YQyN@DZx0;vec|WC~vO|Nc1HYCE!17tul**MArR8OeW}#o`p8p#`W2j|e(je|D3+ zt5CKMdg7-4w_RQ;DAG_tmrxgD<7dJ^h*bhAiFwDU<6#RGT(jF*#vS~*VzYM(tGL*J z@6dQS`m%;{7kyeHaC^jf2|$)goLtJe#Fkm<)9EJTP6yo;bJ{O`mCtC$(Yh}?^hKu5_PRcXI-%S?1cruQX> zk=T|NbR1jRX_{!*JCu0QkqXIk#p%n|_Q%nTC4h>w^)>Yah)dU2<@=g77dqy*6n_Vg za`3K2w2xAz88{YO9Wt^QO^x)FKQ>s<7%%})e8}szfqcvjN!{|mv;Y;`^OrbDc~!!P z#%5f0h>`$L%Km;+aG}dU)dA-!UdSW@8K1D@LpZh2AYt!LmV~G*OZpAz<&X4UV8T=` z*(a@xot#m0HtTBd5-GkLz~e-AHGctVI|A60f84aP5&;@(`VDxt%SUkP*x281*Jq)2 zQtB31U-HO}Fvd~}2^3vX2!VrQD%rdQ?dUHP20S2|N~C1*gV)VZWk#>Xyoj>|4AR{E zTI03oCiIUu%n-&uw#L_FqKNA~?Kxf|mw5ITE?OxvYf%b_E8!ElXL-VIx_?{yvEHUq zt^_45Bf?J9Bpj34te84D2Xq<;6@*lE`#j#wVwa5!a|uS1`^A!w+mgj4_FWk?wrGQC`C8s!6u@k)>HIZRWbMD zozXxlsQ*%SUaieh98OP0ew$hN#IDNl)!F=Ec)b7aHk-MEKg-PA_&Gd(_} z9e@Q-l_nV!>{vv>nD*!0VkaiPL+78B6}9PS&FL((r&#R9D}MoNx{&ZmPua$%9ZgbO ziZ7EyECUc-zX3<$Muon;o8eP z(4Z7%%KdL6(hIWe9 zVPzWbD{!6H&IFk^@=NTiZ*>YZ8ne{E*{^Cy>d;IWnj}l1elOmyvW#e#u>_VH3yCx! z)|OL954t$CF<+NegxQsriUrg=$3H{_>4E1Sjh&uAp&o4+Qg5IEZ3~?bI;5Uvxp85~ zZ0S{0BY(Hz21L>?2{GvV{FanU^ZcVkjs9k8(}#4_NH_!*r>2tHtBWu&w~q~=kLR-9 z+It!~Z;_yu-zvpqYL!)u)TnFi>~MTzhBrJHvEKYeKwKH67EO0)K@b^(F*rOk?$Amc zgrK6CVGh)$CPF48-T1mRdaFu-;zU*_X`>)QM1OskA=IlFi{2~4<3va3?^BQtw!C@f zck~D74fLGAS%L`8V&lhz;cMHKXEA;?!|nU3HxJ{oVAKySmx;egCmb4(Mt0pU=S$}{mjB1|b>Z(Hao`dPJ621Q(Kzj=jjfwu) z)oN&pjV_Ei3VXo5BD?Luxy-vZa$0)|h09Mp_oaIH>n>q4N}f=p@;3JiVaq7?am>=; z+@;BOSEgdn^jWG1XQS9bt&%fRns12uK+Su|Zg}~NyxZ>B=Ic2qd4o{pxCkuG2O(k5^(^1U zf~oDxEc-OE;wd4tdsDFd>w+S{%zya06{pq=C5&^=+?f>@sEAckf_;kd@+Bs5cM?Hi zksiH1xB3lOZ(&!W&SS;hV|4*OkZL%PBv05N0+DK0QrCBy34S9!bo0M^`?Z-?U<*B0 z&r&aE-^f}t(x^5NxBWRsRfe1nH1w~us({rfekuoHAW7xuYP_x5&;fmrK!5W*vZti> z-T<$1*A&}3l6&H37-*t7`JYls!%l`HVxJ%&l??unZ(~VmEq#16*(Y;h%AHDjy)*bB zGt-SS<`vJ0Z687W?q5Cvfy_GkaFHq2dhtk#td=)((n4Gh(kfkw{j?i?fYF_gpPJGq zPLE`a*W#c~vZP>(Z16b6Fn`a+C!#z6W8)<*r%nqw<1Sp8WnzS5q54mp=Jg4|;sy+h zT^1_i{r)9|=1D@~ES2B%LDun8APH)mF>VFd$Fe!^Z1R}dUJ?T)$>ds*H#?3#t`N~X zULrDNmxa4d>|{4;h(V>WZW^L(&X;JuXrlIV?WPK7@`?|+0=3NGvpexQ7M zn{j~1y8m`{y2%x)ld;07NMo|zp1u80Oag*OWZL`ehpmSfXUrQne3e!~$A{6b4i>x$kK=I(B`@)G3IWBXY>|qH%=u&^ zHt)+mdD0nlSPlVSQGYZd$Q45qH<(mv8)o?oP@KQ1o)$s`%*hUX2|Y0jy>KVH7?&u+oLx3^NS*t@h}3y6dZlsG3;vm!^7lKxZ6lJ!#DTpocX3h zOIx#cipWQ>SIpx9shPTdd-uvnp}vM^Aptvwg(!0Pmcb4iW=I>Ebp#S3@K zXnPDT1|`^d6n_)k`rezH+Oj!+YCqa?TTj|mb9 zB*2dwbJaqAIF?s?aPeF&ocsTs@@A`zPPlAq5h^biMIp8Vv|N|;Z@!M*f%_V4vOBoO z64nWsE*I=tnRWLqO)=8~-m%bW6L*QbiOP|4;1>P4?0-;z1iRtdeQV!^(;=AFwJXcp zsB9A3506WqJJu2e>v6#Cw@`dl{@+izIHr7}w!Vas3O~$}g|x2zD(Mq!Pgh)GGjbpq zT?zKO*4C~bh6iZV&`QD`VQs?g)j0aOY<^rwDiO#tcN^IfiEVa*K^Lor&^;~_MWG}MKE6EMarW{8I7;bNKX^($YeAy&4IptC}uwf2qtR7P5B z!tZ&i{~dA{c|2WnMag{7PU(z-ez4z(Bs5%mbm7eVq~T`Wq5IhVy|p+6WK!EO^{F#mgMib@fD zgnuhfx_RG_r!lX%`~|ksbQi3(QW^q-+|P)`a{7CZ>wOTE``wdpg7xREWvwhy^$ri6 zThZdMz=5}o7r@}ZZI~(Q6keTR=tf_>>xK%NYa0${)RN$g*S+Py7te>&3{UP!T;jKt zYomZm)S54KmOs1{xj-L9A!_EQM=%81OMe0-FYShFUg{zp#=l0iMNXm}iPqL}d)4JZ zc($3nYJl%xLKJ`s9g^)Gp})w;87COyaPC&1zh@xdSwX)hQcba@n04O~)C8iwf+xkT?5r0}5 zVPD4&!_2UAF3vza>yPF1nl2&HU5{xL@)BXn&FSSZ$?wwT1K6Gtf;e4(@o$ui;vy!_Vu z*nYZcn8#m5(31vZVxn-UUW6QjeSaAF;CeQ6!2`o@&9#W^SjReRnE2bO_U&XzaY_5mH-(wn^B}<~a-R;LLx)_%=RPA_KpQ z1!3jeK?iJ3%*;1}XF~0IGS9HX&Zh5cPjJd>dF^J0DaJ1|94@0JKShcEV1JnuDoc{% zm3QBT(_{K65Z-}>V{asOz&EGg8zANt(|k+opW3Viim;N;9$#o~W|^Jt>(g{;S<(n| z{s?UQ7RrE06A=?40}V`&Bevn2AW-VRE567p`Bxx^)Akd!4cZW1u`<h6gaOokSo5+xy0n_;Q zRSv|Odk?(c{T5f0*M4am4pU1sxQTSa8wB5RjF3G^(bEUj04rxp`Gq*WV5SnvgGJi-)sEH&AG7zGg~X=ZZwsh4R{@C_;+*iu<XWJ&U~1gv;wL%hR?oVUcbWARmN~X- z!F{mA!r{CQ_Dm>(Iq)6{Btquz?7Bk@qZh}RkuJasTLyb~dpvJ<>jqp|2tB2}@zu(| z|I}-2>TtUZu|W~3JO<6pBVo7Xv=;i5UCays;z!-oWV1H!OMiQji5>Q3ve)`R86r)V zN-oQy9p(`!pXL8vzY{0}!uNsLP0Rm|6YM7q%*x}NN&eRwceuQ5;}%(JG>yYhSd-Bt z_5S$fFa<4Kjpz`=?Gy?JXILEvc7c>lQzVJg!Bvw#h!s|@tanjhrDTIK;2A-oNm+X? zrb7}+8hW~D@PBCB+ySro1=gjg0~Jg1VbT>jt=SAn%s%J&Oi)MLw~Bv4U#GtDbGXP% zw*3PtaWc2#_0m?~9Lt{|lb8;H>4MhVJ2@TUA=b!&@NCGHnZQB%3jL*$*VvViX8WQW z03{et|IGl4%F)ngNS{v9w-v(Yz7F2rHa<*1`s6X=TYp=w`Nye5D>mhHq2UcC#O8JM zUi3amCz!I1UPX8v+)XlH(OIUsI}Fo6oD4;SVnKSZc_bt4$fqIp6wtO#qxsBQUQRrb z6{jkS(QbjUYz6N0AUma%GGugGDB8d+_PW#o!Ph%c0!NQ+W&@{Ex*rY2yvgph_{;%) zedYbG4`jE+TG~k=fx<;a;WcE z_nM|@rt5c4>fW4|hoMvl-2WRV8I}#q=ieytG=IEZ@OooKXiby`o}hHg=I00=gRfmJ zFO}fm_I~Wv0z88oPO6(h!GhKLYNng!+JJa5<+QO`ui5fb4=$l(+jRg|rM%|C2o=yX zR6C2s6pG?}Y~j>Nf7Cnmw&B7^gFBy?)hbKO5bsY42`$WV@1a6WF)V#egym48r$v^G zI)5tsWIcoW+{$g2zbTr69veW42NIko_?cDkA|3?~#B1&%mFOV1CD_}A(s&S|-MP2A zt|wTPPWp<%pZ(;_@rE3ah=QvsAeAV5L{Wk6h=w#T`iICwjS*G)P-9H~nQ4?F_-}aR z^oa*Z)dWTJ7)jxVh8;aN*VJc(13%P5Vt=GJjjg)$@Izv@b8N&3Z9-3Pv~EnlU2O)^ zk0v6Cey$l+@0X77@m_y>I!ar;K;2SxR8FR5Xaj2m(M;c`G&0{_zV5-Dj31`04Lk)= z3g#*1f1>>p1=pu5$mD|5e~fiAg_uxUJVwF9A~i4nulp8^angEQpX5fN$$zJ! zw1smW?L z7t;YS!JCpVzPp+DfqoT{?3*MB?t5o|QykGIm%@n@xGy7l1|Sa#CWAsBAT9iAI_iVT zD)fHw>_!E@=7rgoV$T0qGF*`2et+sM0q!;t$<*TO+)H|Fx1jbJI8Yp@BV9#Fc^C@t z{0zY2rvJg8yN7>%8dd|lDZn%FX4$W)vyE}p40D+E9mLHol18GS3&Jd=$FOI^Ti8P3 zw$~2-vgkW+GMhG!GvCHa>HL`3Kri`fFS4+0TxEHwB>{)nswfenRitIf5y$RM>-2vD zr=R&j7fE>gkiAdUPhQYCU(4bXJQ87;4++Ph2=yp#d3z6>KeEk0EVD*g#Qd86+}F19 zmd0~jC;}QYAi!LPqs^uGSMf}?j`OLx@|KB>LkHK|uObdl_VaTXQkH12^m@F})FLxK zS_FR~&=sgSRRGu~L5wt82KI`ycfNmnmQMY!qEA|g=ue%Y+Tn@aac5}t|C)$kXoaC~ z6{D4K2Ap(=s=vPGml&pJ7oRR8v{wrvlEwlp{V*48`*7}w$_R^eI4b?e&2nKj|zVeX{nEm zf4~bs^zghddr<-Yqbis7)pe7H|woiz2~=|-e@a5F&Yi^ z*s9*qF))tZvIxoCG|V%_Ioq4Bf^FIL?PVqgO#_-Lz2%a8Fy z0uV1v><~i4_&v&F^%X;o(u#l25HI6z{pYfWt!v`9xp~n-#)zxJ>m9&Jq%h$DT3!$0 z;y)ihR`cWEtKi|I1rIlwMip?&gU9Y#lDnrfwM_r2woq&YFml3hqP@S<>D?Y15MHUv z0n=}uhOy#4fFwz%>LnrQ(o|8);fZ!k7s4EF-VPyfZbh5g1U9B=jnjWHw8R$bz-X5~ z>Q>%Ul?32vYdEhS*O@W+-&O!Dw$rR8k*2KebS0HZz}m5IdS$9D`yCNydB*oZ0|M#D zOcN6k@^{OH_!37@EnQ796kokef^PK9XU!wIcw?ncJPYsbxCh_%Cxs5SVPa{uWL!L zt%xqn@w-No3Xx6U*X~XBf*2be@_iz>P3Cb*Kz@5Mtbp`IW{8)!XS7$AwVZEAQ2r>mev^JJ}UDYA7y10uqb%urw2% zOQhMOduc-J*jGzZS8iF|N(`CU_!3tNJ8Z=@?}i^jJ0F&ehI#5#O8{n|Z4&i48eTd{wmNPgs=| zM!8Z__k|7?IVOJ*DR$?Q0a9KRePoB+8*jM^E8_f14^^XbuHn#OyX-PdF+0daUqbsW zvx~z$Ifm;9_uOnw5;ohWzKrASLl3eH8fC!;feq(bM3f5>W>SF*QaN()v7N8MQ({zQ5je97BKZg_C-6Zk@0-F8E^yOM71r zcAQa;u-25=LigIaL84HSxH)v6M5?++aZMtX^uTl%wuo2H1Y@O<$63EHtXD%jZ5_Ey z9tgst=Q4>E=t|s7^NZg#no( zHnp%O@1f4HW$c$D!b-196b+d)c@lv~+^SOgXp2>@;5PQ@?AFGsjo*KZu5P3Bi5AiG zBnTcBZis@LC#ZW_opVW}3$K!v8TsC;?^2@iwJLvy)mf~CuWC-_`cTl z>}n)!HvXgPTS2CXGyIoEkP?F1DKG^Db!J5Kfu^R~RWzpDmO>AySa8?wTN>f?G;tJkdx`J~ z)X9IHJ~9QJHIt`6qKu9U{ei(W#-i5Zf@Q4HWxNT=WhEq`)8{hXCvC_?8N!6vH8qP)8$h<#~XrOFvDm5!JQ zjT5C!X({0SN`#XK?V5HY*Y^+MH(OhI2VUsD^5fJM{}qx41uqxs*Cy1Ue+`5vLPLM? zvF8-q;iI3?<^L{sQ;4*`DXn=4Ng1imr??8z^BVs^graHs zRVk@dcp;hFr3#A;RgWbiHtRU>a-o08O}6!sUi-jUybdM55{6U6cZvZ>U7W}*TIB1y zln%zE7m(j{R4UqENS*We(4iuy-I{+vg?lFD;ZvYX5>Oeglu#-7*%f50RE7d=sBK}P zox+3=@Ja3DWkHwg7VSQxs%meI^c5xc?na&pL5UzpM%mQZM>XWf>4~sF*7%ZKeduRK z=svaS}5oiOEgrUBQkthF_5mEv<&V7F_zhdjZ zTV*65O`f(8dJ6FE$_0i$(m{j3oZ@e7Fn|21W z;^7HokshmFZ}?UG079|1g|k7fzp$v$+73J+%R`}}C39RE8y0Y3q@i;AV0D70w2DX> zc20h3CHLB)h4_EZFfbBC<^`Ozep~oMArSKqEtai#O`GT_Db6~}-c&aJ z{mP~>8DJ%3ok!(~DSG7B8bQ2uzBUPAuKpEGQ*{q11?|$ne5A225^c0G$Ad3}z~F)?#u@htGW>Ye|0AT$%zG~n zKMPg}KQ~y$25d$6XNKCDrZ8g-U9sCubCaJG*m$dS4kA|-$XN}XwwHTHf30tU(64PX zuktrtpxw>y&3_An@SK0sN9PVqWt!@e(X=^z01WLh`m<**v$hb{X*)v;KTC{ZMe~zX zUVG-UJqTH1!7*NkJt>5PC~OKgrIRrNa81f#AFgj^)22CeVmFZrP7`_Q*djeV4d{1Y zUFDlP=vPdj;-3@Q(`WQ<7$vEFKsiYTY(-|6l!eJ=GET zF%|x8Fh_vpt~7rNex$S?FXbJ=_V?CL?mwkk49CTU{;FL0Pd8P4{l0UXP#Z}SWJXQ< zfghHR(pLUmgZ1!)GPzq1a>^?h&}1ppNvvxLs+Q9j;<`I`@ZjjD^AA+BC~n6)ck&7Z z_|F$SsZ*+YDtwYAuG&}T;_&o$vgSPmFIv!i-Y}Kl-2Q)5@**1 zTlG;Q5FzBjP7D%#^Y)caHnFbY6RcbxQ^(7)w8jcMC|2p-g=L1hLyNf>L;f0=t}mX~ zZ2%PV?mB<5CRgY3is0x?i)|vB+CaAt5)T-HtL8TSw?H{giK*e0hK6m-r^{cJ#DOa74B5-)qa~`r=e< z?luz{mfQbe`FM0h{>bZ*z9_-dIxEd@9Ue*(o~B!QAy1q8a&w5RH_KE}e3miUCWtqLAeW0xWjjtJqiqxM#I!OZ3lK1a}VvJyH(i90b8f zf_Q(0MfLWy8d**~r<9a;=;i#_Rbo9yi*>VdAiq9qE-*wr1R`P5!cE zl=xTy_KwS!qbgfO4l9nvA{4QR+zPzbS zWSyPlEYOi!k z;dh22k_r!Y#7I`%Z*VpyIx)p>Gjgo0q-Z_Q{n1;uz6Qm_#}Z*8nN%L%iK;nPHbZ|M zzMPP5%%??ZL9s8p7FD1og8tgAEui6Zb_izFWxMK#4%gJGF%#Yh#0I(J@50DM=!V(r zLh-L31m+%!4xvP!_qh{7=8XNY`qvU3F!wbGzUk|4|&6zHmx2Pbd(cTEia2bz^ zRwqVM(<8oVfaV_wwK}9G_S&mv%bQYMK8eRD_T$KDbL1vAO(dDnElkyh!~HB@<$N^Z}4Fxwu4FyIHlMxEa@=np1G%Uc=6|Z_V)zr%@1w?-Vk^s!C4uHd}bA-o+(%oL3q^NS>5c6p0wplffC4ouwcZV=x;qVmtNIcUDMcl@-urrUY&)2 zmE~@_-o??g0RCOU5hcHrgouB7Wuzp{xw4a{w{G=>cPsoKqb*vK$3RxX-*1|^FRn{gb#)VsNwy@XRduY zl47@Q=wXY@*vD(=W`H;!?18-iz?AW|4 z(EXw8syAk=oW46c+<9}hQOSV-&Q^`m=NKgIU9fC8X@Ytt-Ug!Cwn${AzF}$Ft;FvB=Sv}`*KiYPMnCOiw zNDxc+l@j4_vqJzlIigmul@b+2+o}^+6(nP-$-g< zI83c3uyF-)R&F2-p-n+C?_+9Q%%iZoQF58QVe7#IEJ%fA9Qk2Hx=Yl<6P<$qIN{YfexmtR~>SwZEJ7Gr-Q`oxWdicyr3k(_;tI!Rda9yhXk z7X*?`AySK&u($Le^2F~lPlKbC#vY>^JT~RwFyS!K2El2SZBw<}Hg64oVMp5ansAbL z+fTI}n?^m9ir)ySBWwm!i=6qAiT%@b$sB{RfG+m^rh-VnlljXP0+?q3iRlbW*3Vt6_=nTDnNHc^gG)I5vW5f_0)XpCGWK>!hT}llquXxE#|1s3M z5d#ct7|e!N3@(l4{$ZL`wQI$)&YMT_`6*sW;U2ZoYm%>SYj;1|3C2@xt|f|=vPE>w zD<7}dUB>ojf21FUCz_CY7aj=+}S3 zD{Vn>nsf>a9d(Z5t=K)Pf-^L=Mr`~{PAN%_Pir+Q(SY{X8EN)z{7<)^^fEY-t@R)C z(+V-8zEC-~S*(1yJsvp+WJra{w7g>tw*=5_HxE%V9;VCF=h~QE>_xl&H*}p_n=X{* zc7rBauWfPXGKl7h0RG+snh||kdN+T`GwW8-`p?7U*{%9l)<540fY6E$jM8i0xs<1t zkf8}#=<>+SzUbBgf}ujG`*0d(d5$189U7>CvP4&RRL=>h9H`TQ>xlHHHT;N%g`{8Y!Hg2~Fx7u!Ak>8_ zu4d0w5|zB@`LL7>i5;47;{*zu9s^5awO&pNkR`*Uh+rnVe{|b06R0+3{0o`qS!i4p zYeAntE|-v&(trYWq|pt<3otrg2Hy+;&chw-hRUIcX6}{TpK0B&pO&UzOU19`TqbuH z)dq;AKs@M$Ndfv!$K-hW&cA;}Z+aHuB>XuxQVu0M_p&(-ja7#t$=d~k9TI7IoS}KH zlm5UOJrbU+l+g@zh5y=OCz5UICgBmK$((S5_7qe#N+eapK_)Ys;x2FeE{>$1^1gvB z0C`}QP8A}u)41h#%r({H4FDmLY^ZRFxPc4KVhwe!$f9qM!W8hIN*I6R-C$qxPUEf_ zs@E9@dMN<1Z`VMOQQb&>lWYcOif#C9eu^N^wA0N&sF1;~~a zOQ0f!->i^*HJ$x~bPmvEi3pFH4I1$LXXnh)i)JW0>5f8N`(pb6OE%OdOcT1n;t?ZXKC@e9VuHPt=8+U7SV{I)x zZt^{70ck6!!2uadC-GwC{_q3a0kZMeA6KmAG%=C2_ECQZ697-bYakTG1S)?A$kB!S zo)S%rA^eLQc^;YeByCw|?3$hxGG1bjX`it8rF(Ea_4oQ`Y(o^*9KM>~mT}##neNzd zXeCMJD_Od=;Nl&-WPsf4psO7I<99hvq3krd5v^vt*Y1?L0XG{X_TgZsjps1QrIVN) zz}S&H#Fc-JoOrIZ)*pZk>;@@kFMa2r|zx2TVw1T>|7Zb zY50GzE|YgV+1<+0&DtG{7QuB3#Xllx@nyvsLim5BM;=f?u=dNJyw@>jkMc$8~r{1wMY7^F%k_m}|zWYx`b^v1mzF{*}i0)aiE&&jOP7wKedDh7{dn%I*OokrBNLLcOm;%-JD=@t1W-? zG~$BPq7LnaNv1yizD1H0yW2tv{xN>86B$U)ZAHYBgC`-_(d~0gqfB!9eOv75Nxi7MR75ZtG=Y@Hk+Spe@$}vQ0B_hSF_1^W+{q5eXnRW>GM+<)eMmfPR z8G!yZhIQtLhxoku91(h3?~HsrKa0M9Ape~AhWP#@$6e9l!IY6)0e*z_6r_e^MOtLk zDT8W9wL$-gko2W!GU3Xw|6$YAaM0Dbl;)B0jV<$B=gQ5i1rywjUxZ+YqppmCIYgLP zn!a-@J;9mG_WCv$O!zQ#tN4F+b9`d#*UzZQaOxRmecSE|cV=7&{QM3xNKJj_R1(DJ zh}=<&U`t3?$rj;>$j}PYfY)w~2orn9u%(RZ^Avbq9aFVIH;i7Edn3 zeF8tm<36(2W6915OU+Zt*bOar)I-t&j+Er`dPxOEbct*ZQLYs#G)*K=2O6S_k!193 z4FltODhaU+C0!(KzR!U6fNgvmH2eOzL&kBlc8xE2`05AmI&4$zvd|K+W-$}y@V7Ci zz6Udi6ZSJ{l$3iC+`50ZPwCOgrMKP)a$D@)c6AU?DA7KuiU#^}1Dw`PquB{9k`EQ2B5``jCJ9A1`jN z_c5lVk$^-$OS-GQXhG=IR%2E&lhj;LkV$ukT!0!0a#29)SVV?~cu&iePBc}hOLTTe zGLv(^@Bnr=fDQtT$tFbmvumz zu>&|rT6TSM)TzP>H}!0kD96U<>C3e+zcPIKIhRc;_P>wo5>S1!Mg|K&NZ`vecvE|y{Y$+RNTP<2a%>rNEhqG2kzGN$O5M?-8U zdNJ=!#*6m-d7d*#YGzDehU|u%|)H`vZg9QVcT=$h9ziS=G8c`>- zsDy?vzv*$Z0It$JsTQPFdnXUk!KkYr3P*rQGBsS|`9nEk1(i`0rNh?xqMj>tvNAr2 z<+Y(hskFaI9L1fZByy`%ux#7~M8Z)d&e$rPbS-}$UmLcgU7a!HlLleuDygHXkxF`R zn#iXt1ISgp+G@Xv6#1QfdVYw~BH6jXJ7eR4ZAlrhDQ3i zx#j(zS}qZ(>loM@XlwPDBrqH}0m1{9yI+5WWRiI{RgXM%tjet~)~*5cED~sWK|>lz zHZSWP&Cmz1LGTWke8%h`S9{^Sc%X-0tL_2Xs2CF+*N#9<_DREwP6fc~B>k@)y*SU^ z%5aMl!0$YTjI!_>e>w9dZ}hX%(q4j!!R(G`UI#gSb4n1(GD7eEE1(Rxj#Y>dUb}xb zYX~?$bBW(V1>3WW_UU8N=z{lxVM`GZaYy-A6G_g$$C>;FC}Q&emDgo1ITCYXq~0Qp zO|QtJ5cTVe!#--nHHldcIpQ9d9srMIz@&y4to9%})MTuQSw=8HCl6NFVm1>Ok?zA2 zDSZK6{Zv5xncAMshKlI!RunGFQ+>LZqYl~{Vb55)0EZnR0*s#Y2&J%8 z4fw)XtVprSyx55QL97&&hu!51i{L%Ro4CGUSIpJ~`$2$AhiJGEvusvXg_Fd(WP3pc z;tJrlwj%=E8eG_gEpk4%3JzTStrAFV{YZu%0`XRF`v|}+;(#M)^I%Bl!Z0={0k9f7+nOT1?Yae(kh zBb^ebq94i{=Vq2+W)d&c4;XmRpth7*q*uqZL=F4MITM?*={Wk`opyiMRi)lQ1Sg1z z6C(m8q{Vz94d_5Z52w1ySXeYLB#~FTF$EZ;>z+oo;FCDuatcl0zjBS8vjJT5jWI$n zbz@y|_XW>8A(IHS0^L!S;3;q{tmhNW2JyA#?h4x|nKR!T(JTO<(^Peo`MFXuEfV6V zV%J(tnn}-&80rnb%mIH=g*gdr{BI@trcR;P7;%I+vL!a=FuOOImP-v!uO1qQUN@1% z2P$a$L09RA6O&uX;{>)oLq+aYj(FpDq!;RiRbwDxPKu2SWkJXxSu2GjvB(cT`V6a- z+=>Bo{ripPoQ0PuTc8k*)Ne-N{M61^?b*6&ii<)Gr`I+OJC=VhdAs9@kRwlp`czVw z$gi$jaJnlJ+L`V1x;!`K#i-X0e(EtgwAL04?rkZ*hl}2zmO^;;`qbnyVH?Jp#X;4=3^csr*_eU;6q!y1=e zo|LO{*KuV4&P2nu-0vFI@6bEq2H%Q#0Ur=l^O^tp-{$%sZde~E>!VBW(1PxeC&0)g z>et@@a6$E)FCVG&S&bLnNHIXeV-%$LrI^e?OWAyrL}!22MC)@l%m`HdJW~qp%C*@A z(q`E%Zw6d7b82dY&1XiMRrAnL*MPgCBQ$DsE}QJQ9=op(3}hL=UAAO&T=t z)TR%?3UYth{s%NvkNDp_qe7h}p(;ot_B5p+ht9oGG52fx97&C+RpjGl#{|0oZ&DrI z?w=gs@L*+xg2I=Y@I^(jWMIr(Fe*MbwLv@ESAPGE%LBalHo$x}Ut@L$#%JV;C1&y+ zPeo*JLY;dFv^XfY_7qsQNWaPtLVLUD>feilJ8yK#tC7fB~hLnUc8duCF^3N`di#m((K>PnGnQjnYI|dH7|cs zppSnz1UM)%`jJ)_bKfI+h$5$tF`3QjM$HUoAt_kF@QQt*IV@OVcLSk1MgTQlm3JtY z6DA!3Ja6z9e*>mFi&r=3%fn3Tc2Y~CD94^kt-Qd57Vof_K^fUXoBiwLm&^J4e9kXT zZ8|yiro)8HmmUQD+5{%d7y}5O2RQkT7+ik?gc15u{Ly?5QBiA9v4dr6DdAl(WD~Rd z2Q+JZ0w(Uw{>@kXE%k*zf9@olRj8}L^m~61ETc8xV?O1UeeiatExYhrh$EpPYD)=p zexkhv;z6DKKTf&$Ufy)TojV>3eOXq-dS)`0JV!H;kDv~4Pa9-n4U~$!wH)QfpaFmU zj2M&r0KGWLQR`{Y@G|acRPS4m=IW_YTa^Pj0FGuU)}`?Ye~gMk@U=AB3SM@`w@2VF zk^WyM9ewvyn8EEFji~NZ7AUqgm4+^&Y5{JjbhO^KmbwCvyh5?thYsa2#(XiJVnS6lU1UF?t3hh-q$ezSI;UW{&uWmJn|K$|XbfLLJFACET3^B3&QHm>Yaj+YaT1 z;WbklR?@^UIu?u&*WM$)DVd8m=Eye*9Ql9R)i3Q5<@Z4Hih)!j^%~hHdvt+!$n7My ztdw)-a`;JWY);dmfd|r$iS^fVuHcSrp9;Hpgp~P6uCpZvtB_jI?~S)$ zv*@BiGII-E8dbMS?je=}DZCV!qz!kHj=+^EaofGStYG*}oIQCz%d>w^mdcxt5c()b z1P@oVVdP@_W}Htz0s7Ge<`J_csuB}EUqF(sF%E?{KE1HyJy7AGSv5@P0)Gx9cN`3`5Q|rGl(jCq|>7T~WJdH`&5YqOOBV?&TopNIgLn&cQ(xjvT zxI$SO<7ShwiN=S5Db|1cC%v&g5}j$9(J89QRF6&VqsGZt<&x~X#6o)IaF<*vgK;Hn z>n_Y2b#@>qG8;Rg@57Jip>)P?C$H0VmnzHF-ymBeVIxt%x06--*d3tR5Z9&|^if)I zs9O=^@Zea5C+{TJ7o&JPeqRPKdMiO(L!ll1oG;(v??uHQZgzhXq_Hte|2=YaN)UZdPf_U!!wcr)U^g=KXo^<;{>lu&wO@$YLQAY@pmBAJFf(DrwnqnNTJ zB79==vEY+CHeV){g0>!z$p7x7&CP zkxEC9#({sxD3$mcQSRO-%Iz&PfD$;!Y0HU3j#>IrE*>#tNuB(qdpyK85(^wjJha8R2%`dcV$m38eDmNF6BC7Wiw1G5}i58v__K z)Yxg8gpSGzT+1POPZIN|nNJ)d9mv+kT33VWM(uxJ39$&ua<^qUB(@%+T`+3^OR@IX zcy2}%)LiELP#>mmAtU<~h$itN+m6FQk3{0J{Rb0sH64dJX81)#0d#q{fAmY-*fE84 zBp|*nzuZq?2|%m8Qe98`B-nj*MM%j9fp*r0257WT8wzk)=YMGv+h>Qc4LY#($Hm8e za|eI;r(;_?%r1f{btLeiT8wlPKeU10*GJU=Mow1B3KAk#{IKVp8I} zM{jm_O&M+~R`-=*-@IJ7Osj9{!0$7ED~1&KM~Q9N8R~cMR}w;j|0l$^Q?u94C@fa+ zi}kcrTA$BvLLFhV4a!r-eXDv6`h+*O=!k!&GfYTfa!lj$upHj?OsmFb6aumC^JJ5L z7IDy}wQk3+T}$^VW!^qdNJ9jo-euNw_zT+v7!zOvVN!z}-{S&JI^fz^=Ndq;;K`hL ze0SrY;~PiS3HGzMb*9J=9I`P05qfNRn|b0y_6bY=D;NaKagrqizg%yK({X%yxha3^ zU6ExCYtPJD!u+SkS3zivL9sIbG;8KYts)0|=}W`sJ|bC$EL1~TZ6y3lr$iv89Di0b zxvS$XIAmH#$y46BMhgx~*WwsX%8rt5oB#HI_j8NZS-{R>D52B$@EmFv-8%S444YHOUpS5byIF7hPlaa_}5Swegtf9#=V zb)yOlOuJCrhH6mgR_*(;Ym#l&)KtAG0W)_0dAVi_OD(45DX^0|$BNI{Vjh1xNwPgy zawTMj8+BBZ8Nxga;Njjw*(l}XMC-Odinq1_q&IGfq6&k$|{SKtm0e9Sk0lU{4F|EgaKD;b2+ z0)-l6h57(YwMO??s~f%)csXo;;RhNjm#}Ng(vueo!@q>dfJM-M~TaR ze98ryoVyNIq;&7_Pe4he^@N}k%02f?KP;}XrskmciYr#jz%61%Y%PCyC16Yre#sZi zZ(e6BkR9Yajg|-qDan2v84b{8oKHf{K-#cx^2gNt<-;L#Q)+IEy#=bJz&41$Ajn^k zVg1h28grM<6<#nW22%L1CT!DL{uoQ&fYW0!1p*9}^jFc4qzo*$z>$bjUp;?E#4FoxXvrR4OcD}Dxk{!OXz94(+YuC_hz{DFL~^YVJ0V`K zVn@ARS^tHPYJYHdDUQPdT3*6?RYA);ni`i_p@?*#T8XZw;Lj41RiD*mxmjv1cxu;v z_&Sr=mY{Lpzmy6cWqX&ZChZ8q`8bf!WS?DHsfLM-jD=MMFlv7fBS?~^H&?{hlY5Y$ zzJo36(cGWNIQGzwA-|&I*TM{mtj(DKmG|XD46~=OdL2nDFu+5?{rJM_hHt#d?*R&k ziHN=72Vry`<&R~V5eP?C4M47M7-8mJA5nZNEcMW&XNJ{M-?dUe zgAayy*kU#`$Bcje-<<(>qSfca?WdR5{mcNPV7D4`lJ(CrHkpFK0%Fk zw(xNX5DRmviD);O?ssMf5*Ga>`+c8aBvxwg8fQ+57Rv9|DUf8Hr(e@G8j&LRw?vmh zNvB92FT>FtnRyMILIX#tH3v$$8GUyxTjK)8922Wa^+A6=LWaAg81wuEeL8^UtrjdU z$e6M8Pnp{IG0Zc}p5}k(QO82~(R_l|9@86AS4^h&1-d%@&I>aeY9sJujPsjP*{>FW z-rErW1c-k*&p2{YfP6M(f3y?vIe0TWBz>fV>V-`X!`d9GS*@i4WRRSB;GJ~ob=RpG zaK>aRat)5sV<`+1Q)!U!^v%u8{u3g)?lR;7A=$<&;!EN2VAlYx-eJo=1<>jwA3NRdvanaR9aJ0oBr+b^~mA^9mH? zn3ca0hKm`aF@=-ohlB?br|@0pmp=SJWBfzB{oKCH<$SVc=BY3BLJTXt2-z{&pKFL0?4HI@YVI7^wuBlNc5jWpU7ge* z1Q}B2tRXO3sRR{mAruEEG&YcJ;7E$4ocIwX7_%z$gMm$JF|{Fb>fkEvt7hO)MY6SY z`AXP)7Wl#6nnHRy$!|Yjpx{&iMj#66P;)Ael|5FX0u1xs}QcD6x;HR0wfV zl6|30+3J&jq+Jt{8FQt&ibqci%pHa>KQS2itrjbMj?LOd&QZxau^|l}KMG)hPqbUR9XKWTFs_|a#`#&i zs{w(eLE?yLaq++!)GVc#EzJ4%cPsh7OC+S|A%+T27qEw2skiiysciC}akAn6shgYc z9zayhkY4_m_kcBegF*3}1I&NF+}GRQS9MLUZK!V98L^z`+b)0B8o{Vkp3#kbk7;fH zo#Q|j0jJb;s1+zInP8L6t3Z#B!auxCS7a4wkg?KI#w&7rZBA8MJw`_nHnSg~yWP@? z^vnU9fuTfx^cWxU3VY}O$I0T8(Q|&CzW|xvWJeNWU9XUy|G&U0`p0nYp!v=tRwoMo zj)MYMZ2G`c7z&ww8#_JY4Q(hCo&rqOL^#YcP_e3s_jaVCl4NzZ_V|_M^DJZkARe$w ze-doM-ofc4RNGL%ZJ^|)1+>o~QQ^OCTti`iR_MpFgU>t^2C Date: Tue, 10 Oct 2023 13:16:58 +0200 Subject: [PATCH 1641/2612] telegram-chat: act on reply from self --- doc/telegram-chat.d/03-reply.avif | Bin 0 -> 50126 bytes doc/telegram-chat.md | 15 +++++++++++++++ global-functions.rsc | 2 +- news-and-changes.rsc | 1 + telegram-chat.rsc | 4 +++- 5 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 doc/telegram-chat.d/03-reply.avif diff --git a/doc/telegram-chat.d/03-reply.avif b/doc/telegram-chat.d/03-reply.avif new file mode 100644 index 0000000000000000000000000000000000000000..515853eb902983b864ed16bfbe7e24f1f349d303 GIT binary patch literal 50126 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 G+ywx<1vl9M literal 0 HcmV?d00001 diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index 391042d..3cbc710 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -46,6 +46,8 @@ parameters: Usage and invocation -------------------- +### Activating device(s) + This script is capable of chatting with multiple devices. By default a device is passive and not acting on messages. To activate it send a message containing `! identity` (exclamation mark, optional space and system's @@ -63,6 +65,19 @@ act on your commands. Send a single exclamation mark or non-existent identity to make all devices passive again. +### Reply to message + +Let's assume you received a message from a device before, and want to send +a command to that device. No need to activate it, you can just reply to +that message. + +![reply to message](telegram-chat.d/03-reply.avif) + +Associated messages are cleared on device reboot. + +> âš ī¸ **Warning**: If another device is activated both will act, the one from +> reply and the active one! + Known limitations ----------------- diff --git a/global-functions.rsc b/global-functions.rsc index df374b8..dbedfbc 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 105; +:global ExpectedConfigVersion 106; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index b027fb6..bbbaad6 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -19,6 +19,7 @@ 103="Dropped hard-coded name and timeout from 'hotspot-to-wpa-cleanup', instead a comment is required for dhcp server now."; 104="All relevant scripts were ported to new wifiwave2 and are available for AX devices now!"; 105="Extended 'check-routeros-update' to support automatic update from specific neighbor(s)."; + 106="Modified 'telegram-chat' to make it act on message replies, without activation."; }; # Migration steps to be applied on script updates diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 6083fee..29130db 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -17,6 +17,7 @@ :global TelegramChatIdsTrusted; :global TelegramChatOffset; :global TelegramChatRunTime; +:global TelegramMessageIDs; :global TelegramTokenId; :global CertificateAvailable; @@ -83,7 +84,8 @@ $WaitFullyConnected; $LogPrintExit2 info $0 ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . \ " from update " . $UpdateID . "!") false; } else={ - :if ($TelegramChatActive = true && [ :len ($Message->"text") ] > 0) do={ + :if (($TelegramMessageIDs->([ $ParseJson ($Message->"reply_to_message") ]->"message_id") = 1 || \ + $TelegramChatActive = true) && [ :len ($Message->"text") ] > 0) do={ :if ([ $ValidateSyntax ($Message->"text") ] = true) do={ :local State ""; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); From adca33cc5bcc68911bc811d4b40f387e6b1afd97 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Oct 2023 10:24:04 +0200 Subject: [PATCH 1642/2612] telegram-chat: act on reply without delay --- telegram-chat.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 29130db..f71cbde 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -62,9 +62,10 @@ $WaitFullyConnected; :foreach UpdateArray in=[ :toarray $Data ] do={ :local Update [ $ParseJson $UpdateArray ]; :set UpdateID ($Update->"update_id"); - :if (($TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={ + :local Message [ $ParseJson ($Update->"message") ]; + :local IsReply ($TelegramMessageIDs->([ $ParseJson ($Message->"reply_to_message") ]->"message_id")); + :if (($IsReply = 1 || $TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={ :local Trusted false; - :local Message [ $ParseJson ($Update->"message") ]; :local Chat [ $ParseJson ($Message->"chat") ]; :local From [ $ParseJson ($Message->"from") ]; @@ -84,8 +85,7 @@ $WaitFullyConnected; $LogPrintExit2 info $0 ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . \ " from update " . $UpdateID . "!") false; } else={ - :if (($TelegramMessageIDs->([ $ParseJson ($Message->"reply_to_message") ]->"message_id") = 1 || \ - $TelegramChatActive = true) && [ :len ($Message->"text") ] > 0) do={ + :if (($IsReply = 1 || $TelegramChatActive = true) && [ :len ($Message->"text") ] > 0) do={ :if ([ $ValidateSyntax ($Message->"text") ] = true) do={ :local State ""; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); From 555461c6121465aab748429d6a3226b1a6ca42b4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 Oct 2023 12:50:50 +0200 Subject: [PATCH 1643/2612] telegram-chat: do not nest conditions --- telegram-chat.rsc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index f71cbde..9afac69 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -76,6 +76,7 @@ $WaitFullyConnected; } :if ($Trusted = true) do={ + :local Done false; :if ([ :pick ($Message->"text") 0 1 ] = "!") do={ :if ($Message->"text" ~ ("^! *(" . [ $EscapeForRegEx $Identity ] . "|@" . $TelegramChatGroups . ")\$")) do={ :set TelegramChatActive true; @@ -84,8 +85,9 @@ $WaitFullyConnected; } $LogPrintExit2 info $0 ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . \ " from update " . $UpdateID . "!") false; - } else={ - :if (($IsReply = 1 || $TelegramChatActive = true) && [ :len ($Message->"text") ] > 0) do={ + :set Done true; + } + :if ($Done = false && ($IsReply = 1 || $TelegramChatActive = true) && [ :len ($Message->"text") ] > 0) do={ :if ([ $ValidateSyntax ($Message->"text") ] = true) do={ :local State ""; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); @@ -113,7 +115,6 @@ $WaitFullyConnected; message=("Command:\n" . $Message->"text" . "\n\nThe command failed syntax validation!") }); } } - } } else={ :local MessageText ("Received a message from untrusted contact " . \ [ $IfThenElse ([ :len ($From->"username") ] = 0) "without username" ("'" . $From->"username" . "'") ] . \ From 15873e2fdb20ad74e8ba9f0cf3dd7331ad143809 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 Oct 2023 15:04:22 +0200 Subject: [PATCH 1644/2612] telegram-chat: restore indention --- telegram-chat.rsc | 50 +++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 9afac69..e063e80 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -88,33 +88,33 @@ $WaitFullyConnected; :set Done true; } :if ($Done = false && ($IsReply = 1 || $TelegramChatActive = true) && [ :len ($Message->"text") ] > 0) do={ - :if ([ $ValidateSyntax ($Message->"text") ] = true) do={ - :local State ""; - :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); - $MkDir "tmpfs/telegram-chat"; - $LogPrintExit2 info $0 ("Running command from update " . $UpdateID . ": " . $Message->"text") false; - :execute script=(":do {\n" . $Message->"text" . "\n} on-error={ /file/add name=\"" . $File . ".failed\" };" . \ - "/file/add name=\"" . $File . ".done\"") file=$File; - :if ([ $WaitForFile ($File . ".done") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ - :set State "The command did not finish, still running in background.\n\n"; - } - :if ([ :len [ /file/find where name=($File . ".failed") ] ] > 0) do={ - :set State "The command failed with an error!\n\n"; - } - :local Content [ /file/get ($File . ".txt") contents ]; - $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ - subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Command:\n" . $Message->"text" . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ - ("Output:\n" . $Content) [ $IfThenElse ([ /file/get ($File . ".txt") size ] > 0) \ - ("Output exceeds file read size.") ("No output.") ] ]) }); - /file/remove "tmpfs/telegram-chat"; - } else={ - $LogPrintExit2 info $0 ("The command from update " . $UpdateID . " failed syntax validation!") false; - $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ - subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Command:\n" . $Message->"text" . "\n\nThe command failed syntax validation!") }); + :if ([ $ValidateSyntax ($Message->"text") ] = true) do={ + :local State ""; + :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); + $MkDir "tmpfs/telegram-chat"; + $LogPrintExit2 info $0 ("Running command from update " . $UpdateID . ": " . $Message->"text") false; + :execute script=(":do {\n" . $Message->"text" . "\n} on-error={ /file/add name=\"" . $File . ".failed\" };" . \ + "/file/add name=\"" . $File . ".done\"") file=$File; + :if ([ $WaitForFile ($File . ".done") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ + :set State "The command did not finish, still running in background.\n\n"; } + :if ([ :len [ /file/find where name=($File . ".failed") ] ] > 0) do={ + :set State "The command failed with an error!\n\n"; + } + :local Content [ /file/get ($File . ".txt") contents ]; + $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=("Command:\n" . $Message->"text" . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ + ("Output:\n" . $Content) [ $IfThenElse ([ /file/get ($File . ".txt") size ] > 0) \ + ("Output exceeds file read size.") ("No output.") ] ]) }); + /file/remove "tmpfs/telegram-chat"; + } else={ + $LogPrintExit2 info $0 ("The command from update " . $UpdateID . " failed syntax validation!") false; + $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=("Command:\n" . $Message->"text" . "\n\nThe command failed syntax validation!") }); } + } } else={ :local MessageText ("Received a message from untrusted contact " . \ [ $IfThenElse ([ :len ($From->"username") ] = 0) "without username" ("'" . $From->"username" . "'") ] . \ From 1b62545d8c5b186e9059c9640761a12ad336ec7b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Oct 2023 21:54:50 +0200 Subject: [PATCH 1645/2612] telegram-chat: answer question mark with short notice --- doc/telegram-chat.md | 5 +++++ news-and-changes.rsc | 2 +- telegram-chat.rsc | 8 +++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index 3cbc710..79a9eb1 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -78,6 +78,11 @@ Associated messages are cleared on device reboot. > âš ī¸ **Warning**: If another device is activated both will act, the one from > reply and the active one! +### Ask for devices + +Send a message with a single question mark (`?`) to query for devices +currenty online. The answer can be used for command via reply then. + Known limitations ----------------- diff --git a/news-and-changes.rsc b/news-and-changes.rsc index bbbaad6..49b1671 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -19,7 +19,7 @@ 103="Dropped hard-coded name and timeout from 'hotspot-to-wpa-cleanup', instead a comment is required for dhcp server now."; 104="All relevant scripts were ported to new wifiwave2 and are available for AX devices now!"; 105="Extended 'check-routeros-update' to support automatic update from specific neighbor(s)."; - 106="Modified 'telegram-chat' to make it act on message replies, without activation."; + 106="Modified 'telegram-chat' to make it act on message replies, without activation. Also made it answer a single question mark with a short notice."; }; # Migration steps to be applied on script updates diff --git a/telegram-chat.rsc b/telegram-chat.rsc index e063e80..16edbca 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -77,7 +77,13 @@ $WaitFullyConnected; :if ($Trusted = true) do={ :local Done false; - :if ([ :pick ($Message->"text") 0 1 ] = "!") do={ + :if ($Message->"text" = "?") do={ + $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=("Online, awaiting your commands!") }); + :set Done true; + } + :if ($Done = false && [ :pick ($Message->"text") 0 1 ] = "!") do={ :if ($Message->"text" ~ ("^! *(" . [ $EscapeForRegEx $Identity ] . "|@" . $TelegramChatGroups . ")\$")) do={ :set TelegramChatActive true; } else={ From bc4839f61130695f504ccd3745dd099540db5206 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 Oct 2023 13:05:21 +0200 Subject: [PATCH 1646/2612] telegram-chat: rename variable --- telegram-chat.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 16edbca..1a89544 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -63,8 +63,8 @@ $WaitFullyConnected; :local Update [ $ParseJson $UpdateArray ]; :set UpdateID ($Update->"update_id"); :local Message [ $ParseJson ($Update->"message") ]; - :local IsReply ($TelegramMessageIDs->([ $ParseJson ($Message->"reply_to_message") ]->"message_id")); - :if (($IsReply = 1 || $TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={ + :local IsMyReply ($TelegramMessageIDs->([ $ParseJson ($Message->"reply_to_message") ]->"message_id")); + :if (($IsMyReply = 1 || $TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={ :local Trusted false; :local Chat [ $ParseJson ($Message->"chat") ]; :local From [ $ParseJson ($Message->"from") ]; @@ -93,7 +93,7 @@ $WaitFullyConnected; " from update " . $UpdateID . "!") false; :set Done true; } - :if ($Done = false && ($IsReply = 1 || $TelegramChatActive = true) && [ :len ($Message->"text") ] > 0) do={ + :if ($Done = false && ($IsMyReply = 1 || $TelegramChatActive = true) && [ :len ($Message->"text") ] > 0) do={ :if ([ $ValidateSyntax ($Message->"text") ] = true) do={ :local State ""; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); From c9233773b3a1dd967d1dd5924c5f00c516d55d41 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 Oct 2023 13:07:29 +0200 Subject: [PATCH 1647/2612] telegram-chat: do not act on foreign reply... ... even if active! --- doc/telegram-chat.md | 3 --- telegram-chat.rsc | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index 79a9eb1..397920a 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -75,9 +75,6 @@ that message. Associated messages are cleared on device reboot. -> âš ī¸ **Warning**: If another device is activated both will act, the one from -> reply and the active one! - ### Ask for devices Send a message with a single question mark (`?`) to query for devices diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 1a89544..2bd8ccd 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -63,6 +63,7 @@ $WaitFullyConnected; :local Update [ $ParseJson $UpdateArray ]; :set UpdateID ($Update->"update_id"); :local Message [ $ParseJson ($Update->"message") ]; + :local IsReply [ :len ($Message->"reply_to_message") ]; :local IsMyReply ($TelegramMessageIDs->([ $ParseJson ($Message->"reply_to_message") ]->"message_id")); :if (($IsMyReply = 1 || $TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={ :local Trusted false; @@ -93,7 +94,7 @@ $WaitFullyConnected; " from update " . $UpdateID . "!") false; :set Done true; } - :if ($Done = false && ($IsMyReply = 1 || $TelegramChatActive = true) && [ :len ($Message->"text") ] > 0) do={ + :if ($Done = false && ($IsMyReply = 1 || ($IsReply = 0 && $TelegramChatActive = true)) && [ :len ($Message->"text") ] > 0) do={ :if ([ $ValidateSyntax ($Message->"text") ] = true) do={ :local State ""; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); From fed7f2da46fc02b12d23c0f05111452b8e9935e6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Oct 2023 16:42:24 +0200 Subject: [PATCH 1648/2612] mod/notification-telegram: drop support for non-fixed width font --- global-config.rsc | 2 -- global-functions.rsc | 2 +- mod/notification-telegram.rsc | 15 +++------------ news-and-changes.rsc | 1 + 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/global-config.rsc b/global-config.rsc index 172c4cd..0ea18e5 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -41,8 +41,6 @@ #}; :global TelegramChatGroups "(all)"; #:global TelegramChatGroups "(all|home|office)"; -# This is whether or not to send Telegram messages with fixed-width font. -:global TelegramFixedWidthFont true; # You can send Matrix notifications. Configure these settings and # install the module: diff --git a/global-functions.rsc b/global-functions.rsc index dbedfbc..4617a3a 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 106; +:global ExpectedConfigVersion 107; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 641c6f0..b5729a4 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -40,7 +40,7 @@ ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ http-data=("chat_id=" . ($Message->"chatid") . "&disable_notification=" . ($Message->"silent") . \ "&reply_to_message_id=" . ($Message->"replyto") . "&disable_web_page_preview=true" . \ - "&parse_mode=" . ($Message->"parsemode") . "&text=" . ($Message->"text")) as-value ]->"data"); + "&parse_mode=MarkdownV2&text=" . ($Message->"text")) as-value ]->"data"); :set ($TelegramQueue->$Id); :set ($TelegramMessageIDs->([ $ParseJson ([ $ParseJson $Data ]->"result") ]->"message_id")) 1; } on-error={ @@ -64,7 +64,6 @@ :global IdentityExtra; :global TelegramChatId; :global TelegramChatIdOverride; - :global TelegramFixedWidthFont; :global TelegramMessageIDs; :global TelegramQueue; :global TelegramTokenId; @@ -80,15 +79,9 @@ :global UrlEncode; :local EscapeMD do={ - :global TelegramFixedWidthFont; - :global CharacterReplace; :global IfThenElse; - :if ($TelegramFixedWidthFont != true) do={ - :return ($1 . [ $IfThenElse ($2 = "body") ("\n") "" ]); - } - :local Return $1; :local Chars { "body"={ "\\"; "`" }; @@ -140,7 +133,6 @@ (($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%!") "plain" ]); } :set Text [ $UrlEncode $Text ]; - :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; :do { :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ @@ -150,7 +142,7 @@ ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ "&reply_to_message_id=" . ($Notification->"replyto") . "&disable_web_page_preview=true" . \ - "&parse_mode=" . $ParseMode . "&text=" . $Text) as-value ]->"data"); + "&parse_mode=MarkdownV2&text=" . $Text) as-value ]->"data"); :set ($TelegramMessageIDs->([ $ParseJson ([ $ParseJson $Data ]->"result") ]->"message_id")) 1; } on-error={ $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; @@ -162,8 +154,7 @@ [ $EscapeMD ("This message was queued since " . [ /system/clock/get date ] . \ " " . [ /system/clock/get time ] . " and may be obsolete.") "plain" ]) ]); :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; - parsemode=$ParseMode; text=$Text; silent=($Notification->"silent"); - replyto=($Notification->"replyto") }; + text=$Text; silent=($Notification->"silent"); replyto=($Notification->"replyto") }; :if ([ :len [ /system/scheduler/find where name="\$FlushTelegramQueue" ] ] = 0) do={ /system/scheduler/add name="\$FlushTelegramQueue" interval=1m start-time=startup \ on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;"); diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 49b1671..d20ace0 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -20,6 +20,7 @@ 104="All relevant scripts were ported to new wifiwave2 and are available for AX devices now!"; 105="Extended 'check-routeros-update' to support automatic update from specific neighbor(s)."; 106="Modified 'telegram-chat' to make it act on message replies, without activation. Also made it answer a single question mark with a short notice."; + 107="Dropped support for non-fixed width font in Telegram notifications."; }; # Migration steps to be applied on script updates From 140ec1a3a26af52572e755c126323097e56a4faa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 Oct 2023 23:38:06 +0200 Subject: [PATCH 1649/2612] global-functions: $ParseJson: use temporary variables --- global-functions.rsc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 4617a3a..d510ff9 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -715,11 +715,13 @@ } } else={ :local Key ($Input->$I); - :if ($Input->($I + 1) = ":") do={ - :set ($Return->$Key) ($Input->($I + 2)); + :local Val1 ($Input->($I + 1)); + :local Val2 ($Input->($I + 2)); + :if ($Val1 = ":") do={ + :set ($Return->$Key) $Val2; :set Skip 2; } else={ - :set ($Return->$Key) [ :pick ($Input->($I + 1)) 1 [ :len ($Input->($I + 1)) ] ]; + :set ($Return->$Key) [ :pick $Val1 1 [ :len $Val1 ] ]; :set Skip 1; } } From 3b9df48721c6cb6c3018581749cdbcb6442774a5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 Oct 2023 23:39:27 +0200 Subject: [PATCH 1650/2612] global-functions: $ParseJson: prepare elif-workaround --- global-functions.rsc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index d510ff9..8dc8c02 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -714,13 +714,16 @@ :set $Skip ($Skip - 1); } } else={ + :local Done false; :local Key ($Input->$I); :local Val1 ($Input->($I + 1)); :local Val2 ($Input->($I + 2)); :if ($Val1 = ":") do={ :set ($Return->$Key) $Val2; :set Skip 2; - } else={ + :set Done true; + } + :if ($Done = false) do={ :set ($Return->$Key) [ :pick $Val1 1 [ :len $Val1 ] ]; :set Skip 1; } From c0aab0feadd1ede2cc2d900811f0678f8901de6a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Oct 2023 22:41:28 +0200 Subject: [PATCH 1651/2612] global-functions: $ParseJson: properly handle array --- global-functions.rsc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 8dc8c02..8d06cb1 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -723,6 +723,19 @@ :set Skip 2; :set Done true; } + :if ($Done = false && $Val1 = ":[") do={ + :local Tmp ""; + :local End; + :set Skip 1; + :do { + :set Skip ($Skip + 1); + :local ValX ($Input->($I + $Skip)); + :set End [ :pick $ValX ([ :len $ValX ] - 1) ]; + :set Tmp ($Tmp . "},{" . $ValX); + } while=($End != "]"); + :set ($Return->$Key) ("{" . [ :pick $Tmp 0 ([ :len $Tmp ] - 1) ] . "}"); + :set Done true; + } :if ($Done = false) do={ :set ($Return->$Key) [ :pick $Val1 1 [ :len $Val1 ] ]; :set Skip 1; From 73194b92cf2c4c10b7d45945b15f26c965d03dca Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Oct 2023 22:43:19 +0200 Subject: [PATCH 1652/2612] telegram-chat: use $ParseJson for all JSON --- telegram-chat.rsc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 2bd8ccd..59e56b7 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -52,14 +52,13 @@ $WaitFullyConnected; :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=" . \ $TelegramChatOffset->0 . "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); - :set Data [ :pick $Data ([ :find $Data "[" ] + 1) ([ :len $Data ] - 2) ]; } on-error={ $LogPrintExit2 debug $0 ("Failed getting updates from Telegram.") true; } :local UpdateID 0; :local Uptime [ /system/resource/get uptime ]; -:foreach UpdateArray in=[ :toarray $Data ] do={ +:foreach UpdateArray in=[ :toarray ([ $ParseJson $Data ]->"result") ] do={ :local Update [ $ParseJson $UpdateArray ]; :set UpdateID ($Update->"update_id"); :local Message [ $ParseJson ($Update->"message") ]; From bcc10c82855fb37f2672d28cf79125f921962c68 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 17 Oct 2023 14:01:10 +0200 Subject: [PATCH 1653/2612] telegram-chat: make messages silent... ... at least those not indicating an error. --- telegram-chat.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 59e56b7..c17394a 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -78,7 +78,7 @@ $WaitFullyConnected; :if ($Trusted = true) do={ :local Done false; :if ($Message->"text" = "?") do={ - $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ + $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Online, awaiting your commands!") }); :set Done true; @@ -108,7 +108,7 @@ $WaitFullyConnected; :set State "The command failed with an error!\n\n"; } :local Content [ /file/get ($File . ".txt") contents ]; - $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ + $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Command:\n" . $Message->"text" . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ ("Output:\n" . $Content) [ $IfThenElse ([ /file/get ($File . ".txt") size ] > 0) \ From da0a37802df19eb5ae16b07fd2603f66d31c8f46 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Oct 2023 17:34:53 +0200 Subject: [PATCH 1654/2612] global-functions: $CertificateDownload: http-header-field expects an array --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 8d06cb1..b798047 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -125,7 +125,7 @@ :do { :local LocalFileName ($CommonName . ".pem"); :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); - /tool/fetch check-certificate=yes-without-crl http-header-field=$FetchUserAgent \ + /tool/fetch check-certificate=yes-without-crl http-header-field=({ $FetchUserAgent }) \ ($ScriptUpdatesBaseUrl . "certs/" . $UrlFileName . $ScriptUpdatesUrlSuffix) \ dst-path=$LocalFileName as-value; $WaitForFile $LocalFileName; From 1b00f93fc6af2c5f94f9b32927bf278fb55713d5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Oct 2023 17:38:15 +0200 Subject: [PATCH 1655/2612] global-functions: $ScriptInstallUpdate: http-header-field expects an array --- global-functions.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index b798047..e084171 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -905,8 +905,8 @@ :local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix); $LogPrintExit2 debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url) false; - :local Result [ /tool/fetch check-certificate=yes-without-crl http-header-field=$FetchUserAgent \ - $Url output=user as-value ]; + :local Result [ /tool/fetch check-certificate=yes-without-crl \ + http-header-field=({ $FetchUserAgent }) $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set SourceNew ($Result->"data"); } @@ -989,8 +989,8 @@ :do { :local Url ($ScriptUpdatesBaseUrl . "news-and-changes.rsc" . $ScriptUpdatesUrlSuffix); $LogPrintExit2 debug $0 ("Fetching news, changes and migration: " . $Url) false; - :local Result [ /tool/fetch check-certificate=yes-without-crl http-header-field=$FetchUserAgent \ - $Url output=user as-value ]; + :local Result [ /tool/fetch check-certificate=yes-without-crl \ + http-header-field=({ $FetchUserAgent }) $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set ChangeLogCode ($Result->"data"); } From ef3b8f8ddd9a222df252a6c9e986d2330072ec7f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Oct 2023 17:39:50 +0200 Subject: [PATCH 1656/2612] gps-track: http-header-field expects an array --- gps-track.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gps-track.rsc b/gps-track.rsc index 0d328d5..86506b8 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -26,7 +26,7 @@ $WaitFullyConnected; :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-method=post http-header-field=({ "Content-Type: application/json" }) \ http-data=("{" . \ "\"lat\":\"" . ($Gps->"latitude") . "\"," . \ "\"lon\":\"" . ($Gps->"longitude") . "\"," . \ From 24823441c33b5558ff9b87f6a8586620e7dad079 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Oct 2023 23:43:59 +0200 Subject: [PATCH 1657/2612] log-forward: use colorful bullets to indicate severity --- global-functions.rsc | 5 ++++- log-forward.rsc | 10 +++++++--- news-and-changes.rsc | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index e084171..876f7d8 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 107; +:global ExpectedConfigVersion 108; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -1230,6 +1230,9 @@ "floppy-disk"="\F0\9F\92\BE"; "high-voltage-sign"="\E2\9A\A1"; "incoming-envelope"="\F0\9F\93\A8"; + "information"="\E2\84\B9"; + "large-orange-circle"="\F0\9F\9F\A0"; + "large-red-circle"="\F0\9F\94\B4"; "link"="\F0\9F\94\97"; "lock-with-ink-pen"="\F0\9F\94\8F"; "memo"="\F0\9F\93\9D"; diff --git a/log-forward.rsc b/log-forward.rsc index 96cb257..e847256 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -17,7 +17,6 @@ :global LogForwardIncludeMessage; :global LogForwardLast; :global LogForwardRateLimit; -:global NotificationsWithSymbols; :global EitherOr; :global HexToNum; @@ -53,14 +52,19 @@ $ScriptLock $0; !(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \ topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={ :set MessageVal [ /log/get $Message ]; + :local Bullet "information"; :if ($Last < [ $HexToNum ($MessageVal->".id") ]) do={ :local DupCount ($MessageDups->($MessageVal->"message")); - :if ($MessageVal->"topics" ~ "(emergency|alert|critical|error|warning)") do={ + :if ($MessageVal->"topics" ~ "(warning)") do={ :set Warning true; + :set Bullet "large-orange-circle"; + } + :if ($MessageVal->"topics" ~ "(emergency|alert|critical|error)") do={ + :set Bullet "large-red-circle"; } :if ($DupCount < 3) do={ - :set Messages ($Messages . "\n" . [ $IfThenElse ($NotificationsWithSymbols = true) (" \E2\97\8F ") ] . \ + :set Messages ($Messages . "\n" . [ $SymbolForNotification $Bullet ] . \ $MessageVal->"time" . " " . [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message"); } else={ :set Duplicates true; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index d20ace0..debd756 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -21,6 +21,7 @@ 105="Extended 'check-routeros-update' to support automatic update from specific neighbor(s)."; 106="Modified 'telegram-chat' to make it act on message replies, without activation. Also made it answer a single question mark with a short notice."; 107="Dropped support for non-fixed width font in Telegram notifications."; + 108="Enhanced 'log-forward' to list log messages with colorful bullets to indicate severity."; }; # Migration steps to be applied on script updates From f6e65dd68c20d951564e3a52475522a83c2f9a3d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Oct 2023 16:23:06 +0200 Subject: [PATCH 1658/2612] log-forward: add 'packet' in default filter... ... which is used when logging raw packets from dns and ssh, and possibly others. --- global-config.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config.rsc b/global-config.rsc index 0ea18e5..28148e0 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -105,7 +105,7 @@ # text. Regular expressions are supported. Do *NOT* set an empty string, # that will filter or include everything! # These are filters, so excluding messages from forwarding. -:global LogForwardFilter "(debug|info|raw)"; +:global LogForwardFilter "(debug|info|packet|raw)"; :global LogForwardFilterMessage []; #:global LogForwardFilterMessage "message text"; #:global LogForwardFilterMessage "(message text|another text|...)"; From 5fbf584d4ca128e5acfd0424ec66e2edc24dd946 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Oct 2023 10:03:48 +0200 Subject: [PATCH 1659/2612] sms-forward: pass phone number and message to hook These are available as $Phone and $Message in hook. --- doc/sms-forward.md | 3 ++- sms-forward.rsc | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index a323157..5967903 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -40,7 +40,8 @@ The configuration goes to `global-config-overlay`, this is the only parameter: * `SmsForwardHooks`: an array with pre-defined hooks, where each hook consists of `match` (which is matched against the received message), `allowed-number` (which is matched against the sending phone number or name) and `command`. - For `match` and `allowed-number` regular expressions are supported. + For `match` and `allowed-number` regular expressions are supported. Actual + phone number (`$Phone`) and message (`$Message`) are available for the hook. > â„šī¸ **Info**: Copy relevant configuration from > [`global-config`](../global-config.rsc) (the one without `-overlay`) to diff --git a/sms-forward.rsc b/sms-forward.rsc index 7c6a609..4f2d2e6 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -58,7 +58,8 @@ $WaitFullyConnected; $LogPrintExit2 info $0 ("Running hook '" . $Hook->"match" . "': " . \ $Hook->"command") false; :do { - [ :parse ($Hook->"command") ]; + :local Command [ :parse ($Hook->"command") ]; + $Command Phone=$Phone Message=($SmsVal->"message"); :set Messages ($Messages . "\n\nRan hook '" . $Hook->"match" . "':\n" . \ $Hook->"command"); } on-error={ From 5932586ee4c573903dbd40b4f422ffb2819b9ba2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Oct 2023 07:40:55 +0200 Subject: [PATCH 1660/2612] introduce mod/notification-ntfy... ... for sending notifications via Ntfy (https://ntfy.sh/). TODO: use proper formatting once supported in Android app: https://github.com/binwiederhier/ntfy/issues/889 --- README.md | 1 + doc/backup-cloud.md | 3 +- doc/backup-upload.md | 3 +- doc/check-certificates.md | 3 +- doc/check-health.md | 3 +- doc/check-routeros-update.md | 3 +- doc/collect-wireless-mac.md | 3 +- doc/daily-psk.md | 3 +- doc/log-forward.md | 3 +- doc/mod/notification-email.md | 1 + doc/mod/notification-matrix.md | 1 + doc/mod/notification-ntfy.md | 79 +++++++++++++++++++ doc/mod/notification-telegram.md | 1 + doc/netwatch-notify.md | 3 +- doc/sms-forward.md | 3 +- global-config.rsc | 12 ++- global-functions.rsc | 2 +- mod/notification-ntfy.rsc | 129 +++++++++++++++++++++++++++++++ news-and-changes.rsc | 1 + 19 files changed, 243 insertions(+), 14 deletions(-) create mode 100644 doc/mod/notification-ntfy.md create mode 100644 mod/notification-ntfy.rsc diff --git a/README.md b/README.md index de97c84..ec771f7 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,7 @@ Available modules * [IP address calculation](doc/mod/ipcalc.md) * [Send notifications via e-mail](doc/mod/notification-email.md) * [Send notifications via Matrix](doc/mod/notification-matrix.md) +* [Send notifications via Ntfy](doc/mod/notification-ntfy.md) * [Send notifications via Telegram](doc/mod/notification-telegram.md) * [Download script and run it once](doc/mod/scriptrunonce.md) * [Import ssh keys for public key authentication](doc/mod/ssh-keys-import.md) diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index b612fc4..f084d5b 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -42,7 +42,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: Also notification settings are required for [e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). Usage and invocation diff --git a/doc/backup-upload.md b/doc/backup-upload.md index f9aaa29..b132e56 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -48,7 +48,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: Also notification settings are required for [e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). ### Issues with SFTP client diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 58151f3..95ff534 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -44,7 +44,8 @@ subject alternative name (aka *Subject Alt Name* or *SAN*) can be used. Also notification settings are required for [e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). Usage and invocation diff --git a/doc/check-health.md b/doc/check-health.md index 3f4c70f..34b5faf 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -80,7 +80,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: Also notification settings are required for [e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). --- diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 3b5c2bd..dbe83b8 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -66,7 +66,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: Also notification settings are required for [e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). Usage and invocation diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 9ba1e3a..2b17055 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -47,7 +47,8 @@ entries are to be added. Also notification settings are required for [e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). Usage and invocation diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 60a645f..f551e46 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -72,7 +72,8 @@ For legacy local interface: Also notification settings are required for [e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md) and/or +[trix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). --- diff --git a/doc/log-forward.md b/doc/log-forward.md index 43ae897..4212381 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -67,7 +67,8 @@ To forward **all** (ignoring severity) log messages with topics `account` Also notification settings are required for [e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). Tips & Tricks diff --git a/doc/mod/notification-email.md b/doc/mod/notification-email.md index 8dc2ecf..6b1142d 100644 --- a/doc/mod/notification-email.md +++ b/doc/mod/notification-email.md @@ -73,6 +73,7 @@ See also -------- * [Send notifications via Matrix](notification-matrix.md) +* [Send notifications via Ntfy](notification-ntfy.md) * [Send notifications via Telegram](notification-telegram.md) --- diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index ab8efc9..e9e3174 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -119,6 +119,7 @@ See also -------- * [Send notifications via e-mail](notification-email.md) +* [Send notifications via Ntfy](notification-ntfy.md) * [Send notifications via Telegram](notification-telegram.md) --- diff --git a/doc/mod/notification-ntfy.md b/doc/mod/notification-ntfy.md new file mode 100644 index 0000000..64e49f0 --- /dev/null +++ b/doc/mod/notification-ntfy.md @@ -0,0 +1,79 @@ +Send notifications via Ntfy +=========================== + +[âŦ…ī¸ Go back to main README](../../README.md) + +> â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base +> installation. See [main README](../../README.md) for details. + +Description +----------- + +This module adds support for sending notifications via +[Ntfy](https://ntfy.sh/). A queue is used to make sure +notifications are not lost on failure but sent later. + +Requirements and installation +----------------------------- + +Just install the module: + + $ScriptInstallUpdate mod/notification-ntfy; + +Also install the Ntfy app on your mobile device or use the +[web app](https://ntfy.sh/app) in a browser of your choice. + +Configuration +------------- + +Creating an account is not required. Just choose a topic and you are good +to go. + +> âš ī¸ **Warning**: If you use ntfy without sign-up, the topic is essentially +> a password, so pick something that's not easily guessable. + +Edit `global-config-overlay`, add `NtfyServer` (leave it unchanged, unless +you are self-hosting the service) and `NtfyTopic` with your choosen topic. +Then reload the configuration. + +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + +Usage and invocation +-------------------- + +There's nothing special to do. Every script or function sending a notification +will now send it to your Ntfy topic. + +But of course you can use the function to send notifications directly. Give +it a try: + + $SendNtfy "Subject..." "Body..." + +Alternatively this sends a notification with all available and configured +methods: + + $SendNotification "Subject..." "Body..." + +To use the functions in your own scripts you have to declare them first. +Place this before you call them: + + :global SendNtfy; + :global SendNotification; + +In case there is a situation when the queue needs to be purged there is a +function available: + + $PurgeNtfyQueue; + +See also +-------- + +* [Send notifications via e-mail](notification-email.md) +* [Send notifications via Matrix](notification-matrix.md) +* [Send notifications via Telegram](notification-telegram.md) + +--- +[âŦ…ī¸ Go back to main README](../../README.md) +[âŦ†ī¸ Go back to top](#top) diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index 89659c8..387d511 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -98,6 +98,7 @@ See also * [Chat with your router and send commands via Telegram bot](../telegram-chat.md) * [Send notifications via e-mail](notification-email.md) * [Send notifications via Matrix](notification-matrix.md) +* [Send notifications via Ntfy](notification-ntfy.md) --- [âŦ…ī¸ Go back to main README](../../README.md) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 6df233b..b673af8 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -40,7 +40,8 @@ The hosts to be checked have to be added to netwatch with specific comment: Also notification settings are required for [e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). ### Hooks diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 5967903..823805e 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -49,7 +49,8 @@ The configuration goes to `global-config-overlay`, this is the only parameter: Notification settings are required for [e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). Tips & Tricks diff --git a/global-config.rsc b/global-config.rsc index 28148e0..5d39c86 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -52,9 +52,15 @@ #:global MatrixAccessToken "123456ABCDEFGHI..."; #:global MatrixRoom "!example:matrix.org"; -# It is possible to override e-mail, Telegram and Matrix setting for every -# script. This is done in arrays, where 'Override' is appended to the -# variable name, like this: +# You can send Ntfy notifications. Configure these settings and +# install the module: +# $ScriptInstallUpdate mod/notification-ntfy +:global NtfyServer "ntfy.sh"; +:global NtfyTopic ""; + +# It is possible to override e-mail, Telegram, Matrix and Ntfy setting +# for every script. This is done in arrays, where 'Override' is appended +# to the variable name, like this: #:global EmailGeneralToOverride { # "check-certificates"="override@example.com"; # "backup-email"="backup@example.com"; diff --git a/global-functions.rsc b/global-functions.rsc index 876f7d8..2433e57 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 108; +:global ExpectedConfigVersion 109; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc new file mode 100644 index 0000000..a94e1be --- /dev/null +++ b/mod/notification-ntfy.rsc @@ -0,0 +1,129 @@ +#!rsc by RouterOS +# RouterOS script: mod/notification-ntfy +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# send notifications via Ntfy (ntfy.sh) +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-ntfy.md + +:global FlushNtfyQueue; +:global NotificationFunctions; +:global PurgeNtfyQueue; +:global SendNtfy; +:global SendNtfy2; + +# flush ntfy queue +:set FlushNtfyQueue do={ + :global NtfyQueue; + :global NtfyMessageIDs; + + :global IsFullyConnected; + :global LogPrintExit2; + + :if ([ $IsFullyConnected ] = false) do={ + $LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false; + :return false; + } + + :local AllDone true; + :local QueueLen [ :len $NtfyQueue ]; + + :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ + $LogPrintExit2 warning $0 ("Flushing Ntfy messages from scheduler, but queue is empty.") false; + } + + :foreach Id,Message in=$NtfyQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :do { + /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + ($Message->"url") http-header-field=($Message->"headers") http-data=($Message->"text") as-value; + :set ($NtfyQueue->$Id); + } on-error={ + $LogPrintExit2 debug $0 ("Sending queued Ntfy message failed.") false; + :set AllDone false; + } + } + } + + :if ($AllDone = true && $QueueLen = [ :len $NtfyQueue ]) do={ + /system/scheduler/remove [ find where name=$0 ]; + :set NtfyQueue; + } +} + +# send notification via ntfy - expects one array argument +:set ($NotificationFunctions->"ntfy") do={ + :local Notification $1; + + :global Identity; + :global IdentityExtra; + :global NtfyQueue; + :global NtfyServer; + :global NtfyServerOverride; + :global NtfyTopic; + :global NtfyTopicOverride; + + :global EitherOr; + :global IfThenElse; + :global LogPrintExit2; + :global SymbolForNotification; + :global UrlEncode; + + :local Server [ $EitherOr ($NtfyServerOverride->($Notification->"origin")) $NtfyServer ]; + :local Topic [ $EitherOr ($NtfyTopicOverride->($Notification->"origin")) $NtfyTopic ]; + + :if ([ :len $Topic ] = 0) do={ + :return false; + } + + :local Url ("https://" . $NtfyServer . "/" . [ $UrlEncode $NtfyTopic ]); + :local Headers ({ ("Priority: " . [ $IfThenElse ($Notification->"silent") "low" "default" ]); \ + ("Title: " . "[" . $IdentityExtra . $Identity . "] " . ($Notification->"subject")) }); + :local Text (($Notification->"message") . "\n"); + :if ([ :len ($Notification->"link") ] > 0) do={ + :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . ($Notification->"link")); + } + + :do { + /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + $Url http-header-field=$Headers http-data=$Text as-value; + } on-error={ + $LogPrintExit2 info $0 ("Failed sending ntfy notification! Queuing...") false; + + :if ([ :typeof $NtfyQueue ] = "nothing") do={ + :set NtfyQueue ({}); + } + :set Text ($Text . "\n" . [ $SymbolForNotification "alarm-clock" ] . \ + "This message was queued since " . [ /system/clock/get date ] . " " . \ + [ /system/clock/get time ] . " and may be obsolete."); + :set ($NtfyQueue->[ :len $NtfyQueue ]) { url=$Url; headers=$Headers; text=$Text }; + :if ([ :len [ /system/scheduler/find where name="\$FlushNtfyQueue" ] ] = 0) do={ + /system/scheduler/add name="\$FlushNtfyQueue" interval=1m start-time=startup \ + on-event=(":global FlushNtfyQueue; \$FlushNtfyQueue;"); + } + } +} + +# purge the Ntfy queue +:set PurgeNtfyQueue do={ + :global NtfyQueue; + + /system/scheduler/remove [ find where name="\$FlushNtfyQueue" ]; + :set NtfyQueue; +} + +# send notification via ntfy - expects at least two string arguments +:set SendNtfy do={ + :global SendNtfy2; + + $SendNtfy2 ({ subject=$1; message=$2; link=$3; silent=$4 }); +} + +# send notification via ntfy - expects one array argument +:set SendNtfy2 do={ + :local Notification $1; + + :global NotificationFunctions; + + ($NotificationFunctions->"ntfy") ("\$NotificationFunctions->\"ntfy\"") $Notification; +} diff --git a/news-and-changes.rsc b/news-and-changes.rsc index debd756..29c8bd6 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -22,6 +22,7 @@ 106="Modified 'telegram-chat' to make it act on message replies, without activation. Also made it answer a single question mark with a short notice."; 107="Dropped support for non-fixed width font in Telegram notifications."; 108="Enhanced 'log-forward' to list log messages with colorful bullets to indicate severity."; + 109="Added support to send notifications via Ntfy (ntfy.sh)."; }; # Migration steps to be applied on script updates From d3992c13a08d7dec8529dbca888e92699eaba931 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Oct 2023 14:54:20 +0200 Subject: [PATCH 1661/2612] mod/notification-ntfy: check for root certificate availability ... at least with default server. --- mod/notification-ntfy.rsc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index a94e1be..e2fc558 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -63,6 +63,7 @@ :global NtfyTopic; :global NtfyTopicOverride; + :global CertificateAvailable; :global EitherOr; :global IfThenElse; :global LogPrintExit2; @@ -85,6 +86,11 @@ } :do { + :if ($NtfyServer = "ntfy.sh") do={ + :if ([ $CertificateAvailable "R3" ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; + } + } /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ $Url http-header-field=$Headers http-data=$Text as-value; } on-error={ From cfc8c4f1eac5c17346ea307a806c4a26f0b0a7f6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Oct 2023 07:22:43 +0200 Subject: [PATCH 1662/2612] global-functions: $SymbolForNotification: support fallback without symbols --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 2433e57..e4bbb7d 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1255,7 +1255,7 @@ :global SymbolByUnicodeName; :if ($NotificationsWithSymbols != true) do={ - :return ""; + :return [ :tostr $2 ]; } :local Return ""; :foreach Symbol in=[ :toarray $1 ] do={ From c0a734fa217a9b94c6cba6071aed2d57fd886c75 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Oct 2023 07:27:05 +0200 Subject: [PATCH 1663/2612] global-functions: $ScriptInstallUpdate: use pushpin as bullet --- global-functions.rsc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index e4bbb7d..896d6ce 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -842,7 +842,6 @@ :global Identity; :global IDonate; :global NoNewsAndChangesNotification; - :global NotificationsWithSymbols; :global ScriptUpdatesBaseUrl; :global ScriptUpdatesFetch; :global ScriptUpdatesUrlSuffix; @@ -1038,7 +1037,7 @@ :for I from=($ExpectedConfigVersionBefore + 1) to=$ExpectedConfigVersion do={ :local Change ($GlobalConfigChanges->[ :tostr $I ]); :set NotificationMessage ($NotificationMessage . "\n " . \ - [ $IfThenElse ($NotificationsWithSymbols = true) ("\E2\97\8F") "*" ] . " " . $Change); + [ $SymbolForNotification "pushpin" "* " ] . $Change); $LogPrintExit2 info $0 ("Change " . $I . ": " . $Change) false; } } else={ From 7a1ffb659cd2fc39900fd3b466a237bec82b4739 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Oct 2023 17:26:52 +0200 Subject: [PATCH 1664/2612] global-functions: $ScriptInstallUpdate: rename variable --- global-functions.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 896d6ce..d9a040e 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -894,13 +894,13 @@ } :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ - :local Comment [ $ParseKeyValueStore ($ScriptVal->"comment") ]; - :if (!($Comment->"ignore" = true)) do={ + :local ScriptInfo [ $ParseKeyValueStore ($ScriptVal->"comment") ]; + :if (!($ScriptInfo->"ignore" = true)) do={ :do { :local BaseUrl $ScriptUpdatesBaseUrl; :local UrlSuffix $ScriptUpdatesUrlSuffix; - :if ([ :typeof ($Comment->"base-url") ] = "str") do={ :set BaseUrl ($Comment->"base-url"); } - :if ([ :typeof ($Comment->"url-suffix") ] = "str") do={ :set UrlSuffix ($Comment->"url-suffix"); } + :if ([ :typeof ($ScriptInfo->"base-url") ] = "str") do={ :set BaseUrl ($ScriptInfo->"base-url"); } + :if ([ :typeof ($ScriptInfo->"url-suffix") ] = "str") do={ :set UrlSuffix ($ScriptInfo->"url-suffix"); } :local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix); $LogPrintExit2 debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url) false; From 382f92856883ad66b483dd3fef9dfc95b69fbcac Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Oct 2023 17:27:52 +0200 Subject: [PATCH 1665/2612] global-functions: $ScriptInstallUpdate: drop support for scripts from storage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nobody ever used that, no? (Well, except me - just before I implemented fetching. 😜) --- global-config.rsc | 3 +-- global-functions.rsc | 12 ++---------- news-and-changes.rsc | 1 + 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/global-config.rsc b/global-config.rsc index 5d39c86..0c0a7b9 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -202,8 +202,7 @@ # This is the address used to send gps data to. :global GpsTrackUrl "https://example.com/index.php"; -# Enable this to fetch scripts from given url. -:global ScriptUpdatesFetch true; +# This is the base url to fetch scripts from. :global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/"; # alternative urls - main: stable code - next: currently in development #:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/main/"; diff --git a/global-functions.rsc b/global-functions.rsc index d9a040e..c6aee1f 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 109; +:global ExpectedConfigVersion 110; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -843,7 +843,6 @@ :global IDonate; :global NoNewsAndChangesNotification; :global ScriptUpdatesBaseUrl; - :global ScriptUpdatesFetch; :global ScriptUpdatesUrlSuffix; :global CertificateAvailable; @@ -878,12 +877,8 @@ :foreach Script in=[ /system/script/find where source~"^#!rsc by RouterOS\r?\n" ] do={ :local ScriptVal [ /system/script/get $Script ]; - :local ScriptFile [ /file/find where name=("script-updates/" . $ScriptVal->"name") . ".rsc" ]; + :local ScriptInfo [ $ParseKeyValueStore ($ScriptVal->"comment") ]; :local SourceNew; - :if ([ :len $ScriptFile ] > 0) do={ - :set SourceNew [ /file/get $ScriptFile contents ]; - /file/remove $ScriptFile; - } :foreach Scheduler in=[ /system/scheduler/find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ :local SchedulerVal [ /system/scheduler/get $Scheduler ]; @@ -893,8 +888,6 @@ } } - :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ - :local ScriptInfo [ $ParseKeyValueStore ($ScriptVal->"comment") ]; :if (!($ScriptInfo->"ignore" = true)) do={ :do { :local BaseUrl $ScriptUpdatesBaseUrl; @@ -919,7 +912,6 @@ } } } - } :if ([ :len $SourceNew ] > 0) do={ :if ($SourceNew != $ScriptVal->"source") do={ diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 29c8bd6..e16f074 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -23,6 +23,7 @@ 107="Dropped support for non-fixed width font in Telegram notifications."; 108="Enhanced 'log-forward' to list log messages with colorful bullets to indicate severity."; 109="Added support to send notifications via Ntfy (ntfy.sh)."; + 110="Dropped support for loading scripts from local storage."; }; # Migration steps to be applied on script updates From 2ab3468700e35f4171bb541be571d3a0c58dd509 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Oct 2023 17:29:25 +0200 Subject: [PATCH 1666/2612] global-functions: $ScriptInstallUpdate: restore indention No functional change. --- global-functions.rsc | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index c6aee1f..4a8980a 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -888,30 +888,29 @@ } } - :if (!($ScriptInfo->"ignore" = true)) do={ - :do { - :local BaseUrl $ScriptUpdatesBaseUrl; - :local UrlSuffix $ScriptUpdatesUrlSuffix; - :if ([ :typeof ($ScriptInfo->"base-url") ] = "str") do={ :set BaseUrl ($ScriptInfo->"base-url"); } - :if ([ :typeof ($ScriptInfo->"url-suffix") ] = "str") do={ :set UrlSuffix ($ScriptInfo->"url-suffix"); } - :local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix); - - $LogPrintExit2 debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url) false; - :local Result [ /tool/fetch check-certificate=yes-without-crl \ - http-header-field=({ $FetchUserAgent }) $Url output=user as-value ]; - :if ($Result->"status" = "finished") do={ - :set SourceNew ($Result->"data"); - } - } on-error={ - :if ($ScriptVal->"source" = "#!rsc by RouterOS\n") do={ - $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . \ - "', removing dummy. Typo on installation?") false; - /system/script/remove $Script; - } else={ - $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!") false; - } + :if (!($ScriptInfo->"ignore" = true)) do={ + :do { + :local BaseUrl $ScriptUpdatesBaseUrl; + :local UrlSuffix $ScriptUpdatesUrlSuffix; + :if ([ :typeof ($ScriptInfo->"base-url") ] = "str") do={ :set BaseUrl ($ScriptInfo->"base-url"); } + :if ([ :typeof ($ScriptInfo->"url-suffix") ] = "str") do={ :set UrlSuffix ($ScriptInfo->"url-suffix"); } + :local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix); + $LogPrintExit2 debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url) false; + :local Result [ /tool/fetch check-certificate=yes-without-crl \ + http-header-field=({ $FetchUserAgent }) $Url output=user as-value ]; + :if ($Result->"status" = "finished") do={ + :set SourceNew ($Result->"data"); + } + } on-error={ + :if ($ScriptVal->"source" = "#!rsc by RouterOS\n") do={ + $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . \ + "', removing dummy. Typo on installation?") false; + /system/script/remove $Script; + } else={ + $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!") false; } } + } :if ([ :len $SourceNew ] > 0) do={ :if ($SourceNew != $ScriptVal->"source") do={ From 286e3d9cf907984a6e9886eda40dc7958845b93d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Oct 2023 17:35:30 +0200 Subject: [PATCH 1667/2612] global-functions: $ScriptInstallUpdate: use $EitherOr --- global-functions.rsc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 4a8980a..878e95e 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -890,10 +890,8 @@ :if (!($ScriptInfo->"ignore" = true)) do={ :do { - :local BaseUrl $ScriptUpdatesBaseUrl; - :local UrlSuffix $ScriptUpdatesUrlSuffix; - :if ([ :typeof ($ScriptInfo->"base-url") ] = "str") do={ :set BaseUrl ($ScriptInfo->"base-url"); } - :if ([ :typeof ($ScriptInfo->"url-suffix") ] = "str") do={ :set UrlSuffix ($ScriptInfo->"url-suffix"); } + :local BaseUrl [ $EitherOr ($ScriptInfo->"base-url") $ScriptUpdatesBaseUrl ]; + :local UrlSuffix [ $EitherOr ($ScriptInfo->"url-suffix") $ScriptUpdatesUrlSuffix ]; :local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix); $LogPrintExit2 debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url) false; :local Result [ /tool/fetch check-certificate=yes-without-crl \ From 0e83d2e317288442de06e6aea16aaaf0f7654f08 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 Oct 2023 21:15:05 +0200 Subject: [PATCH 1668/2612] daily-psk: use named array --- daily-psk.capsman.rsc | 13 ++++--------- daily-psk.local.rsc | 13 ++++--------- daily-psk.template.rsc | 13 ++++--------- daily-psk.wifiwave2.rsc | 13 ++++--------- 4 files changed, 16 insertions(+), 36 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index 0b5e666..b228d86 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -66,15 +66,9 @@ $WaitFullyConnected; /caps-man/access-list/set $AccList private-passphrase=$NewPsk; :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ - :foreach SeenSsid in=$Seen do={ - :if ($SeenSsid = $Ssid) do={ - $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; - :set Skip 1; - } - } - - :if ($Skip = 0) do={ - :set Seen ($Seen, $Ssid); + :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; \ @@ -84,6 +78,7 @@ $WaitFullyConnected; [ $FormatLine "PSK" $NewPsk ] . "\n" . \ [ $FormatLine "Date" $Date ] . "\n\n" . \ "A client device specific rule must not exist!"); link=$Link }); + :set ($Seen->$Ssid) 1; } } } diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index df6d962..523e026 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -65,15 +65,9 @@ $WaitFullyConnected; /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ - :foreach SeenSsid in=$Seen do={ - :if ($SeenSsid = $Ssid) do={ - $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; - :set Skip 1; - } - } - - :if ($Skip = 0) do={ - :set Seen ($Seen, $Ssid); + :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; \ @@ -83,6 +77,7 @@ $WaitFullyConnected; [ $FormatLine "PSK" $NewPsk ] . "\n" . \ [ $FormatLine "Date" $Date ] . "\n\n" . \ "A client device specific rule must not exist!"); link=$Link }); + :set ($Seen->$Ssid) 1; } } } diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 125e6c5..ad9198a 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -81,15 +81,9 @@ $WaitFullyConnected; :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ :if ([ :len [ /interface/wifiwave2/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ - :foreach SeenSsid in=$Seen do={ - :if ($SeenSsid = $Ssid) do={ - $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; - :set Skip 1; - } - } - - :if ($Skip = 0) do={ - :set Seen ($Seen, $Ssid); + :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; \ @@ -99,6 +93,7 @@ $WaitFullyConnected; [ $FormatLine "PSK" $NewPsk ] . "\n" . \ [ $FormatLine "Date" $Date ] . "\n\n" . \ "A client device specific rule must not exist!"); link=$Link }); + :set ($Seen->$Ssid) 1; } } } diff --git a/daily-psk.wifiwave2.rsc b/daily-psk.wifiwave2.rsc index 40c79cd..1be000d 100644 --- a/daily-psk.wifiwave2.rsc +++ b/daily-psk.wifiwave2.rsc @@ -66,15 +66,9 @@ $WaitFullyConnected; /interface/wifiwave2/access-list/set $AccList passphrase=$NewPsk; :if ([ :len [ /interface/wifiwave2/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ - :foreach SeenSsid in=$Seen do={ - :if ($SeenSsid = $Ssid) do={ - $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; - :set Skip 1; - } - } - - :if ($Skip = 0) do={ - :set Seen ($Seen, $Ssid); + :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; \ @@ -84,6 +78,7 @@ $WaitFullyConnected; [ $FormatLine "PSK" $NewPsk ] . "\n" . \ [ $FormatLine "Date" $Date ] . "\n\n" . \ "A client device specific rule must not exist!"); link=$Link }); + :set ($Seen->$Ssid) 1; } } } From 8bfbc9dd7edb6792da9397b0b056d40060da9bbc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 Oct 2023 21:40:56 +0200 Subject: [PATCH 1669/2612] accesslist-duplicates: use named array --- accesslist-duplicates.capsman.rsc | 22 ++++++++------------- accesslist-duplicates.local.rsc | 22 ++++++++------------- accesslist-duplicates.template.rsc | 30 ++++++++++++----------------- accesslist-duplicates.wifiwave2.rsc | 22 ++++++++------------- 4 files changed, 36 insertions(+), 60 deletions(-) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index 8831cc6..b5a7347 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -20,22 +20,16 @@ :foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Mac [ /caps-man/access-list/get $AccList mac-address ]; :foreach SeenMac in=$Seen do={ - :if ($SeenMac = $Mac) do={ - :local Skip 0; - :foreach ShownMac in=$Shown do={ - :if ($ShownMac = $Mac) do={ :set Skip 1; } - } - :if ($Skip = 0) do={ - /caps-man/access-list/print where mac-address=$Mac; - :set Shown ($Shown, $Mac); + :if ($SeenMac = $Mac && $Shown->$Mac != 1) do={ + /caps-man/access-list/print where mac-address=$Mac; - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /caps-man/access-list/remove $Remove; - } + :put "\nNumeric id to remove, any key to skip!"; + :local Remove [ :tonum [ $Read ] ]; + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /caps-man/access-list/remove $Remove; } + :set ($Shown->$Mac) 1; } } :set Seen ($Seen, $Mac); diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index d4b8867..e90a002 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -20,22 +20,16 @@ :foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; :foreach SeenMac in=$Seen do={ - :if ($SeenMac = $Mac) do={ - :local Skip 0; - :foreach ShownMac in=$Shown do={ - :if ($ShownMac = $Mac) do={ :set Skip 1; } - } - :if ($Skip = 0) do={ - /interface/wireless/access-list/print where mac-address=$Mac; - :set Shown ($Shown, $Mac); + :if ($SeenMac = $Mac && $Shown->$Mac != 1) do={ + /interface/wireless/access-list/print where mac-address=$Mac; - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /interface/wireless/access-list/remove $Remove; - } + :put "\nNumeric id to remove, any key to skip!"; + :local Remove [ :tonum [ $Read ] ]; + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /interface/wireless/access-list/remove $Remove; } + :set ($Shown->$Mac) 1; } } :set Seen ($Seen, $Mac); diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index 85d444e..0bacd0d 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -25,26 +25,20 @@ :local Mac [ /interface/wifiwave2/access-list/get $AccList mac-address ]; :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; :foreach SeenMac in=$Seen do={ - :if ($SeenMac = $Mac) do={ - :local Skip 0; - :foreach ShownMac in=$Shown do={ - :if ($ShownMac = $Mac) do={ :set Skip 1; } - } - :if ($Skip = 0) do={ - /caps-man/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; - :set Shown ($Shown, $Mac); + :if ($SeenMac = $Mac && $Shown->$Mac != 1) do={ + /caps-man/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; - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /caps-man/access-list/remove $Remove; - /interface/wifiwave2/access-list/remove $Remove; - /interface/wireless/access-list/remove $Remove; - } + :put "\nNumeric id to remove, any key to skip!"; + :local Remove [ :tonum [ $Read ] ]; + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /caps-man/access-list/remove $Remove; + /interface/wifiwave2/access-list/remove $Remove; + /interface/wireless/access-list/remove $Remove; } + :set ($Shown->$Mac) 1; } } :set Seen ($Seen, $Mac); diff --git a/accesslist-duplicates.wifiwave2.rsc b/accesslist-duplicates.wifiwave2.rsc index 7c0ecf4..7d34b2a 100644 --- a/accesslist-duplicates.wifiwave2.rsc +++ b/accesslist-duplicates.wifiwave2.rsc @@ -20,22 +20,16 @@ :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 ]; :foreach SeenMac in=$Seen do={ - :if ($SeenMac = $Mac) do={ - :local Skip 0; - :foreach ShownMac in=$Shown do={ - :if ($ShownMac = $Mac) do={ :set Skip 1; } - } - :if ($Skip = 0) do={ - /interface/wifiwave2/access-list/print where mac-address=$Mac; - :set Shown ($Shown, $Mac); + :if ($SeenMac = $Mac && $Shown->$Mac != 1) do={ + /interface/wifiwave2/access-list/print where mac-address=$Mac; - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /interface/wifiwave2/access-list/remove $Remove; - } + :put "\nNumeric id to remove, any key to skip!"; + :local Remove [ :tonum [ $Read ] ]; + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /interface/wifiwave2/access-list/remove $Remove; } + :set ($Shown->$Mac) 1; } } :set Seen ($Seen, $Mac); From 00e8766ce357126939d7441da8fba9c6ca25984b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 Oct 2023 21:46:10 +0200 Subject: [PATCH 1670/2612] accesslist-duplicates: use another named array --- accesslist-duplicates.capsman.rsc | 21 +++++++++------------ accesslist-duplicates.local.rsc | 21 +++++++++------------ accesslist-duplicates.template.rsc | 29 +++++++++++++---------------- accesslist-duplicates.wifiwave2.rsc | 21 +++++++++------------ 4 files changed, 40 insertions(+), 52 deletions(-) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index b5a7347..b09ef6a 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -19,18 +19,15 @@ :foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Mac [ /caps-man/access-list/get $AccList mac-address ]; - :foreach SeenMac in=$Seen do={ - :if ($SeenMac = $Mac && $Shown->$Mac != 1) do={ - /caps-man/access-list/print where mac-address=$Mac; - - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /caps-man/access-list/remove $Remove; - } - :set ($Shown->$Mac) 1; + :if ($Seen->$Mac = 1 && $Shown->$Mac != 1) do={ + /caps-man/access-list/print where mac-address=$Mac; + :put "\nNumeric id to remove, any key to skip!"; + :local Remove [ :tonum [ $Read ] ]; + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /caps-man/access-list/remove $Remove; } + :set ($Shown->$Mac) 1; } - :set Seen ($Seen, $Mac); + :set ($Seen->$Mac) 1; } diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index e90a002..bffee5a 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -19,18 +19,15 @@ :foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; - :foreach SeenMac in=$Seen do={ - :if ($SeenMac = $Mac && $Shown->$Mac != 1) do={ - /interface/wireless/access-list/print where mac-address=$Mac; - - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /interface/wireless/access-list/remove $Remove; - } - :set ($Shown->$Mac) 1; + :if ($Seen->$Mac = 1 && $Shown->$Mac != 1) do={ + /interface/wireless/access-list/print where mac-address=$Mac; + :put "\nNumeric id to remove, any key to skip!"; + :local Remove [ :tonum [ $Read ] ]; + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /interface/wireless/access-list/remove $Remove; } + :set ($Shown->$Mac) 1; } - :set Seen ($Seen, $Mac); + :set ($Seen->$Mac) 1; } diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index 0bacd0d..28c851c 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -24,22 +24,19 @@ :local Mac [ /caps-man/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 ]; - :foreach SeenMac in=$Seen do={ - :if ($SeenMac = $Mac && $Shown->$Mac != 1) do={ - /caps-man/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; - - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /caps-man/access-list/remove $Remove; - /interface/wifiwave2/access-list/remove $Remove; - /interface/wireless/access-list/remove $Remove; - } - :set ($Shown->$Mac) 1; + :if ($Seen->$Mac = 1 && $Shown->$Mac != 1) do={ + /caps-man/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; + :put "\nNumeric id to remove, any key to skip!"; + :local Remove [ :tonum [ $Read ] ]; + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /caps-man/access-list/remove $Remove; + /interface/wifiwave2/access-list/remove $Remove; + /interface/wireless/access-list/remove $Remove; } + :set ($Shown->$Mac) 1; } - :set Seen ($Seen, $Mac); + :set ($Seen->$Mac) 1; } diff --git a/accesslist-duplicates.wifiwave2.rsc b/accesslist-duplicates.wifiwave2.rsc index 7d34b2a..6897a51 100644 --- a/accesslist-duplicates.wifiwave2.rsc +++ b/accesslist-duplicates.wifiwave2.rsc @@ -19,18 +19,15 @@ :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 ]; - :foreach SeenMac in=$Seen do={ - :if ($SeenMac = $Mac && $Shown->$Mac != 1) do={ - /interface/wifiwave2/access-list/print where mac-address=$Mac; - - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /interface/wifiwave2/access-list/remove $Remove; - } - :set ($Shown->$Mac) 1; + :if ($Seen->$Mac = 1 && $Shown->$Mac != 1) do={ + /interface/wifiwave2/access-list/print where mac-address=$Mac; + :put "\nNumeric id to remove, any key to skip!"; + :local Remove [ :tonum [ $Read ] ]; + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /interface/wifiwave2/access-list/remove $Remove; } + :set ($Shown->$Mac) 1; } - :set Seen ($Seen, $Mac); + :set ($Seen->$Mac) 1; } From ab44377fb6d01a2b7ccfab71ebf68b9306bc4df7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 17 Oct 2023 00:01:38 +0200 Subject: [PATCH 1671/2612] accesslist-duplicates: remove extra check Why did we have that? Possibly for performance? Well, should not be a problem now. --- accesslist-duplicates.capsman.rsc | 4 +--- accesslist-duplicates.local.rsc | 4 +--- accesslist-duplicates.template.rsc | 4 +--- accesslist-duplicates.wifiwave2.rsc | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index b09ef6a..b986862 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -15,11 +15,10 @@ :global Read; :local Seen ({}); -:local Shown ({}); :foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Mac [ /caps-man/access-list/get $AccList mac-address ]; - :if ($Seen->$Mac = 1 && $Shown->$Mac != 1) do={ + :if ($Seen->$Mac = 1) do={ /caps-man/access-list/print where mac-address=$Mac; :put "\nNumeric id to remove, any key to skip!"; :local Remove [ :tonum [ $Read ] ]; @@ -27,7 +26,6 @@ :put ("Removing numeric id " . $Remove . "...\n"); /caps-man/access-list/remove $Remove; } - :set ($Shown->$Mac) 1; } :set ($Seen->$Mac) 1; } diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index bffee5a..b136de3 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -15,11 +15,10 @@ :global Read; :local Seen ({}); -:local Shown ({}); :foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; - :if ($Seen->$Mac = 1 && $Shown->$Mac != 1) do={ + :if ($Seen->$Mac = 1) do={ /interface/wireless/access-list/print where mac-address=$Mac; :put "\nNumeric id to remove, any key to skip!"; :local Remove [ :tonum [ $Read ] ]; @@ -27,7 +26,6 @@ :put ("Removing numeric id " . $Remove . "...\n"); /interface/wireless/access-list/remove $Remove; } - :set ($Shown->$Mac) 1; } :set ($Seen->$Mac) 1; } diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index 28c851c..1e5fc80 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -16,7 +16,6 @@ :global Read; :local Seen ({}); -:local Shown ({}); :foreach AccList in=[ /caps-man/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={ @@ -24,7 +23,7 @@ :local Mac [ /caps-man/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 && $Shown->$Mac != 1) do={ + :if ($Seen->$Mac = 1) do={ /caps-man/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; @@ -36,7 +35,6 @@ /interface/wifiwave2/access-list/remove $Remove; /interface/wireless/access-list/remove $Remove; } - :set ($Shown->$Mac) 1; } :set ($Seen->$Mac) 1; } diff --git a/accesslist-duplicates.wifiwave2.rsc b/accesslist-duplicates.wifiwave2.rsc index 6897a51..4297898 100644 --- a/accesslist-duplicates.wifiwave2.rsc +++ b/accesslist-duplicates.wifiwave2.rsc @@ -15,11 +15,10 @@ :global Read; :local Seen ({}); -:local Shown ({}); :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 && $Shown->$Mac != 1) do={ + :if ($Seen->$Mac = 1) do={ /interface/wifiwave2/access-list/print where mac-address=$Mac; :put "\nNumeric id to remove, any key to skip!"; :local Remove [ :tonum [ $Read ] ]; @@ -27,7 +26,6 @@ :put ("Removing numeric id " . $Remove . "...\n"); /interface/wifiwave2/access-list/remove $Remove; } - :set ($Shown->$Mac) 1; } :set ($Seen->$Mac) 1; } From fffe0a3b502fa43c3b836264bd1a7ca63f5b8aaa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 17 Oct 2023 21:22:51 +0200 Subject: [PATCH 1672/2612] telegram-chat: retry on fetch failure... ... and exit with a warning. --- telegram-chat.rsc | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index c17394a..7486276 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -47,13 +47,22 @@ $WaitFullyConnected; $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; } -:local Data; -:do { - :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ - ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=" . \ - $TelegramChatOffset->0 . "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); -} on-error={ - $LogPrintExit2 debug $0 ("Failed getting updates from Telegram.") true; +:local Data false; +:for I from=2 to=0 do={ + :if ($Data = false) do={ + :do { + :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ + ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=" . \ + $TelegramChatOffset->0 . "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); + } on-error={ + $LogPrintExit2 debug $0 ("Fetch failed, " . $I . " retries pending.") false; + :delay 2s; + } + } +} + +:if ($Data = false) do={ + $LogPrintExit2 warning $0 ("Failed getting updates from Telegram.") true; } :local UpdateID 0; From 9138c17f8c3bbd415a0defe6ada431075a7c8f04 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 18 Oct 2023 18:25:33 +0200 Subject: [PATCH 1673/2612] =?UTF-8?q?global-functions:=20$ParseJson:=20ret?= =?UTF-8?q?urn=20array=20as=20...=20array=20=F0=9F=98=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to assemble the string here, just to split it again later. --- global-functions.rsc | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 878e95e..443771d 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -719,26 +719,33 @@ :local Val1 ($Input->($I + 1)); :local Val2 ($Input->($I + 2)); :if ($Val1 = ":") do={ - :set ($Return->$Key) $Val2; :set Skip 2; + :set ($Return->$Key) $Val2; :set Done true; } :if ($Done = false && $Val1 = ":[") do={ - :local Tmp ""; - :local End; + :local Last false; :set Skip 1; + :set ($Return->$Key) ({}); :do { :set Skip ($Skip + 1); :local ValX ($Input->($I + $Skip)); - :set End [ :pick $ValX ([ :len $ValX ] - 1) ]; - :set Tmp ($Tmp . "},{" . $ValX); - } while=($End != "]"); - :set ($Return->$Key) ("{" . [ :pick $Tmp 0 ([ :len $Tmp ] - 1) ] . "}"); + :if ([ :pick $ValX ([ :len $ValX ] - 1) ] = "]") do={ + :set Last true; + :set ValX [ :pick $ValX 0 ([ :len $ValX ] - 1) ]; + } + :set ($Return->$Key) (($Return->$Key), $ValX); + } while=($Last = false); + :set Done true; + } + :if ($Done = false && $Val1 = ":[]") do={ + :set Skip 1; + :set ($Return->$Key) ({}); :set Done true; } :if ($Done = false) do={ - :set ($Return->$Key) [ :pick $Val1 1 [ :len $Val1 ] ]; :set Skip 1; + :set ($Return->$Key) [ :pick $Val1 1 [ :len $Val1 ] ]; } } } From 4c365c131d28b0eb45ee72b12ef10c846b535e79 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 18 Oct 2023 18:26:22 +0200 Subject: [PATCH 1674/2612] telegram-chat: drop extra conversion --- telegram-chat.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 7486276..197cbf4 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -67,7 +67,7 @@ $WaitFullyConnected; :local UpdateID 0; :local Uptime [ /system/resource/get uptime ]; -:foreach UpdateArray in=[ :toarray ([ $ParseJson $Data ]->"result") ] do={ +:foreach UpdateArray in=([ $ParseJson $Data ]->"result") do={ :local Update [ $ParseJson $UpdateArray ]; :set UpdateID ($Update->"update_id"); :local Message [ $ParseJson ($Update->"message") ]; From b81f3850ae85d6443bfffee75ecd00588447def1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 19 Oct 2023 09:19:34 +0200 Subject: [PATCH 1675/2612] telegram-chat: log when sending notice --- telegram-chat.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 197cbf4..e0a6295 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -87,6 +87,7 @@ $WaitFullyConnected; :if ($Trusted = true) do={ :local Done false; :if ($Message->"text" = "?") do={ + $LogPrintExit2 info $0 ("Sending notice for update " . $UpdateID . ".") false; $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Online, awaiting your commands!") }); From 92b4af7b90d291466433fbb0173e8b93e6459655 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 19 Oct 2023 12:36:19 +0200 Subject: [PATCH 1676/2612] log-forward: keep the warning in subject for higher severity --- log-forward.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/log-forward.rsc b/log-forward.rsc index e847256..6cf61a9 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -61,6 +61,7 @@ $ScriptLock $0; :set Bullet "large-orange-circle"; } :if ($MessageVal->"topics" ~ "(emergency|alert|critical|error)") do={ + :set Warning true; :set Bullet "large-red-circle"; } :if ($DupCount < 3) do={ From 1f6040178fa14fafb1561c97a7f5aff9449c1ba6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 19 Oct 2023 21:13:04 +0200 Subject: [PATCH 1677/2612] telegram-chat: rework the retry logic ... with increasing delay. --- telegram-chat.rsc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index e0a6295..686becc 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -48,15 +48,17 @@ $WaitFullyConnected; } :local Data false; -:for I from=2 to=0 do={ +:for I from=1 to=4 do={ :if ($Data = false) do={ :do { :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=" . \ $TelegramChatOffset->0 . "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); } on-error={ - $LogPrintExit2 debug $0 ("Fetch failed, " . $I . " retries pending.") false; - :delay 2s; + :if ($I < 4) do={ + $LogPrintExit2 debug $0 ("Fetch failed, " . $I . ". try.") false; + :delay (($I * $I) "s"); + } } } } From d4e5194a65b5a40ce458382d28b8af45086b80f7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 19 Oct 2023 21:15:23 +0200 Subject: [PATCH 1678/2612] fw-addr-lists: rework the retry logic ... with increasing delay. --- fw-addr-lists.rsc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 38fdd96..26e9f98 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -50,13 +50,16 @@ $WaitFullyConnected; } } - :for I from=2 to=0 do={ + :for I from=1 to=4 do={ :if ($Data = false) do={ :do { - :set Data ([ /tool/fetch ($List->"url") check-certificate=$CheckCertificate output=user as-value ]->"data"); + :set Data ([ /tool/fetch check-certificate=$CheckCertificate output=user \ + ($List->"url") as-value ]->"data"); } on-error={ - $LogPrintExit2 debug $0 ("Failed downloading, " . $I . " retries pending: " . $List->"url") false; - :delay 2s; + :if ($I < 4) do={ + $LogPrintExit2 debug $0 ("Failed downloading, " . $I . ". try: " . $List->"url") false; + :delay (($I * $I) . "s"); + } } } } From ff35f0c87f4dc9ea75b2e911d9cb397ab2c120f7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 24 Oct 2023 16:26:14 +0200 Subject: [PATCH 1679/2612] check-health: reverse logic for RAM (free -> utilization)... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... to bring it in sync with CPU utilization. Also make the output more verbose, at least for the warning. ---- âœ‚ī¸ ---- đŸ—ƒī¸đŸ“ˆī¸ Health warning: RAM utilization The RAM utilization on MikroTik is at 81%! total: 64 MiB used: 52 MiB free: 11 MiB ---- âœ‚ī¸ ---- đŸ—ƒī¸đŸ“‰ī¸ Health recovery: RAM utilization The RAM utilization on MikroTik decreased to 65%. ---- âœ‚ī¸ ---- --- check-health.rsc | 25 +++++++++--------- .../notification-03-free-ram-low.avif | Bin 6457 -> 0 bytes .../notification-03-ram-utilization-high.avif | Bin 0 -> 7527 bytes .../notification-04-free-ram-ok.avif | Bin 6772 -> 0 bytes .../notification-04-ram-utilization-ok.avif | Bin 0 -> 6637 bytes doc/check-health.md | 14 +++++----- 6 files changed, 20 insertions(+), 19 deletions(-) delete mode 100644 doc/check-health.d/notification-03-free-ram-low.avif create mode 100644 doc/check-health.d/notification-03-ram-utilization-high.avif delete mode 100644 doc/check-health.d/notification-04-free-ram-ok.avif create mode 100644 doc/check-health.d/notification-04-ram-utilization-ok.avif diff --git a/check-health.rsc b/check-health.rsc index af0d70b..3ada4c8 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -12,8 +12,8 @@ :global CheckHealthCPUUtilization; :global CheckHealthCPUUtilizationNotified; -:global CheckHealthFreeRAMNotified; :global CheckHealthLast; +:global CheckHealthRAMUtilizationNotified; :global CheckHealthTemperature; :global CheckHealthTemperatureDeviation; :global CheckHealthTemperatureNotified; @@ -52,20 +52,21 @@ $ScriptLock $0; :set CheckHealthCPUUtilizationNotified false; } -:local CheckHealthFreeRAM ($Resource->"free-memory" * 100 / $Resource->"total-memory"); -:if ($CheckHealthFreeRAM < 20 && $CheckHealthFreeRAMNotified != true) do={ +:local CheckHealthRAMUtilization (($Resource->"total-memory" - $Resource->"free-memory") * 100 / $Resource->"total-memory"); +:if ($CheckHealthRAMUtilization >=80 && $CheckHealthRAMUtilizationNotified != true) do={ $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "card-file-box,chart-decreasing" ] . "Health warning: free RAM"); \ - message=("The available free RAM on " . $Identity . " is at " . $CheckHealthFreeRAM . "% (" . \ - ($Resource->"free-memory" / 1024 / 1024) . "MiB)!") }); - :set CheckHealthFreeRAMNotified true; + subject=([ $SymbolForNotification "card-file-box,chart-increasing" ] . "Health warning: RAM utilization"); \ + message=("The RAM utilization on " . $Identity . " is at " . $CheckHealthRAMUtilization . "%!\n\n" . \ + [ $FormatLine "total" (($Resource->"total-memory" / 1024 / 1024) . " MiB") ] . "\n" . \ + [ $FormatLine "used" ((($Resource->"total-memory" - $Resource->"free-memory") / 1024 / 1024) . " MiB") ] . "\n" . \ + [ $FormatLine "free" (($Resource->"free-memory" / 1024 / 1024) . " MiB") ]) }); + :set CheckHealthRAMUtilizationNotified true; } -:if ($CheckHealthFreeRAM > 30 && $CheckHealthFreeRAMNotified = true) do={ +:if ($CheckHealthRAMUtilization < 70 && $CheckHealthRAMUtilizationNotified = true) do={ $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "card-file-box,chart-increasing" ] . "Health recovery: free RAM"); \ - message=("The available free RAM on " . $Identity . " increased to " . $CheckHealthFreeRAM . "% (" . \ - ($Resource->"free-memory" / 1024 / 1024) . "MiB).") }); - :set CheckHealthFreeRAMNotified 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={ diff --git a/doc/check-health.d/notification-03-free-ram-low.avif b/doc/check-health.d/notification-03-free-ram-low.avif deleted file mode 100644 index effc87cdc223f99accf0969cdd04f02e5a8a4b55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6457 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 literal 0 HcmV?d00001 diff --git a/doc/check-health.d/notification-04-free-ram-ok.avif b/doc/check-health.d/notification-04-free-ram-ok.avif deleted file mode 100644 index cadb1d01373f7624cc251ccda0a66ca0428eab93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6772 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 diff --git a/doc/check-health.d/notification-04-ram-utilization-ok.avif b/doc/check-health.d/notification-04-ram-utilization-ok.avif new file mode 100644 index 0000000000000000000000000000000000000000..d995b9a198bf3de91e117781f89535c6f048f343 GIT binary patch literal 6637 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 z Date: Wed, 25 Oct 2023 08:57:39 +0200 Subject: [PATCH 1680/2612] global-functions: $ParseJson: prevent infinite loop... ... which could happen on corrupted or truncated input. --- global-functions.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 443771d..12e13fe 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -700,6 +700,7 @@ :set ParseJson do={ :local Input [ :tostr $1 ]; + :local InLen; :local Return ({}); :local Skip 0; @@ -707,8 +708,9 @@ :set Input [ :pick $Input 1 ([ :len $Input ] - 1) ]; } :set Input [ :toarray $Input ]; + :set InLen [ :len $Input ]; - :for I from=0 to=[ :len $Input ] do={ + :for I from=0 to=$InLen do={ :if ($Skip > 0 || $Input->$I = "\n" || $Input->$I = "\r\n") do={ :if ($Skip > 0) do={ :set $Skip ($Skip - 1); @@ -735,7 +737,7 @@ :set ValX [ :pick $ValX 0 ([ :len $ValX ] - 1) ]; } :set ($Return->$Key) (($Return->$Key), $ValX); - } while=($Last = false); + } while=($Last = false && $I + $Skip < $InLen); :set Done true; } :if ($Done = false && $Val1 = ":[]") do={ From 8f75c17e0be4835f216b9cb7aaf697182346f4c9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Oct 2023 11:52:50 +0200 Subject: [PATCH 1681/2612] global: switch eworm.de to new certificate chain (E1 / ISRG Root X2) old chain: R3 / ISRG Root X1 new chain: E1 / ISRG Root X2 No user interaction or migration is required for existing installations as we install 'E1' and 'ISRG Root X2' for some time already. --- INITIAL-COMMANDS.md | 12 ++-- README.d/01-download-certs.avif | Bin 2105 -> 4420 bytes README.d/02-import-certs.avif | Bin 2266 -> 3606 bytes README.d/03-check-certs.avif | Bin 4850 -> 8223 bytes README.md | 14 ++-- certs/E1.pem | 119 -------------------------------- global-config.rsc | 4 +- global-functions | 4 -- global-functions.rsc | 4 -- 9 files changed, 15 insertions(+), 142 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index a53ae0f..da951aa 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -10,13 +10,13 @@ Initial commands Run the complete base installation: { - /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem" as-value; + /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/E1.pem" dst-path="letsencrypt-E1.pem" as-value; :delay 1s; - /certificate/import file-name=letsencrypt-R3.pem passphrase=""; - :if ([ :len [ /certificate/find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ] ] != 2) do={ + /certificate/import file-name=letsencrypt-E1.pem passphrase=""; + :if ([ :len [ /certificate/find where fingerprint="46494e30379059df18be52124305e606fc59070e5b21076ce113954b60517cda" or fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470" ] ] != 2) do={ :error "Something is wrong with your certificates!"; }; - /file/remove "letsencrypt-R3.pem"; + /file/remove "letsencrypt-E1.pem"; :delay 1s; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ /system/script/add name=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . ".rsc") output=user as-value]->"data"); @@ -24,8 +24,8 @@ Run the complete base installation: /system/script { run global-config; run global-functions; }; /system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }"; :global CertificateNameByCN; - $CertificateNameByCN "R3"; - $CertificateNameByCN "ISRG Root X1"; + $CertificateNameByCN "E1"; + $CertificateNameByCN "ISRG Root X2"; }; Then continue setup with diff --git a/README.d/01-download-certs.avif b/README.d/01-download-certs.avif index 4da73fabdc93faddeca4f6dba83f23f877ac6edf..b27b23b8ca7990d261be1e4b23349de6d493f767 100644 GIT binary patch literal 4420 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 delta 1904 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 delta 2066 zcmV+t2<`Wl9NH0(A_4&Nkt9JW9%*cEV*mgE07L))0RRC200031009~R00+PT001ay zX>Mi!000000g;>?k?d)I2gq$?VRRAz3JEwR@;EjS5YTBdun$aR0^Kx2V&2}qq}ZSz z;_l=D&+&pWw~bE&Tke5W%$D8P}@0~z=St$no-d3wG)1IH&Rq8 zdj!<Wujl! z|MdGi+;8ZNeSZwLSd`6eq3C6Q|G7&IfD&WZdzVt}Rm#Ybab|KXEB-{A^l&9(3on=l zVJ=OR;J6AamKn-EH?g>l%X_$^S@n@|HBQ8ID=ZPg8$2Dlx^D{MBw#+zg2^Vjd^B_0 z!Z|CiC-{Lgui*)Qd4{tHT*INeKQO3fsRau>$_$HXO6ECBFStjGXFo6iQ2K!U?CxG2 z57LE3#-##X-v#Fr=COVXGEn@;H$1^8tv_`TjLt=Q{k4DrRcFp%eZ@QtZNJa3!7Nwf z!k>px+KK>F=dht+=MDG1b86xiX(y^RvHko%@wP+zO}J-&4Y>wwt`oXj(X9WVSYMno zYHN$%i=^FGD|D#=yzRcJ5{!tUF}n7)-dYs@QLX`WrPf-UK@_DecPVQ~4B5@ZoFP;^ zK-)#QbjkJ^vYz5pwq|fYdJvuJs{9vXG{ZM_SAYTaO^^k!%1HM1&}foYF24#_*jpoP zLxN%EbEy%3=S`7n^#1!VBjDxCSzL$#)*^1w?7WV%yvrT z1Ob7&jICU!@)|_dd5SZ+VssRP#|lU8YFkeO;tLmz0;fI~cBoA+UWK%tfU&)?DEG0%mS zgG0#+s`9edU@wRUFY?KnYGxp;6Dt+ea-uxtQ?ay0nte}gVj@m)RO42Jd!JGJblfrf zDLfUxxN`8$g=z3CwlH6ICmQOcsimXPoK(LXxElviz1I`JsB-q|eZtd^(DFpbCOGRb zWr65_v0q2S75D=Ir60um=zjA9OV01Z{_tKY& zd#3M~1_&K6SDu|t5T{T68|BQq%wSz8qbD(c8my!m5uO)V^4Xz6N-BnOy#S(TJQJDR zK7IsG;lzXO80;6F?{lG|lyh#g^uUiFrh8~k*b=)Vou1%42xh1Doh%YLMmO)i+820B z>09TFwI*s6=e)&hFGf<6BJr3Mo+Mb`S|)A%^6@UaijlE|d{1kyT-#yns=MaN3?MW)JiG$c7i9zeZZ{5Sx z+Y@nF;1P(wp2a}zg4FL zjAhxKR7`;O2y9e;<_!~e!JNQhnz1I%ng2W^cyn9G>os%)Ny=xVl~YJ)N;c=ls|GUJ z>h9Wy_tQRXZ0Il8{UEp7*{+313mPARMNk66o0vQ|JY9bT?Gr?lEQErgjPi># zRTH%>@B0R@hw&z76<2;++M7qHGO{5AG}FpL zTBo{kGVbme^TK{>y(T%%@gDFs?)2 zv7Pw>JDtyD{?TVheoB@0YE9!ZI-1pJj5+pvgi^k1At4|fh6B8;tRq5tk$s()BYZ?& zHcRc|Z3=0y#~}O-TP1w1XGt!W7`y`P$&i8e3Wc^|iz3^<#~?u#nVJc%aO?0{x=pZl z5R2Dp4r@h2C>O&1FgC}3NYl#NYft;b*N$pv7uPy{wQ1h^p*Pakf1Sv9vlpc~^j6nk zl;~i#bt$PFPsx@DImb%{76})E4l}>|I%PH^Y!qnRl;i|IPGwT(PM1PPkq|o3R`a_l zW$^_?e3#0;8Z{B!3Wv{}EnXa?{VcPi_>Ph;OCAL_qe?XZw!3+MLWDiezflP>y{k^gUqA&!#x8wF)s@$x(Msm5x^0gK(aE>yiFvai(CGjst4jjvDzf0wnbby7;NAPOAZH02lrTcliUabV=vCY5AhFC>f(80rQCHU zv%(OJ-*r$Eo8eDYojzMOGwJ+gtVHH`&Q5 ws~h4Rdo@JoahQv`Rphn}EX{hm&s3gPpTdV$cu>VTyjsO4v diff --git a/README.d/03-check-certs.avif b/README.d/03-check-certs.avif index adf1161c9646f9f4575624e675abf927a9b4da13..3c7def2746b23206a3f47a6b1bc0d927c43e3258 100644 GIT binary patch literal 8223 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 H)B+eyPq_~% diff --git a/README.md b/README.md index ec771f7..cadd9a0 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ download the certificates. If you intend to download the scripts from a different location (for example from github.com) install the corresponding certificate chain. - /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem"; + /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/E1.pem" dst-path="letsencrypt-E1.pem"; ![screenshot: download certs](README.d/01-download-certs.avif) @@ -67,21 +67,21 @@ Note that the commands above do *not* verify server certificate, so if you want to be safe download with your workstations's browser and transfer the files to your MikroTik device. -* [ISRG Root X1](https://letsencrypt.org/certs/isrgrootx1.pem) -* Let's Encrypt [R3](https://letsencrypt.org/certs/lets-encrypt-r3.pem) +* [ISRG Root X2](https://letsencrypt.org/certs/isrg-root-x2.pem) +* Let's Encrypt [E1](https://letsencrypt.org/certs/lets-encrypt-e1.pem) Then we import the certificates. - /certificate/import file-name=letsencrypt-R3.pem passphrase=""; + /certificate/import file-name=letsencrypt-E1.pem passphrase=""; ![screenshot: import certs](README.d/02-import-certs.avif) For basic verification we rename the certificates and print their count. Make sure the certificate count is **two**. - /certificate/set name="R3" [ find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" ]; - /certificate/set name="ISRG-Root-X1" [ find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ]; - /certificate/print count-only where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6"; + /certificate/set name="E1" [ find where common-name="E1" ]; + /certificate/set name="ISRG-Root-X2" [ find where common-name="ISRG Root X2" ]; + /certificate/print count-only where fingerprint="46494e30379059df18be52124305e606fc59070e5b21076ce113954b60517cda" or fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470"; ![screenshot: check certs](README.d/03-check-certs.avif) diff --git a/certs/E1.pem b/certs/E1.pem index 4c3c212..a62fc03 100644 --- a/certs/E1.pem +++ b/certs/E1.pem @@ -122,122 +122,3 @@ zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 /q4AaOeMSQ+2b1tbFfLn -----END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 82:10:cf:b0:d2:40:e3:59:44:63:e0:bb:63:82:8b:00 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 - Validity - Not Before: Jun 4 11:04:38 2015 GMT - Not After : Jun 4 11:04:38 2035 GMT - Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (4096 bit) - Modulus: - 00:ad:e8:24:73:f4:14:37:f3:9b:9e:2b:57:28:1c: - 87:be:dc:b7:df:38:90:8c:6e:3c:e6:57:a0:78:f7: - 75:c2:a2:fe:f5:6a:6e:f6:00:4f:28:db:de:68:86: - 6c:44:93:b6:b1:63:fd:14:12:6b:bf:1f:d2:ea:31: - 9b:21:7e:d1:33:3c:ba:48:f5:dd:79:df:b3:b8:ff: - 12:f1:21:9a:4b:c1:8a:86:71:69:4a:66:66:6c:8f: - 7e:3c:70:bf:ad:29:22:06:f3:e4:c0:e6:80:ae:e2: - 4b:8f:b7:99:7e:94:03:9f:d3:47:97:7c:99:48:23: - 53:e8:38:ae:4f:0a:6f:83:2e:d1:49:57:8c:80:74: - b6:da:2f:d0:38:8d:7b:03:70:21:1b:75:f2:30:3c: - fa:8f:ae:dd:da:63:ab:eb:16:4f:c2:8e:11:4b:7e: - cf:0b:e8:ff:b5:77:2e:f4:b2:7b:4a:e0:4c:12:25: - 0c:70:8d:03:29:a0:e1:53:24:ec:13:d9:ee:19:bf: - 10:b3:4a:8c:3f:89:a3:61:51:de:ac:87:07:94:f4: - 63:71:ec:2e:e2:6f:5b:98:81:e1:89:5c:34:79:6c: - 76:ef:3b:90:62:79:e6:db:a4:9a:2f:26:c5:d0:10: - e1:0e:de:d9:10:8e:16:fb:b7:f7:a8:f7:c7:e5:02: - 07:98:8f:36:08:95:e7:e2:37:96:0d:36:75:9e:fb: - 0e:72:b1:1d:9b:bc:03:f9:49:05:d8:81:dd:05:b4: - 2a:d6:41:e9:ac:01:76:95:0a:0f:d8:df:d5:bd:12: - 1f:35:2f:28:17:6c:d2:98:c1:a8:09:64:77:6e:47: - 37:ba:ce:ac:59:5e:68:9d:7f:72:d6:89:c5:06:41: - 29:3e:59:3e:dd:26:f5:24:c9:11:a7:5a:a3:4c:40: - 1f:46:a1:99:b5:a7:3a:51:6e:86:3b:9e:7d:72:a7: - 12:05:78:59:ed:3e:51:78:15:0b:03:8f:8d:d0:2f: - 05:b2:3e:7b:4a:1c:4b:73:05:12:fc:c6:ea:e0:50: - 13:7c:43:93:74:b3:ca:74:e7:8e:1f:01:08:d0:30: - d4:5b:71:36:b4:07:ba:c1:30:30:5c:48:b7:82:3b: - 98:a6:7d:60:8a:a2:a3:29:82:cc:ba:bd:83:04:1b: - a2:83:03:41:a1:d6:05:f1:1b:c2:b6:f0:a8:7c:86: - 3b:46:a8:48:2a:88:dc:76:9a:76:bf:1f:6a:a5:3d: - 19:8f:eb:38:f3:64:de:c8:2b:0d:0a:28:ff:f7:db: - e2:15:42:d4:22:d0:27:5d:e1:79:fe:18:e7:70:88: - ad:4e:e6:d9:8b:3a:c6:dd:27:51:6e:ff:bc:64:f5: - 33:43:4f - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E - Signature Algorithm: sha256WithRSAEncryption - 55:1f:58:a9:bc:b2:a8:50:d0:0c:b1:d8:1a:69:20:27:29:08: - ac:61:75:5c:8a:6e:f8:82:e5:69:2f:d5:f6:56:4b:b9:b8:73: - 10:59:d3:21:97:7e:e7:4c:71:fb:b2:d2:60:ad:39:a8:0b:ea: - 17:21:56:85:f1:50:0e:59:eb:ce:e0:59:e9:ba:c9:15:ef:86: - 9d:8f:84:80:f6:e4:e9:91:90:dc:17:9b:62:1b:45:f0:66:95: - d2:7c:6f:c2:ea:3b:ef:1f:cf:cb:d6:ae:27:f1:a9:b0:c8:ae: - fd:7d:7e:9a:fa:22:04:eb:ff:d9:7f:ea:91:2b:22:b1:17:0e: - 8f:f2:8a:34:5b:58:d8:fc:01:c9:54:b9:b8:26:cc:8a:88:33: - 89:4c:2d:84:3c:82:df:ee:96:57:05:ba:2c:bb:f7:c4:b7:c7: - 4e:3b:82:be:31:c8:22:73:73:92:d1:c2:80:a4:39:39:10:33: - 23:82:4c:3c:9f:86:b2:55:98:1d:be:29:86:8c:22:9b:9e:e2: - 6b:3b:57:3a:82:70:4d:dc:09:c7:89:cb:0a:07:4d:6c:e8:5d: - 8e:c9:ef:ce:ab:c7:bb:b5:2b:4e:45:d6:4a:d0:26:cc:e5:72: - ca:08:6a:a5:95:e3:15:a1:f7:a4:ed:c9:2c:5f:a5:fb:ff:ac: - 28:02:2e:be:d7:7b:bb:e3:71:7b:90:16:d3:07:5e:46:53:7c: - 37:07:42:8c:d3:c4:96:9c:d5:99:b5:2a:e0:95:1a:80:48:ae: - 4c:39:07:ce:cc:47:a4:52:95:2b:ba:b8:fb:ad:d2:33:53:7d: - e5:1d:4d:6d:d5:a1:b1:c7:42:6f:e6:40:27:35:5c:a3:28:b7: - 07:8d:e7:8d:33:90:e7:23:9f:fb:50:9c:79:6c:46:d5:b4:15: - b3:96:6e:7e:9b:0c:96:3a:b8:52:2d:3f:d6:5b:e1:fb:08:c2: - 84:fe:24:a8:a3:89:da:ac:6a:e1:18:2a:b1:a8:43:61:5b:d3: - 1f:dc:3b:8d:76:f2:2d:e8:8d:75:df:17:33:6c:3d:53:fb:7b: - cb:41:5f:ff:dc:a2:d0:61:38:e1:96:b8:ac:5d:8b:37:d7:75: - d5:33:c0:99:11:ae:9d:41:c1:72:75:84:be:02:41:42:5f:67: - 24:48:94:d1:9b:27:be:07:3f:b9:b8:4f:81:74:51:e1:7a:b7: - ed:9d:23:e2:be:e0:d5:28:04:13:3c:31:03:9e:dd:7a:6c:8f: - c6:07:18:c6:7f:de:47:8e:3f:28:9e:04:06:cf:a5:54:34:77: - bd:ec:89:9b:e9:17:43:df:5b:db:5f:fe:8e:1e:57:a2:cd:40: - 9d:7e:62:22:da:de:18:27 ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- diff --git a/global-config.rsc b/global-config.rsc index 0c0a7b9..dfb25ec 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -88,11 +88,11 @@ :global FwAddrLists { # "allow"={ # { url="https://eworm.de/ros/fw-addr-lists/allow"; -# cert="R3" }; +# cert="E1" }; # }; "block"={ # { url="https://eworm.de/ros/fw-addr-lists/block"; -# cert="R3" }; +# cert="E1" }; { url="https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt"; cert="GlobalSign Atlas R3 DV TLS CA 2022 Q3" }; { url="https://sslbl.abuse.ch/blacklist/sslipblacklist.txt"; diff --git a/global-functions b/global-functions index ce55b15..431a343 100644 --- a/global-functions +++ b/global-functions @@ -54,10 +54,6 @@ :global SymbolForNotification; :global ValidateSyntax; - :if ([ $CertificateAvailable "R3" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; - } - :if ([ $CertificateAvailable "E1" ] = false) do={ $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; } diff --git a/global-functions.rsc b/global-functions.rsc index 12e13fe..96b8845 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -865,10 +865,6 @@ :global SymbolForNotification; :global ValidateSyntax; - :if ([ $CertificateAvailable "R3" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; - } - :if ([ $CertificateAvailable "E1" ] = false) do={ $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; } From dce779250c4546570579a901ae7dcba87429fabe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Oct 2023 21:21:39 +0200 Subject: [PATCH 1682/2612] README: explain sensitive property --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index cadd9a0..917eba6 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,9 @@ Then we import the certificates. /certificate/import file-name=letsencrypt-E1.pem passphrase=""; +Do not worry that the command is not shown - that happens because it contains +a sensitive property, the passphrase. + ![screenshot: import certs](README.d/02-import-certs.avif) For basic verification we rename the certificates and print their count. Make From 72b485125500cb30572f6bb31cff3c1f551fb766 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Oct 2023 08:42:32 +0200 Subject: [PATCH 1683/2612] global-functions: introduce $LogPrintOnce This does work just like $LogPrintExit2, except it acts just *once* for each message, until device is rebooted. --- global-functions.rsc | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 96b8845..bacda7c 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -45,6 +45,7 @@ :global IsMacLocallyAdministered; :global IsTimeSync; :global LogPrintExit2; +:global LogPrintOnce; :global MkDir; :global NotificationFunctions; :global ParseDate; @@ -613,6 +614,28 @@ } } +# log and print, once until reboot +:set LogPrintOnce do={ + :local Severity [ :tostr $1 ]; + :local Name [ :tostr $2 ]; + :local Message [ :tostr $3 ]; + + :global LogPrintExit2; + + :global LogPrintOnceMessages; + + :if ([ :typeof $LogPrintOnceMessages ] = "nothing") do={ + :set LogPrintOnceMessages ({}); + } + + :if ($LogPrintOnceMessages->$Message = 1) do={ + :return true; + } + + :set ($LogPrintOnceMessages->$Message) 1; + $LogPrintExit2 $Severity $Name $Message false; +} + # create directory :set MkDir do={ :local Path [ :tostr $1 ]; From 3474b9a15c75ba4bb0af438362cd096be848da91 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Oct 2023 08:58:29 +0200 Subject: [PATCH 1684/2612] dhcp-to-dns: allow multiple records for one mac address Now that we can have differnt name suffixes via networks it makes sense to allow multiple records for one mac address. Also update the wording for messages... --- dhcp-to-dns.rsc | 55 +++++++++++++++++++++++++------------------- global-functions.rsc | 2 +- news-and-changes.rsc | 2 ++ 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index d6a39e5..e7620fa 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -25,7 +25,7 @@ $ScriptLock $0 false 10; :local Ttl 5m; -:local CommentPrefix ("managed by " . $0 . " for "); +:local CommentPrefix ("managed by " . $0); :local CommentString ("--- " . $0 . " above ---"); :if ([ :len [ /ip/dns/static/find where (name=$CommentString or (comment=$CommentString and name=-)) type=NXDOMAIN disabled ] ] = 0) do={ @@ -34,14 +34,16 @@ $ScriptLock $0 false 10; } :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) (!type or type=A) ] do={ +:foreach DnsRecord in=[ /ip/dns/static/find where comment~("^" . $CommentPrefix . "\\b") (!type or type=A) ] do={ :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; - :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; - :if ([ :len [ /ip/dhcp-server/lease/find where active-mac-address=$MacAddress active-address=($DnsRecordVal->"address") status=bound ] ] > 0) do={ - $LogPrintExit2 debug $0 ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; + :local DnsRecordInfo [ $ParseKeyValueStore ($DnsRecordVal->"comment") ]; + :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 " . $DnsRecordInfo->"macaddress" . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting record.") false; } else={ :local Found false; - $LogPrintExit2 info $0 ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry.") false; + $LogPrintExit2 info $0 ("Lease expired for " . $DnsRecordInfo->"macaddress" . " in " . \ + $DnsRecordInfo->"server" . ", deleting record (" . $DnsRecordVal->"name" . ").") false; /ip/dns/static/remove $DnsRecord; /ip/dns/static/remove [ find where type=CNAME comment=($DnsRecordVal->"comment") ]; } @@ -51,17 +53,12 @@ $ScriptLock $0 false 10; :local LeaseVal; :do { :set LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local DupMacLeases [ /ip/dhcp-server/lease/find where active-mac-address=($LeaseVal->"active-mac-address") status=bound ]; - :if ([ :len $DupMacLeases ] > 1) do={ - $LogPrintExit2 debug $0 ("Multiple bound leases found for mac-address " . ($LeaseVal->"active-mac-address") . ", using last one.") false; - :set LeaseVal [ /ip/dhcp-server/lease/get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) ]; - } } on-error={ $LogPrintExit2 debug $0 ("A lease just vanished, ignoring.") false; } :if ([ :len ($LeaseVal->"active-address") ] > 0) do={ - :local Comment ($CommentPrefix . $LeaseVal->"active-mac-address"); + :local Comment ($CommentPrefix . ", macaddress=" . $LeaseVal->"active-mac-address" . ", server=" . $LeaseVal->"server"); :local MacDash [ $CharacterReplace ($LeaseVal->"active-mac-address") ":" "-" ]; :local HostName [ $CharacterReplace [ $EitherOr ([ $ParseKeyValueStore ($LeaseVal->"comment") ]->"hostname") ($LeaseVal->"host-name") ] " " "" ]; :local Network [ /ip/dhcp-server/network/find where ($LeaseVal->"active-address") in address ]; @@ -78,26 +75,36 @@ $ScriptLock $0 false 10; :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; :if ($DnsRecordVal->"address" = $LeaseVal->"active-address" && $DnsRecordVal->"name" = ($MacDash . "." . $NetDomain)) do={ - $LogPrintExit2 debug $0 ("DNS entry for " . $LeaseVal->"active-mac-address" . " does not need updating.") false; + $LogPrintExit2 debug $0 ("The A record for " . $LeaseVal->"active-mac-address" . " in " . \ + $LeaseVal->"server" . " does not need updating.") false; } else={ - $LogPrintExit2 info $0 ("Replacing DNS entry for " . $LeaseVal->"active-mac-address" . " (" . ($MacDash . "." . $NetDomain) . " -> " . $LeaseVal->"active-address" . ").") false; + $LogPrintExit2 info $0 ("Updating A record for " . $LeaseVal->"active-mac-address" . " in " . \ + $LeaseVal->"server" . " (" . ($MacDash . "." . $NetDomain) . " -> " . $LeaseVal->"active-address" . ").") false; /ip/dns/static/set address=($LeaseVal->"active-address") name=($MacDash . "." . $NetDomain) $DnsRecord; } - :local Cname [ /ip/dns/static/find where comment=$Comment type=CNAME ]; - :if ([ :len $Cname ] = 0 && [ :len $HostName ] > 0) do={ - $LogPrintExit2 info $0 ("Host name appeared, adding CNAME (" . ($HostName . "." . $NetDomain) . " -> " . ($MacDash . "." . $NetDomain) . ").") false; + :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" != ($HostName . "." . $NetDomain) || $CNameVal->"cname" != ($MacDash . "." . $NetDomain)) do={ + $LogPrintExit2 info $0 ("Deleting CNAME record with wrong data for " . $LeaseVal->"active-mac-address" . " in " . \ + $LeaseVal->"server" . ".") false; + /ip/dns/static/remove $CName; + } + } + :if ([ :len $HostName ] > 0 && [ :len [ /ip/dns/static/find where name=($HostName . "." . $NetDomain) type=CNAME ] ] = 0) do={ + $LogPrintExit2 info $0 ("Adding CNAME record for " . $LeaseVal->"active-mac-address" . " in " . \ + $LeaseVal->"server" . " (" . ($HostName . "." . $NetDomain) . " -> " . ($MacDash . "." . $NetDomain) . ").") false; /ip/dns/static/add name=($HostName . "." . $NetDomain) type=CNAME cname=($MacDash . "." . $NetDomain) ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } - :if ([ :len $Cname ] > 0 && [ /ip/dns/static/get $Cname name ] != ($HostName . "." . $NetDomain)) do={ - $LogPrintExit2 info $0 ("Host name or domain changed, updating CNAME (" . ($HostName . "." . $NetDomain) . " -> " . ($MacDash . "." . $NetDomain) . ").") false; - /ip/dns/static/set name=($HostName . "." . $NetDomain) cname=($MacDash . "." . $NetDomain) $Cname; - } + } else={ - $LogPrintExit2 info $0 ("Adding new DNS entry for " . $LeaseVal->"active-mac-address" . " (" . ($MacDash . "." . $NetDomain) . " -> " . $LeaseVal->"active-address" . ").") false; + $LogPrintExit2 info $0 ("Adding A record for " . $LeaseVal->"active-mac-address" . " in " . \ + $LeaseVal->"server" . " (" . ($MacDash . "." . $NetDomain) . " -> " . $LeaseVal->"active-address" . ").") false; /ip/dns/static/add name=($MacDash . "." . $NetDomain) type=A address=($LeaseVal->"active-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; - :if ([ :len $HostName ] > 0) do={ - $LogPrintExit2 info $0 ("Adding new CNAME (" . ($HostName . "." . $NetDomain) . " -> " . ($MacDash . "." . $NetDomain) . ").") false; + :if ([ :len $HostName ] > 0 && [ :len [ /ip/dns/static/find where name=($HostName . "." . $NetDomain) type=CNAME ] ] = 0) do={ + $LogPrintExit2 info $0 ("Adding CNAME record for " . $LeaseVal->"active-mac-address" . " in " . \ + $LeaseVal->"server" . " (" . ($HostName . "." . $NetDomain) . " -> " . ($MacDash . "." . $NetDomain) . ").") false; /ip/dns/static/add name=($HostName . "." . $NetDomain) type=CNAME cname=($MacDash . "." . $NetDomain) ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } diff --git a/global-functions.rsc b/global-functions.rsc index bacda7c..9b47f85 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 110; +:global ExpectedConfigVersion 111; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index e16f074..5ee3030 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -24,6 +24,7 @@ 108="Enhanced 'log-forward' to list log messages with colorful bullets to indicate severity."; 109="Added support to send notifications via Ntfy (ntfy.sh)."; 110="Dropped support for loading scripts from local storage."; + 111="Modified 'dhcp-to-dns' to allow multiple records for one mac address."; }; # Migration steps to be applied on script updates @@ -31,4 +32,5 @@ 97=":local Rec [ /ip/dns/static/find where comment~\"^managed by dhcp-to-dns for \" ]; :if ([ :len \$Rec ] > 0) do={ /ip/dns/static/remove \$Rec; /system/script/run dhcp-to-dns; }"; 100=":global ScriptInstallUpdate; :if ([ :len [ /system/script/find where name=\"ssh-keys-import\" source~\"^#!rsc by RouterOS\\n\" ] ] > 0) do={ /system/script/set name=\"mod/ssh-keys-import\" ssh-keys-import; \$ScriptInstallUpdate; }"; 104=":global CharacterReplace; :global ScriptInstallUpdate; :foreach Script in={ \"capsman-download-packages\"; \"capsman-rolling-upgrade\"; \"hotspot-to-wpa\"; \"hotspot-to-wpa-cleanup\" } do={ /system/script/set name=(\$Script . \".capsman\") [ find where name=\$Script ]; :foreach Scheduler in=[ /system/scheduler/find where on-event~(\$Script . \"([^-.]|\\\$)\") ] do={ /system/scheduler/set \$Scheduler on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Script (\$Script . \".capsman\") ]; }; }; /ip/hotspot/user/profile/set on-login=\"hotspot-to-wpa.capsman\" [ find where on-login=\"hotspot-to-wpa\" ]; \$ScriptInstallUpdate;"; + 111=":local Rec [ /ip/dns/static/find where comment~\"^managed by dhcp-to-dns for \" ]; :if ([ :len \$Rec ] > 0) do={ /ip/dns/static/remove \$Rec; /system/script/run dhcp-to-dns; }"; }; From c34599fe46f91f83aac8bce78f3e250a0a46f60e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Oct 2023 09:08:23 +0200 Subject: [PATCH 1685/2612] dhcp-to-dns: warn on duplicate names --- dhcp-to-dns.rsc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index e7620fa..5bd4462 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -19,6 +19,7 @@ :global EitherOr; :global IfThenElse; :global LogPrintExit2; +:global LogPrintOnce; :global ParseKeyValueStore; :global ScriptLock; @@ -108,6 +109,10 @@ $ScriptLock $0 false 10; /ip/dns/static/add name=($HostName . "." . $NetDomain) type=CNAME cname=($MacDash . "." . $NetDomain) ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } + + :if ([ :len [ /ip/dns/static/find where name=($MacDash . "." . $NetDomain) (!type or type=A) ] ] > 1) do={ + $LogPrintOnce warning $0 ("The name '" . $MacDash . "." . $NetDomain . "' appeared in more than one A record!"); + } } else={ $LogPrintExit2 debug $0 ("No address available... Ignoring.") false; } From 576364f44a99f35ca7055338a5f95228f46b0492 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Oct 2023 10:12:47 +0200 Subject: [PATCH 1686/2612] dhcp-to-dns: info on mac address bound multiple time --- dhcp-to-dns.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 5bd4462..e363b85 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -54,6 +54,9 @@ $ScriptLock $0 false 10; :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") . "!"); + } } on-error={ $LogPrintExit2 debug $0 ("A lease just vanished, ignoring.") false; } From a769ed072b00d94e200b39efe02acaf4ac6e66cb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Oct 2023 22:34:52 +0200 Subject: [PATCH 1687/2612] dhcp-to-dns: prepare full names for A and CNAME records --- dhcp-to-dns.rsc | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index e363b85..c1a6548 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -73,48 +73,50 @@ $ScriptLock $0 false 10; :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 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" = ($MacDash . "." . $NetDomain)) do={ + :if ($DnsRecordVal->"address" = $LeaseVal->"active-address" && $DnsRecordVal->"name" = $FullA) do={ $LogPrintExit2 debug $0 ("The A record for " . $LeaseVal->"active-mac-address" . " in " . \ $LeaseVal->"server" . " does not need updating.") false; } else={ $LogPrintExit2 info $0 ("Updating A record for " . $LeaseVal->"active-mac-address" . " in " . \ - $LeaseVal->"server" . " (" . ($MacDash . "." . $NetDomain) . " -> " . $LeaseVal->"active-address" . ").") false; - /ip/dns/static/set address=($LeaseVal->"active-address") name=($MacDash . "." . $NetDomain) $DnsRecord; + $LeaseVal->"server" . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ").") false; + /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" != ($HostName . "." . $NetDomain) || $CNameVal->"cname" != ($MacDash . "." . $NetDomain)) do={ + :if ($CNameVal->"name" != $FullCN || $CNameVal->"cname" != $FullA) do={ $LogPrintExit2 info $0 ("Deleting CNAME record with wrong data for " . $LeaseVal->"active-mac-address" . " in " . \ $LeaseVal->"server" . ".") false; /ip/dns/static/remove $CName; } } - :if ([ :len $HostName ] > 0 && [ :len [ /ip/dns/static/find where name=($HostName . "." . $NetDomain) type=CNAME ] ] = 0) do={ + :if ([ :len $HostName ] > 0 && [ :len [ /ip/dns/static/find where name=$FullCN type=CNAME ] ] = 0) do={ $LogPrintExit2 info $0 ("Adding CNAME record for " . $LeaseVal->"active-mac-address" . " in " . \ - $LeaseVal->"server" . " (" . ($HostName . "." . $NetDomain) . " -> " . ($MacDash . "." . $NetDomain) . ").") false; - /ip/dns/static/add name=($HostName . "." . $NetDomain) type=CNAME cname=($MacDash . "." . $NetDomain) ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + $LeaseVal->"server" . " (" . $FullCN . " -> " . $FullA . ").") false; + /ip/dns/static/add name=$FullCN type=CNAME cname=$FullA ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } else={ $LogPrintExit2 info $0 ("Adding A record for " . $LeaseVal->"active-mac-address" . " in " . \ - $LeaseVal->"server" . " (" . ($MacDash . "." . $NetDomain) . " -> " . $LeaseVal->"active-address" . ").") false; - /ip/dns/static/add name=($MacDash . "." . $NetDomain) type=A address=($LeaseVal->"active-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; - :if ([ :len $HostName ] > 0 && [ :len [ /ip/dns/static/find where name=($HostName . "." . $NetDomain) type=CNAME ] ] = 0) do={ + $LeaseVal->"server" . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ").") false; + /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 " . $LeaseVal->"active-mac-address" . " in " . \ - $LeaseVal->"server" . " (" . ($HostName . "." . $NetDomain) . " -> " . ($MacDash . "." . $NetDomain) . ").") false; - /ip/dns/static/add name=($HostName . "." . $NetDomain) type=CNAME cname=($MacDash . "." . $NetDomain) ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + $LeaseVal->"server" . " (" . $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=($MacDash . "." . $NetDomain) (!type or type=A) ] ] > 1) do={ - $LogPrintOnce warning $0 ("The name '" . $MacDash . "." . $NetDomain . "' appeared in more than one A record!"); + :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!"); } } else={ $LogPrintExit2 debug $0 ("No address available... Ignoring.") false; From a407332ea16da2d859ff994d20cc4f7137eb89b7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Oct 2023 22:39:41 +0200 Subject: [PATCH 1688/2612] dhcp-to-dns: prepare string 'mac in server' --- dhcp-to-dns.rsc | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index c1a6548..57488c4 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -38,13 +38,14 @@ $ScriptLock $0 false 10; :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 " . $DnsRecordInfo->"macaddress" . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting record.") false; + $LogPrintExit2 debug $0 ("Lease for " . $MacInServer . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting record.") false; } else={ :local Found false; - $LogPrintExit2 info $0 ("Lease expired for " . $DnsRecordInfo->"macaddress" . " in " . \ - $DnsRecordInfo->"server" . ", deleting record (" . $DnsRecordVal->"name" . ").") 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") ]; } @@ -75,17 +76,16 @@ $ScriptLock $0 false 10; [ $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={ - $LogPrintExit2 debug $0 ("The A record for " . $LeaseVal->"active-mac-address" . " in " . \ - $LeaseVal->"server" . " does not need updating.") false; + $LogPrintExit2 debug $0 ("The A record for " . $MacInServer . " (" . $FullA . ") does not need updating.") false; } else={ - $LogPrintExit2 info $0 ("Updating A record for " . $LeaseVal->"active-mac-address" . " in " . \ - $LeaseVal->"server" . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ").") false; + $LogPrintExit2 info $0 ("Updating A record for " . $MacInServer . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ").") false; /ip/dns/static/set address=($LeaseVal->"active-address") name=$FullA $DnsRecord; } @@ -93,24 +93,20 @@ $ScriptLock $0 false 10; :if ([ :len $CName ] > 0) do={ :local CNameVal [ /ip/dns/static/get $CName ]; :if ($CNameVal->"name" != $FullCN || $CNameVal->"cname" != $FullA) do={ - $LogPrintExit2 info $0 ("Deleting CNAME record with wrong data for " . $LeaseVal->"active-mac-address" . " in " . \ - $LeaseVal->"server" . ".") false; + $LogPrintExit2 info $0 ("Deleting CNAME record with wrong data for " . $MacInServer . ".") false; /ip/dns/static/remove $CName; } } :if ([ :len $HostName ] > 0 && [ :len [ /ip/dns/static/find where name=$FullCN type=CNAME ] ] = 0) do={ - $LogPrintExit2 info $0 ("Adding CNAME record for " . $LeaseVal->"active-mac-address" . " in " . \ - $LeaseVal->"server" . " (" . $FullCN . " -> " . $FullA . ").") false; + $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; } } else={ - $LogPrintExit2 info $0 ("Adding A record for " . $LeaseVal->"active-mac-address" . " in " . \ - $LeaseVal->"server" . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ").") false; + $LogPrintExit2 info $0 ("Adding A record for " . $MacInServer . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ").") false; /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 " . $LeaseVal->"active-mac-address" . " in " . \ - $LeaseVal->"server" . " (" . $FullCN . " -> " . $FullA . ").") false; + $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; } } From f60c72dc78da3ff14ccc23988b342d94a662f406 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Oct 2023 22:55:15 +0200 Subject: [PATCH 1689/2612] netwatch-dns: match on word boundary --- netwatch-dns.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 119a367..3e3e27c 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -26,7 +26,7 @@ $ScriptLock $0; :local DnsFallback ({}); :local DnsCurrent [ /ip/dns/get servers ]; -:foreach Host in=[ /tool/netwatch/find where comment~"dns" status="up" ] do={ +:foreach Host in=[ /tool/netwatch/find where comment~"\\bdns\\b" status="up" ] do={ :local HostVal [ /tool/netwatch/get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; @@ -61,7 +61,7 @@ $ScriptLock $0; :local DohCert ""; :local DohCurrent [ /ip/dns/get use-doh-server ]; -:foreach Host in=[ /tool/netwatch/find where comment~"doh" status="up" ] do={ +:foreach Host in=[ /tool/netwatch/find where comment~"\\bdoh\\b" status="up" ] do={ :local HostVal [ /tool/netwatch/get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; From 4321d8fa54cd2b8454a072ad68355380248d5818 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Oct 2023 22:55:40 +0200 Subject: [PATCH 1690/2612] netwatch-notify: match on word boundary --- netwatch-notify.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 5482ea3..28bde24 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -58,7 +58,7 @@ $ScriptLock $0; :set NetwatchNotify ({}); } -:foreach Host in=[ /tool/netwatch/find where comment~"notify" !disabled status!="unknown" ] do={ +:foreach Host in=[ /tool/netwatch/find where comment~"\\bnotify\\b" !disabled status!="unknown" ] do={ :local HostVal [ /tool/netwatch/get $Host ]; :local Type [ $IfThenElse ($HostVal->"type" ~ "^(https?-get|tcp-conn)\$") "service" "host" ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; From fe2641ae0f7634b3c72cc32ca698f8d1c9c70003 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 May 2023 20:10:40 +0200 Subject: [PATCH 1691/2612] global-functions: $ParseDate: drop code for old format... ... and increase required RouterOS. We should probably wait some time before merging this: Even current versions have some hidden places with old format: [admin@MikroTik] > /system/resource/print [...] version: 7.10.2 (stable) build-time: Jul/12/2023 09:45:11 [...] (Though this is written with capital letter and fails anyway...) Something similar goes for `/ip/neighbor`, where format depends on remote devices. Does anybody need to parse this? --- README.md | 2 +- global-functions.rsc | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 917eba6..5898aaa 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ RouterOS Scripts [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.9-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.10beta5-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) diff --git a/global-functions.rsc b/global-functions.rsc index 9b47f85..e307560 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.9beta4 +# requires RouterOS, version=7.10beta5 # # global functions # https://git.eworm.de/cgit/routeros-scripts/about/ @@ -704,15 +704,6 @@ :set ParseDate do={ :local Date [ :tostr $1 ]; - :if ([ :pick $Date 4 5 ] != "-") do={ - :local Months { "jan"=1; "feb"=2; "mar"=3; "apr"=4; "may"=5; "jun"=6; - "jul"=7; "aug"=8; "sep"=9; "oct"=10; "nov"=11; "dec"=12 }; - - :return ({ "year"=[ :tonum [ :pick $Date 7 11 ] ]; - "month"=($Months->[ :pick $Date 0 3 ]); - "day"=[ :tonum [ :pick $Date 4 6 ] ] }); - } - :return ({ "year"=[ :tonum [ :pick $Date 0 4 ] ]; "month"=[ :tonum [ :pick $Date 5 7 ] ]; "day"=[ :tonum [ :pick $Date 8 10 ] ] }); From c2649ae8328cf5d975e5c0130811801f80c33721 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 15 Jun 2023 22:50:38 +0200 Subject: [PATCH 1692/2612] README: reference stable version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5898aaa..dfd4d6f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ RouterOS Scripts [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.10beta5-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.10-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) From 79f3002a38d2d69acc51c59e609b09b1d982b545 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Nov 2023 14:25:20 +0100 Subject: [PATCH 1693/2612] README: print name with proplist for certificate verification --- README.d/03-check-certs.avif | Bin 8223 -> 9339 bytes README.md | 7 ++++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.d/03-check-certs.avif b/README.d/03-check-certs.avif index 3c7def2746b23206a3f47a6b1bc0d927c43e3258..33bdc408e4dcd3c35e95c87109926d801f8c9fe8 100644 GIT binary patch delta 8097 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 delta 6970 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 diff --git a/README.md b/README.md index dfd4d6f..4ad3d2f 100644 --- a/README.md +++ b/README.md @@ -79,12 +79,13 @@ a sensitive property, the passphrase. ![screenshot: import certs](README.d/02-import-certs.avif) -For basic verification we rename the certificates and print their count. Make -sure the certificate count is **two**. +For basic verification we rename the certificates and print them by +fingerprint. Make sure exactly these two certificates ("*E1*" and +"*ISRG-Root-X2*") are shown. /certificate/set name="E1" [ find where common-name="E1" ]; /certificate/set name="ISRG-Root-X2" [ find where common-name="ISRG Root X2" ]; - /certificate/print count-only where fingerprint="46494e30379059df18be52124305e606fc59070e5b21076ce113954b60517cda" or fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470"; + /certificate/print proplist=name where fingerprint="46494e30379059df18be52124305e606fc59070e5b21076ce113954b60517cda" or fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470"; ![screenshot: check certs](README.d/03-check-certs.avif) From c3045f372350bd8dd0a8f10efb8a4b938e896145 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Nov 2023 09:38:47 +0100 Subject: [PATCH 1694/2612] mod/ssh-keys-import: parse key into array --- mod/ssh-keys-import.rsc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 31bb3e6..fb6fee1 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -14,6 +14,7 @@ :local Key [ :tostr $1 ]; :local User [ :tostr $2 ]; + :global CharacterReplace; :global GetRandom20CharAlNum; :global LogPrintExit2; :global MkDir; @@ -28,9 +29,9 @@ $LogPrintExit2 warning $0 ("User '" . $User . "' does not exist.") true; } - :local Type [ :pick $Key 0 [ :find $Key " " ] ]; - :if (!(([ $RequiredRouterOS $0 "7.12beta1" ] = true && $Type = "ssh-ed25519") || $Type = "ssh-rsa")) do={ - $LogPrintExit2 warning $0 ("SSH key of type '" . $Type . "' is not supported.") true; + :local KeyVal [ :toarray [ $CharacterReplace $Key " " "," ] ]; + :if (!(([ $RequiredRouterOS $0 "7.12beta1" ] = true && $KeyVal->0 = "ssh-ed25519") || $KeyVal->0 = "ssh-rsa")) do={ + $LogPrintExit2 warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported.") true; } :if ([ $MkDir "tmpfs/ssh-keys-import" ] = false) do={ @@ -53,6 +54,7 @@ :local FileName [ :tostr $1 ]; :local User [ :tostr $2 ]; + :global CharacterReplace; :global EitherOr; :global LogPrintExit2; :global ParseKeyValueStore; @@ -73,17 +75,17 @@ :local Continue false; :local Line [ :pick $Keys 0 [ :find $Keys "\n" ] ]; :set Keys [ :pick $Keys ([ :find $Keys "\n" ] + 1) [ :len $Keys ] ]; - :local Type [ :pick $Line 0 [ :find $Line " " ] ]; - :if (([ $RequiredRouterOS $0 "7.12beta1" ] = true && $Type = "ssh-ed25519") || $Type = "ssh-rsa") do={ + :local KeyVal [ :toarray [ $CharacterReplace $Key " " "," ] ]; + :if (([ $RequiredRouterOS $0 "7.12beta1" ] = true && $KeyVal->0 = "ssh-ed25519") || $KeyVal->0 = "ssh-rsa") do={ $SSHKeysImport $Line $User; :set Continue true; } - :if ($Continue = false && $Type = "#") do={ + :if ($Continue = false && $KeyVal->0 = "#") do={ :set User [ $EitherOr ([ $ParseKeyValueStore [ :pick $Line 2 [ :len $Line ] ] ]->"user") $User ]; :set Continue true; } - :if ($Continue = false && [ :len $Type ] > 0) do={ - $LogPrintExit2 warning $0 ("SSH key of type '" . $Type . "' is not supported.") false; + :if ($Continue = false && [ :len ($KeyVal->0) ] > 0) do={ + $LogPrintExit2 warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported.") false; } } while=([ :len $Keys ] > 0); } From 1265caca60bf097d66ef9ef0814e8f04f9720170 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Nov 2023 09:46:25 +0100 Subject: [PATCH 1695/2612] mod/ssh-keys-import: calculate fingerprint... ... and store it in key-owner, which is descriptive only. This requires RouterOS 7.12beta1 for the 'transform' property for ':convert' command. --- doc/mod/ssh-keys-import.md | 8 +++++++- global-functions.rsc | 2 +- mod/ssh-keys-import.rsc | 7 ++++++- news-and-changes.rsc | 1 + 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md index cf28ee2..9f7f7ce 100644 --- a/doc/mod/ssh-keys-import.md +++ b/doc/mod/ssh-keys-import.md @@ -3,6 +3,8 @@ Import ssh keys for public key authentication [âŦ…ī¸ Go back to main README](../../README.md) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12beta1-yellow?style=flat)](https://mikrotik.com/download/changelogs/) + > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base > installation. See [main README](../../README.md) for details. @@ -35,7 +37,11 @@ been added: $SSHKeysImport "ssh-ed25519 AAAAC3Nza...ZVugJT user" admin; The third part of the key (`user` in this example) is inherited as -`key-owner` in RouterOS. +`key-owner` in RouterOS. Also the `MD5` fingerprint is recorded, this helps +to audit and verify the available keys. + +> â„šī¸ī¸ **Info**: Use `ssh-keygen` to show a fingerprint of an existing public +> key file: `ssh-keygen -l -E md5 -f ~/.ssh/id_ed25519.pub` ### Import several keys from file diff --git a/global-functions.rsc b/global-functions.rsc index e307560..7eb1ec5 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 111; +:global ExpectedConfigVersion 112; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index fb6fee1..0e82785 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2020-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12beta1 +# # import ssh keys for public key authentication # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ssh-keys-import.md @@ -38,12 +40,15 @@ $LogPrintExit2 warning $0 ("Creating directory 'tmpfs/ssh-keys-import' failed!") true; } + :local FingerPrintMD5 [ :convert from=base64 transform=md5 to=hex ($KeyVal->1) ]; :local FileName ("tmpfs/ssh-keys-import/key-" . [ $GetRandom20CharAlNum 6 ] . ".pub"); - /file/add name=$FileName contents=$Key; + /file/add name=$FileName contents=($Key . ", md5=" . $FingerPrintMD5); $WaitForFile $FileName; :do { /user/ssh-keys/import public-key-file=$FileName user=$User; + $LogPrintExit2 info $0 ("Imported ssh public key (" . $KeyVal->2 . ", " . $KeyVal->0 . ", " . \ + "MD5:" . $FingerPrintMD5 . ") for user '" . $User . "'.") false; } on-error={ $LogPrintExit2 warning $0 ("Failed importing key.") true; } diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 5ee3030..babcec8 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -25,6 +25,7 @@ 109="Added support to send notifications via Ntfy (ntfy.sh)."; 110="Dropped support for loading scripts from local storage."; 111="Modified 'dhcp-to-dns' to allow multiple records for one mac address."; + 112="Enhanced 'mod/ssh-keys-import' to record the fingerprint of keys."; }; # Migration steps to be applied on script updates From 042ff1cfda2f4832eff4fc7cf161f50aa44fa9bd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Aug 2023 15:26:18 +0200 Subject: [PATCH 1696/2612] mod/ssh-keys-import: drop the version check for ed25519 keys... ... now that we require RouterOS 7.12beta1 anyway. --- mod/ssh-keys-import.rsc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 0e82785..023407a 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -20,7 +20,6 @@ :global GetRandom20CharAlNum; :global LogPrintExit2; :global MkDir; - :global RequiredRouterOS; :global WaitForFile; :if ([ :len $Key ] = 0 || [ :len $User ] = 0) do={ @@ -32,7 +31,7 @@ } :local KeyVal [ :toarray [ $CharacterReplace $Key " " "," ] ]; - :if (!(([ $RequiredRouterOS $0 "7.12beta1" ] = true && $KeyVal->0 = "ssh-ed25519") || $KeyVal->0 = "ssh-rsa")) do={ + :if (!($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa")) do={ $LogPrintExit2 warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported.") true; } @@ -63,7 +62,6 @@ :global EitherOr; :global LogPrintExit2; :global ParseKeyValueStore; - :global RequiredRouterOS; :global SSHKeysImport; :if ([ :len $FileName ] = 0 || [ :len $User ] = 0) do={ @@ -81,7 +79,7 @@ :local Line [ :pick $Keys 0 [ :find $Keys "\n" ] ]; :set Keys [ :pick $Keys ([ :find $Keys "\n" ] + 1) [ :len $Keys ] ]; :local KeyVal [ :toarray [ $CharacterReplace $Key " " "," ] ]; - :if (([ $RequiredRouterOS $0 "7.12beta1" ] = true && $KeyVal->0 = "ssh-ed25519") || $KeyVal->0 = "ssh-rsa") do={ + :if ($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa") do={ $SSHKeysImport $Line $User; :set Continue true; } From b22dfbfc948edced83f1eb24e20b4a21f35a85f0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Nov 2023 13:34:02 +0100 Subject: [PATCH 1697/2612] mod/ssh-keys-import: do not import twice --- mod/ssh-keys-import.rsc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 023407a..dd80fe9 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -40,6 +40,13 @@ } :local FingerPrintMD5 [ :convert from=base64 transform=md5 to=hex ($KeyVal->1) ]; + + :if ([ :len [ /user/ssh-keys/find where user=$User key-owner~("\\bmd5=" . $FingerPrintMD5 . "\\b") ] ] > 0) do={ + $LogPrintExit2 warning $0 ("The ssh public key (MD5:" . $FingerPrintMD5 . \ + ") is already available for user '" . $User . "'.") false; + :return false; + } + :local FileName ("tmpfs/ssh-keys-import/key-" . [ $GetRandom20CharAlNum 6 ] . ".pub"); /file/add name=$FileName contents=($Key . ", md5=" . $FingerPrintMD5); $WaitForFile $FileName; From 98d7eee454bde21932cea700fda3d74ab4fc1336 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 7 Nov 2023 13:48:49 +0100 Subject: [PATCH 1698/2612] mod/ssh-keys-import: continue import after intermediate failure --- mod/ssh-keys-import.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index dd80fe9..1513114 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -87,7 +87,11 @@ :set Keys [ :pick $Keys ([ :find $Keys "\n" ] + 1) [ :len $Keys ] ]; :local KeyVal [ :toarray [ $CharacterReplace $Key " " "," ] ]; :if ($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa") do={ - $SSHKeysImport $Line $User; + :do { + $SSHKeysImport $Line $User; + } on-error={ + $LogPrintExit2 warning $0 ("Failed importing key for user '" . $User . "'.") false; + } :set Continue true; } :if ($Continue = false && $KeyVal->0 = "#") do={ From 3cc41495bccef368560d2fc8311af09909f0d0aa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 Nov 2023 15:16:37 +0100 Subject: [PATCH 1699/2612] doc/mod/ssh-keys-import: reference stable version --- doc/mod/ssh-keys-import.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md index 9f7f7ce..5fd95af 100644 --- a/doc/mod/ssh-keys-import.md +++ b/doc/mod/ssh-keys-import.md @@ -3,7 +3,7 @@ Import ssh keys for public key authentication [âŦ…ī¸ Go back to main README](../../README.md) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12beta1-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base > installation. See [main README](../../README.md) for details. From 0f3746c894c643afc82f854b7ef4d80b98cbf264 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 Nov 2023 17:31:14 +0100 Subject: [PATCH 1700/2612] doc/mod/notification-email: end all commands with a semicolon --- doc/mod/notification-email.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/mod/notification-email.md b/doc/mod/notification-email.md index 6b1142d..373f8fe 100644 --- a/doc/mod/notification-email.md +++ b/doc/mod/notification-email.md @@ -51,12 +51,12 @@ will now send it to your e-mail account. But of course you can use the function to send notifications directly. Give it a try: - $SendEMail "Subject..." "Body..." + $SendEMail "Subject..." "Body..."; Alternatively this sends a notification with all available and configured methods: - $SendNotification "Subject..." "Body..." + $SendNotification "Subject..." "Body..."; To use the functions in your own scripts you have to declare them first. Place this before you call them: From 2acc0aba7e16355faa47f036bf30c3058932c97e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 Nov 2023 17:29:25 +0100 Subject: [PATCH 1701/2612] doc/mod/notification-matrix: end all commands with a semicolon --- doc/mod/notification-matrix.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index e9e3174..4ae6e18 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -97,12 +97,12 @@ will now send it to your Matrix account. But of course you can use the function to send notifications directly. Give it a try: - $SendMatrix "Subject..." "Body..." + $SendMatrix "Subject..." "Body..."; Alternatively this sends a notification with all available and configured methods: - $SendNotification "Subject..." "Body..." + $SendNotification "Subject..." "Body..."; To use the functions in your own scripts you have to declare them first. Place this before you call them: From 255fc531addffedf7f713f99526993ee94ac1869 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 Nov 2023 17:30:35 +0100 Subject: [PATCH 1702/2612] doc/mod/notification-ntfy: end all commands with a semicolon --- doc/mod/notification-ntfy.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/mod/notification-ntfy.md b/doc/mod/notification-ntfy.md index 64e49f0..f4cad8a 100644 --- a/doc/mod/notification-ntfy.md +++ b/doc/mod/notification-ntfy.md @@ -49,12 +49,12 @@ will now send it to your Ntfy topic. But of course you can use the function to send notifications directly. Give it a try: - $SendNtfy "Subject..." "Body..." + $SendNtfy "Subject..." "Body..."; Alternatively this sends a notification with all available and configured methods: - $SendNotification "Subject..." "Body..." + $SendNotification "Subject..." "Body..."; To use the functions in your own scripts you have to declare them first. Place this before you call them: From 59f8f3038949a332ae28e52d8329ebe200f8ef1b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 Nov 2023 17:31:39 +0100 Subject: [PATCH 1703/2612] doc/mod/notification-telegram: end all commands with a semicolon --- doc/mod/notification-telegram.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index 387d511..444938f 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -60,12 +60,12 @@ will now send it to your Telegram account. But of course you can use the function to send notifications directly. Give it a try: - $SendTelegram "Subject..." "Body..." + $SendTelegram "Subject..." "Body..."; Alternatively this sends a notification with all available and configured methods: - $SendNotification "Subject..." "Body..." + $SendNotification "Subject..." "Body..."; To use the functions in your own scripts you have to declare them first. Place this before you call them: From 2d7efd8d6c3ee03847ebb13357424289590d8041 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 Nov 2023 13:08:49 +0100 Subject: [PATCH 1704/2612] mod/notification-matrix: introduce $SetupMatrix{Authenticate,JoinRoom} for setup Well, now that we have a JSON parser... Let's improve the user experience a bit. --- .../01-authenticate.avif | Bin 0 -> 4209 bytes .../notification-matrix.d/01-home-server.avif | Bin 2317 -> 0 bytes .../02-access-token.avif | Bin 4105 -> 0 bytes .../notification-matrix.d/02-join-room.avif | Bin 0 -> 3955 bytes .../notification-matrix.d/03-join-room.avif | Bin 3166 -> 0 bytes doc/mod/notification-matrix.md | 83 ++++++++---------- global-functions.rsc | 2 +- mod/notification-matrix.rsc | 79 +++++++++++++++++ news-and-changes.rsc | 1 + 9 files changed, 120 insertions(+), 45 deletions(-) create mode 100644 doc/mod/notification-matrix.d/01-authenticate.avif delete mode 100644 doc/mod/notification-matrix.d/01-home-server.avif delete mode 100644 doc/mod/notification-matrix.d/02-access-token.avif create mode 100644 doc/mod/notification-matrix.d/02-join-room.avif delete mode 100644 doc/mod/notification-matrix.d/03-join-room.avif diff --git a/doc/mod/notification-matrix.d/01-authenticate.avif b/doc/mod/notification-matrix.d/01-authenticate.avif new file mode 100644 index 0000000000000000000000000000000000000000..1db516b784b2779b1ab1054fcb149753b2c53dbf GIT binary patch literal 4209 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 Iq5{po0Ha9~3;+NC literal 0 HcmV?d00001 diff --git a/doc/mod/notification-matrix.d/01-home-server.avif b/doc/mod/notification-matrix.d/01-home-server.avif deleted file mode 100644 index 683c7b581bbf141e83a831ddfec8c47a8383d6e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2317 zcmXv|2|UyP8~-kI6c&@_=Pneo)>y9GM=WQUa>s00#^y{vLMReeD3WWAnGo#v#{+Rtnm{CB_bU?s0CC2kORpa-GV^Ik~n;X5Jbl9 zHv#~cJO>;&Ux-WyBm7bL`1m+1;2DZEz9qY_03uitG0-1N4C71|1bCu35{y9h^W671 z!8r^JIuHxyT*dbD_6&vshYo5gRB01skL3@l&K$P%J}{0l_L`V@T{My}Grjx`)VC6Y ztWUP#a#_CR(EVtf{%u%*xeGUmP_0!6T=bJa^)^n!KkH&YvsNTBM8nQOIUGE+j+nX+ zY0b-FT(>$dgMmm1v>f{3MfDjU2?@o@l=Vx+W9;+w6~3@2p!oq@fybx4b@sV2(tOg* zD1o}m={0bQO14 z&JVW~09%vhG0ldLA2*OsPGDx-+cL@SCK0l_2Qxno8N}LoSv#}i!s>$70PsslyfJMq zm9MTCtnigjoXhOY*P;lZvLg~PI(OX}OY)j;uhV6lf;x3^9ie%S{Os7IJo!7ctpyE9 zRtWO7=I)fr{Hmca{CndW>em+QQ)P7j=Ere-AzD*+8dbFUBPU*56-7onImhT54o0eW zN-ZivjS1S%gF2@sKSNXn6oy<2rV(XcP&&OXVWaQdYD&)q+z(~|&H4@1{ATTf%eyY& zT>oa<%Ztg$HX_^foRC3hox;n7hb~8`vQ}Cj z3zP`Z4C~77LgWe?Ts%=%$v5HI0b_cPn6>FJly+n{kBZIHL{BKByr}PvpI5dnF-}K1 zv6XuKr_s-HdF_h@RzCE#fo!DescrGBig|K^_jY35qGpSa%g-NKvV*$mNnHys`hrDy zyTVRTcy~M>59SA%Xd3HY!5^1vRr*y1UUHIhUSpDiwxk8Cffn;A=wM zRj0OB=$&%rsFYRynysSurs)I2wdSO`onF@veVvxjSjP5xK#qP))24q}uH#QvS5%}- zfMn9yS4F}HxT~H7sqw+?>p!hkTEaN<_QQm2Z)IxIcGb{gy~WQH(cIUy)AfX6Jpzn| zL`u4xc4&nYxEo*A!&&X_N0yJc-fL$kwRtb5>%k^>V;z4#=^?mg<)@7X!l7UCz=u&+ z>=cFd*mFxsj47J9-{~G6l^leLiv|^8Bsyxx*Ri?Nhze`uafVIIyaFGJx3s4H{m!<{ zrV9BpJa*2_N^>tJT1>pP=W1)&Z{MO3fz`uO@Axs8iK|(Tk5Hph7$~3Yh3Rc$;57C1 z)h3C|_}<)_(^qw9 zjq`@KtnHQi5^4qpjP%2;1}zJRfhBHOVnA@b z{*xi_6`*t#h)oDD*{gY$Ht&m~?{z8Z51%Qwe9#5I>Hgd0t;JD`0;AkfNgM8g_C=qw z%WR(ZoB49Xrki%>uR(i7UR8Wjn6l{p6uHR!S#vMq+oWxGnJ?xayj7<{I-99DdORb- zoyWoQ@m(?8x75m*FE1hRt%}HX92}uLy)bqQ*1D83@;p>szLcas&~l<>mOkhH&?L(BB`0EjRZS+?&0t6R?XXubaZu>wVY$j`u_@{N>IcOdbrHnwbbgM zr#>%vJ(J8Buz0I4r|>kjv$-?O{K-% z;%wljdCfqZ@aMtksXE3Z!XeH{5o(ZcV+EDFVG(9p$Xnl%^inbzjy-a%DpcC4EF)$Z)yiEb6|<8tw#%HoEj24UP1tnTe!zS%i;&0Gh@ z^Hvj#;=)4H5sZVpO_N<8`5`a+tHHH*#fM8t=0=0T9Zw~PoZ5N&$o U;E;tj+vMsflf~@RR9+VP7Z!sp761SM diff --git a/doc/mod/notification-matrix.d/02-access-token.avif b/doc/mod/notification-matrix.d/02-access-token.avif deleted file mode 100644 index 54109a6b8f5296e696011d65b227fbbf9d98040e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4105 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 HYY6xk29A|S literal 0 HcmV?d00001 diff --git a/doc/mod/notification-matrix.d/03-join-room.avif b/doc/mod/notification-matrix.d/03-join-room.avif deleted file mode 100644 index 45974b86b5fc39c652591cebd32650bcc78f0b5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3166 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 diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index 4ae6e18..b309d3d 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -21,8 +21,8 @@ Just install the module: $ScriptInstallUpdate mod/notification-matrix; Also install a Matrix client on at least one of your mobile and/or desktop -devices. As there is no privilege separation you should create a dedicated -notification account, in addition to your general user account. +devices. Create and setup an account there, we will reference that as +"*general account*" later. Configuration ------------- @@ -35,58 +35,53 @@ reload the configuration. > [`global-config`](../../global-config.rsc) (the one without `-overlay`) to > your local `global-config-overlay` and modify it to your specific needs. -### Home server +The Matrix server is connected via encrypted https, and certificate +verification is applied. So make sure you have the certificate chain for +your server in device's certificate store. + +> â„šī¸ **Info**: The *matrix.org* server uses a Cloudflare certificate. You can +> install that with: `$CertificateAvailable "Cloudflare Inc ECC CA-3"` + +### From other device + +If you have setup your Matrix *notification account* before just reuse that. +Copy the relevant configuration to the device to be configured. + +### Setup new account + +As there is no privilege separation you should create a dedicated account +for use with these scripts, in addition to your *general account*. +We will reference that as "*notification account*" in the following steps. + +#### Authenticate Matrix user accounts are identified by a unique user id in the form of -`@localpart:domain`. The `domain` part is not necessarily your home server -address, you have to resolve it with the procedure described in the -[Matrix specification](https://spec.matrix.org/latest/client-server-api/#server-discovery). +`@localpart:domain`. Use that and your password to generate an access token +and write first part of the configuration: -Your best bet is to query the server at `domain` with the -[well-known uri](https://spec.matrix.org/latest/client-server-api/#well-known-uri). -For "*matrix.org*" this query is: + $SetupMatrixAuthenticate "@example:matrix.org" "v3ry-s3cr3t"; - /tool/fetch "https://matrix.org/.well-known/matrix/client" output=user; +![authenticate](notification-matrix.d/01-authenticate.avif) -![home server](notification-matrix.d/01-home-server.avif) +#### Join Room -So the home server for "*matrix.org*" is "*matrix-client.matrix.org*". -Please strip the protocol ("*https://*") for `MatrixHomeServer` if given. +Every Matix chat is a room, so we have to create one. Do that with your +*general account*, this makes sure your *general account* is the room owner. +Then join the room and invite the *notification account* by its user id +"*@example:matrix.org*". +Look up the *room id* within the Matrix client, it should read like +"*!WUcxpSjKyxSGelouhA:matrix.org*" (starting with an exclamation mark and +ending with the domain). -### Access token +Finally make the *notification account* join into the room by accepting +the invite. -After discovering the correct home server an access token has to be created. -For this the login credentials (username and password) of the notification -account must be sent to the home server via -[client server api](https://matrix.org/docs/guides/client-server-api#login). + $SetupMatrixJoinRoom "!WUcxpSjKyxSGelouhA:matrix.org"; -We use the home server discovered above, "*matrix-client.matrix.org*". -The user is "*example*" and password is "*v3ry-s3cr3t*". +![join room](notification-matrix.d/02-join-room.avif) - /tool/fetch "https://matrix-client.matrix.org/_matrix/client/r0/login" http-method=post http-data="{\"type\":\"m.login.password\", \"user\":\"example\", \"password\":\"v3ry-s3cr3t\"}" output=user; - -![access token](notification-matrix.d/02-access-token.avif) - -The server replied with a JSON object containing the `access_token`, use that -for `MatrixAccessToken`. - -### Room - -Every Matix chat is a room, so we have to create one. Do so with your general -user, this makes sure your general user is the room owner. Then join the room -and invite the notification user by its user id "*@example:matrix.org*". Look -up the room id within the Matrix client, it should read like -"*!WUcxpSjKyxSGelouhA:matrix.org*". Use that for `MatrixRoom`. - -Finally join the notification user to the room by accepting the invite. Again, -this can be done with -[client server api](https://matrix.org/docs/guides/client-server-api#joining-a-room-via-an-invite). -Make sure to replace room id ("*!*" is escaped with "*%21*") and access token -with your data. - - /tool/fetch "https://matrix-client.matrix.org/_matrix/client/r0/rooms/%21WUcxpSjKyxSGelouhA:matrix.org/join?access_token=yt_ZXdvcm0tdGVzdA_NNqUyvKHRhBLZmnzVVSK_0xu6yN" http-method=post http-data="" output=user; - -![join room](notification-matrix.d/03-join-room.avif) +The settings have been appended to `global-config-overlay`. You may want to +edit to move it to an appropriate place. Usage and invocation -------------------- diff --git a/global-functions.rsc b/global-functions.rsc index 7eb1ec5..5c6e3c5 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 112; +:global ExpectedConfigVersion 113; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 03cfb13..a8983a7 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -12,6 +12,8 @@ :global PurgeMatrixQueue; :global SendMatrix; :global SendMatrix2; +:global SetupMatrixAuthenticate; +:global SetupMatrixJoinRoom; # flush Matrix queue :set FlushMatrixQueue do={ @@ -175,3 +177,80 @@ ($NotificationFunctions->"matrix") ("\$NotificationFunctions->\"matrix\"") $Notification; } + +# setup - get home server and access token +:set SetupMatrixAuthenticate do={ + :local User [ :tostr $1 ]; + :local Pass [ :tostr $2 ]; + + :global CharacterReplace; + :global LogPrintExit2; + :global ParseJson; + :global UrlEncode; + + :global MatrixAccessToken; + :global MatrixHomeServer; + + :local Domain [ :pick $User ([ :find $User ":" ] + 1) [ :len $User] ]; + :do { + :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ + ("https://" . $Domain . "/.well-known/matrix/client") as-value ]->"data"); + :set MatrixHomeServer ([ $ParseJson ([ $ParseJson [ $CharacterReplace $Data " " "" ] ]->"m.homeserver") ]->"base_url"); + $LogPrintExit2 debug $0 ("Home server is: " . $MatrixHomeServer) false; + } on-error={ + $LogPrintExit2 error $0 ("Failed getting home server!") true; + } + + :if ([ :pick $MatrixHomeServer 0 8 ] = "https://") do={ + :set MatrixHomeServer [ :pick $MatrixHomeServer 8 [ :len $MatrixHomeServer ] ]; + } + + :do { + :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ + http-method=post http-data=("{\"type\":\"m.login.password\", \"user\":\"" . $User . "\", \"password\":\"" . $Pass . "\"}") \ + ("https://" . $MatrixHomeServer . "/_matrix/client/r0/login") as-value ]->"data"); + :set MatrixAccessToken ([ $ParseJson $Data ]->"access_token"); + $LogPrintExit2 debug $0 ("Access token is: " . $MatrixAccessToken) false; + } on-error={ + $LogPrintExit2 error $0 ("Failed logging in (and getting access token)!") true; + } + + :do { + /system/script/set global-config-overlay source=([ get global-config-overlay source ] . "\n" . \ + ":global MatrixHomeServer \"" . $MatrixHomeServer . "\";\n" . \ + ":global MatrixAccessToken \"" . $MatrixAccessToken . "\";\n"); + $LogPrintExit2 info $0 ("Appended configuration to global-config-overlay. Now create and join a room, please!") false; + } on-error={ + $LogPrintExit2 error $0 ("Failed appending configuration to global-config-overlay!") true; + } +} + +# setup - join a room +:set SetupMatrixJoinRoom do={ + :global MatrixRoom [ :tostr $1 ]; + + :global LogPrintExit2; + :global UrlEncode; + + :global MatrixAccessToken; + :global MatrixHomeServer; + :global MatrixRoom; + + :do { + /tool/fetch check-certificate=yes-without-crl output=none \ + http-method=post http-data="" \ + ("https://" . $MatrixHomeServer . "/_matrix/client/r0/rooms/" . [ $UrlEncode $MatrixRoom ] . \ + "/join?access_token=" . [ $UrlEncode $MatrixAccessToken ]) as-value; + $LogPrintExit2 debug $0 ("Joined the room.") false; + } on-error={ + $LogPrintExit2 error $0 ("Failed joining the room!") true; + } + + :do { + /system/script/set global-config-overlay source=([ get global-config-overlay source ] . "\n" . \ + ":global MatrixRoom \"" . $MatrixRoom . "\";\n"); + $LogPrintExit2 info $0 ("Appended configuration to global-config-overlay. Please review and cleanup!") false; + } on-error={ + $LogPrintExit2 error $0 ("Failed appending configuration to global-config-overlay!") true; + } +} diff --git a/news-and-changes.rsc b/news-and-changes.rsc index babcec8..64e114f 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -26,6 +26,7 @@ 110="Dropped support for loading scripts from local storage."; 111="Modified 'dhcp-to-dns' to allow multiple records for one mac address."; 112="Enhanced 'mod/ssh-keys-import' to record the fingerprint of keys."; + 113="Added helper functions for easier setup to Matrix notification module."; }; # Migration steps to be applied on script updates From 5b047223d17d0ce4c5e3fba3cadba4d546ef30cb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Aug 2023 15:33:15 +0200 Subject: [PATCH 1705/2612] accesslist-duplicates: use /terminal/ask This was introduced in RouterOS 7.12beta1. --- accesslist-duplicates.capsman.rsc | 8 ++++---- accesslist-duplicates.local.rsc | 8 ++++---- accesslist-duplicates.template.rsc | 8 ++++---- accesslist-duplicates.wifiwave2.rsc | 8 ++++---- doc/accesslist-duplicates.md | 2 ++ 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index b986862..3fd688e 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2018-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12beta1 +# # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md # @@ -12,16 +14,14 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Read; - :local Seen ({}); :foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Mac [ /caps-man/access-list/get $AccList mac-address ]; :if ($Seen->$Mac = 1) do={ /caps-man/access-list/print where mac-address=$Mac; - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; + :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; diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index b136de3..c19be20 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2018-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12beta1 +# # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md # @@ -12,16 +14,14 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Read; - :local Seen ({}); :foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; :if ($Seen->$Mac = 1) do={ /interface/wireless/access-list/print where mac-address=$Mac; - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; + :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; diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index 1e5fc80..beb7ef2 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2018-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12beta1 +# # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md # @@ -13,8 +15,6 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Read; - :local Seen ({}); :foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ @@ -27,8 +27,8 @@ /caps-man/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; - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; + :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; diff --git a/accesslist-duplicates.wifiwave2.rsc b/accesslist-duplicates.wifiwave2.rsc index 4297898..c28a8f6 100644 --- a/accesslist-duplicates.wifiwave2.rsc +++ b/accesslist-duplicates.wifiwave2.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2018-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12beta1 +# # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md # @@ -12,16 +14,14 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Read; - :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; - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; + :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; diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index e3767e7..06295d9 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -3,6 +3,8 @@ Find and remove access list duplicates [âŦ…ī¸ Go back to main README](../README.md) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12beta1-yellow?style=flat)](https://mikrotik.com/download/changelogs/) + > â„šī¸ī¸ **Info**: This script can not be used on its own but requires the base > installation. See [main README](../README.md) for details. From ebce360a4e0adeda3f43d0b6b322bfd12964b45d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Aug 2023 15:40:22 +0200 Subject: [PATCH 1706/2612] doc/accesslist-duplicates: reference stable version --- doc/accesslist-duplicates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index 06295d9..ba5ac4b 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -3,7 +3,7 @@ Find and remove access list duplicates [âŦ…ī¸ Go back to main README](../README.md) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12beta1-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) > â„šī¸ī¸ **Info**: This script can not be used on its own but requires the base > installation. See [main README](../README.md) for details. From e36ac19c8b210ccdb83dc020ec0b381f310567da Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 18 Aug 2023 15:35:50 +0200 Subject: [PATCH 1707/2612] global-functions: drop $Read ... which is no longer required now that RouterOS 7.12beta1 provides /terminal/ask. --- global-functions.rsc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 5c6e3c5..90ed0b6 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -53,7 +53,6 @@ :global ParseKeyValueStore; :global PrettyPrint; :global RandomDelay; -:global Read; :global RequiredRouterOS; :global ScriptFromTerminal; :global ScriptInstallUpdate; @@ -804,11 +803,6 @@ :delay ([ $GetRandomNumber $1 ] . [ $EitherOr $2 "s" ]); } -# read input from user -:set Read do={ - :return; -} - # check for required RouterOS version :set RequiredRouterOS do={ :local Caller [ :tostr $1 ]; From dcca53e449e95c10e7a7d5830d704b173ffc191c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 10:41:01 +0100 Subject: [PATCH 1708/2612] hotspot-to-wpa: drop dead code --- hotspot-to-wpa.template.rsc | 1 - 1 file changed, 1 deletion(-) diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index f465722..c676fe6 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -101,7 +101,6 @@ $LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $ :local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; :if ([ :len $VlanMode] > 0) do={ /caps-man/access-list/set $Entry vlan-mode=$VlanMode; - /interface/wifiwave2/access-list/set $Entry vlan-mode=$VlanMode; } # NOT /interface/wifiwave2 # From 64bae1fd1b740ca0c9b4d51b920840c59ce5a469 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 14:04:30 +0100 Subject: [PATCH 1709/2612] doc/capsman-download-packages: hint on cleanup --- doc/capsman-download-packages.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index 8174c13..f6e6f96 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -45,6 +45,9 @@ If no packages are found the script tries to download missing packages for legacy CAPsMAN by guessing from system log. For `wifiwave2` a default set of packages (`routeros` and `wifiwave2` for *arm* and *arm64*) is downloaded. +> â„šī¸ **Info**: If you have packages in the directory and things go wrong for +> what ever unknown reason: Remove **all** packages and start over. + Usage and invocation -------------------- From 690953e4c53e6eef855de04659fefceb3906d2df Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 15:13:12 +0100 Subject: [PATCH 1710/2612] doc/collect-wireless-mac: fix copy-and-paste error --- doc/collect-wireless-mac.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 2b17055..6407c3a 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -28,7 +28,7 @@ or legacy wifi with CAPsMAN (`/caps-man`) or local wireless interface For `wifiwave2`: - $ScriptInstallUpdate collect-wireless-mac.capsman.wifiwave2; + $ScriptInstallUpdate collect-wireless-mac.wifiwave2; For legacy CAPsMAN: From 18360f92b377dbb42b9da5441270a6dcaee1bfbf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 17:31:34 +0100 Subject: [PATCH 1711/2612] capsman-download-packages: update template comment --- capsman-download-packages.template.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 71bced0..80f1988 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -7,8 +7,8 @@ # download and cleanup packages for CAP installation from CAPsMAN # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md # -# !! This is just a template! Replace '%PATH%' with 'caps-man', -# !! 'interface/wireless' or 'interface/wifiwave2'! +# !! This is just a template to generate the real script! +# !! Pattern '%TEMPL%' is replaced, paths are filtered. :local 0 "capsman-download-packages%TEMPL%"; :global GlobalFunctionsReady; From 0d530294f5f0608114c8f0cd409f0041bb2c1b74 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 17:31:42 +0100 Subject: [PATCH 1712/2612] capsman-rolling-upgrade: update template comment --- capsman-rolling-upgrade.template.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index 0890ad2..fc6872c 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -9,8 +9,8 @@ # upgrade CAPs one after another # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md # -# !! This is just a template! Replace '%PATH%' with 'caps-man', -# !! 'interface/wireless' or 'interface/wifiwave2'! +# !! This is just a template to generate the real script! +# !! Pattern '%TEMPL%' is replaced, paths are filtered. :local 0 "capsman-rolling-upgrade%TEMPL%"; :global GlobalFunctionsReady; From 4f04fa73fceb8841b61e4adedaab3cd4925dad00 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 22:26:22 +0100 Subject: [PATCH 1713/2612] mode-button: rename scheduler --- mode-button.rsc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mode-button.rsc b/mode-button.rsc index 87e8740..dae9d99 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -16,10 +16,10 @@ :set ($ModeButton->"count") ($ModeButton->"count" + 1); -:local Scheduler [ /system/scheduler/find where name="\$ModeButtonScheduler" ]; +:local Scheduler [ /system/scheduler/find where name="_ModeButtonScheduler" ]; :if ([ :len $Scheduler ] = 0) do={ - $LogPrintExit2 info $0 ("Creating scheduler \$ModeButtonScheduler, counting presses...") false; + $LogPrintExit2 info $0 ("Creating scheduler _ModeButtonScheduler, counting presses...") false; :global ModeButtonScheduler do={ :global ModeButton; @@ -44,7 +44,7 @@ :set ($ModeButton->"count") 0; :set ModeButtonScheduler; - /system/scheduler/remove [ find where name=$0 ]; + /system/scheduler/remove [ find where name="_ModeButtonScheduler" ]; :if ([ :len $Code ] > 0) do={ :if ([ $ValidateSyntax $Code ] = true) do={ @@ -68,9 +68,9 @@ $LogPrintExit2 info $0 ("No action defined for " . $Count . " mode-button presses.") false; } } - /system/scheduler/add name="\$ModeButtonScheduler" \ + /system/scheduler/add name="_ModeButtonScheduler" \ on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s; } else={ - $LogPrintExit2 debug $0 ("Updating scheduler \$ModeButtonScheduler...") false; + $LogPrintExit2 debug $0 ("Updating scheduler _ModeButtonScheduler...") false; /system/scheduler/set $Scheduler start-time=[ /system/clock/get time ]; } From f7c72b6ed96e45bf1fbb54c46ce09e1fccc791be Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 22:27:15 +0100 Subject: [PATCH 1714/2612] packages-update: rename scheduler --- packages-update.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index caaac6a..85a241a 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -95,8 +95,8 @@ $ScriptLock $0; $RandomDelay 3600; /system/reboot; } - /system/scheduler/add name="\$RebootForUpdate" start-time=03:00:00 interval=1d \ - on-event=("/system/scheduler/remove \"\\\$RebootForUpdate\"; " . \ + /system/scheduler/add name="_RebootForUpdate" start-time=03:00:00 interval=1d \ + on-event=("/system/scheduler/remove \"_RebootForUpdate\"; " . \ ":global RebootForUpdate; \$RebootForUpdate;"); $LogPrintExit2 info $0 ("Scheduled reboot for update between 03:00 and 04:00.") true; } From a5e2282d0fb44b67bcb8dcc5bc7068b395fdd973 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 22:34:45 +0100 Subject: [PATCH 1715/2612] mod/notification-email: rename scheduler --- mod/notification-email.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index a505a50..774af4c 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -26,7 +26,7 @@ :local AllDone true; :local QueueLen [ :len $EmailQueue ]; - :local Scheduler [ /system/scheduler/find where name=$0 ]; + :local Scheduler [ /system/scheduler/find where name="_FlushEmailQueue" ]; :if ([ :len $Scheduler ] > 0 && [ /system/scheduler/get $Scheduler interval ] < 1m) do={ /system/scheduler/set interval=1m comment="Doing initial checks..." $Scheduler; @@ -152,8 +152,8 @@ [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \ attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") }; - :if ([ :len [ /system/scheduler/find where name="\$FlushEmailQueue" ] ] = 0) do={ - /system/scheduler/add name="\$FlushEmailQueue" interval=1s start-time=startup \ + :if ([ :len [ /system/scheduler/find where name="_FlushEmailQueue" ] ] = 0) do={ + /system/scheduler/add name="_FlushEmailQueue" interval=1s start-time=startup \ comment="Queuing new mail..." on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); } } @@ -162,7 +162,7 @@ :set PurgeEMailQueue do={ :global EmailQueue; - /system/scheduler/remove [ find where name="\$FlushEmailQueue" ]; + /system/scheduler/remove [ find where name="_FlushEmailQueue" ]; :set EmailQueue; } From 5c2454be8b767550251172c7b234585de1ded268 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 22:35:06 +0100 Subject: [PATCH 1716/2612] mod/notification-matrix: rename scheduler --- mod/notification-matrix.rsc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index a8983a7..378faab 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -30,7 +30,7 @@ :local AllDone true; :local QueueLen [ :len $MatrixQueue ]; - :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ + :if ([ :len [ /system/scheduler/find where name="_FlushMatrixQueue" ] ] > 0 && $QueueLen = 0) do={ $LogPrintExit2 warning $0 ("Flushing Matrix messages from scheduler, but queue is empty.") false; } @@ -52,7 +52,7 @@ } :if ($AllDone = true && $QueueLen = [ :len $MatrixQueue ]) do={ - /system/scheduler/remove [ find where name=$0 ]; + /system/scheduler/remove [ find where name="_FlushMatrixQueue" ]; :set MatrixQueue; } } @@ -147,8 +147,8 @@ :set ($MatrixQueue->[ :len $MatrixQueue ]) { room=$Room; \ accesstoken=$AccessToken; homeserver=$HomeServer; \ plain=$Plain; formatted=$Formatted }; - :if ([ :len [ /system/scheduler/find where name="\$FlushMatrixQueue" ] ] = 0) do={ - /system/scheduler/add name="\$FlushMatrixQueue" interval=1m start-time=startup \ + :if ([ :len [ /system/scheduler/find where name="_FlushMatrixQueue" ] ] = 0) do={ + /system/scheduler/add name="_FlushMatrixQueue" interval=1m start-time=startup \ on-event=(":global FlushMatrixQueue; \$FlushMatrixQueue;"); } } @@ -158,7 +158,7 @@ :set PurgeMatrixQueue do={ :global MatrixQueue; - /system/scheduler/remove [ find where name="\$FlushMatrixQueue" ]; + /system/scheduler/remove [ find where name="_FlushMatrixQueue" ]; :set MatrixQueue; } From 75c41501c270a4e6fd2db34323f38e12cfdf86d9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 22:35:23 +0100 Subject: [PATCH 1717/2612] mod/notification-ntfy: rename scheduler --- mod/notification-ntfy.rsc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index e2fc558..5c0e9e5 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -28,7 +28,7 @@ :local AllDone true; :local QueueLen [ :len $NtfyQueue ]; - :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ + :if ([ :len [ /system/scheduler/find where name="_FlushNtfyQueue" ] ] > 0 && $QueueLen = 0) do={ $LogPrintExit2 warning $0 ("Flushing Ntfy messages from scheduler, but queue is empty.") false; } @@ -46,7 +46,7 @@ } :if ($AllDone = true && $QueueLen = [ :len $NtfyQueue ]) do={ - /system/scheduler/remove [ find where name=$0 ]; + /system/scheduler/remove [ find where name="_FlushNtfyQueue" ]; :set NtfyQueue; } } @@ -103,8 +103,8 @@ "This message was queued since " . [ /system/clock/get date ] . " " . \ [ /system/clock/get time ] . " and may be obsolete."); :set ($NtfyQueue->[ :len $NtfyQueue ]) { url=$Url; headers=$Headers; text=$Text }; - :if ([ :len [ /system/scheduler/find where name="\$FlushNtfyQueue" ] ] = 0) do={ - /system/scheduler/add name="\$FlushNtfyQueue" interval=1m start-time=startup \ + :if ([ :len [ /system/scheduler/find where name="_FlushNtfyQueue" ] ] = 0) do={ + /system/scheduler/add name="_FlushNtfyQueue" interval=1m start-time=startup \ on-event=(":global FlushNtfyQueue; \$FlushNtfyQueue;"); } } @@ -114,7 +114,7 @@ :set PurgeNtfyQueue do={ :global NtfyQueue; - /system/scheduler/remove [ find where name="\$FlushNtfyQueue" ]; + /system/scheduler/remove [ find where name="_FlushNtfyQueue" ]; :set NtfyQueue; } From 8c8f834179f0ab618f031ec50739bbafd4c4261e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 22:35:38 +0100 Subject: [PATCH 1718/2612] mod/notification-telegram: rename scheduler --- mod/notification-telegram.rsc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index b5729a4..66be7d3 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -29,7 +29,7 @@ :local AllDone true; :local QueueLen [ :len $TelegramQueue ]; - :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ + :if ([ :len [ /system/scheduler/find where name="_FlushTelegramQueue" ] ] > 0 && $QueueLen = 0) do={ $LogPrintExit2 warning $0 ("Flushing Telegram messages from scheduler, but queue is empty.") false; } @@ -51,7 +51,7 @@ } :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ - /system/scheduler/remove [ find where name=$0 ]; + /system/scheduler/remove [ find where name="_FlushTelegramQueue" ]; :set TelegramQueue; } } @@ -155,8 +155,8 @@ " " . [ /system/clock/get time ] . " and may be obsolete.") "plain" ]) ]); :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; text=$Text; silent=($Notification->"silent"); replyto=($Notification->"replyto") }; - :if ([ :len [ /system/scheduler/find where name="\$FlushTelegramQueue" ] ] = 0) do={ - /system/scheduler/add name="\$FlushTelegramQueue" interval=1m start-time=startup \ + :if ([ :len [ /system/scheduler/find where name="_FlushTelegramQueue" ] ] = 0) do={ + /system/scheduler/add name="_FlushTelegramQueue" interval=1m start-time=startup \ on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;"); } } @@ -166,7 +166,7 @@ :set PurgeTelegramQueue do={ :global TelegramQueue; - /system/scheduler/remove [ find where name="\$FlushTelegramQueue" ]; + /system/scheduler/remove [ find where name="_FlushTelegramQueue" ]; :set TelegramQueue; } From 448b44cde664a5da65c3b8726e8f512483693eca Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 10:10:56 +0100 Subject: [PATCH 1719/2612] Makefile: support new wifi package... ... introduced with RouterOS 7.13beta1. --- Makefile | 25 ++++++++++++++++--------- capsman-download-packages.template.rsc | 8 ++++---- capsman-rolling-upgrade.template.rsc | 4 ++-- daily-psk.template.rsc | 2 +- hotspot-to-wpa-cleanup.template.rsc | 4 ++-- hotspot-to-wpa.template.rsc | 8 ++++---- 6 files changed, 29 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 100aa78..b18b09a 100644 --- a/Makefile +++ b/Makefile @@ -4,31 +4,38 @@ CAPSMAN = $(wildcard *.capsman.rsc) LOCAL = $(wildcard *.local.rsc) +WIFI = $(wildcard *.wifi.rsc) WIFIWAVE2 = $(wildcard *.wifiwave2.rsc) MARKDOWN = $(wildcard *.md doc/*.md doc/mod/*.md) HTML = $(MARKDOWN:.md=.html) -all: $(CAPSMAN) $(LOCAL) $(WIFIWAVE2) $(HTML) +all: $(CAPSMAN) $(LOCAL) $(WIFI) $(WIFIWAVE2) $(HTML) %.html: %.md Makefile markdown $< | sed 's/href="\([-_\./[:alnum:]]*\)\.md"/href="\1.html"/g' > $@ -%.local.rsc: %.template.rsc Makefile - sed -e '/\/caps-man/d' -e '/\/interface\/wifiwave2/d' -e 's|%TEMPL%|.local|' \ - -e '/^# NOT \/interface\/wireless #$$/,/^# NOT \/interface\/wireless #$$/d' \ +%.capsman.rsc: %.template.rsc Makefile + sed -e '/\/interface\/wifi\//d' -e '/\/interface\/wifiwave2\//d' -e '/\/interface\/wireless\//d' -e 's|%TEMPL%|.capsman|' \ + -e '/^# NOT \/caps-man\/ #$$/,/^# NOT \/caps-man\/ #$$/d' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ -%.capsman.rsc: %.template.rsc Makefile - sed -e '/\/interface\/wifiwave2/d' -e '/\/interface\/wireless/d' -e 's|%TEMPL%|.capsman|' \ - -e '/^# NOT \/caps-man #$$/,/^# NOT \/caps-man #$$/d' \ +%.local.rsc: %.template.rsc Makefile + sed -e '/\/caps-man\//d' -e '/\/interface\/wifi\//d' -e '/\/interface\/wifiwave2\//d' -e 's|%TEMPL%|.local|' \ + -e '/^# NOT \/interface\/wireless\/ #$$/,/^# NOT \/interface\/wireless\/ #$$/d' \ + -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ + < $< > $@ + +%.wifi.rsc: %.template.rsc Makefile + sed -e '/\/caps-man\//d' -e '/\/interface\/wifiwave2\//d' -e '/\/interface\/wireless\//d' -e 's|%TEMPL%|.wifi|' \ + -e '/^# NOT \/interface\/wifi\/ #$$/,/^# NOT \/interface\/wifi\/ #$$/d' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ %.wifiwave2.rsc: %.template.rsc Makefile - sed -e '/\/caps-man/d' -e '/\/interface\/wireless/d' -e 's|%TEMPL%|.wifiwave2|' \ - -e '/^# NOT \/interface\/wifiwave2 #$$/,/^# NOT \/interface\/wifiwave2 #$$/d' \ + 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!' \ < $< > $@ diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 80f1988..88fda60 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -55,7 +55,7 @@ $WaitFullyConnected; } } -# NOT /interface/wifiwave2 # +# NOT /interface/wifiwave2/ # :if ([ :len [ /system/logging/find where topics~"error" !(topics~"!error") \ !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ $LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \ @@ -81,8 +81,8 @@ $WaitFullyConnected; :set Updated true; } } -# NOT /interface/wifiwave2 # -# NOT /caps-man # +# NOT /interface/wifiwave2/ # +# NOT /caps-man/ # :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={ @@ -93,7 +93,7 @@ $WaitFullyConnected; } } } -# NOT /caps-man # +# NOT /caps-man/ # :if ($Updated = true) do={ :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index fc6872c..7800eec 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -33,9 +33,9 @@ $ScriptLock $0; :local RemoteCapVal [ /caps-man/remote-cap/get $RemoteCap ]; :local RemoteCapVal [ /interface/wifiwave2/capsman/remote-cap/get $RemoteCap ]; :if ([ :len $RemoteCapVal ] > 1) do={ -# NOT /caps-man # +# NOT /caps-man/ # :set ($RemoteCapVal->"name") ($RemoteCapVal->"common-name"); -# NOT /caps-man # +# NOT /caps-man/ # $LogPrintExit2 info $0 ("Starting upgrade for " . $RemoteCapVal->"name" . \ " (" . $RemoteCapVal->"identity" . ")...") false; /caps-man/remote-cap/upgrade $RemoteCap; diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index ad9198a..1cb89d0 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -66,7 +66,7 @@ $WaitFullyConnected; :local Ssid [ /interface/wifiwave2/configuration/get $Configuration ssid ]; :local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ]; :local OldPsk [ /interface/wifiwave2/access-list/get $AccList passphrase ]; - # /caps-man /interface/wifiwave2 above - /interface/wireless below + # /caps-man/ /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 ]; diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 8cc732b..d033b20 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -4,9 +4,9 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 -# NOT /caps-man # +# NOT /caps-man/ # # requires RouterOS, version=7.12beta3 -# NOT /caps-man # +# NOT /caps-man/ # # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index c676fe6..5443271 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -74,9 +74,9 @@ $LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $ :local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ :local Entry [ /interface/wifiwave2/access-list/find where mac-address=$MacAddress \ comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; -# NOT /caps-man # +# NOT /caps-man/ # :set ($Template->"private-passphrase") ($Template->"passphrase"); -# NOT /caps-man # +# NOT /caps-man/ # :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; :if ([ :len $PrivatePassphrase ] > 0) do={ :if ($PrivatePassphrase = "ignore") do={ @@ -97,12 +97,12 @@ $LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $ /caps-man/access-list/set $Entry vlan-id=$VlanId; /interface/wifiwave2/access-list/set $Entry vlan-id=$VlanId; } -# NOT /interface/wifiwave2 # +# NOT /interface/wifiwave2/ # :local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; :if ([ :len $VlanMode] > 0) do={ /caps-man/access-list/set $Entry vlan-mode=$VlanMode; } -# NOT /interface/wifiwave2 # +# NOT /interface/wifiwave2/ # :delay 2s; /caps-man/access-list/set $Entry action=accept; From ba406ae0fe7fedb60a80c6a142b2ec280d478984 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 10:19:05 +0100 Subject: [PATCH 1720/2612] accesslist-duplicates: support new wifi package --- accesslist-duplicates.template.rsc | 4 ++++ accesslist-duplicates.wifi.rsc | 31 ++++++++++++++++++++++++++++++ doc/accesslist-duplicates.md | 15 ++++++++++----- 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 accesslist-duplicates.wifi.rsc diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index beb7ef2..c83b428 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -18,13 +18,16 @@ :local Seen ({}); :foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ +:foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :foreach AccList in=[ /interface/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!" ] ]; @@ -32,6 +35,7 @@ :if ([ :typeof $Remove ] = "num") do={ :put ("Removing numeric id " . $Remove . "...\n"); /caps-man/access-list/remove $Remove; + /interface/wifi/access-list/remove $Remove; /interface/wifiwave2/access-list/remove $Remove; /interface/wireless/access-list/remove $Remove; } diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc new file mode 100644 index 0000000..4ca8be8 --- /dev/null +++ b/accesslist-duplicates.wifi.rsc @@ -0,0 +1,31 @@ +#!rsc by RouterOS +# RouterOS script: accesslist-duplicates.wifi +# Copyright (c) 2018-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12beta1 +# +# print duplicate antries in wireless access list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "accesslist-duplicates.wifi"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:local Seen ({}); + +:foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ + :local Mac [ /interface/wifi/access-list/get $AccList mac-address ]; + :if ($Seen->$Mac = 1) do={ + /interface/wifi/access-list/print where mac-address=$Mac; + :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; + + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /interface/wifi/access-list/remove $Remove; + } + } + :set ($Seen->$Mac) 1; +} diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index ba5ac4b..7cb0bc2 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -17,11 +17,16 @@ entries in wireless access list. Requirements and installation ----------------------------- -Depending on whether you use `wifiwave2` package (`/interface/wifiwave2`) -or legacy wifi with CAPsMAN (`/caps-man`) or local wireless interface -(`/interface/wireless`) you need to install a different script. +Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` +package (`/interface/wifiwave2`), legacy wifi with CAPsMAN (`/caps-man`) +or local wireless interface (`/interface/wireless`) you need to install a +different script. -For `wifiwave2`: +For `wifi` (RouterOS 7.13 and later): + + $ScriptInstallUpdate accesslist-duplicates.wifi; + +For `wifiwave2` (up to RouterOS 7.12): $ScriptInstallUpdate accesslist-duplicates.wifiwave2; @@ -38,7 +43,7 @@ Usage and invocation Run this script from a terminal: - /system/script/run accesslist-duplicates.local; + /system/script/run accesslist-duplicates.wifi; ![screenshot: example](accesslist-duplicates.d/01-example.avif) From 5eb130f0fc137bc3fa02d6a28b75f2c9a3b101de Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 10:26:06 +0100 Subject: [PATCH 1721/2612] capsman-download-packages: support new wifi package --- capsman-download-packages.template.rsc | 9 ++++ capsman-download-packages.wifi.rsc | 74 ++++++++++++++++++++++++++ doc/capsman-download-packages.md | 29 +++++++--- 3 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 capsman-download-packages.wifi.rsc diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 88fda60..7b37c36 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -25,6 +25,7 @@ $ScriptLock $0; $WaitFullyConnected; :local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; +:local PackagePath [ $CleanFilePath [ /interface/wifi/capsman/get package-path ] ]; :local PackagePath [ $CleanFilePath [ /interface/wifiwave2/capsman/get package-path ] ]; :local InstalledVersion [ /system/package/update/get installed-version ]; :local Updated false; @@ -55,6 +56,7 @@ $WaitFullyConnected; } } +# NOT /interface/wifi/ # # NOT /interface/wifiwave2/ # :if ([ :len [ /system/logging/find where topics~"error" !(topics~"!error") \ !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ @@ -82,11 +84,17 @@ $WaitFullyConnected; } } # NOT /interface/wifiwave2/ # +# NOT /interface/wifi/ # # NOT /caps-man/ # :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={ +# NOT /interface/wifi/ # :foreach Package in={ "routeros"; "wifiwave2" } do={ +# NOT /interface/wifi/ # +# NOT /interface/wifiwave2/ # + :foreach Package in={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" } do={ +# NOT /interface/wifiwave2/ # :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ :set Updated true; } @@ -101,6 +109,7 @@ $WaitFullyConnected; /system/script/run $Script; } else={ /caps-man/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 ]; } } diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc new file mode 100644 index 0000000..3552924 --- /dev/null +++ b/capsman-download-packages.wifi.rsc @@ -0,0 +1,74 @@ +#!rsc by RouterOS +# RouterOS script: capsman-download-packages.wifi +# Copyright (c) 2018-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# download and cleanup packages for CAP installation from CAPsMAN +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "capsman-download-packages.wifi"; +: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/wifi/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"; "wifi-qcom"; "wifi-qcom-ac" } do={ + :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ + :set Updated true; + } + } + } +} + +:if ($Updated = true) do={ + :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); + :if ([ :len $Script ] > 0) do={ + /system/script/run $Script; + } else={ + /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; + } +} diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index f6e6f96..ccd2ee5 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -18,11 +18,16 @@ This script automatically downloads these packages. Requirements and installation ----------------------------- -Just install the script on CAPsMAN device. Depending on whether you use -`wifiwave2` package (`/interface/wifiwave2`) or legacy wifi with CAPsMAN -(`/caps-man`) you need to install a different script. +Just install the script on CAPsMAN device. +Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` +package (`/interface/wifiwave2`) or legacy wifi with CAPsMAN (`/caps-man`) +you need to install a different script. -For `wifiwave2`: +For `wifi` (RouterOS 7.13 and later): + + $ScriptInstallUpdate capsman-download-packages.wifi; + +For `wifiwave2` (up to RouterOS 7.12): $ScriptInstallUpdate capsman-download-packages.wifiwave2; @@ -30,7 +35,12 @@ For legacy CAPsMAN: $ScriptInstallUpdate capsman-download-packages.capsman; -Optionally add a scheduler to run after startup. For `wifiwave2`: +Optionally add a scheduler to run after startup. For `wifi` (RouterOS 7.13 +and later): + + /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; @@ -42,8 +52,11 @@ Packages available in local storage in older version are downloaded unconditionally. If no packages are found the script tries to download missing packages for -legacy CAPsMAN by guessing from system log. For `wifiwave2` a default set -of packages (`routeros` and `wifiwave2` for *arm* and *arm64*) is downloaded. +legacy CAPsMAN by guessing from system log. For `wifi` and `wifiwave2` a +default set of packages is downloaded. + + * `wifi`: `routeros`, `wifi-qcom` and `wifi-qcom-ac` for *arm* and *arm64* + * `wifiwave2`: `routeros` and `wifiwave2` for *arm* and *arm64* > â„šī¸ **Info**: If you have packages in the directory and things go wrong for > what ever unknown reason: Remove **all** packages and start over. @@ -53,7 +66,7 @@ Usage and invocation Run the script manually: - /system/script/run capsman-download-packages.wifiwave2; + /system/script/run capsman-download-packages.wifi; ... or from scheduler. From cf4f0c5c936ba895c6d17e580b61755ca8e6bdd5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 10:28:12 +0100 Subject: [PATCH 1722/2612] capsman-rolling-upgrade: support new wifi package --- capsman-rolling-upgrade.template.rsc | 4 +++ capsman-rolling-upgrade.wifi.rsc | 41 ++++++++++++++++++++++++++++ doc/capsman-rolling-upgrade.md | 15 ++++++---- 3 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 capsman-rolling-upgrade.wifi.rsc diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index 7800eec..10245b5 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -24,13 +24,16 @@ $ScriptLock $0; :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 ] ]; :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/ # @@ -39,6 +42,7 @@ $ScriptLock $0; $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; diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc new file mode 100644 index 0000000..3e13bf4 --- /dev/null +++ b/capsman-rolling-upgrade.wifi.rsc @@ -0,0 +1,41 @@ +#!rsc by RouterOS +# RouterOS script: capsman-rolling-upgrade.wifi +# Copyright (c) 2018-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: capsman-rolling-upgrade +# +# 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 "capsman-rolling-upgrade.wifi"; +: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/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"); + } +} diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index 5c038e9..bbc8e14 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -20,11 +20,16 @@ parallel. Requirements and installation ----------------------------- -Just install the script on CAPsMAN device. Depending on whether you use -`wifiwave2` package (`/interface/wifiwave2`) or legacy wifi with CAPsMAN -(`/caps-man`) you need to install a different script. +Just install the script on CAPsMAN device. +Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` +package (`/interface/wifiwave2`) or legacy wifi with CAPsMAN (`/caps-man`) +you need to install a different script. -For `wifiwave2`: +For `wifi` (RouterOS 7.13 and later): + + $ScriptInstallUpdate capsman-rolling-upgrade.wifi; + +For `wifiwave2` (up to RouterOS 7.12): $ScriptInstallUpdate capsman-rolling-upgrade.wifiwave2; @@ -41,7 +46,7 @@ that script when required. Alternatively run it manually: - /system/script/run capsman-rolling-upgrade.wifiwave2; + /system/script/run capsman-rolling-upgrade.wifi; See also -------- From d598b2d70e27df5376f4433cef3dc2e6b34c0f0a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 10:29:42 +0100 Subject: [PATCH 1723/2612] collect-wireless-mac: support new wifi package --- collect-wireless-mac.template.rsc | 8 +++ collect-wireless-mac.wifi.rsc | 90 +++++++++++++++++++++++++++++++ doc/collect-wireless-mac.md | 13 +++-- 3 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 collect-wireless-mac.wifi.rsc diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index 75073a4..97760d6 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -29,23 +29,28 @@ $ScriptLock $0 false 10; :if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ +:if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ :if ([ :len [ /interface/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={ @@ -54,11 +59,13 @@ $ScriptLock $0 false 10; :if ([ :len ($RegVal->"mac-address") ] > 0) do={ :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); + :local AccessList ([ /interface/wifi/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :local AccessList ([ /interface/wifiwave2/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ [ /caps-man/access-list/get $AccessList comment ]) false; + [ /interface/wifi/access-list/get $AccessList comment ]) false; [ /interface/wifiwave2/access-list/get $AccessList comment ]) false; [ /interface/wireless/access-list/get $AccessList comment ]) false; } @@ -87,6 +94,7 @@ $ScriptLock $0 false 10; "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; \ diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc new file mode 100644 index 0000000..40ad4d2 --- /dev/null +++ b/collect-wireless-mac.wifi.rsc @@ -0,0 +1,90 @@ +#!rsc by RouterOS +# RouterOS script: collect-wireless-mac.wifi +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=40 +# +# 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 "collect-wireless-mac.wifi"; +: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/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ + /interface/wifi/access-list/add comment="--- collected above ---" disabled=yes; + $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={ + :local AccessList ([ /interface/wifi/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/wifi/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/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; + } +} diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 6407c3a..e73cf58 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -22,11 +22,16 @@ and modify it to your needs. Requirements and installation ----------------------------- -Depending on whether you use `wifiwave2` package (`/interface/wifiwave2`) -or legacy wifi with CAPsMAN (`/caps-man`) or local wireless interface -(`/interface/wireless`) you need to install a different script. +Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` +package (`/interface/wifiwave2`), legacy wifi with CAPsMAN (`/caps-man`) +or local wireless interface (`/interface/wireless`) you need to install a +different script. -For `wifiwave2`: +For `wifi` (RouterOS 7.13 and later): + + $ScriptInstallUpdate collect-wireless-mac.wifi; + +For `wifiwave2` (up to RouterOS 7.12): $ScriptInstallUpdate collect-wireless-mac.wifiwave2; From 53103be32469cd58f0eafff64dbaa4a34fd29a3f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 10:31:40 +0100 Subject: [PATCH 1724/2612] daily-psk: support new wifi package --- daily-psk.template.rsc | 9 ++++- daily-psk.wifi.rsc | 85 ++++++++++++++++++++++++++++++++++++++++++ doc/daily-psk.md | 22 ++++++++--- 3 files changed, 109 insertions(+), 7 deletions(-) create mode 100644 daily-psk.wifi.rsc diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 1cb89d0..e7d9b54 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -56,17 +56,22 @@ $WaitFullyConnected; :local NewPsk [ $GeneratePSK $Date ]; :foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ +:foreach AccList in=[ /interface/wifi/access-list/find where comment~$DailyPskMatchComment ] do={ :foreach AccList in=[ /interface/wifiwave2/access-list/find where comment~$DailyPskMatchComment ] do={ :foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; + :local SsidRegExp [ /interface/wifi/access-list/get $AccList ssid-regexp ]; :local 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/wifiwave2/ above - /interface/wireless/ below + # /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 ]; @@ -75,10 +80,12 @@ $WaitFullyConnected; :if ($NewPsk != $OldPsk) do={ $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; /caps-man/access-list/set $AccList private-passphrase=$NewPsk; + /interface/wifi/access-list/set $AccList passphrase=$NewPsk; /interface/wifiwave2/access-list/set $AccList passphrase=$NewPsk; /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ + :if ([ :len [ /interface/wifi/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ :if ([ :len [ /interface/wifiwave2/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ :if ($Seen->$Ssid = 1) do={ diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc new file mode 100644 index 0000000..a8b1320 --- /dev/null +++ b/daily-psk.wifi.rsc @@ -0,0 +1,85 @@ +#!rsc by RouterOS +# RouterOS script: daily-psk.wifi +# Copyright (c) 2013-2023 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update daily PSK (pre shared key) +# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "daily-psk.wifi"; +: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/wifi/access-list/find where comment~$DailyPskMatchComment ] do={ + :local SsidRegExp [ /interface/wifi/access-list/get $AccList ssid-regexp ]; + :local Configuration ([ /interface/wifi/configuration/find where ssid~$SsidRegExp ]->0); + :local Ssid [ /interface/wifi/configuration/get $Configuration ssid ]; + :local OldPsk [ /interface/wifi/access-list/get $AccList passphrase ]; + :local Skip 0; + + :if ($NewPsk != $OldPsk) do={ + $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + /interface/wifi/access-list/set $AccList passphrase=$NewPsk; + + :if ([ :len [ /interface/wifi/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ + :if ($Seen->$Ssid = 1) do={ + $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; + } + } + } +} diff --git a/doc/daily-psk.md b/doc/daily-psk.md index f551e46..6eb656c 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -21,12 +21,18 @@ Requirements and installation Just install this script. -Depending on whether you use `wifiwave2` package (`/interface/wifiwave2`) -or legacy wifi with CAPsMAN (`/caps-man`) or local wireless interface -(`/interface/wireless`) you need to install a different script and add -schedulers to run the script: +Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` +package (`/interface/wifiwave2`), legacy wifi with CAPsMAN (`/caps-man`) +or local wireless interface (`/interface/wireless`) you need to install a +different script and add schedulers to run the script: -For `wifiwave2`: +For `wifi` (RouterOS 7.13 and later): + + $ScriptInstallUpdate daily-psk.wifi; + /system/scheduler/add interval=1d name=daily-psk on-event="/system/script/run daily-psk.wifi;" start-time=03:00:00; + /system/scheduler/add name=daily-psk@startup on-event="/system/script/run daily-psk.wifi;" start-time=startup; + +For `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; @@ -58,7 +64,11 @@ The configuration goes to `global-config-overlay`, these are the parameters: > [`global-config`](../global-config.rsc) (the one without `-overlay`) to > your local `global-config-overlay` and modify it to your specific needs. -Then add an access list entry. For `wifiwave2`: +Then add an access list entry. For `wifi` (RouterOS 7.13 and later): + + /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"; From fe1f4385029f4ab43880eebfd2491ba668caa7e5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 10:35:17 +0100 Subject: [PATCH 1725/2612] dhcp-lease-comment: support new wifi package --- dhcp-lease-comment.template.rsc | 2 ++ dhcp-lease-comment.wifi.rsc | 33 +++++++++++++++++++++++++++++++++ doc/dhcp-lease-comment.md | 13 +++++++++---- 3 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 dhcp-lease-comment.wifi.rsc diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index 0f16285..05b1254 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -24,10 +24,12 @@ $ScriptLock $0; :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/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 ]; } diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc new file mode 100644 index 0000000..fe34b09 --- /dev/null +++ b/dhcp-lease-comment.wifi.rsc @@ -0,0 +1,33 @@ +#!rsc by RouterOS +# RouterOS script: dhcp-lease-comment.wifi +# Copyright (c) 2013-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=60 +# +# update dhcp-server lease comment with infos from access-list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "dhcp-lease-comment.wifi"; +: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/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; + /ip/dhcp-server/lease/set comment=$NewComment $Lease; + } +} diff --git a/doc/dhcp-lease-comment.md b/doc/dhcp-lease-comment.md index cd29641..ae0edfb 100644 --- a/doc/dhcp-lease-comment.md +++ b/doc/dhcp-lease-comment.md @@ -15,11 +15,16 @@ from wireless access list. Requirements and installation ----------------------------- -Depending on whether you use `wifiwave2` package (`/interface/wifiwave2`) -or legacy wifi with CAPsMAN (`/caps-man`) or local wireless interface -(`/interface/wireless`) you need to install a different script. +Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` +package (`/interface/wifiwave2`), legacy wifi with CAPsMAN (`/caps-man`) +or local wireless interface (`/interface/wireless`) you need to install a +different script. -For `wifiwave2`: +For `wifi` (RouterOS 7.13 and later): + + $ScriptInstallUpdate dhcp-lease-comment.wifi; + +For `wifiwave2` (up to RouterOS 7.12): $ScriptInstallUpdate dhcp-lease-comment.wifiwave2; From 97383dfbfb872b62ec68e654c2966745943d4cca Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 10:36:22 +0100 Subject: [PATCH 1726/2612] hotspot-to-wpa{,-cleanup}: support new wifi package --- doc/hotspot-to-wpa.md | 28 ++++++++-- hotspot-to-wpa-cleanup.template.rsc | 6 ++ hotspot-to-wpa-cleanup.wifi.rsc | 69 +++++++++++++++++++++++ hotspot-to-wpa.template.rsc | 16 ++++++ hotspot-to-wpa.wifi.rsc | 86 +++++++++++++++++++++++++++++ 5 files changed, 199 insertions(+), 6 deletions(-) create mode 100644 hotspot-to-wpa-cleanup.wifi.rsc create mode 100644 hotspot-to-wpa.wifi.rsc diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index 4909eef..f0ffce9 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -19,11 +19,18 @@ Requirements and installation You need a properly configured hotspot on one (open) SSID and a WP2 enabled SSID with suffix "`-wpa`". -Then install the script. Depending on whether you use `wifiwave2` package -(`/interface/wifiwave2`) or legacy wifi with CAPsMAN (`/caps-man`) you need -to install a different script and set it as `on-login` script in hotspot. +Then install the script. +Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` +package (`/interface/wifiwave2`) or legacy wifi with CAPsMAN (`/caps-man`) +you need to install a different script and set it as `on-login` script in +hotspot. -For `wifiwave2`: +For `wifi` (RouterOS 7.13 and later): + + $ScriptInstallUpdate hotspot-to-wpa.wifi; + /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 ]; @@ -39,7 +46,12 @@ With just `hotspot-to-wpa` installed the mac addresses will last in the access list forever. Install the optional script for automatic cleanup and add a scheduler. -For `wifiwave2`: +For `wifi` (RouterOS 7.13 and later): + + $ScriptInstallUpdate hotspot-to-wpa-cleanup.wifi,lease-script; + /system/scheduler/add interval=1d name=hotspot-to-wpa-cleanup on-event="/system/script/run hotspot-to-wpa-cleanup.wifi;" start-time=startup; + +For `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; @@ -86,7 +98,11 @@ Additionally templates can be created to give more options for access list: * `vlan-mode`: set the VLAN mode for device For a hotspot called `example` the template could look like this. For -`wifiwave2`: +`wifi` (RouterOS 7.13 and later): + + /interface/wifi/access-list/add comment="hotspot-to-wpa template example" disabled=yes private-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 private-passphrase="ignore" ssid-regexp="^example\$" vlan-id=10; diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index d033b20..0f89cec 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -36,8 +36,10 @@ $ScriptLock $0 false 10; } :foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ +:foreach Client in=[ /interface/wifi/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ :foreach Client in=[ /interface/wifiwave2/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ :local ClientVal [ /caps-man/registration-table/get $Client ]; + :local ClientVal [ /interface/wifi/registration-table/get $Client ]; :local ClientVal [ /interface/wifiwave2/registration-table/get $Client ]; :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ mac-address=($ClientVal->"mac-address") ] do={ @@ -51,15 +53,18 @@ $ScriptLock $0 false 10; } :foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \ +:foreach Client in=[ /interface/wifi/access-list/find where comment~"^hotspot-to-wpa:" \ :foreach Client in=[ /interface/wifiwave2/access-list/find where comment~"^hotspot-to-wpa:" \ !(comment~[ /system/clock/get date ]) ] do={ :local ClientVal [ /caps-man/access-list/get $Client ]; + :local ClientVal [ /interface/wifi/access-list/get $Client ]; :local ClientVal [ /interface/wifiwave2/access-list/get $Client ]; :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ mac-address=($ClientVal->"mac-address") ] ] = 0) do={ $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ " did not connect to WPA, removing from access list.") false; /caps-man/access-list/remove $Client; + /interface/wifi/access-list/remove $Client; /interface/wifiwave2/access-list/remove $Client; } } @@ -71,6 +76,7 @@ $ScriptLock $0 false 10; $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ + /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ /interface/wifiwave2/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ mac-address=($LeaseVal->"mac-address") ]; /ip/dhcp-server/lease/remove $Lease; diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc new file mode 100644 index 0000000..1cee316 --- /dev/null +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -0,0 +1,69 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa-cleanup.wifi +# Copyright (c) 2021-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=80 +# requires RouterOS, version=7.12beta3 +# +# manage and clean up private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "hotspot-to-wpa-cleanup.wifi"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global EitherOr; +:global LogPrintExit2; +:global ParseKeyValueStore; +:global ScriptLock; + +$ScriptLock $0 false 10; + +:local DHCPServers ({}); +:foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ + :local ServerVal [ /ip/dhcp-server/get $Server ] + :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; + :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ + :set ($DHCPServers->($ServerVal->"name")) \ + [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; + } +} + +:foreach Client in=[ /interface/wifi/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ + :local ClientVal [ /interface/wifi/registration-table/get $Client ]; + :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ + mac-address=($ClientVal->"mac-address") ] do={ + :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ + $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ + " connected to WPA, making lease static.") false; + /ip/dhcp-server/lease/make-static $Lease; + /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; + } + } +} + +:foreach Client in=[ /interface/wifi/access-list/find where comment~"^hotspot-to-wpa:" \ + !(comment~[ /system/clock/get date ]) ] do={ + :local ClientVal [ /interface/wifi/access-list/get $Client ]; + :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ + mac-address=($ClientVal->"mac-address") ] ] = 0) do={ + $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ + " did not connect to WPA, removing from access list.") false; + /interface/wifi/access-list/remove $Client; + } +} + +:foreach Server,Timeout in=$DHCPServers do={ + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ + server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ + " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; + /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ + mac-address=($LeaseVal->"mac-address") ]; + /ip/dhcp-server/lease/remove $Lease; + } +} diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index 5443271..a858285 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -36,22 +36,28 @@ $ScriptLock $0; :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; :if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ +:if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ :if ([ :len [ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; /interface/wifiwave2/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; } :local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); +:local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); :local PlaceBefore ([ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); :if ([ :len [ /caps-man/access-list/find where \ +:if ([ :len [ /interface/wifi/access-list/find where \ :if ([ :len [ /interface/wifiwave2/access-list/find where \ comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; /interface/wifiwave2/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; } :local Template [ /caps-man/access-list/get ([ find where \ +:local Template [ /interface/wifi/access-list/get ([ find where \ :local Template [ /interface/wifiwave2/access-list/get ([ find where \ comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; @@ -65,13 +71,16 @@ $ScriptLock $0; $LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \ " (user " . $UserName . ").") false; /caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; +/interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; /interface/wifiwave2/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; /caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ +/interface/wifi/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ /interface/wifiwave2/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ action=reject place-before=$PlaceBefore; :local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ +:local Entry [ /interface/wifi/access-list/find where mac-address=$MacAddress \ :local Entry [ /interface/wifiwave2/access-list/find where mac-address=$MacAddress \ comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; # NOT /caps-man/ # @@ -81,29 +90,36 @@ $LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $ :if ([ :len $PrivatePassphrase ] > 0) do={ :if ($PrivatePassphrase = "ignore") do={ /caps-man/access-list/set $Entry !private-passphrase; + /interface/wifi/access-list/set $Entry !passphrase; /interface/wifiwave2/access-list/set $Entry !passphrase; } else={ /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; + /interface/wifi/access-list/set $Entry passphrase=$PrivatePassphrase; /interface/wifiwave2/access-list/set $Entry passphrase=$PrivatePassphrase; } } :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; :if ([ :len $SsidRegexp ] > 0) do={ /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; + /interface/wifi/access-list/set $Entry ssid-regexp=$SsidRegexp; /interface/wifiwave2/access-list/set $Entry ssid-regexp=$SsidRegexp; } :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; :if ([ :len $VlanId ] > 0) do={ /caps-man/access-list/set $Entry vlan-id=$VlanId; + /interface/wifi/access-list/set $Entry vlan-id=$VlanId; /interface/wifiwave2/access-list/set $Entry vlan-id=$VlanId; } +# NOT /interface/wifi/ # # NOT /interface/wifiwave2/ # :local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; :if ([ :len $VlanMode] > 0) do={ /caps-man/access-list/set $Entry vlan-mode=$VlanMode; } # NOT /interface/wifiwave2/ # +# NOT /interface/wifi/ # :delay 2s; /caps-man/access-list/set $Entry action=accept; +/interface/wifi/access-list/set $Entry action=accept; /interface/wifiwave2/access-list/set $Entry action=accept; diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc new file mode 100644 index 0000000..f7c99a9 --- /dev/null +++ b/hotspot-to-wpa.wifi.rsc @@ -0,0 +1,86 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa.wifi +# Copyright (c) 2019-2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# add private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# +# !! Do not edit this file, it is generated from template! + +:local 0 "hotspot-to-wpa.wifi"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global EitherOr; +:global LogPrintExit2; +:global ParseKeyValueStore; +:global ScriptLock; + +$ScriptLock $0; + +:local MacAddress $"mac-address"; +:local UserName $username; + +:if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ + $LogPrintExit2 error $0 ("This script is supposed to run from hotspot on login.") true; +} + +:local Date [ /system/clock/get date ]; +:local UserVal ({}); +:if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ + :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; +} +:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; +:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; + +:if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; +} +:local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + +:if ([ :len [ /interface/wifi/access-list/find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ + /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; +} +:local Template [ /interface/wifi/access-list/get ([ find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; + +:if ($Template->"action" = "reject") do={ + $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; +} + +# allow login page to load +:delay 1s; + +$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ").") false; +/interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; +/interface/wifi/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + action=reject place-before=$PlaceBefore; + +:local Entry [ /interface/wifi/access-list/find where mac-address=$MacAddress \ + comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; +:set ($Template->"private-passphrase") ($Template->"passphrase"); +:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; +:if ([ :len $PrivatePassphrase ] > 0) do={ + :if ($PrivatePassphrase = "ignore") do={ + /interface/wifi/access-list/set $Entry !passphrase; + } else={ + /interface/wifi/access-list/set $Entry passphrase=$PrivatePassphrase; + } +} +:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; +:if ([ :len $SsidRegexp ] > 0) do={ + /interface/wifi/access-list/set $Entry ssid-regexp=$SsidRegexp; +} +:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; +:if ([ :len $VlanId ] > 0) do={ + /interface/wifi/access-list/set $Entry vlan-id=$VlanId; +} + +:delay 2s; +/interface/wifi/access-list/set $Entry action=accept; From 4c3430fbb66489e11174caed38ccf8593d5903cb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 17:39:41 +0100 Subject: [PATCH 1727/2612] notify about parted scripts for wifi package --- global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 90ed0b6..f0446bd 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 113; +:global ExpectedConfigVersion 114; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 64e114f..d0b3820 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -27,6 +27,7 @@ 111="Modified 'dhcp-to-dns' to allow multiple records for one mac address."; 112="Enhanced 'mod/ssh-keys-import' to record the fingerprint of keys."; 113="Added helper functions for easier setup to Matrix notification module."; + 114="All relevant scripts were ported to new wifi package for RouterOS 7.13 and later. Migration is complex and thus not done automatically!"; }; # Migration steps to be applied on script updates From 890cd6c58d3de7e91a95c4593243d30f1b6234af Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 11:36:47 +0100 Subject: [PATCH 1728/2612] global-functions: introduce $HumanReadableNum --- global-functions.rsc | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index f0446bd..090269d 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -38,6 +38,7 @@ :global GetRandomNumber; :global Grep; :global HexToNum; +:global HumanReadableNum; :global IfThenElse; :global IsDefaultRouteReachable; :global IsDNSResolving; @@ -465,6 +466,36 @@ :return $Return; } +# return human readable number +:global HumanReadableNum do={ + :local Input [ :tonum $1 ]; + :local Base [ :tonum $2 ]; + + :global EitherOr; + + :local Prefix "kMGTPE"; + :local Pow 1; + + :set Base [ $EitherOr $Base 1024 ]; + + :if ($Input < $Base) do={ + :return $Input; + } + + :for I from=0 to=[ :len $Prefix ] do={ + :set Pow ($Pow * $Base); + :if ($Input / $Base < $Pow) do={ + :set Prefix [ :pick $Prefix $I ]; + :local Tmp1 ($Input * 100 / $Pow); + :local Tmp2 ($Tmp1 / 100); + :if ($Tmp2 >= 100) do={ + :return ($Tmp2 . $Prefix); + } + :return ($Tmp2 . "." . [ :pick $Tmp1 [ :len $Tmp2 ] ([ :len $Tmp1 ] - [ :len $Tmp2 ] + 1) ] . $Prefix); + } + } +} + # mimic conditional/ternary operator (condition ? consequent : alternative) :set IfThenElse do={ :if ([ :tostr $1 ] = "true" || [ :tobool $1 ] = true) do={ From 180d6b8733504cab058aaf4928a54e24b980c696 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 11:44:38 +0100 Subject: [PATCH 1729/2612] backup-cloud: use $HumanReadableNum for file size --- backup-cloud.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 934edb9..c1bbe11 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -18,6 +18,7 @@ :global DeviceInfo; :global FormatLine; +:global HumanReadableNum; :global LogPrintExit2; :global RandomDelay; :global ScriptFromTerminal; @@ -51,7 +52,7 @@ $WaitFullyConnected; message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ [ $FormatLine "Name" ($Cloud->"name") ] . "\n" . \ - [ $FormatLine "Size" ($Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)") ] . "\n" . \ + [ $FormatLine "Size" ([ $HumanReadableNum ($Cloud->"size") 1024 ] . "iB") ] . "\n" . \ [ $FormatLine "Download key" ($Cloud->"secret-download-key") ]); silent=true }); } on-error={ $SendNotification2 ({ origin=$0; \ From 4d70b7fea4f744df13591b0535a68cd48a092165 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 14:06:40 +0100 Subject: [PATCH 1730/2612] backup-upload: give more info on files --- backup-upload.rsc | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 4c8af4a..46b4c7b 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -26,6 +26,7 @@ :global CharacterReplace; :global DeviceInfo; :global FormatLine; +:global HumanReadableNum; :global IfThenElse; :global LogPrintExit2; :global MkDir; @@ -70,7 +71,8 @@ $WaitFullyConnected; :do { /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \ user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".backup"); - :set BackupFile ($FileName . ".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"; @@ -88,7 +90,8 @@ $WaitFullyConnected; :do { /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \ user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".rsc"); - :set ExportFile ($FileName . ".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"; @@ -108,7 +111,8 @@ $WaitFullyConnected; :do { /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \ user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf.txt"); - :set ConfigFile ($FileName . ".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"; @@ -124,9 +128,18 @@ $SendNotification2 ({ origin=$0; \ ([ $SymbolForNotification "floppy-disk,up-arrow" ] . "Backup & Config upload") ]; \ message=("Backup and config export upload for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ - [ $FormatLine "Backup file" $BackupFile ] . "\n" . \ - [ $FormatLine "Export file" $ExportFile ] . "\n" . \ - [ $FormatLine "Config file" $ConfigFile ]); silent=true }); + [ $IfThenElse ([ :typeof $BackupFile ] = "array") \ + ("Backup file:\n" . [ $FormatLine " name" ($BackupFile->"name") ] . "\n" . \ + [ $FormatLine " size" [ $HumanReadableNum ($BackupFile->"size") 1024 ] ]) \ + [ $FormatLine "Backup file" $BackupFile ] ] . "\n" . \ + [ $IfThenElse ([ :typeof $ExportFile ] = "array") \ + ("Export file:\n" . [ $FormatLine " name" ($ExportFile->"name") ] . "\n" . \ + [ $FormatLine " size" [ $HumanReadableNum ($ExportFile->"size") 1024 ] ]) \ + [ $FormatLine "Export file" $ExportFile ] ] . "\n" . \ + [ $IfThenElse ([ :typeof $ConfigFile ] = "array") \ + ("Config file:\n" . [ $FormatLine " name" ($ConfigFile->"name") ] . "\n" . \ + [ $FormatLine " size" [ $HumanReadableNum ($ConfigFile->"size") 1024 ] ]) \ + [ $FormatLine "Config file" $ConfigFile ] ]); silent=true }); :if ($Failed = 1) do={ :error "An error occured!"; From 5f457e5c37ee58f592ca677766515725212a5fad Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 14:22:55 +0100 Subject: [PATCH 1731/2612] backup-upload: build file info in a function --- backup-upload.rsc | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 46b4c7b..5c5e37e 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -25,8 +25,6 @@ :global CharacterReplace; :global DeviceInfo; -:global FormatLine; -:global HumanReadableNum; :global IfThenElse; :global LogPrintExit2; :global MkDir; @@ -122,24 +120,30 @@ $WaitFullyConnected; /file/remove ($FilePath . ".conf.txt"); } +: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=$0; \ subject=[ $IfThenElse ($Failed > 0) \ ([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Backup & Config upload with failure") \ ([ $SymbolForNotification "floppy-disk,up-arrow" ] . "Backup & Config upload") ]; \ message=("Backup and config export upload for " . $Identity . ".\n\n" . \ [ $DeviceInfo ] . "\n\n" . \ - [ $IfThenElse ([ :typeof $BackupFile ] = "array") \ - ("Backup file:\n" . [ $FormatLine " name" ($BackupFile->"name") ] . "\n" . \ - [ $FormatLine " size" [ $HumanReadableNum ($BackupFile->"size") 1024 ] ]) \ - [ $FormatLine "Backup file" $BackupFile ] ] . "\n" . \ - [ $IfThenElse ([ :typeof $ExportFile ] = "array") \ - ("Export file:\n" . [ $FormatLine " name" ($ExportFile->"name") ] . "\n" . \ - [ $FormatLine " size" [ $HumanReadableNum ($ExportFile->"size") 1024 ] ]) \ - [ $FormatLine "Export file" $ExportFile ] ] . "\n" . \ - [ $IfThenElse ([ :typeof $ConfigFile ] = "array") \ - ("Config file:\n" . [ $FormatLine " name" ($ConfigFile->"name") ] . "\n" . \ - [ $FormatLine " size" [ $HumanReadableNum ($ConfigFile->"size") 1024 ] ]) \ - [ $FormatLine "Config file" $ConfigFile ] ]); silent=true }); + [ $FileInfo "Backup file" $BackupFile ] . "\n" . \ + [ $FileInfo "Export file" $ExportFile ] . "\n" . \ + [ $FileInfo "Config file" $ConfigFile ]); silent=true }); :if ($Failed = 1) do={ :error "An error occured!"; From 23c5c461a6a3a6eb26df0e34b67bf537287c096a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 15:02:39 +0100 Subject: [PATCH 1732/2612] check-health: use $HumanReadableNum for RAM utilization --- check-health.rsc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/check-health.rsc b/check-health.rsc index 3ada4c8..e7977f7 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -22,6 +22,7 @@ :global Identity; :global FormatLine; +:global HumanReadableNum; :global IfThenElse; :global LogPrintExit2; :global ScriptLock; @@ -57,9 +58,9 @@ $ScriptLock $0; $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "card-file-box,chart-increasing" ] . "Health warning: RAM utilization"); \ message=("The RAM utilization on " . $Identity . " is at " . $CheckHealthRAMUtilization . "%!\n\n" . \ - [ $FormatLine "total" (($Resource->"total-memory" / 1024 / 1024) . " MiB") ] . "\n" . \ - [ $FormatLine "used" ((($Resource->"total-memory" - $Resource->"free-memory") / 1024 / 1024) . " MiB") ] . "\n" . \ - [ $FormatLine "free" (($Resource->"free-memory" / 1024 / 1024) . " MiB") ]) }); + [ $FormatLine "total" ([ $HumanReadableNum ($Resource->"total-memory") 1024 ] . "iB") ] . "\n" . \ + [ $FormatLine "used" ([ $HumanReadableNum ($Resource->"total-memory" - $Resource->"free-memory") 1024 ] . "iB") ] . "\n" . \ + [ $FormatLine "free" ([ $HumanReadableNum ($Resource->"free-memory") 1024 ] . "iB") ]) }); :set CheckHealthRAMUtilizationNotified true; } :if ($CheckHealthRAMUtilization < 70 && $CheckHealthRAMUtilizationNotified = true) do={ From c7e2ff71e6d2308c96e32ad62174fb756892bcc7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 15:07:07 +0100 Subject: [PATCH 1733/2612] check-health: decrease indention in messages --- check-health.rsc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/check-health.rsc b/check-health.rsc index e7977f7..ff47968 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -58,9 +58,9 @@ $ScriptLock $0; $SendNotification2 ({ origin=$0; \ 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") ] . "\n" . \ - [ $FormatLine "used" ([ $HumanReadableNum ($Resource->"total-memory" - $Resource->"free-memory") 1024 ] . "iB") ] . "\n" . \ - [ $FormatLine "free" ([ $HumanReadableNum ($Resource->"free-memory") 1024 ] . "iB") ]) }); + [ $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={ @@ -96,8 +96,8 @@ $ScriptLock $0; subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \ $NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ - [ $FormatLine "old value" ($CheckHealthLast->$Name . " V") ] . "\n" . \ - [ $FormatLine "new value" ($Value . " V") ]) }); + [ $FormatLine "old value" ($CheckHealthLast->$Name . " V") 12 ] . "\n" . \ + [ $FormatLine "new value" ($Value . " V") 12 ]) }); } else={ :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ $SendNotification2 ({ origin=$0; \ From 6384f6a23986dfc0f851dcecedd6838e1b975e41 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Nov 2023 18:51:54 +0100 Subject: [PATCH 1734/2612] drop old files left from migration --- global-config.changes | 123 -------------------- global-functions | 257 ------------------------------------------ news-and-changes.rsc | 3 +- 3 files changed, 2 insertions(+), 381 deletions(-) delete mode 100644 global-config.changes delete mode 100644 global-functions diff --git a/global-config.changes b/global-config.changes deleted file mode 100644 index 47cfbc6..0000000 --- a/global-config.changes +++ /dev/null @@ -1,123 +0,0 @@ -# News, changes and migration by RouterOS Scripts -# Copyright (c) 2019-2023 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md - -:global IfThenElse; -:global RequiredRouterOS; - -# Changes for global-config to be added to notification on script updates -:global GlobalConfigChanges { - 1="Moved variables from 'global-config' to 'global-functions' for independence"; - 2="Variable names became CamelCase to work around scripting issues"; - 3="Variable for certificate renew passphrase became an array to support multiple passphrases"; - 4="Added option to ignore global-config changes"; - 5="Split off new script 'cloud-backup' from 'email-backup'"; - 6="Introduced script 'upload-backup' with new configuration parameters"; - 7="Introduced script 'check-health' with new configuration parameters"; - 8="Added donation hint and option to silence it"; - 9="Introduced configuration overlay 'global-config-overlay'"; - 10="Made health threshold for voltage configurable"; - 11="Introduced function '\$ScriptInstallUpdate' to install new and update existing scripts"; - 12="Removed '\$ScriptUpdatesConfigChangesIgnore', comment '\$GlobalConfigVersion' in 'global-config-overlay' to disable change notifications"; - 13="Configuration for script 'bridge-port-to-default' changed with new syntax in comment"; - 14="Dropped script 'script-updates', use '\$ScriptInstallUpdate' exclusively!"; - 15="New documentation is online! https://git.eworm.de/cgit/routeros-scripts/about/#available-scripts"; - 16="Happy with RouterOS Scripts and have a GitHub and/or GitLab account? Please star!"; - 17="Introduced script 'early-errors'"; - 18=("Added a simple IP calculation function, try: \$IPCalc " . [ /ip/address/get ([ find ]->0) address ]); - 19="Commenting scripts with 'ignore', 'base-url=...' and 'url-suffix=...' is honored on update"; - 20="Added support for hooks to 'netwatch-notify'"; - 21="Added support for installing patch updates automatically by 'check-routeros-update'"; - 22="Dropped '\$ScriptUpdatesIgnore' from global configuration, auto-migrating to ignore flag in comment" - 23="Added 'log-forward' with configurable filter, which replaces 'early-errors'"; - 24="Made symbols in notifications configurable."; - 25="Added support for DHCP server name in DNS FQDN via '\$ServerNameInZone'"; - 26="Made check count threshold in 'netwatch-notify' configurable."; - 27="Added queue for Telegram notifications to resend later on error."; - 28="Made 'dhcp-to-dns' act on all bound leases, not just dynamic ones."; - 29="Added filter on log message text for 'log-forward'."; - 30="Implemented simple rate limit for 'log-forward' to prevent flooding."; - 31="Switched Telegram notifications to fixed-width font, with opt-out."; - 32="Merged mode (& reset) button scripts in single new script 'mode-button'."; - 33="Added configurable deviation on health temperature recovery threshold against notification flooding."; - 34="Introduced script 'ospf-to-leds' to visualize OSPF instance state via LEDs."; - 35="Implemented visual feedback for 'mode-button' with configurable LED."; - 36="Added support for installing updates automatically if seen in neighbor list."; - 37="Implemented simple dependency model in 'netwatch-notify'."; - 38="Imported new Let's Encrypt intermediate certificate 'R3'."; - 39="Added support for interface specific address list entries in 'ipv6-update'."; - 40="Made the certificate renewal time configurable."; - 41="Implemented migration mechanism for script updates."; - 42="Made severity in terminal output colorful, with opt-out."; - 43="Added queue for e-mail notifications to resend later on error."; - 44="Dropped script 'global-wait', all scripts wait on their own now."; - 45="We have a Telegram Group! Come along and say hello: https://t.me/routeros_scripts"; - 46="Added configurable random delay in backup scripts to stretch execution and prevent resource congestion."; - 47="Removed obsolete intermediate certificate 'Let's Encrypt Authority X3' from store."; - 48="Added support for overriding e-mail and Telegram settings for every script."; - 49="Dropped '\$EmailBackupTo' & '\$EmailBackupCc' from configuration, use settings override if required."; - 50="Added support for dynamic address update in 'netwatch-notify'."; - 51="Added 'ipsec-to-dns' to add DNS records for IPSec peers from mode-config."; - 52="Updated Let's Encrypt trust chain to use root certificate 'ISRG Root X1'. Do not re-import the old chain!"; - 53="Added support to send notifications via Matrix."; - 54="Support for Telegram notifications moved to a module. It is installed automatically if required."; - 55="Added reverse logic in 'log-forward', so messages can be included even if filtered before."; - 56="Added tags in all backup, lease and ppp-on-up scripts. These are used by 'packages-update', 'lease-script' and 'ppp-on-up' to find the scripts."; - 57="Celebrating the 1.000th commit - Hooray!"; - 58="Added a cleanup script for 'hotspot-to-wpa' to purge old access list entries."; - 59="Updating CAP with 'check-routeros-update' is now possible with opt-in."; - 60="Implemented a pre-down hook in 'netwatch-notify' that fires at two thirds of failed checks."; - 61="Finally removed old scripts."; - 62="Added '\$ScriptRunOnce' to run a script from URL once without installation, intended to aid configuration management and the like."; - 63="Moved optional functions '\$IPCalc' and '\$ScriptRunOnce' to modules."; - 64="Implemented '\$InspectVar' in module to inspect variables."; - 65="Added module to manage VLANs on bridge ports."; - 66="Moved script 'bridge-port-to-default' to new module."; - 67="Moved modules to directory with shorter name."; - 68="Reintroduced 'global-wait' for functions in scheduler."; - 69="Support hard lower limit for voltage in 'check-health'."; - 70="MikroTik started pushing RouterOS v7. Changes are no longer required."; - 71="MikroTik is pushing RouterOS v7 even more, in parallel branches. If you want to keep RouterOS v6 for some time see https://git.eworm.de/cgit/routeros-scripts/about/#requirements"; - 72="Introduced new script 'netwatch-dns' to manage DNS and DoH servers from netwatch."; - 73="Renamed backup scripts ('cloud-backup' -> 'backup-cloud', 'email-backup' -> 'backup-email', 'upload-backup' -> 'backup-upload')."; - 74="Extended 'hotspot-to-wpa', it can now read additional configuration from templates and hotspot users."; - 75=("Finally merged the RouterOS v7 code into the main branch. " . [ $IfThenElse ([ $RequiredRouterOS "global-config.changes" "7.0" false ] = true) \ - ("You may now drop '\$ScriptUpdatesUrlSuffix' from 'global-config-overlay'.") \ - ("Still running RouterOS v6, so last reminder to see https://git.eworm.de/cgit/routeros-scripts/about/#requirements") ]); - 76="Added an option to suppress notifications on host down with 'netwatch-notify'."; - 77="Introduced new script 'firmware-upgrade-reboot'. Handle with care!"; - 78="New documentation is online for notifications via Telegram & Matrix, variable inspection, ip address calculation and running scripts once."; - 79="Introduced new script 'backup-partition' to save configuration to fallback partition."; - 80="The 'routeros-v7' branch will now freeze, and vanish any time in future. You already switched to 'main' branch, well done!"; - 81="Dropped script 'rotate-ntp', as the limitation does no longer exist."; - 82="Renamed the comment parameter 'hostname' to just 'name' for 'netwatch-notify'."; - 83="Introduced new setting to disable news and change notifications, dropped version from configuration."; - 84="Support for e-mail notifications moved to a module. It is installed automatically if required."; - 85="Dropped 'netwatch-syslog', filtering in firewall is advised."; - 86="Added support for hooks in 'sms-forward'. This now provides similar functionality to 'sms-action', but is more flexible."; - 87="Added support for extra text (or emojis \F0\9F\9A\80) in notification tags."; - 88="Added support for monitoring CPU utilization and available free RAM in 'check-health'."; - 89="Made the warning time for 'check-certificates' configurable."; - 90="Chat with your router! Introduced 'telegram-chat' to chat via Telegram bot and send commands to your router."; - 91="Dropped check for CAP in 'check-routeros-update' to solve issues with wifiwave2 package."; - 92="Made qr-code url configurable for 'daily-psk'."; - 93="Added support to backup global-config-overlay in 'backup-email' and 'backup-upload'."; - 94="Added support for host addresses in address-list for 'ipv6-update'."; - 95="Renamed script files in repository, running migration. Warnings (one per script) are expected, no user interaction is required."; -}; - -# Migration steps to be applied on script updates -:global GlobalConfigMigration { - 41=":global SendNotification; \$SendNotification (\"Migration mechanism\") (\"Congratulations!\nSuccessfully tested the new migration mechanism.\");"; - 47="/certificate/remove [ find where fingerprint=\"731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568\" or fingerprint=\"25847d668eb4f04fdd40b12b6b0740c567da7d024308eb6c2c96fe41d9de218d\" ];"; - 52=":global CertificateDownload; :if ([ :len [ /certificate/find where fingerprint=\"67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd\" or fingerprint=\"96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6\" ] ] < 2) do={ \$CertificateDownload \"R3\"; }; /certificate/remove [ find where fingerprint=\"0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739\" ];"; - 54=":global ScriptInstallUpdate; :global TelegramTokenId; :global TelegramChatId; :if ([ :len \$TelegramTokenId ] > 0 && [ :len \$TelegramChatId ] > 0) do={ \$ScriptInstallUpdate mod/notification-telegram; }"; - 61="/system/script/remove [ find where name~\"^(early-errors|mode-button-(event|scheduler)|script-updates)\\\$\" source~\"^#!rsc by RouterOS\\n\" ];"; - 66=":global ScriptInstallUpdate; :if ([ :len [ /system/script/find where name=\"bridge-port-to-default\" ] ] > 0) do={ /system/script/remove [ find where name~\"^bridge-port-to(-default|ggle)\\\$\" ]; \$ScriptInstallUpdate mod/bridge-port-to; }"; - 67=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Script in=[ /system/script/find where name~\"^global-functions.d/\" ] do={ /system/script/set name=[ \$CharacterReplace [ /system/script/get \$Script name ] \"global-functions.d/\" \"mod/\" ] \$Script; }; \$ScriptInstallUpdate;"; - 73=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Old,New in={ \"cloud-backup\"=\"backup-cloud\"; \"email-backup\"=\"backup-email\"; \"upload-backup\"=\"backup-upload\" } do={ /system/script/set name=\$New [ find where name=\$Old ]; :foreach Scheduler in=[ /system/scheduler/find where on-event~\$Old ] do={ /system/scheduler/set \$Scheduler name=[ \$CharacterReplace [ get \$Scheduler name ] \$Old \$New ] on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Old \$New ]; }; }; \$ScriptInstallUpdate;"; - 81=":global NtpPool; :if ([ :len [ /system/script/find where name=\"rotate-ntp\" ] ] > 0) do={ /system/script/remove [ find where name=\"rotate-ntp\" ]; /system/scheduler/remove [ find where name=\"rotate-ntp\" ]; /system/ntp/client/set servers=\$NtpPool; };"; - 82=":global CharacterReplace; :foreach Netwatch in=[ /tool/netwatch/find where comment~\"notify\" !disabled ] do={ /tool/netwatch/set \$Netwatch comment=[ \$CharacterReplace [ get \$Netwatch comment ] \"hostname=\" \"name=\" ]; };"; - 84=":global ScriptInstallUpdate; :global EmailGeneralTo; :if ([ /tool/e-mail/get address ] != \"0.0.0.0\" && [ :len \$EmailGeneralTo ] > 0) do={ \$ScriptInstallUpdate mod/notification-email; }"; - 95=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Script in=[ /system/script/find where name~\"\\\\.rsc\\\$\" source~\"^#!rsc by RouterOS\\n\" ] do={ /system/script/set \$Script name=[ \$CharacterReplace [ get \$Script name ] \".rsc\" \"\" ]; }; \$ScriptInstallUpdate;"; -}; diff --git a/global-functions b/global-functions deleted file mode 100644 index 431a343..0000000 --- a/global-functions +++ /dev/null @@ -1,257 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: global-functions -# Copyright (c) 2013-2023 Christian Hesse -# Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# requires RouterOS, version=7.7 -# -# WARNING: If you find this stripped version of global-functions -# on your Router something went wrong and migration failed. To -# recover run this function: $RouterOSScriptsRecover - -# expected configuration version -:global ExpectedConfigVersion 95; - -# global functions -:global RouterOSScriptsRecover; -:global ScriptInstallUpdate; - -# recover from failed migration -:set RouterOSScriptsRecover do={ - :global ScriptInstallUpdate; - - :foreach Script in={ "global-config"; "global-functions" } do={ - /system/script/set name=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . ".rsc") output=user as-value]->"data"); - /system/script/run $Script; - } - - $ScriptInstallUpdate; -} - -# install new scripts, update existing scripts -:set ScriptInstallUpdate do={ - :local Scripts [ :toarray $1 ]; - :local NewComment [ :tostr $2 ]; - - :global ExpectedConfigVersion; - :global Identity; - :global IDonate; - :global NoNewsAndChangesNotification; - :global NotificationsWithSymbols; - :global ScriptUpdatesBaseUrl; - :global ScriptUpdatesFetch; - :global ScriptUpdatesUrlSuffix; - - :global CertificateAvailable; - :global EitherOr; - :global Grep; - :global IfThenElse; - :global LogPrintExit2; - :global ParseKeyValueStore; - :global RequiredRouterOS; - :global SendNotification2; - :global SymbolForNotification; - :global ValidateSyntax; - - :if ([ $CertificateAvailable "E1" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; - } - - :foreach Script in=$Scripts do={ - :if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={ - $LogPrintExit2 info $0 ("Adding new script: " . $Script) false; - /system/script/add name=$Script owner=$Script source="#!rsc by RouterOS\n" comment=$NewComment; - } - } - - :local ExpectedConfigVersionBefore $ExpectedConfigVersion; - :local ReloadGlobalFunctions false; - :local ReloadGlobalConfig false; - - :foreach Script in=[ /system/script/find where source~"^#!rsc by RouterOS\n" ] do={ - :local ScriptVal [ /system/script/get $Script ]; - :local ScriptFile [ /file/find where name=("script-updates/" . $ScriptVal->"name") ]; - :local SourceNew; - :if ([ :len $ScriptFile ] > 0) do={ - :set SourceNew [ /file/get $ScriptFile contents ]; - /file/remove $ScriptFile; - } - - :foreach Scheduler in=[ /system/scheduler/find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ - :local SchedulerVal [ /system/scheduler/get $Scheduler ]; - :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ - $LogPrintExit2 warning $0 ("Policies differ for script '" . $ScriptVal->"name" . \ - "' and its scheduler '" . $SchedulerVal->"name" . "'!") false; - } - } - - :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ - :local Comment [ $ParseKeyValueStore ($ScriptVal->"comment") ]; - :if (!($Comment->"ignore" = true)) do={ - :do { - :local BaseUrl $ScriptUpdatesBaseUrl; - :local UrlSuffix $ScriptUpdatesUrlSuffix; - :if ([ :typeof ($Comment->"base-url") ] = "str") do={ :set BaseUrl ($Comment->"base-url"); } - :if ([ :typeof ($Comment->"url-suffix") ] = "str") do={ :set UrlSuffix ($Comment->"url-suffix"); } - :local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix); - - $LogPrintExit2 debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url) false; - :local Result [ /tool/fetch check-certificate=yes-without-crl $Url output=user as-value ]; - :if ($Result->"status" = "finished") do={ - :set SourceNew ($Result->"data"); - } - } on-error={ - :if ($ScriptVal->"source" = "#!rsc by RouterOS\n") do={ - $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . \ - "', removing dummy. Typo on installation?") false; - /system/script/remove $Script; - } else={ - $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!") false; - } - } - } - } - - :if ([ :len $SourceNew ] > 0) do={ - :if ($SourceNew != $ScriptVal->"source") do={ - :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ - :local Required ([ $ParseKeyValueStore [ $Grep $SourceNew "# requires RouterOS, " ] ]->"version"); - :if ([ $RequiredRouterOS $0 [ $EitherOr $Required "0.0" ] false ] = true) do={ - :if ([ $ValidateSyntax $SourceNew ] = true) do={ - $LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; - /system/script/set owner=($ScriptVal->"name") source=$SourceNew $Script; - :if ($ScriptVal->"name" = "global-config") do={ - :set ReloadGlobalConfig true; - } - :if ($ScriptVal->"name" = "global-functions" || $ScriptVal->"name" ~ ("^mod/.")) do={ - :set ReloadGlobalFunctions true; - } - } else={ - $LogPrintExit2 warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . \ - "' failed! Ignoring!") false; - } - } else={ - $LogPrintExit2 warning $0 ("The script '" . $ScriptVal->"name" . "' requires RouterOS " . \ - $Required . ", which is not met by your installation. Ignoring!") false; - } - } else={ - $LogPrintExit2 warning $0 ("Looks like new script '" . $ScriptVal->"name" . \ - "' is not valid (missing shebang). Ignoring!") false; - } - } else={ - $LogPrintExit2 debug $0 ("Script '" . $ScriptVal->"name" . "' did not change.") false; - } - } else={ - $LogPrintExit2 debug $0 ("No update for script '" . $ScriptVal->"name" . "'.") false; - } - } - - :if ($ReloadGlobalFunctions = true) do={ - $LogPrintExit2 info $0 ("Reloading global functions.") false; - :do { - /system/script/run global-functions; - } on-error={ - $LogPrintExit2 error $0 ("Reloading global functions failed!") false; - } - } - - :if ($ReloadGlobalConfig = true) do={ - $LogPrintExit2 info $0 ("Reloading global configuration.") false; - :do { - /system/script/run global-config; - } on-error={ - $LogPrintExit2 error $0 ("Reloading global configuration failed!" . \ - " Syntax error or missing overlay?") false; - } - } - - :if ($ExpectedConfigVersionBefore > $ExpectedConfigVersion) do={ - $LogPrintExit2 warning $0 ("The configuration version decreased from " . \ - $ExpectedConfigVersionBefore . " to " . $ExpectedConfigVersion . \ - ". Installed an older version?") false; - } - - :if ($ExpectedConfigVersionBefore < $ExpectedConfigVersion) do={ - :global GlobalConfigChanges; - :global GlobalConfigMigration; - :local ChangeLogCode; - - :do { - :local Url ($ScriptUpdatesBaseUrl . "news-and-changes.rsc" . $ScriptUpdatesUrlSuffix); - $LogPrintExit2 debug $0 ("Fetching news, changes and migration: " . $Url) false; - :local Result [ /tool/fetch check-certificate=yes-without-crl $Url output=user as-value ]; - :if ($Result->"status" = "finished") do={ - :set ChangeLogCode ($Result->"data"); - } - } on-error={ - $LogPrintExit2 warning $0 ("Failed fetching news, changes and migration!") false; - } - - :if ([ :len $ChangeLogCode ] > 0) do={ - :if ([ $ValidateSyntax $ChangeLogCode ] = true) do={ - :do { - [ :parse $ChangeLogCode ]; - } on-error={ - $LogPrintExit2 warning $0 ("The changelog failed to run!") false; - } - } else={ - $LogPrintExit2 warning $0 ("The changelog failed syntax validation!") false; - } - } - - :if ([ :len $GlobalConfigMigration ] > 0) do={ - :for I from=($ExpectedConfigVersionBefore + 1) to=$ExpectedConfigVersion do={ - :local Migration ($GlobalConfigMigration->[ :tostr $I ]); - :if ([ :typeof $Migration ] = "str") do={ - :if ([ $ValidateSyntax $Migration ] = true) do={ - $LogPrintExit2 info $0 ("Applying migration for change " . $I . ": " . $Migration) false; - :do { - [ :parse $Migration ]; - } on-error={ - $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed to run!") false; - } - } else={ - $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed syntax validation!") false; - } - } - } - } - - :local NotificationMessage ("The configuration version on " . $Identity . " increased " . \ - "to " . $ExpectedConfigVersion . ", current configuration may need modification. " . \ - "Please review and update global-config-overlay, then re-run global-config."); - $LogPrintExit2 info $0 ($NotificationMessage) false; - - :if ([ :len $GlobalConfigChanges ] > 0) do={ - :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); - :for I from=($ExpectedConfigVersionBefore + 1) to=$ExpectedConfigVersion do={ - :local Change ($GlobalConfigChanges->[ :tostr $I ]); - :set NotificationMessage ($NotificationMessage . "\n " . \ - [ $IfThenElse ($NotificationsWithSymbols = true) ("\E2\97\8F") "*" ] . " " . $Change); - $LogPrintExit2 info $0 ("Change " . $I . ": " . $Change) false; - } - } else={ - :set NotificationMessage ($NotificationMessage . "\n\nNews and changes are not available."); - } - - :if ($NoNewsAndChangesNotification != true) do={ - :local Link; - :if ($IDonate != true) do={ - :set NotificationMessage ($NotificationMessage . \ - "\n\n==== donation hint ====\n" . \ - "This project is developed in private spare time and usage is " . \ - "free of charge for you. If you like the scripts and think this is " . \ - "of value for you or your business please consider a donation."); - :set Link "https://git.eworm.de/cgit/routeros-scripts/about/#donate"; - } - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "pushpin" ] . "News and configuration changes"); \ - message=$NotificationMessage; link=$Link }); - } - - :set GlobalConfigChanges; - :set GlobalConfigMigration; - } -} diff --git a/news-and-changes.rsc b/news-and-changes.rsc index d0b3820..f4c50c2 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -5,7 +5,8 @@ :global IfThenElse; :global RequiredRouterOS; -# News, changes and migration up to change 95 are in global-config.changes! +# News, changes and migration up to change 95: +# https://git.eworm.de/cgit/routeros-scripts/plain/global-config.changes?h=change-95 # Changes for global-config to be added to notification on script updates :global GlobalConfigChanges { From ab8c9d04ffb331dd5c00f0cceae395a871df7936 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Nov 2023 13:15:28 +0100 Subject: [PATCH 1735/2612] check-routeros-update: rename scheduler This was missing for commit f7c72b6ed96e45bf1fbb54c46ce09e1fccc791be... --- check-routeros-update.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index d77164d..0b621f7 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -41,7 +41,7 @@ $ScriptLock $0; $WaitFullyConnected; -:if ([ :len [ /system/scheduler/find where name="\$RebootForUpdate" ] ] > 0) do={ +:if ([ :len [ /system/scheduler/find where name="_RebootForUpdate" ] ] > 0) do={ :error "A reboot for update is already scheduled."; } From 11daef75f033443e1b15beadb5b74985db4f5812 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Nov 2023 13:06:44 +0100 Subject: [PATCH 1736/2612] packages-update: refuse automatic update to RouterOS 7.13 ... as migration to wireless or wifi package has to be done. Please update manually by running: /system/package/update/install --- packages-update.rsc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages-update.rsc b/packages-update.rsc index 85a241a..d011ea1 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -33,6 +33,11 @@ $ScriptLock $0; :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; +:if ($NumInstalled < 0x070d0000 && $NumLatest > 0x070d0000) do={ + $LogPrintExit2 error $0 ("Migration to wireless/wifi package in RouterOS " . \ + ($Update->"latest-version") . " is pending. Please update manually!") true; +} + :local DoDowngrade false; :if ($NumInstalled > $NumLatest) do={ :if ([ $ScriptFromTerminal $0 ] = true) do={ From b75b0bf6bea8ed02cab0db32e948ea0f7de13d08 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Nov 2023 21:17:44 +0100 Subject: [PATCH 1737/2612] backup-upload: get rid of '.txt' file extension --- backup-upload.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 5c5e37e..02916c6 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -103,12 +103,12 @@ $WaitFullyConnected; :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"); - $WaitForFile ($FilePath . ".conf.txt"); + file=($FilePath . ".conf\00"); + $WaitForFile ($FilePath . ".conf"); :do { /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \ - user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf.txt"); + user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf"); :set ConfigFile [ /file/get ($FilePath . ".conf") ]; :set ($ConfigFile->"name") ($FileName . ".conf"); } on-error={ @@ -117,7 +117,7 @@ $WaitFullyConnected; :set Failed 1; } - /file/remove ($FilePath . ".conf.txt"); + /file/remove ($FilePath . ".conf"); } :local FileInfo do={ From d1abbede75253e3f10be0cba6e7ae68a1700865f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Nov 2023 21:18:39 +0100 Subject: [PATCH 1738/2612] backup-email: get rid of '.txt' file extension --- backup-email.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backup-email.rsc b/backup-email.rsc index 95e9015..f4f1fc8 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -82,10 +82,10 @@ $WaitFullyConnected; :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"); - $WaitForFile ($FilePath . ".conf.txt"); - :set ConfigFile ($FileName . ".conf.txt"); - :set Attach ($Attach, ($FilePath . ".conf.txt")); + file=($FilePath . ".conf\00"); + $WaitForFile ($FilePath . ".conf"); + :set ConfigFile ($FileName . ".conf"); + :set Attach ($Attach, ($FilePath . ".conf")); } # send email with status and files From cae5f425a6c9d1f5797d85f6d4cd21867cc5cf8f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 Nov 2023 21:20:44 +0100 Subject: [PATCH 1739/2612] telegram-chat: get rid of '.txt' file extension --- telegram-chat.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 686becc..9515119 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -112,18 +112,18 @@ $WaitFullyConnected; $MkDir "tmpfs/telegram-chat"; $LogPrintExit2 info $0 ("Running command from update " . $UpdateID . ": " . $Message->"text") false; :execute script=(":do {\n" . $Message->"text" . "\n} on-error={ /file/add name=\"" . $File . ".failed\" };" . \ - "/file/add name=\"" . $File . ".done\"") file=$File; + "/file/add name=\"" . $File . ".done\"") file=($File . "\00"); :if ([ $WaitForFile ($File . ".done") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ :set State "The command did not finish, still running in background.\n\n"; } :if ([ :len [ /file/find where name=($File . ".failed") ] ] > 0) do={ :set State "The command failed with an error!\n\n"; } - :local Content [ /file/get ($File . ".txt") contents ]; + :local Content [ /file/get $File contents ]; $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Command:\n" . $Message->"text" . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ - ("Output:\n" . $Content) [ $IfThenElse ([ /file/get ($File . ".txt") size ] > 0) \ + ("Output:\n" . $Content) [ $IfThenElse ([ /file/get $File size ] > 0) \ ("Output exceeds file read size.") ("No output.") ] ]) }); /file/remove "tmpfs/telegram-chat"; } else={ From 1cc0e3429b4017d97529a49a09e50487d9630929 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 23 Nov 2023 14:41:46 +0100 Subject: [PATCH 1740/2612] global-functions: introduce $AlignRight --- global-functions.rsc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 090269d..c356606 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -20,6 +20,7 @@ :global Identity [ /system/identity/get name ]; # global functions +:global AlignRight; :global CertificateAvailable; :global CertificateDownload; :global CertificateNameByCN; @@ -72,6 +73,19 @@ :global WaitFullyConnected; :global WaitTimeSync; +# align string to the right +:global AlignRight do={ + :local Input [ :tostr $1 ]; + :local Len [ :tonum $2 ]; + + :global EitherOr; + + :local Spaces " "; + :set Len [ $EitherOr $Len 8 ]; + + :return ([ :pick $Spaces 0 ($Len - [ :len $Input ]) ] . $Input); +} + # check and download required certificate :set CertificateAvailable do={ :local CommonName [ :tostr $1 ]; From 81a86ee0430c0ffccfa7e8116d383341037e07da Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 27 Nov 2023 13:17:17 +0100 Subject: [PATCH 1741/2612] netwatch-dns: get doh host name from static dns --- doc/netwatch-dns.md | 9 +++++++++ netwatch-dns.rsc | 7 ++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index a208d00..70b766a 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -43,6 +43,15 @@ Giving a specific query url for DoH is possible: Note that using a name in DoH url may introduce a chicken-and-egg issue! +Adding a static DNS record has the same result for the url, but always +resolves to the same address. + + /ip/dns/static/add name="dns.nextdns.io" address=199.247.16.158; + /tool/netwatch/add comment="doh" host=199.247.16.158; + +Be aware that you have to keep the ip address in sync with real world +manually! + Importing a certificate automatically is possible, at least if available in the repository (see `certs` sub directory). diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 3e3e27c..c5c8ed1 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -64,10 +64,15 @@ $ScriptLock $0; :foreach Host in=[ /tool/netwatch/find where comment~"\\bdoh\\b" status="up" ] do={ :local HostVal [ /tool/netwatch/get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; + :local HostName [ /ip/dns/static/find where name address=($HostVal->"host") \ + (!type or type="A" or type="AAAA") !disabled !dynamic ]; + :if ([ :len $HostName ] > 0) do={ + :set HostName [ /ip/dns/static/get ($HostName->0) name ]; + } :if ($HostInfo->"doh" = true && $HostInfo->"disabled" != true && $DohServer = "") do={ :set DohServer [ $EitherOr ($HostInfo->"doh-url") \ - ("https://" . $HostVal->"host" . "/dns-query") ]; + ("https://" . [ $EitherOr $HostName ($HostVal->"host") ] . "/dns-query") ]; :set DohCert ($HostInfo->"doh-cert"); } } From 4e1d54d733bb2ff551edca957d331af357e9fd5b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Nov 2023 13:20:15 +0100 Subject: [PATCH 1742/2612] global-functions: $SymbolForNotification: properly append space to alt text --- global-functions.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index c356606..a569699 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1084,7 +1084,7 @@ :for I from=($ExpectedConfigVersionBefore + 1) to=$ExpectedConfigVersion do={ :local Change ($GlobalConfigChanges->[ :tostr $I ]); :set NotificationMessage ($NotificationMessage . "\n " . \ - [ $SymbolForNotification "pushpin" "* " ] . $Change); + [ $SymbolForNotification "pushpin" "*" ] . $Change); $LogPrintExit2 info $0 ("Change " . $I . ": " . $Change) false; } } else={ @@ -1299,9 +1299,10 @@ :set SymbolForNotification do={ :global NotificationsWithSymbols; :global SymbolByUnicodeName; + :global IfThenElse; :if ($NotificationsWithSymbols != true) do={ - :return [ :tostr $2 ]; + :return [ $IfThenElse ([ :len $2 ] > 0) ([ :tostr $2 ] . " ") "" ]; } :local Return ""; :foreach Symbol in=[ :toarray $1 ] do={ From 080bef89a934980271a50eed25a494a0bc33d007 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Nov 2023 14:13:10 +0100 Subject: [PATCH 1743/2612] global-functions: $SymbolByUnicodeName: rename up-arrow -> arrow-up ... so arrows are grouped in case we add more. --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index a569699..876f2cd 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1265,6 +1265,7 @@ :local Symbols { "abacus"="\F0\9F\A7\AE"; "alarm-clock"="\E2\8F\B0"; + "arrow-up"="\E2\AC\86"; "calendar"="\F0\9F\93\85"; "card-file-box"="\F0\9F\97\83"; "chart-decreasing"="\F0\9F\93\89"; @@ -1287,7 +1288,6 @@ "scissors"="\E2\9C\82"; "sparkles"="\E2\9C\A8"; "speech-balloon"="\F0\9F\92\AC"; - "up-arrow"="\E2\AC\86"; "warning-sign"="\E2\9A\A0"; "white-heavy-check-mark"="\E2\9C\85" } From 495eff48de7f825ea013609f5de0c42330db163e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 30 Nov 2023 12:01:59 +0100 Subject: [PATCH 1744/2612] global-functions: introduce $MAX --- global-functions.rsc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 876f2cd..709a615 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -48,6 +48,7 @@ :global IsTimeSync; :global LogPrintExit2; :global LogPrintOnce; +:global MAX; :global MkDir; :global NotificationFunctions; :global ParseDate; @@ -680,6 +681,12 @@ $LogPrintExit2 $Severity $Name $Message false; } +# get max value +:set MAX do={ + :if ($1 > $2) do={ :return $1; } + :return $2; +} + # create directory :set MkDir do={ :local Path [ :tostr $1 ]; From c6bf722e49c55af3a4d870f2fdca1460ece2bc1b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 30 Nov 2023 12:02:51 +0100 Subject: [PATCH 1745/2612] global-functions: introduce $MIN --- global-functions.rsc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 709a615..d4f5ebf 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -49,6 +49,7 @@ :global LogPrintExit2; :global LogPrintOnce; :global MAX; +:global MIN; :global MkDir; :global NotificationFunctions; :global ParseDate; @@ -687,6 +688,12 @@ :return $2; } +# get min value +:set MIN do={ + :if ($1 < $2) do={ :return $1; } + :return $2; +} + # create directory :set MkDir do={ :local Path [ :tostr $1 ]; From aba477039518dd3806a7f19c40735f0433fb7467 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 30 Nov 2023 13:18:15 +0100 Subject: [PATCH 1746/2612] fw-addr-lists: support timeout per list This works with something like this: :global FwAddrLists { "allow"={ { url="https://eworm.de/ros/fw-addr-lists/allow"; cert="E1"; timeout=1w }; }; ... } All urls for one named list should have the same timeout! With different timeout values and identical addresses the behavior is besically undefined, depending on order. --- fw-addr-lists.rsc | 14 ++++++++------ global-config.rsc | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 26e9f98..845b597 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -14,6 +14,7 @@ :global FwAddrListTimeOut; :global CertificateAvailable; +:global EitherOr; :global LogPrintExit2; :global ScriptLock; :global WaitFullyConnected; @@ -42,6 +43,7 @@ $WaitFullyConnected; :foreach List in=$FwList do={ :local CheckCertificate "no"; :local Data false; + :local TimeOut [ $EitherOr [ :totime ($List->"timeout") ] $FwAddrListTimeOut ]; :if ([ :len ($List->"cert") ] > 0) do={ :set CheckCertificate "yes-without-crl"; @@ -75,7 +77,7 @@ $WaitFullyConnected; :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) 1; + :set ($Addresses->$Address) $TimeOut; } :set Data [ :pick $Data ([ :len $Line ] + 1) [ :len $Data ] ]; } @@ -83,9 +85,9 @@ $WaitFullyConnected; :foreach Entry in=[ /ip/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={ :local Address [ /ip/firewall/address-list/get $Entry address ]; - :if (($Addresses->$Address) = 1) do={ - $LogPrintExit2 debug $0 ("Renewing: " . $Address) false; - /ip/firewall/address-list/set $Entry timeout=$FwAddrListTimeOut; + :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={ @@ -98,9 +100,9 @@ $WaitFullyConnected; } :foreach Address,Ignore in=$Addresses do={ - $LogPrintExit2 debug $0 ("Adding: " . $Address) false; + $LogPrintExit2 debug $0 ("Adding for " . ($Addresses->$Address) . ": " . $Address) false; :do { - /ip/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$FwAddrListTimeOut; + /ip/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=($Addresses->$Address); :set ($Addresses->$Address); :set CntAdd ($CntAdd + 1); } on-error={ diff --git a/global-config.rsc b/global-config.rsc index dfb25ec..14a4e98 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -88,7 +88,7 @@ :global FwAddrLists { # "allow"={ # { url="https://eworm.de/ros/fw-addr-lists/allow"; -# cert="E1" }; +# cert="E1"; timeout=1w }; # }; "block"={ # { url="https://eworm.de/ros/fw-addr-lists/block"; From 15e347303bfb1d8dc600dd8c1a6cd6e8bbe6268f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Dec 2023 09:28:59 +0100 Subject: [PATCH 1747/2612] global-functions: $DeviceInfo: add SNMP location and contact --- global-functions.rsc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index d4f5ebf..6167348 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -219,16 +219,21 @@ :global IfThenElse; :global FormatLine; + :local License [ /system/license/get ]; :local Resource [ /system/resource/get ]; :local RouterBoard; :do { :set RouterBoard [[ :parse "/system/routerboard/get" ]]; } on-error={ } - :local License [ /system/license/get ]; + :local Snmp [ /snmp/get ]; :local Update [ /system/package/update/get ]; :return ( \ [ $FormatLine "Hostname" $Identity ] . "\n" . \ + [ $IfThenElse ([ :len ($Snmp->"location") ] > 0) \ + ([ $FormatLine "Location" ($Snmp->"location") ] . "\n") ] . \ + [ $IfThenElse ([ :len ($Snmp->"contact") ] > 0) \ + ([ $FormatLine "Contact" ($Snmp->"contact") ] . "\n") ] . \ [ $FormatLine "Board name" ($Resource->"board-name") ] . "\n" . \ [ $FormatLine "Architecture" ($Resource->"architecture-name") ] . "\n" . \ [ $IfThenElse ($RouterBoard->"routerboard" = true) \ From 8f24b4c490ddb4404521feed8a579a34351568f5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Dec 2023 10:56:48 +0100 Subject: [PATCH 1748/2612] global-functions: introduce $CharacterMultiply --- global-functions.rsc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 6167348..bb4f098 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -24,6 +24,7 @@ :global CertificateAvailable; :global CertificateDownload; :global CertificateNameByCN; +:global CharacterMultiply; :global CharacterReplace; :global CleanFilePath; :global DeviceInfo; @@ -172,6 +173,15 @@ name=[ $CharacterReplace [ $CharacterReplace [ $CharacterReplace $CommonName "'" "-" ] " " "-" ] "---" "-" ]; } +# multiply given character(s) +:set CharacterMultiply do={ + :local Return ""; + :for I from=1 to=$2 do={ + :set Return ($Return . $1); + } + :return $Return; +} + # character replace :set CharacterReplace do={ :local String [ :tostr $1 ]; From 5e2e65b25207ceae7d847285336fe4791df339bc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Dec 2023 10:58:27 +0100 Subject: [PATCH 1749/2612] global-functions: $AlignRight: use $CharacterMultiply --- global-functions.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index bb4f098..ffa02c7 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -81,10 +81,11 @@ :local Input [ :tostr $1 ]; :local Len [ :tonum $2 ]; + :global CharacterMultiply; :global EitherOr; - :local Spaces " "; :set Len [ $EitherOr $Len 8 ]; + :local Spaces [ $CharacterMultiply " " $Len ]; :return ([ :pick $Spaces 0 ($Len - [ :len $Input ]) ] . $Input); } From 1bb2871e0badcbdf56605ccfd64e319e61556172 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Dec 2023 10:59:41 +0100 Subject: [PATCH 1750/2612] global-functions: $FormatLine: use $CharacterMultiply --- global-functions.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index ffa02c7..34d3df0 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -377,12 +377,14 @@ :local Key [ :tostr $1 ]; :local Value [ :tostr $2 ]; :local Indent [ :tonum $3 ]; - :local Spaces " "; + :local Spaces; :local Return ""; + :global CharacterMultiply; :global EitherOr; :set Indent [ $EitherOr $Indent 16 ]; + :local Spaces [ $CharacterMultiply " " $Indent ]; :if ([ :len $Key ] > 0) do={ :set Return ($Key . ":"); } :if ([ :len $Key ] > ($Indent - 2)) do={ From 84368ec6ebe758d4f7f5745bb1b8c48a292025bb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Dec 2023 09:44:32 +0100 Subject: [PATCH 1751/2612] mod/notification-email: $QuotedPrintable: minor rework We have to encode all characters from 0x00 to 0x1f as well... Also the equal sign is nothing special here, just adding to list. --- mod/notification-email.rsc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 774af4c..76f198f 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -170,27 +170,28 @@ :global QuotedPrintable do={ :local Input [ :tostr $1 ]; + :global CharacterMultiply; + :if ([ :len $Input ] = 0) do={ :return $Input; } :local Return ""; - :local Chars ("\80\81\82\83\84\85\86\87\88\89\8A\8B\8C\8D\8E\8F\90\91\92\93\94\95\96\97" . \ - "\98\99\9A\9B\9C\9D\9E\9F\A0\A1\A2\A3\A4\A5\A6\A7\A8\A9\AA\AB\AC\AD\AE\AF\B0\B1\B2\B3" . \ - "\B4\B5\B6\B7\B8\B9\BA\BB\BC\BD\BE\BF\C0\C1\C2\C3\C4\C5\C6\C7\C8\C9\CA\CB\CC\CD\CE\CF" . \ - "\D0\D1\D2\D3\D4\D5\D6\D7\D8\D9\DA\DB\DC\DD\DE\DF\E0\E1\E2\E3\E4\E5\E6\E7\E8\E9\EA\EB" . \ - "\EC\ED\EE\EF\F0\F1\F2\F3\F4\F5\F6\F7\F8\F9\FA\FB\FC\FD\FE\FF"); - :local Hex { "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"; "9"; "A"; "B"; "C"; "D"; "E"; "F" }; + :local Chars ( \ + "\00\01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F\10\11\12\13\14\15\16\17\18\19\1A\1B\1C\1D\1E\1F" . \ + [ $CharacterMultiply ("\00") 29 ] . "=" . [ $CharacterMultiply ("\00") 65 ] . "\7F" . \ + "\80\81\82\83\84\85\86\87\88\89\8A\8B\8C\8D\8E\8F\90\91\92\93\94\95\96\97\98\99\9A\9B\9C\9D\9E\9F" . \ + "\A0\A1\A2\A3\A4\A5\A6\A7\A8\A9\AA\AB\AC\AD\AE\AF\B0\B1\B2\B3\B4\B5\B6\B7\B8\B9\BA\BB\BC\BD\BE\BF" . \ + "\C0\C1\C2\C3\C4\C5\C6\C7\C8\C9\CA\CB\CC\CD\CE\CF\D0\D1\D2\D3\D4\D5\D6\D7\D8\D9\DA\DB\DC\DD\DE\DF" . \ + "\E0\E1\E2\E3\E4\E5\E6\E7\E8\E9\EA\EB\EC\ED\EE\EF\F0\F1\F2\F3\F4\F5\F6\F7\F8\F9\FA\FB\FC\FD\FE\FF"); + :local Hex "0123456789ABCDEF"; :for I from=0 to=([ :len $Input ] - 1) do={ :local Char [ :pick $Input $I ]; :local Replace [ :find $Chars $Char ]; - :if ($Char = "=") do={ - :set Char "=3D"; - } :if ([ :typeof $Replace ] = "num") do={ - :set Char ("=" . ($Hex->($Replace / 16 + 8)) . ($Hex->($Replace % 16))); + :set Char ("=" . [ :pick $Hex ($Replace / 16)] . [ :pick $Hex ($Replace % 16) ]); } :set Return ($Return . $Char); } From e4b10d4b76b7ccd22695ba5074857cdc542014ea Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Dec 2023 11:45:28 +0100 Subject: [PATCH 1752/2612] mod/notification-email: $QuotedPrintable: also encode question mark Following the RFC it is not required, but looks like Thunderbird has an issue here... https://datatracker.ietf.org/doc/html/rfc2045#section-6.7 --- mod/notification-email.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 76f198f..e10353c 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -179,7 +179,7 @@ :local Return ""; :local Chars ( \ "\00\01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F\10\11\12\13\14\15\16\17\18\19\1A\1B\1C\1D\1E\1F" . \ - [ $CharacterMultiply ("\00") 29 ] . "=" . [ $CharacterMultiply ("\00") 65 ] . "\7F" . \ + [ $CharacterMultiply ("\00") 29 ] . "=\00?" . [ $CharacterMultiply ("\00") 63 ] . "\7F" . \ "\80\81\82\83\84\85\86\87\88\89\8A\8B\8C\8D\8E\8F\90\91\92\93\94\95\96\97\98\99\9A\9B\9C\9D\9E\9F" . \ "\A0\A1\A2\A3\A4\A5\A6\A7\A8\A9\AA\AB\AC\AD\AE\AF\B0\B1\B2\B3\B4\B5\B6\B7\B8\B9\BA\BB\BC\BD\BE\BF" . \ "\C0\C1\C2\C3\C4\C5\C6\C7\C8\C9\CA\CB\CC\CD\CE\CF\D0\D1\D2\D3\D4\D5\D6\D7\D8\D9\DA\DB\DC\DD\DE\DF" . \ From 94607496ae07118e5bea8da728719c4c138e425f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Dec 2023 12:01:52 +0100 Subject: [PATCH 1753/2612] check-certificates: fix typo and syntax --- check-certificates.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 3410d4d..e9b5de1 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -126,7 +126,7 @@ $WaitFullyConnected; :if ($CertVal->"fingerprint" != [ /certificate/get $Cert fingerprint ]) do={ $LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was updated in place.") false; :set CertVal [ /certificate/get $Cert ]; - } else { + } else={ $LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; :local CertNew [ /certificate/find where name~("^" . [ $EscapeForRegEx [ $UrlEncode $LastName ] ] . "\\.(p12|pem)_[0-9]+\$") \ @@ -153,7 +153,7 @@ $WaitFullyConnected; /certificate/remove $Cert; /certificate/set $CertNew name=($CertVal->"name"); :set CertNewVal; - :set CertVal [ /certificate/get $CertNew ];; + :set CertVal [ /certificate/get $CertNew ]; } $SendNotification2 ({ origin=$0; silent=true; \ From 3df99b0ee08af968afb8ec0382acde448a5d79b3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Dec 2023 11:22:05 +0100 Subject: [PATCH 1754/2612] check-certificates: give full certificate chain --- check-certificates.rsc | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index e9b5de1..b6336ff 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -75,25 +75,45 @@ } :local FormatInfo do={ - :local CertVal $1; + :local Cert $1; :global FormatLine; :global FormatMultiLines; :global IfThenElse; - :global ParseKeyValueStore; - + :global EitherOr; + :local FormatExpire do={ :global CharacterReplace; :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; } + :local FormatCertChain do={ + :local Cert $1; + + :global ParseKeyValueStore; + + :local CertVal [ /certificate/get $Cert ]; + :local Return ""; + + :while (true) do={ + :set Return ($Return . [ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN"); + :if (($CertVal->"akid") = "" || ($CertVal->"akid") = ($CertVal->"skid")) do={ + :return $Return; + } + :set Return ($Return . " -> "); + :set CertVal [ /certificate/get [ find where skid=($CertVal->"akid") ] ]; + } + } + + :local CertVal [ /certificate/get $Cert ]; + :return ( \ [ $FormatLine "Name" ($CertVal->"name") ] . "\n" . \ [ $IfThenElse ([ :len ($CertVal->"common-name") ] > 0) ([ $FormatLine "CommonName" ($CertVal->"common-name") ] . "\n") ] . \ [ $IfThenElse ([ :len ($CertVal->"subject-alt-name") ] > 0) ([ $FormatMultiLines "SubjectAltNames" ($CertVal->"subject-alt-name") ] . "\n") ] . \ [ $FormatLine "Private key" [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] ] . "\n" . \ [ $FormatLine "Fingerprint" ($CertVal->"fingerprint") ] . "\n" . \ - [ $FormatLine "Issuer" ($CertVal->"ca" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN")) ] . "\n" . \ + [ $FormatLine "Issuer" [ $EitherOr ($CertVal->"ca") [ $FormatCertChain $Cert ] ] ] . "\n" . \ "Validity:\n" . \ [ $FormatLine " from" ($CertVal->"invalid-before") ] . "\n" . \ [ $FormatLine " to" ($CertVal->"invalid-after") ] . "\n" . \ @@ -105,6 +125,7 @@ $WaitFullyConnected; :foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ :local CertVal [ /certificate/get $Cert ]; + :local CertNew; :local LastName; :do { @@ -129,7 +150,7 @@ $WaitFullyConnected; } else={ $LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; - :local CertNew [ /certificate/find where name~("^" . [ $EscapeForRegEx [ $UrlEncode $LastName ] ] . "\\.(p12|pem)_[0-9]+\$") \ + :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 ]; @@ -158,7 +179,7 @@ $WaitFullyConnected; $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 $CertVal ]) }); + 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; @@ -176,7 +197,7 @@ $WaitFullyConnected; $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning: " . ($CertVal->"name")); \ - message=("A certificate on " . $Identity . " " . $State . ".\n\n" . [ $FormatInfo $CertVal ]) }); + 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; } From a08df7bdec4a7ddbd758d5066fc59ebb17709413 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Dec 2023 12:14:52 +0100 Subject: [PATCH 1755/2612] check-certificates: prevent infinte loop --- check-certificates.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index b6336ff..c501a28 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -95,7 +95,7 @@ :local CertVal [ /certificate/get $Cert ]; :local Return ""; - :while (true) do={ + :for I from=0 to=3 do={ :set Return ($Return . [ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN"); :if (($CertVal->"akid") = "" || ($CertVal->"akid") = ($CertVal->"skid")) do={ :return $Return; @@ -103,6 +103,7 @@ :set Return ($Return . " -> "); :set CertVal [ /certificate/get [ find where skid=($CertVal->"akid") ] ]; } + :return ($Return . "..."); } :local CertVal [ /certificate/get $Cert ]; From 8de6995c4b38f80439f0b70dc19f747f4f58f83d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Dec 2023 12:35:13 +0100 Subject: [PATCH 1756/2612] check-certificates: add workaround for broken certificates... ... where the issuer array is borked. Or is this a RouterOS issue? [eworm@carpo] > $InspectVar [ $ParseKeyValueStore [ /certificate/get ISRG-Root-X2 issuer ] ] -type-> array -key-> C -type-> str -value-> US,O=Internet Security Research Group,CN=ISRG Root X2 A good certificate looks like this: [eworm@carpo] > $InspectVar [ $ParseKeyValueStore [ /certificate/get [ find where name~"eworm.net" ] issuer ] ] -type-> array -key-> C -type-> str -value-> US -key-> CN -type-> str -value-> E1 -key-> O -type-> str -value-> Let's Encrypt --- check-certificates.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index c501a28..87ad1e5 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -90,18 +90,20 @@ :local FormatCertChain do={ :local Cert $1; + :global EitherOr; :global ParseKeyValueStore; :local CertVal [ /certificate/get $Cert ]; :local Return ""; :for I from=0 to=3 do={ - :set Return ($Return . [ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN"); + :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 . " -> "); - :set CertVal [ /certificate/get [ find where skid=($CertVal->"akid") ] ]; } :return ($Return . "..."); } From a12ccba29e93372e81e41ed1ceeb57cba74e3602 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Dec 2023 12:53:50 +0100 Subject: [PATCH 1757/2612] check-certificates: improve wording --- check-certificates.rsc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 87ad1e5..bc6f43a 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -80,7 +80,6 @@ :global FormatLine; :global FormatMultiLines; :global IfThenElse; - :global EitherOr; :local FormatExpire do={ :global CharacterReplace; @@ -96,7 +95,7 @@ :local CertVal [ /certificate/get $Cert ]; :local Return ""; - :for I from=0 to=3 do={ + :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") ] ]; @@ -116,7 +115,7 @@ [ $IfThenElse ([ :len ($CertVal->"subject-alt-name") ] > 0) ([ $FormatMultiLines "SubjectAltNames" ($CertVal->"subject-alt-name") ] . "\n") ] . \ [ $FormatLine "Private key" [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] ] . "\n" . \ [ $FormatLine "Fingerprint" ($CertVal->"fingerprint") ] . "\n" . \ - [ $FormatLine "Issuer" [ $EitherOr ($CertVal->"ca") [ $FormatCertChain $Cert ] ] ] . "\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" . \ From 9fb596135e335f0ca4cfc1a8ad6047b58ba319d5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Dec 2023 22:10:15 +0100 Subject: [PATCH 1758/2612] check-certificates: properly renew from template --- check-certificates.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index bc6f43a..45e18e4 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -146,7 +146,7 @@ $WaitFullyConnected; } } - :if ($CertVal->"fingerprint" != [ /certificate/get $Cert fingerprint ]) do={ + :if ([ :len ($CertVal->"fingerprint") ] > 0 && $CertVal->"fingerprint" != [ /certificate/get $Cert fingerprint ]) do={ $LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was updated in place.") false; :set CertVal [ /certificate/get $Cert ]; } else={ From d3611cebbd6ae725b209bbc82a65751d8e8f5770 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Dec 2023 22:21:51 +0100 Subject: [PATCH 1759/2612] mod/notification-email: $NotificationFunctions->"email": support hook for signature You can compose your own signature by creating a function: :global NotificationEMailSignature do={ :global EitherOr; :local RouterBoard [ /system/routerboard/get ]; :return ( \ [ $EitherOr ($RouterBoard->"board-name") ($RouterBoard->"model") ] . " s/n " . $RouterBoard->"serial-number" . " | " . \ "RouterOS " . [ /system/package/update/get installed-version ] . " | " . \ "IP " . [ /ip/cloud/get public-address ]); } --- mod/notification-email.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index e10353c..5d5aed1 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -131,6 +131,7 @@ :global EitherOr; :global IfThenElse; + :global NotificationEMailSignature; :global NotificationEMailSubject; :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; @@ -144,7 +145,7 @@ :if ([ :typeof $EmailQueue ] = "nothing") do={ :set EmailQueue ({}); } - :local Signature [ /system/note/get note ]; + :local Signature [ $EitherOr [ $NotificationEMailSignature ] [ /system/note/get note ] ]; :set ($EmailQueue->[ :len $EmailQueue ]) { to=$To; cc=$Cc; subject=[ $NotificationEMailSubject ($Notification->"subject") ]; From 52b8e67309ce8497482bf057cc0934badb8cefe8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 27 Nov 2023 18:30:11 +0100 Subject: [PATCH 1760/2612] =?UTF-8?q?celebrating=20=E2=9C=A8=E2=AD=90=201.?= =?UTF-8?q?000=20stars=20=E2=AD=90=E2=9C=A8=20on=20Github!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- global-functions.rsc | 3 ++- news-and-changes.rsc | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 34d3df0..93da798 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 114; +:global ExpectedConfigVersion 115; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -1320,6 +1320,7 @@ "scissors"="\E2\9C\82"; "sparkles"="\E2\9C\A8"; "speech-balloon"="\F0\9F\92\AC"; + "star"="\E2\AD\90"; "warning-sign"="\E2\9A\A0"; "white-heavy-check-mark"="\E2\9C\85" } diff --git a/news-and-changes.rsc b/news-and-changes.rsc index f4c50c2..1040a67 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -4,6 +4,7 @@ :global IfThenElse; :global RequiredRouterOS; +:global SymbolForNotification; # News, changes and migration up to change 95: # https://git.eworm.de/cgit/routeros-scripts/plain/global-config.changes?h=change-95 @@ -29,6 +30,7 @@ 112="Enhanced 'mod/ssh-keys-import' to record the fingerprint of keys."; 113="Added helper functions for easier setup to Matrix notification module."; 114="All relevant scripts were ported to new wifi package for RouterOS 7.13 and later. Migration is complex and thus not done automatically!"; + 115=("Celebrating " . [ $SymbolForNotification "sparkles,star" ] . "1.000 stars " . [ $SymbolForNotification "star,sparkles" ] . "on Github! Please continue starring..."); }; # Migration steps to be applied on script updates From 69af86957271e51fddd8a34a1135fe0c95d7cbca Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 27 Nov 2023 18:38:57 +0100 Subject: [PATCH 1761/2612] mention the donation hint... --- global-functions.rsc | 4 +++- news-and-changes.rsc | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 93da798..952f869 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 115; +:global ExpectedConfigVersion 116; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -1297,6 +1297,7 @@ :local Symbols { "abacus"="\F0\9F\A7\AE"; "alarm-clock"="\E2\8F\B0"; + "arrow-down"="\E2\AC\87"; "arrow-up"="\E2\AC\86"; "calendar"="\F0\9F\93\85"; "card-file-box"="\F0\9F\97\83"; @@ -1307,6 +1308,7 @@ "earth"="\F0\9F\8C\8D"; "fire"="\F0\9F\94\A5"; "floppy-disk"="\F0\9F\92\BE"; + "heart"="\E2\99\A5"; "high-voltage-sign"="\E2\9A\A1"; "incoming-envelope"="\F0\9F\93\A8"; "information"="\E2\84\B9"; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 1040a67..11b4e61 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -2,6 +2,8 @@ # Copyright (c) 2019-2023 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +:global IDonate; + :global IfThenElse; :global RequiredRouterOS; :global SymbolForNotification; @@ -31,6 +33,9 @@ 113="Added helper functions for easier setup to Matrix notification module."; 114="All relevant scripts were ported to new wifi package for RouterOS 7.13 and later. Migration is complex and thus not done automatically!"; 115=("Celebrating " . [ $SymbolForNotification "sparkles,star" ] . "1.000 stars " . [ $SymbolForNotification "star,sparkles" ] . "on Github! Please continue starring..."); + 116=("... and also please keep in mind that it takes a huge amount of time maintaining these scripts. " . [ $IfThenElse ($IDonate != true) \ + ("Following the donation hint " . [ $SymbolForNotification "arrow-down" "below" ] . "to keep me motivated is much appreciated. Thanks!") \ + ("Looks like you did donate already. " . [ $SymbolForNotification "heart" "<3" ] . "Much appreciated, thanks!") ]); }; # Migration steps to be applied on script updates From db5ff00b5ae6592c7996f1044230595a8936ce92 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Dec 2023 10:59:23 +0100 Subject: [PATCH 1762/2612] doc/capsman-download-packages: mention package-path --- doc/capsman-download-packages.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index ccd2ee5..eae6dc3 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -18,7 +18,11 @@ This script automatically downloads these packages. Requirements and installation ----------------------------- -Just install the script on CAPsMAN device. +Make sure you have the `package-path` set in your CAPsMAN configuration, +as that is where packages are downloaded to and where the system expects +them. + +Then just install the script on CAPsMAN device. Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` package (`/interface/wifiwave2`) or legacy wifi with CAPsMAN (`/caps-man`) you need to install a different script. From f9528f0ac55da4ce2ef904dc10760012a68ae75a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Dec 2023 15:57:28 +0100 Subject: [PATCH 1763/2612] fw-addr-lists: warn on possible truncation ... as fetch truncates data at about 64kB, reported in SUP-132297. --- fw-addr-lists.rsc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 845b597..34a06bc 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -16,6 +16,7 @@ :global CertificateAvailable; :global EitherOr; :global LogPrintExit2; +:global LogPrintOnce; :global ScriptLock; :global WaitFullyConnected; @@ -72,6 +73,10 @@ $WaitFullyConnected; $LogPrintExit2 warning $0 ("Failed downloading list from: " . $List->"url") false; } + :if ([ :len $Data ] > 63000) do={ + $LogPrintOnce warning $0 ("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")); From 5fdc8d9e65a9a37377e53ceb4b15258d734e764f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 14 Dec 2023 08:54:04 +0100 Subject: [PATCH 1764/2612] doc/mode-button: document required type of led --- doc/mode-button.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mode-button.md b/doc/mode-button.md index 6374b83..38a4b11 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -52,7 +52,7 @@ Configuration The configuration goes to `global-config-overlay`, these are the parameters: * `ModeButton`: an array with defined actions -* `ModeButtonLED`: led to give visual feedback +* `ModeButtonLED`: led to give visual feedback, `type` must be `on` or `off` > â„šī¸ **Info**: Copy relevant configuration from > [`global-config`](../global-config.rsc) (the one without `-overlay`) to From 5aaa24b50737686f81bf16ec22c39f1b7a596420 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 20 Dec 2023 12:11:12 +0100 Subject: [PATCH 1765/2612] capsman-download-packages: use default set for legacy capsman... ... as well - now that 'wireless' package has been split from 'routeros' guessing kind of broke. It required several attempts and intermittent errors in logs to get things right. --- capsman-download-packages.capsman.rsc | 31 ++++++-------------- capsman-download-packages.template.rsc | 39 ++++++-------------------- doc/capsman-download-packages.md | 5 ++-- 3 files changed, 18 insertions(+), 57 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index 99ff052..a42edd5 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -53,29 +53,14 @@ $WaitFullyConnected; } } -:if ([ :len [ /system/logging/find where topics~"error" !(topics~"!error") \ - !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ - $LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \ - "Probably can not download packages automatically.") false; -} else={ - :if ($Updated = false && [ /system/resource/get uptime ] < 2m) do={ - $LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false; - :delay 2m; - } -} - -:foreach Log in=[ /log/find where topics=({"caps"; "error"}) \ - message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \ - "-.*\\.npk', no such file") ] do={ - :local Message [ /log/get $Log message ]; - :local Package [ :pick $Message \ - ([ :find $Message "'" ] + 1) \ - [ :find $Message ("-" . $InstalledVersion . "-") ] ]; - :local Arch [ :pick $Message \ - ([ :find $Message ("-" . $InstalledVersion . "-") ] + 2 + [ :len $InstalledVersion ]) \ - [ :find $Message ".npk" ] ]; - :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ - :set Updated true; +:if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ + $LogPrintExit2 info $0 ("No packages available, downloading default set.") false; + :foreach Arch in={ "arm"; "mipsbe" } do={ + :foreach Package in={ "routeros"; "wireless" } do={ + :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ + :set Updated true; + } + } } } diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 7b37c36..299c2fc 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -56,38 +56,15 @@ $WaitFullyConnected; } } -# NOT /interface/wifi/ # -# NOT /interface/wifiwave2/ # -:if ([ :len [ /system/logging/find where topics~"error" !(topics~"!error") \ - !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ - $LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \ - "Probably can not download packages automatically.") false; -} else={ - :if ($Updated = false && [ /system/resource/get uptime ] < 2m) do={ - $LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false; - :delay 2m; - } -} - -:foreach Log in=[ /log/find where topics=({"caps"; "error"}) \ - message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \ - "-.*\\.npk', no such file") ] do={ - :local Message [ /log/get $Log message ]; - :local Package [ :pick $Message \ - ([ :find $Message "'" ] + 1) \ - [ :find $Message ("-" . $InstalledVersion . "-") ] ]; - :local Arch [ :pick $Message \ - ([ :find $Message ("-" . $InstalledVersion . "-") ] + 2 + [ :len $InstalledVersion ]) \ - [ :find $Message ".npk" ] ]; - :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ - :set Updated true; - } -} -# NOT /interface/wifiwave2/ # -# NOT /interface/wifi/ # -# NOT /caps-man/ # :if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ $LogPrintExit2 info $0 ("No packages available, downloading default set.") false; +# NOT /interface/wifi/ # +# NOT /interface/wifiwave2/ # + :foreach Arch in={ "arm"; "mipsbe" } do={ + :foreach Package in={ "routeros"; "wireless" } do={ +# NOT /interface/wifi/ # +# NOT /interface/wifiwave2/ # +# NOT /caps-man/ # :foreach Arch in={ "arm"; "arm64" } do={ # NOT /interface/wifi/ # :foreach Package in={ "routeros"; "wifiwave2" } do={ @@ -95,13 +72,13 @@ $WaitFullyConnected; # NOT /interface/wifiwave2/ # :foreach Package in={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" } do={ # NOT /interface/wifiwave2/ # +# NOT /caps-man/ # :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ :set Updated true; } } } } -# NOT /caps-man/ # :if ($Updated = true) do={ :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index eae6dc3..1292504 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -55,12 +55,11 @@ For legacy CAPsMAN: Packages available in local storage in older version are downloaded unconditionally. -If no packages are found the script tries to download missing packages for -legacy CAPsMAN by guessing from system log. For `wifi` and `wifiwave2` a -default set of packages is downloaded. +If no packages are found the script downloads a default set of packages: * `wifi`: `routeros`, `wifi-qcom` and `wifi-qcom-ac` for *arm* and *arm64* * `wifiwave2`: `routeros` and `wifiwave2` for *arm* and *arm64* + * legacy CAPsMAN: `routeros` and `wireless` for *arm* and *mipsbe* > â„šī¸ **Info**: If you have packages in the directory and things go wrong for > what ever unknown reason: Remove **all** packages and start over. From 0377064f65e124aa7ce060f18310fb65976b412e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 20 Dec 2023 12:29:24 +0100 Subject: [PATCH 1766/2612] capsman-download-packages: avaiable packages only... ... as things became more complicated with 'wifi-qcom*'. --- capsman-download-packages.template.rsc | 4 +++- capsman-download-packages.wifi.rsc | 4 +++- doc/capsman-download-packages.md | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 299c2fc..8cbd733 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -70,7 +70,9 @@ $WaitFullyConnected; :foreach Package in={ "routeros"; "wifiwave2" } do={ # NOT /interface/wifi/ # # NOT /interface/wifiwave2/ # - :foreach Package in={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" } do={ + :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/ # :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 3552924..89fe0dc 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -56,7 +56,9 @@ $WaitFullyConnected; :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"; "wifi-qcom"; "wifi-qcom-ac" } 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; } diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index 1292504..5b9550d 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -57,7 +57,7 @@ unconditionally. If no packages are found the script downloads a default set of packages: - * `wifi`: `routeros`, `wifi-qcom` and `wifi-qcom-ac` for *arm* and *arm64* + * `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* From 1c26d082673e9b72638a3001ab9bedce9399407a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 21 Dec 2023 11:33:09 +0100 Subject: [PATCH 1767/2612] mod/ssh-keys-import: unbreak import from file Looks like this broke in c3045f372350bd8dd0a8f10efb8a4b938e896145 where a non-existent variable name was used. --- mod/ssh-keys-import.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 1513114..79c1e22 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -85,7 +85,7 @@ :local Continue false; :local Line [ :pick $Keys 0 [ :find $Keys "\n" ] ]; :set Keys [ :pick $Keys ([ :find $Keys "\n" ] + 1) [ :len $Keys ] ]; - :local KeyVal [ :toarray [ $CharacterReplace $Key " " "," ] ]; + :local KeyVal [ :toarray [ $CharacterReplace $Line " " "," ] ]; :if ($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa") do={ :do { $SSHKeysImport $Line $User; From 777c388b431ca0673ccec833358590af69d8eeb7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 22 Dec 2023 14:47:54 +0100 Subject: [PATCH 1768/2612] global-functions: $GetMacVendor: get new certificate The service now uses: GTS CA 1P5 -> GTS Root R1 --- certs/GTS CA 1P5.pem | 238 +++++++++++++++++++++++++++++++++++++++++++ global-functions.rsc | 2 +- 2 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 certs/GTS CA 1P5.pem diff --git a/certs/GTS CA 1P5.pem b/certs/GTS CA 1P5.pem new file mode 100644 index 0000000..5be738d --- /dev/null +++ b/certs/GTS CA 1P5.pem @@ -0,0 +1,238 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 02:03:bc:50:a3:27:53:f0:91:80:22:ed:f1 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1 + Validity + Not Before: Aug 13 00:00:42 2020 GMT + Not After : Sep 30 00:00:42 2027 GMT + Subject: C=US, O=Google Trust Services LLC, CN=GTS CA 1P5 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b3:82:f0:24:8c:bf:2d:87:af:b2:d9:a7:ae:fa: + ca:ba:44:d6:5b:3e:fe:b2:f7:b2:65:16:dc:de:10: + e8:4f:2d:10:58:5a:28:86:87:a1:ee:6a:b3:a0:d9: + 75:4f:7f:a1:52:01:8b:55:a8:4a:5b:06:48:c8:36: + 12:25:ab:89:f9:f2:23:5f:9d:60:65:f9:5c:da:be: + 3a:e8:5c:6d:7d:9c:d0:84:18:85:30:cd:4e:9b:ec: + 3c:d8:b3:e1:96:d4:f3:c5:0b:65:db:8f:b0:74:cb: + f6:1e:f3:78:f1:ac:95:c5:dd:73:c3:31:88:81:af: + 74:aa:6f:fd:0c:e3:05:95:f0:c5:10:4f:65:63:fa: + a0:af:c6:18:3d:c5:a1:df:97:79:d7:05:89:b3:30: + b0:74:ae:3d:92:10:6b:8c:15:77:dd:0b:04:57:fb: + 81:03:dd:ea:22:34:d5:e5:56:b2:f0:c4:8d:41:b1: + c3:02:db:62:ec:80:d0:ff:76:d4:86:e4:04:1a:b6: + b6:0c:2b:62:71:7d:d9:af:d9:f1:5e:fa:c0:1e:ca: + a0:19:5c:55:f0:80:d1:2a:0c:07:86:90:9f:35:e3: + 28:2b:5b:ef:23:c8:a3:1d:a4:a3:3a:ee:fe:83:dc: + 82:4c:25:b0:4d:c5:51:ad:9e:9b:d3:5b:84:c2:1a: + 5a:e9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + D5:FC:9E:0D:DF:1E:CA:DD:08:97:97:6E:2B:C5:5F:C5:2B:F5:EC:B8 + X509v3 Authority Key Identifier: + E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E + Authority Information Access: + OCSP - URI:http://ocsp.pki.goog/gtsr1 + CA Issuers - URI:http://pki.goog/repo/certs/gtsr1.der + X509v3 CRL Distribution Points: + Full Name: + URI:http://crl.pki.goog/gtsr1/gtsr1.crl + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.11129.2.5.3 + CPS: https://pki.goog/repository/ + Policy: 2.23.140.1.2.1 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 6c:63:27:ee:23:df:e5:52:68:4d:81:66:91:85:df:7d:65:e5: + 5b:37:31:08:26:b2:07:5d:9a:be:b1:ca:01:b9:ad:bf:9d:77: + f6:51:1d:d7:98:c5:0b:49:a1:7b:a1:d7:d3:68:e5:44:0f:8b: + ba:36:dd:42:82:77:d2:8d:dd:f5:3f:fb:eb:c8:07:98:93:ee: + 5a:d0:b5:3d:de:4b:1c:2d:8c:4d:ec:7e:8c:7b:fe:4e:40:fd: + f0:b4:b3:59:02:10:51:5c:e3:c0:2b:fd:b7:06:48:51:7e:09: + 5e:3f:0f:dc:a7:fe:97:e7:79:c5:0e:44:89:78:c5:69:59:29: + a0:9a:3a:48:36:29:a6:94:93:55:2d:b8:47:b5:e9:96:b5:9f: + 07:cd:a6:ab:3e:32:8a:c0:86:83:c5:c1:41:c8:9f:2f:35:8e: + 0d:c0:07:7a:e1:ac:c9:65:b5:cb:8a:a7:dd:71:d8:61:65:39: + 84:ac:32:3e:f7:7a:36:f1:56:9f:57:a9:41:6d:5a:90:a7:db: + 3a:ea:75:80:0c:63:0b:69:74:6f:07:4c:15:f3:37:28:a5:19: + a4:6e:f5:f6:20:cd:63:b2:7e:c4:2b:09:75:89:da:d1:3c:2e: + 72:4f:36:1a:a1:9e:44:d0:cd:9b:a6:23:08:3f:97:a1:a7:9e: + 5a:a5:f7:09:94:ad:5d:76:5d:28:56:d1:1a:66:51:51:07:7b: + de:3d:b0:c8:ef:30:7a:24:2d:be:b8:b3:86:f6:4b:f7:f0:b5: + 4f:ff:ce:c6:f9:f6:3f:2a:27:08:0f:09:3e:23:5a:c7:e3:42: + 2d:7a:36:e4:3d:98:96:60:39:98:ea:d1:db:63:2a:eb:78:09: + b1:4e:21:b3:8e:b7:ce:3e:92:f1:95:5c:a4:39:d0:c0:2b:c8: + 53:15:f5:d2:2f:82:cd:06:74:67:99:90:77:37:0a:97:2d:c5: + 1c:1e:f4:d0:5b:e9:15:e3:ea:02:09:c8:13:d7:13:70:65:bf: + fb:88:9b:5a:25:be:77:09:e1:a7:6a:4e:11:75:b9:1e:4d:f1: + 00:1b:6a:66:79:8e:c3:6e:d8:6d:a2:22:a2:6d:05:fb:2c:f2: + f1:50:e5:a0:d1:d8:9f:35:7d:fc:70:ab:59:2a:02:f1:be:b0: + d3:f1:f8:cd:12:b9:6a:25:90:5b:e3:85:20:e6:f5:da:cb:40: + 1c:19:34:20:03:61:77:ba:7f:48:0f:49:0b:29:eb:e7:61:64: + c7:63:d1:47:eb:1c:e1:ee:94:46:ef:39:73:cc:ee:4f:2b:8d: + dc:fb:58:a7:b3:65:20:99:95:b9:fb:55:6f:d7:96:6e:94:3d: + f4:7a:92:8e:63:1d:df:6d +-----BEGIN CERTIFICATE----- +MIIFjDCCA3SgAwIBAgINAgO8UKMnU/CRgCLt8TANBgkqhkiG9w0BAQsFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw +MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFQNTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALOC8CSMvy2Hr7LZp676yrpE1ls+/rL3smUW3N4Q6E8tEFha +KIaHoe5qs6DZdU9/oVIBi1WoSlsGSMg2EiWrifnyI1+dYGX5XNq+OuhcbX2c0IQY +hTDNTpvsPNiz4ZbU88ULZduPsHTL9h7zePGslcXdc8MxiIGvdKpv/QzjBZXwxRBP +ZWP6oK/GGD3Fod+XedcFibMwsHSuPZIQa4wVd90LBFf7gQPd6iI01eVWsvDEjUGx +wwLbYuyA0P921IbkBBq2tgwrYnF92a/Z8V76wB7KoBlcVfCA0SoMB4aQnzXjKCtb +7yPIox2kozru/oPcgkwlsE3FUa2em9NbhMIaWukCAwEAAaOCAXYwggFyMA4GA1Ud +DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T +AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU1fyeDd8eyt0Il5duK8VfxSv17LgwHwYD +VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG +CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw +AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt +MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsME0G +A1UdIARGMEQwOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br +aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAgEA +bGMn7iPf5VJoTYFmkYXffWXlWzcxCCayB12avrHKAbmtv5139lEd15jFC0mhe6HX +02jlRA+LujbdQoJ30o3d9T/768gHmJPuWtC1Pd5LHC2MTex+jHv+TkD98LSzWQIQ +UVzjwCv9twZIUX4JXj8P3Kf+l+d5xQ5EiXjFaVkpoJo6SDYpppSTVS24R7XplrWf +B82mqz4yisCGg8XBQcifLzWODcAHeuGsyWW1y4qn3XHYYWU5hKwyPvd6NvFWn1ep +QW1akKfbOup1gAxjC2l0bwdMFfM3KKUZpG719iDNY7J+xCsJdYna0Twuck82GqGe +RNDNm6YjCD+XoaeeWqX3CZStXXZdKFbRGmZRUQd73j2wyO8weiQtvrizhvZL9/C1 +T//Oxvn2PyonCA8JPiNax+NCLXo25D2YlmA5mOrR22Mq63gJsU4hs463zj6S8ZVc +pDnQwCvIUxX10i+CzQZ0Z5mQdzcKly3FHB700FvpFePqAgnIE9cTcGW/+4ibWiW+ +dwnhp2pOEXW5Hk3xABtqZnmOw27YbaIiom0F+yzy8VDloNHYnzV9/HCrWSoC8b6w +0/H4zRK5aiWQW+OFIOb12stAHBk0IANhd7p/SA9JCynr52Fkx2PRR+sc4e6URu85 +c8zuTyuN3PtYp7NlIJmVuftVb9eWbpQ99HqSjmMd320= +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 02:03:e5:93:6f:31:b0:13:49:88:6b:a2:17 + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1 + Validity + Not Before: Jun 22 00:00:00 2016 GMT + Not After : Jun 22 00:00:00 2036 GMT + Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:b6:11:02:8b:1e:e3:a1:77:9b:3b:dc:bf:94:3e: + b7:95:a7:40:3c:a1:fd:82:f9:7d:32:06:82:71:f6: + f6:8c:7f:fb:e8:db:bc:6a:2e:97:97:a3:8c:4b:f9: + 2b:f6:b1:f9:ce:84:1d:b1:f9:c5:97:de:ef:b9:f2: + a3:e9:bc:12:89:5e:a7:aa:52:ab:f8:23:27:cb:a4: + b1:9c:63:db:d7:99:7e:f0:0a:5e:eb:68:a6:f4:c6: + 5a:47:0d:4d:10:33:e3:4e:b1:13:a3:c8:18:6c:4b: + ec:fc:09:90:df:9d:64:29:25:23:07:a1:b4:d2:3d: + 2e:60:e0:cf:d2:09:87:bb:cd:48:f0:4d:c2:c2:7a: + 88:8a:bb:ba:cf:59:19:d6:af:8f:b0:07:b0:9e:31: + f1:82:c1:c0:df:2e:a6:6d:6c:19:0e:b5:d8:7e:26: + 1a:45:03:3d:b0:79:a4:94:28:ad:0f:7f:26:e5:a8: + 08:fe:96:e8:3c:68:94:53:ee:83:3a:88:2b:15:96: + 09:b2:e0:7a:8c:2e:75:d6:9c:eb:a7:56:64:8f:96: + 4f:68:ae:3d:97:c2:84:8f:c0:bc:40:c0:0b:5c:bd: + f6:87:b3:35:6c:ac:18:50:7f:84:e0:4c:cd:92:d3: + 20:e9:33:bc:52:99:af:32:b5:29:b3:25:2a:b4:48: + f9:72:e1:ca:64:f7:e6:82:10:8d:e8:9d:c2:8a:88: + fa:38:66:8a:fc:63:f9:01:f9:78:fd:7b:5c:77:fa: + 76:87:fa:ec:df:b1:0e:79:95:57:b4:bd:26:ef:d6: + 01:d1:eb:16:0a:bb:8e:0b:b5:c5:c5:8a:55:ab:d3: + ac:ea:91:4b:29:cc:19:a4:32:25:4e:2a:f1:65:44: + d0:02:ce:aa:ce:49:b4:ea:9f:7c:83:b0:40:7b:e7: + 43:ab:a7:6c:a3:8f:7d:89:81:fa:4c:a5:ff:d5:8e: + c3:ce:4b:e0:b5:d8:b3:8e:45:cf:76:c0:ed:40:2b: + fd:53:0f:b0:a7:d5:3b:0d:b1:8a:a2:03:de:31:ad: + cc:77:ea:6f:7b:3e:d6:df:91:22:12:e6:be:fa:d8: + 32:fc:10:63:14:51:72:de:5d:d6:16:93:bd:29:68: + 33:ef:3a:66:ec:07:8a:26:df:13:d7:57:65:78:27: + de:5e:49:14:00:a2:00:7f:9a:a8:21:b6:a9:b1:95: + b0:a5:b9:0d:16:11:da:c7:6c:48:3c:40:e0:7e:0d: + 5a:cd:56:3c:d1:97:05:b9:cb:4b:ed:39:4b:9c:c4: + 3f:d2:55:13:6e:24:b0:d6:71:fa:f4:c1:ba:cc:ed: + 1b:f5:fe:81:41:d8:00:98:3d:3a:c8:ae:7a:98:37: + 18:05:95 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E + Signature Algorithm: sha384WithRSAEncryption + Signature Value: + 9f:aa:42:26:db:0b:9b:be:ff:1e:96:92:2e:3e:a2:65:4a:6a: + 98:ba:22:cb:7d:c1:3a:d8:82:0a:06:c6:f6:a5:de:c0:4e:87: + 66:79:a1:f9:a6:58:9c:aa:f9:b5:e6:60:e7:e0:e8:b1:1e:42: + 41:33:0b:37:3d:ce:89:70:15:ca:b5:24:a8:cf:6b:b5:d2:40: + 21:98:cf:22:34:cf:3b:c5:22:84:e0:c5:0e:8a:7c:5d:88:e4: + 35:24:ce:9b:3e:1a:54:1e:6e:db:b2:87:a7:fc:f3:fa:81:55: + 14:62:0a:59:a9:22:05:31:3e:82:d6:ee:db:57:34:bc:33:95: + d3:17:1b:e8:27:a2:8b:7b:4e:26:1a:7a:5a:64:b6:d1:ac:37: + f1:fd:a0:f3:38:ec:72:f0:11:75:9d:cb:34:52:8d:e6:76:6b: + 17:c6:df:86:ab:27:8e:49:2b:75:66:81:10:21:a6:ea:3e:f4: + ae:25:ff:7c:15:de:ce:8c:25:3f:ca:62:70:0a:f7:2f:09:66: + 07:c8:3f:1c:fc:f0:db:45:30:df:62:88:c1:b5:0f:9d:c3:9f: + 4a:de:59:59:47:c5:87:22:36:e6:82:a7:ed:0a:b9:e2:07:a0: + 8d:7b:7a:4a:3c:71:d2:e2:03:a1:1f:32:07:dd:1b:e4:42:ce: + 0c:00:45:61:80:b5:0b:20:59:29:78:bd:f9:55:cb:63:c5:3c: + 4c:f4:b6:ff:db:6a:5f:31:6b:99:9e:2c:c1:6b:50:a4:d7:e6: + 18:14:bd:85:3f:67:ab:46:9f:a0:ff:42:a7:3a:7f:5c:cb:5d: + b0:70:1d:2b:34:f5:d4:76:09:0c:eb:78:4c:59:05:f3:33:42: + c3:61:15:10:1b:77:4d:ce:22:8c:d4:85:f2:45:7d:b7:53:ea: + ef:40:5a:94:0a:5c:20:5f:4e:40:5d:62:22:76:df:ff:ce:61: + bd:8c:23:78:d2:37:02:e0:8e:de:d1:11:37:89:f6:bf:ed:49: + 07:62:ae:92:ec:40:1a:af:14:09:d9:d0:4e:b2:a2:f7:be:ee: + ee:d8:ff:dc:1a:2d:de:b8:36:71:e2:fc:79:b7:94:25:d1:48: + 73:5b:a1:35:e7:b3:99:67:75:c1:19:3a:2b:47:4e:d3:42:8e: + fd:31:c8:16:66:da:d2:0c:3c:db:b3:8e:c9:a1:0d:80:0f:7b: + 16:77:14:bf:ff:db:09:94:b2:93:bc:20:58:15:e9:db:71:43: + f3:de:10:c3:00:dc:a8:2a:95:b6:c2:d6:3f:90:6b:76:db:6c: + fe:8c:bc:f2:70:35:0c:dc:99:19:35:dc:d7:c8:46:63:d5:36: + 71:ae:57:fb:b7:82:6d:dc +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo +27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w +Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw +TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl +qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH +szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 +Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk +MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p +aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN +VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb +C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy +h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 +7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J +ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef +MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ +Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT +6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ +0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm +2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb +bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c +-----END CERTIFICATE----- diff --git a/global-functions.rsc b/global-functions.rsc index 952f869..c32e742 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -426,7 +426,7 @@ } :do { - :if ([ $CertificateAvailable "R3" ] = false) do={ + :if ([ $CertificateAvailable "GTS CA 1P5" ] = false) do={ $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; } :local Vendor ([ /tool/fetch check-certificate=yes-without-crl \ From 9a73fc526f1c5cbece6790f2d11049a2667856ef Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 1 Jan 2024 15:25:25 +0100 Subject: [PATCH 1769/2612] update copyright for 2024 --- accesslist-duplicates.capsman.rsc | 2 +- accesslist-duplicates.local.rsc | 2 +- accesslist-duplicates.template.rsc | 2 +- accesslist-duplicates.wifi.rsc | 2 +- accesslist-duplicates.wifiwave2.rsc | 2 +- backup-cloud.rsc | 2 +- backup-email.rsc | 2 +- backup-partition.rsc | 2 +- backup-upload.rsc | 2 +- capsman-download-packages.capsman.rsc | 2 +- capsman-download-packages.template.rsc | 2 +- capsman-download-packages.wifi.rsc | 2 +- capsman-download-packages.wifiwave2.rsc | 2 +- capsman-rolling-upgrade.capsman.rsc | 2 +- capsman-rolling-upgrade.template.rsc | 2 +- capsman-rolling-upgrade.wifi.rsc | 2 +- capsman-rolling-upgrade.wifiwave2.rsc | 2 +- certificate-renew-issued.rsc | 2 +- check-certificates.rsc | 2 +- check-health.rsc | 2 +- check-lte-firmware-upgrade.rsc | 2 +- check-routeros-update.rsc | 2 +- collect-wireless-mac.capsman.rsc | 2 +- collect-wireless-mac.local.rsc | 2 +- collect-wireless-mac.template.rsc | 2 +- collect-wireless-mac.wifi.rsc | 2 +- collect-wireless-mac.wifiwave2.rsc | 2 +- daily-psk.capsman.rsc | 2 +- daily-psk.local.rsc | 2 +- daily-psk.template.rsc | 2 +- daily-psk.wifi.rsc | 2 +- daily-psk.wifiwave2.rsc | 2 +- dhcp-lease-comment.capsman.rsc | 2 +- dhcp-lease-comment.local.rsc | 2 +- dhcp-lease-comment.template.rsc | 2 +- dhcp-lease-comment.wifi.rsc | 2 +- dhcp-lease-comment.wifiwave2.rsc | 2 +- dhcp-to-dns.rsc | 2 +- firmware-upgrade-reboot.rsc | 2 +- fw-addr-lists.rsc | 2 +- global-config-overlay.rsc | 2 +- global-config.rsc | 2 +- global-functions.rsc | 2 +- global-wait.rsc | 2 +- gps-track.rsc | 2 +- hotspot-to-wpa-cleanup.capsman.rsc | 2 +- hotspot-to-wpa-cleanup.template.rsc | 2 +- hotspot-to-wpa-cleanup.wifi.rsc | 2 +- hotspot-to-wpa-cleanup.wifiwave2.rsc | 2 +- hotspot-to-wpa.capsman.rsc | 2 +- hotspot-to-wpa.template.rsc | 2 +- hotspot-to-wpa.wifi.rsc | 2 +- hotspot-to-wpa.wifiwave2.rsc | 2 +- ip-addr-bridge.rsc | 2 +- ipsec-to-dns.rsc | 2 +- ipv6-update.rsc | 2 +- lease-script.rsc | 2 +- leds-day-mode.rsc | 2 +- leds-night-mode.rsc | 2 +- leds-toggle-mode.rsc | 2 +- log-forward.rsc | 2 +- mod/bridge-port-to.rsc | 2 +- mod/bridge-port-vlan.rsc | 2 +- mod/inspectvar.rsc | 2 +- mod/ipcalc.rsc | 2 +- mod/notification-email.rsc | 2 +- mod/notification-matrix.rsc | 2 +- mod/notification-ntfy.rsc | 2 +- mod/notification-telegram.rsc | 2 +- mod/scriptrunonce.rsc | 2 +- mod/ssh-keys-import.rsc | 2 +- mode-button.rsc | 2 +- netwatch-dns.rsc | 2 +- netwatch-notify.rsc | 2 +- news-and-changes.rsc | 2 +- ospf-to-leds.rsc | 2 +- packages-update.rsc | 2 +- ppp-on-up.rsc | 2 +- sms-action.rsc | 2 +- sms-forward.rsc | 2 +- super-mario-theme.rsc | 2 +- telegram-chat.rsc | 2 +- unattended-lte-firmware-upgrade.rsc | 2 +- update-gre-address.rsc | 2 +- update-tunnelbroker.rsc | 2 +- 85 files changed, 85 insertions(+), 85 deletions(-) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index 3fd688e..d5b55ad 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.capsman -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.12beta1 diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index c19be20..2904437 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.local -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.12beta1 diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index c83b428..a2cb3a2 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates%TEMPL% -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.12beta1 diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc index 4ca8be8..0035119 100644 --- a/accesslist-duplicates.wifi.rsc +++ b/accesslist-duplicates.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.wifi -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.12beta1 diff --git a/accesslist-duplicates.wifiwave2.rsc b/accesslist-duplicates.wifiwave2.rsc index c28a8f6..4dfda12 100644 --- a/accesslist-duplicates.wifiwave2.rsc +++ b/accesslist-duplicates.wifiwave2.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.wifiwave2 -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.12beta1 diff --git a/backup-cloud.rsc b/backup-cloud.rsc index c1bbe11..155ba5c 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: backup-cloud -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=40 diff --git a/backup-email.rsc b/backup-email.rsc index f4f1fc8..b087f35 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: backup-email -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=20 diff --git a/backup-partition.rsc b/backup-partition.rsc index b03ad7e..fe1fa66 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: backup-partition -# Copyright (c) 2022-2023 Christian Hesse +# Copyright (c) 2022-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=70 diff --git a/backup-upload.rsc b/backup-upload.rsc index 02916c6..fc438d6 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: backup-upload -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=50 diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index a42edd5..58b2f1f 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-download-packages.capsman -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 8cbd733..90af59c 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-download-packages%TEMPL% -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 89fe0dc..93caeb9 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-download-packages.wifi -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-download-packages.wifiwave2.rsc b/capsman-download-packages.wifiwave2.rsc index 6a12b2d..49ef625 100644 --- a/capsman-download-packages.wifiwave2.rsc +++ b/capsman-download-packages.wifiwave2.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-download-packages.wifiwave2 -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc index 7f83b6c..1445d4d 100644 --- a/capsman-rolling-upgrade.capsman.rsc +++ b/capsman-rolling-upgrade.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-rolling-upgrade.capsman -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index 10245b5..569cdc1 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-rolling-upgrade%TEMPL% -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc index 3e13bf4..426193d 100644 --- a/capsman-rolling-upgrade.wifi.rsc +++ b/capsman-rolling-upgrade.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-rolling-upgrade.wifi -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-rolling-upgrade.wifiwave2.rsc b/capsman-rolling-upgrade.wifiwave2.rsc index c0c08e7..a362bae 100644 --- a/capsman-rolling-upgrade.wifiwave2.rsc +++ b/capsman-rolling-upgrade.wifiwave2.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-rolling-upgrade.wifiwave2 -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc index 2b18a76..c3b4bdb 100644 --- a/certificate-renew-issued.rsc +++ b/certificate-renew-issued.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: certificate-renew-issued -# Copyright (c) 2019-2023 Christian Hesse +# Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # renew locally issued certificates diff --git a/check-certificates.rsc b/check-certificates.rsc index 45e18e4..5f2c710 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-certificates -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for certificate validity diff --git a/check-health.rsc b/check-health.rsc index ff47968..52c22ca 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-health -# Copyright (c) 2019-2023 Christian Hesse +# Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for RouterOS health state diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index a2aec01..f57f349 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-lte-firmware-upgrade -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for LTE firmware upgrade, send notification diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 0b621f7..3f7813a 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-routeros-update -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # check for RouterOS update, send notification and/or install diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index 65effa8..9868733 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.capsman -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index 0594ceb..5252d9f 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.local -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index 97760d6..df95f52 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac%TEMPL% -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc index 40ad4d2..40d2a9c 100644 --- a/collect-wireless-mac.wifi.rsc +++ b/collect-wireless-mac.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.wifi -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 diff --git a/collect-wireless-mac.wifiwave2.rsc b/collect-wireless-mac.wifiwave2.rsc index 86cfd64..32e88d5 100644 --- a/collect-wireless-mac.wifiwave2.rsc +++ b/collect-wireless-mac.wifiwave2.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.wifiwave2 -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index b228d86..2260588 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk.capsman -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 523e026..5478534 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk.local -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index e7d9b54..1111b64 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk%TEMPL% -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index a8b1320..6a621e4 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk.wifi -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/daily-psk.wifiwave2.rsc b/daily-psk.wifiwave2.rsc index 1be000d..e769a6c 100644 --- a/daily-psk.wifiwave2.rsc +++ b/daily-psk.wifiwave2.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk.wifiwave2 -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc index 89d2c4e..802063a 100644 --- a/dhcp-lease-comment.capsman.rsc +++ b/dhcp-lease-comment.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.capsman -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc index 11e92cc..9ab2d8c 100644 --- a/dhcp-lease-comment.local.rsc +++ b/dhcp-lease-comment.local.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.local -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index 05b1254..8916282 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment%TEMPL% -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc index fe34b09..214e2d5 100644 --- a/dhcp-lease-comment.wifi.rsc +++ b/dhcp-lease-comment.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.wifi -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-lease-comment.wifiwave2.rsc b/dhcp-lease-comment.wifiwave2.rsc index 200c53b..3860c9a 100644 --- a/dhcp-lease-comment.wifiwave2.rsc +++ b/dhcp-lease-comment.wifiwave2.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.wifiwave2 -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 57488c4..78e7639 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-to-dns -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=20 diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc index ec2babc..5c5c14f 100644 --- a/firmware-upgrade-reboot.rsc +++ b/firmware-upgrade-reboot.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: firmware-upgrade-reboot -# Copyright (c) 2022-2023 Christian Hesse +# Copyright (c) 2022-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # install firmware upgrade, and reboot diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 34a06bc..35f9a00 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: fw-addr-lists -# Copyright (c) 2023 Christian Hesse +# Copyright (c) 2023-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # download, import and update firewall address-lists diff --git a/global-config-overlay.rsc b/global-config-overlay.rsc index af4b52c..9ffd90c 100644 --- a/global-config-overlay.rsc +++ b/global-config-overlay.rsc @@ -1,5 +1,5 @@ # Overlay for global configuration by RouterOS Scripts -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global configuration, custom overlay diff --git a/global-config.rsc b/global-config.rsc index 14a4e98..6066fef 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-config -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global configuration diff --git a/global-functions.rsc b/global-functions.rsc index c32e742..d124ac1 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-functions -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/global-wait.rsc b/global-wait.rsc index fe1928b..448643c 100644 --- a/global-wait.rsc +++ b/global-wait.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-wait -# Copyright (c) 2020-2023 Christian Hesse +# Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # wait for global-functions to finish diff --git a/gps-track.rsc b/gps-track.rsc index 86506b8..cd66250 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: gps-track -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # track gps data by sending json data to http server diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index b9a6620..95ae531 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa-cleanup.capsman -# Copyright (c) 2021-2023 Christian Hesse +# Copyright (c) 2021-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 0f89cec..45cf06c 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa-cleanup%TEMPL% -# Copyright (c) 2021-2023 Christian Hesse +# Copyright (c) 2021-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index 1cee316..f61f418 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa-cleanup.wifi -# Copyright (c) 2021-2023 Christian Hesse +# Copyright (c) 2021-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 diff --git a/hotspot-to-wpa-cleanup.wifiwave2.rsc b/hotspot-to-wpa-cleanup.wifiwave2.rsc index e316c17..0ff3c3f 100644 --- a/hotspot-to-wpa-cleanup.wifiwave2.rsc +++ b/hotspot-to-wpa-cleanup.wifiwave2.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa-cleanup.wifiwave2 -# Copyright (c) 2021-2023 Christian Hesse +# Copyright (c) 2021-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index a7ebafb..8ea2e6b 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa.capsman -# Copyright (c) 2019-2023 Christian Hesse +# Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # add private WPA passphrase after hotspot login diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index a858285..b6ce561 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa%TEMPL% -# Copyright (c) 2019-2023 Christian Hesse +# Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # add private WPA passphrase after hotspot login diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index f7c99a9..77afad1 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa.wifi -# Copyright (c) 2019-2023 Christian Hesse +# Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # add private WPA passphrase after hotspot login diff --git a/hotspot-to-wpa.wifiwave2.rsc b/hotspot-to-wpa.wifiwave2.rsc index ea44a9d..0c12d39 100644 --- a/hotspot-to-wpa.wifiwave2.rsc +++ b/hotspot-to-wpa.wifiwave2.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa.wifiwave2 -# Copyright (c) 2019-2023 Christian Hesse +# Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # add private WPA passphrase after hotspot login diff --git a/ip-addr-bridge.rsc b/ip-addr-bridge.rsc index 99fcba5..758cd46 100644 --- a/ip-addr-bridge.rsc +++ b/ip-addr-bridge.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ip-addr-bridge -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # enable or disable ip addresses based on bridge port state diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index d961865..aed7e56 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ipsec-to-dns -# Copyright (c) 2021-2023 Christian Hesse +# Copyright (c) 2021-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # and add/remove/update DNS entries from IPSec mode-config diff --git a/ipv6-update.rsc b/ipv6-update.rsc index 7e1d34f..2e905e4 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ipv6-update -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update firewall and dns settings on IPv6 prefix change diff --git a/lease-script.rsc b/lease-script.rsc index f8bc129..35fa7b4 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: lease-script -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run scripts on DHCP lease diff --git a/leds-day-mode.rsc b/leds-day-mode.rsc index ca2e8d8..b7c6b5b 100644 --- a/leds-day-mode.rsc +++ b/leds-day-mode.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-day-mode -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # enable LEDs diff --git a/leds-night-mode.rsc b/leds-night-mode.rsc index cdd8127..fb7c7a2 100644 --- a/leds-night-mode.rsc +++ b/leds-night-mode.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-night-mode -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # disable LEDs diff --git a/leds-toggle-mode.rsc b/leds-toggle-mode.rsc index da972b7..136c9d1 100644 --- a/leds-toggle-mode.rsc +++ b/leds-toggle-mode.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-toggle-mode -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # toggle LEDs mode diff --git a/log-forward.rsc b/log-forward.rsc index 6cf61a9..1067184 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: log-forward -# Copyright (c) 2020-2023 Christian Hesse +# Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # forward log messages via notification diff --git a/mod/bridge-port-to.rsc b/mod/bridge-port-to.rsc index 86689c9..a78f31b 100644 --- a/mod/bridge-port-to.rsc +++ b/mod/bridge-port-to.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/bridge-port-to -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # reset bridge ports to default bridge diff --git a/mod/bridge-port-vlan.rsc b/mod/bridge-port-vlan.rsc index 792a6c4..72cf772 100644 --- a/mod/bridge-port-vlan.rsc +++ b/mod/bridge-port-vlan.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/bridge-port-vlan -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # manage VLANs on bridge ports diff --git a/mod/inspectvar.rsc b/mod/inspectvar.rsc index e06d799..c6c8bdd 100644 --- a/mod/inspectvar.rsc +++ b/mod/inspectvar.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/inspectvar -# Copyright (c) 2020-2023 Christian Hesse +# Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # inspect variables diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc index eaa5c97..b098b44 100644 --- a/mod/ipcalc.rsc +++ b/mod/ipcalc.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/ipcalc -# Copyright (c) 2020-2023 Christian Hesse +# Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # ip address calculation diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 5d5aed1..93cb941 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/notification-email -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # send notifications via e-mail diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 378faab..5c6169d 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/notification-matrix -# Copyright (c) 2013-2023 Michael Gisbers +# Copyright (c) 2013-2024 Michael Gisbers # Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index 5c0e9e5..4dc6d84 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/notification-ntfy -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # send notifications via Ntfy (ntfy.sh) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 66be7d3..e778506 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/notification-telegram -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # send notifications via Telegram diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index 199d852..38348a0 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/scriptrunonece -# Copyright (c) 2020-2023 Christian Hesse +# Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # download script and run it once diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 79c1e22..7f3ed06 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/ssh-keys-import -# Copyright (c) 2020-2023 Christian Hesse +# Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.12beta1 diff --git a/mode-button.rsc b/mode-button.rsc index dae9d99..3c3e37e 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mode-button -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # act on multiple mode and reset button presses diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index c5c8ed1..bf0b24e 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: netwatch-dns -# Copyright (c) 2022-2023 Christian Hesse +# Copyright (c) 2022-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # monitor and manage dns/doh with netwatch diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 28bde24..2586c09 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: netwatch-notify -# Copyright (c) 2020-2023 Christian Hesse +# Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # monitor netwatch and send notifications diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 11b4e61..0c81628 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -1,5 +1,5 @@ # News, changes and migration by RouterOS Scripts -# Copyright (c) 2019-2023 Christian Hesse +# Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global IDonate; diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc index 2dc8448..416fc0e 100644 --- a/ospf-to-leds.rsc +++ b/ospf-to-leds.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ospf-to-leds -# Copyright (c) 2020-2023 Christian Hesse +# Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # visualize ospf instance state via leds diff --git a/packages-update.rsc b/packages-update.rsc index d011ea1..68574bd 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: packages-update -# Copyright (c) 2019-2023 Christian Hesse +# Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # download packages and reboot for installation diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc index ac01c97..ad19fc6 100644 --- a/ppp-on-up.rsc +++ b/ppp-on-up.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ppp-on-up -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run scripts on ppp up diff --git a/sms-action.rsc b/sms-action.rsc index f5de11f..b553762 100644 --- a/sms-action.rsc +++ b/sms-action.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: sms-action -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # run action on received SMS diff --git a/sms-forward.rsc b/sms-forward.rsc index 4f2d2e6..3249654 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: sms-forward -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # Anatoly Bubenkov # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/super-mario-theme.rsc b/super-mario-theme.rsc index 7787a12..63308b0 100644 --- a/super-mario-theme.rsc +++ b/super-mario-theme.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: super-mario-theme -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # play Super Mario theme diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 9515119..3361978 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: telegram-chat -# Copyright (c) 2023 Christian Hesse +# Copyright (c) 2023-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # use Telegram to chat with your Router and send commands diff --git a/unattended-lte-firmware-upgrade.rsc b/unattended-lte-firmware-upgrade.rsc index eac65c3..1cbdbfb 100644 --- a/unattended-lte-firmware-upgrade.rsc +++ b/unattended-lte-firmware-upgrade.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: unattended-lte-firmware-upgrade -# Copyright (c) 2018-2023 Christian Hesse +# Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # schedule unattended lte firmware upgrade diff --git a/update-gre-address.rsc b/update-gre-address.rsc index e38839c..5a5fd45 100644 --- a/update-gre-address.rsc +++ b/update-gre-address.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: update-gre-address -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # update gre interface remote address with dynamic address from diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index 60cb003..bfe0bfc 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: update-tunnelbroker -# Copyright (c) 2013-2023 Christian Hesse +# Copyright (c) 2013-2024 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # From 0760ea91211b59ba20ddb08a2372d851e11a409f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 5 Jan 2024 17:05:34 +0100 Subject: [PATCH 1770/2612] check-lte-firmware-upgrade: fail on empty version string --- check-lte-firmware-upgrade.rsc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index f57f349..149c008 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -45,6 +45,11 @@ $ScriptLock $0; :return false; } + :if ([ :len ($Firmware->"latest") ] = 0) do={ + $LogPrintExit2 info $0 ("An empty string is not a valid version.") false; + :return false; + } + :if (($Firmware->"installed") = ($Firmware->"latest")) do={ :if ([ $ScriptFromTerminal $0 ] = true) do={ $LogPrintExit2 info $0 ("No firmware upgrade available for LTE interface " . $IntName . ".") false; From 8c458592f51fcf065b903226f7a407f9a92ebb83 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 7 Jan 2024 23:13:54 +0100 Subject: [PATCH 1771/2612] check-lte-firmware-upgrade: unbreak terminal detectiono MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This broke with commit 50d7e1fa41b8f8a6a1379de5521798346fd1ae9f... đŸĢŖ --- check-lte-firmware-upgrade.rsc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index 149c008..d6bda72 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -21,7 +21,8 @@ $ScriptLock $0; } :local CheckInterface do={ - :local Interface $1; + :local ScriptName $1; + :local Interface $2; :global Identity; :global SentLteFirmwareUpgradeNotification; @@ -51,13 +52,13 @@ $ScriptLock $0; } :if (($Firmware->"installed") = ($Firmware->"latest")) do={ - :if ([ $ScriptFromTerminal $0 ] = true) do={ + :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ $LogPrintExit2 info $0 ("No firmware upgrade available for LTE interface " . $IntName . ".") false; } :return true; } - :if ([ $ScriptFromTerminal $0 ] = true && \ + :if ([ $ScriptFromTerminal $ScriptName ] = true && \ [ :len [ /system/script/find where name="unattended-lte-firmware-upgrade" ] ] > 0) do={ :put ("Do you want to start unattended lte firmware upgrade for interface " . $IntName . "? [y/N]"); :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ @@ -89,5 +90,5 @@ $ScriptLock $0; } :foreach Interface in=[ /interface/lte/find ] do={ - $CheckInterface $Interface; + $CheckInterface $0 $Interface; } From 4249ad61df4c596097da1e808e4e8e4bb8a25cf9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 8 Jan 2024 00:25:55 +0100 Subject: [PATCH 1772/2612] global-functions: $CertificateDownload: move delay up We still had cases where fetch misbehaves... But this was permanent. Perhaps we should not touch the certificate too early... --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index d124ac1..8dd1f07 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -149,6 +149,7 @@ dst-path=$LocalFileName as-value; $WaitForFile $LocalFileName; /certificate/import file-name=$LocalFileName passphrase="" as-value; + :delay 1s; /file/remove $LocalFileName; :foreach Cert in=[ /certificate/find where name~("^" . $LocalFileName . "_[0-9]+\$") ] do={ @@ -159,7 +160,6 @@ "CommonName \"" . $CommonName . "\"!") false; :return false; } - :delay 1s; :return true; } From d6645e8157b9c21493a2cda9ecc292c73aec7e9f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 9 Jan 2024 23:00:13 +0100 Subject: [PATCH 1773/2612] certs: add new DigiCert certificates... ... used by Cloudflare. --- ...Cert Global G2 TLS RSA SHA256 2020 CA1.pem | 182 ++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 certs/DigiCert Global G2 TLS RSA SHA256 2020 CA1.pem diff --git a/certs/DigiCert Global G2 TLS RSA SHA256 2020 CA1.pem b/certs/DigiCert Global G2 TLS RSA SHA256 2020 CA1.pem new file mode 100644 index 0000000..12084ee --- /dev/null +++ b/certs/DigiCert Global G2 TLS RSA SHA256 2020 CA1.pem @@ -0,0 +1,182 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0c:f5:bd:06:2b:56:02:f4:7a:b8:50:2c:23:cc:f0:66 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2 + Validity + Not Before: Mar 30 00:00:00 2021 GMT + Not After : Mar 29 23:59:59 2031 GMT + Subject: C=US, O=DigiCert Inc, CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:cc:f7:10:62:4f:a6:bb:63:6f:ed:90:52:56:c5: + 6d:27:7b:7a:12:56:8a:f1:f4:f9:d6:e7:e1:8f:bd: + 95:ab:f2:60:41:15:70:db:12:00:fa:27:0a:b5:57: + 38:5b:7d:b2:51:93:71:95:0e:6a:41:94:5b:35:1b: + fa:7b:fa:bb:c5:be:24:30:fe:56:ef:c4:f3:7d:97: + e3:14:f5:14:4d:cb:a7:10:f2:16:ea:ab:22:f0:31: + 22:11:61:69:90:26:ba:78:d9:97:1f:e3:7d:66:ab: + 75:44:95:73:c8:ac:ff:ef:5d:0a:8a:59:43:e1:ac: + b2:3a:0f:f3:48:fc:d7:6b:37:c1:63:dc:de:46:d6: + db:45:fe:7d:23:fd:90:e8:51:07:1e:51:a3:5f:ed: + 49:46:54:7f:2c:88:c5:f4:13:9c:97:15:3c:03:e8: + a1:39:dc:69:0c:32:c1:af:16:57:4c:94:47:42:7c: + a2:c8:9c:7d:e6:d4:4d:54:af:42:99:a8:c1:04:c2: + 77:9c:d6:48:e4:ce:11:e0:2a:80:99:f0:43:70:cf: + 3f:76:6b:d1:4c:49:ab:24:5e:c2:0d:82:fd:46:a8: + ab:6c:93:cc:62:52:42:75:92:f8:9a:fa:5e:5e:b2: + b0:61:e5:1f:1f:b9:7f:09:98:e8:3d:fa:83:7f:47: + 69:a1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + 74:85:80:C0:66:C7:DF:37:DE:CF:BD:29:37:AA:03:1D:BE:ED:CD:17 + X509v3 Authority Key Identifier: + 4E:22:54:20:18:95:E6:E3:6E:E6:0F:FA:FA:B9:12:ED:06:17:8F:39 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + CA Issuers - URI:http://cacerts.digicert.com/DigiCertGlobalRootG2.crt + X509v3 CRL Distribution Points: + Full Name: + URI:http://crl3.digicert.com/DigiCertGlobalRootG2.crl + X509v3 Certificate Policies: + Policy: 2.16.840.1.114412.2.1 + Policy: 2.23.140.1.1 + Policy: 2.23.140.1.2.1 + Policy: 2.23.140.1.2.2 + Policy: 2.23.140.1.2.3 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 90:f1:70:cb:28:97:69:97:7c:74:fd:c0:fa:26:7b:53:ab:ad: + cd:65:fd:ba:9c:06:9c:8a:d7:5a:43:87:ed:4d:4c:56:5f:ad: + c1:c5:b5:05:20:2e:59:d1:ff:4a:f5:a0:2a:d8:b0:95:ad:c9: + 2e:4a:3b:d7:a7:f6:6f:88:29:fc:30:3f:24:84:bb:c3:b7:7b: + 93:07:2c:af:87:6b:76:33:ed:00:55:52:b2:59:9e:e4:b9:d0: + f3:df:e7:0f:fe:dd:f8:c4:b9:10:72:81:09:04:5f:cf:97:9e: + 2e:32:75:8e:cf:9a:58:d2:57:31:7e:37:01:81:b2:66:6d:29: + 1a:b1:66:09:6d:d1:6e:90:f4:b9:fa:2f:01:14:c5:5c:56:64: + 01:d9:7d:87:a8:38:53:9f:8b:5d:46:6d:5c:c6:27:84:81:d4: + 7e:8c:8c:a3:9b:52:e7:c6:88:ec:37:7c:2a:fb:f0:55:5a:38: + 72:10:d8:00:13:cf:4c:73:db:aa:37:35:a8:29:81:69:9c:76: + bc:de:18:7b:90:d4:ca:cf:ef:67:03:fd:04:5a:21:16:b1:ff: + ea:3f:df:dc:82:f5:eb:f4:59:92:23:0d:24:2a:95:25:4c:ca: + a1:91:e6:d4:b7:ac:87:74:b3:f1:6d:a3:99:db:f9:d5:bd:84: + 40:9f:07:98 +-----BEGIN CERTIFICATE----- +MIIEyDCCA7CgAwIBAgIQDPW9BitWAvR6uFAsI8zwZjANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0yMTAzMzAwMDAwMDBaFw0zMTAzMjkyMzU5NTlaMFkxCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMzAxBgNVBAMTKkRpZ2lDZXJ0IEdsb2Jh +bCBHMiBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAMz3EGJPprtjb+2QUlbFbSd7ehJWivH0+dbn4Y+9lavyYEEV +cNsSAPonCrVXOFt9slGTcZUOakGUWzUb+nv6u8W+JDD+Vu/E832X4xT1FE3LpxDy +FuqrIvAxIhFhaZAmunjZlx/jfWardUSVc8is/+9dCopZQ+GssjoP80j812s3wWPc +3kbW20X+fSP9kOhRBx5Ro1/tSUZUfyyIxfQTnJcVPAPooTncaQwywa8WV0yUR0J8 +osicfebUTVSvQpmowQTCd5zWSOTOEeAqgJnwQ3DPP3Zr0UxJqyRewg2C/Uaoq2yT +zGJSQnWS+Jr6Xl6ysGHlHx+5fwmY6D36g39HaaECAwEAAaOCAYIwggF+MBIGA1Ud +EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFHSFgMBmx9833s+9KTeqAx2+7c0XMB8G +A1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYIKwYBBQUHAQEEajBoMCQG +CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQAYIKwYBBQUHMAKG +NGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RH +Mi5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29t +L0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDA9BgNVHSAENjA0MAsGCWCGSAGG/WwC +ATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgGBmeBDAECAzANBgkqhkiG +9w0BAQsFAAOCAQEAkPFwyyiXaZd8dP3A+iZ7U6utzWX9upwGnIrXWkOH7U1MVl+t +wcW1BSAuWdH/SvWgKtiwla3JLko716f2b4gp/DA/JIS7w7d7kwcsr4drdjPtAFVS +slme5LnQ89/nD/7d+MS5EHKBCQRfz5eeLjJ1js+aWNJXMX43AYGyZm0pGrFmCW3R +bpD0ufovARTFXFZkAdl9h6g4U5+LXUZtXMYnhIHUfoyMo5tS58aI7Dd8KvvwVVo4 +chDYABPPTHPbqjc1qCmBaZx2vN4Ye5DUys/vZwP9BFohFrH/6j/f3IL16/RZkiMN +JCqVJUzKoZHm1Lesh3Sz8W2jmdv51b2EQJ8HmA== +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 03:3a:f1:e6:a7:11:a9:a0:bb:28:64:b1:1d:09:fa:e5 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2 + Validity + Not Before: Aug 1 12:00:00 2013 GMT + Not After : Jan 15 12:00:00 2038 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bb:37:cd:34:dc:7b:6b:c9:b2:68:90:ad:4a:75: + ff:46:ba:21:0a:08:8d:f5:19:54:c9:fb:88:db:f3: + ae:f2:3a:89:91:3c:7a:e6:ab:06:1a:6b:cf:ac:2d: + e8:5e:09:24:44:ba:62:9a:7e:d6:a3:a8:7e:e0:54: + 75:20:05:ac:50:b7:9c:63:1a:6c:30:dc:da:1f:19: + b1:d7:1e:de:fd:d7:e0:cb:94:83:37:ae:ec:1f:43: + 4e:dd:7b:2c:d2:bd:2e:a5:2f:e4:a9:b8:ad:3a:d4: + 99:a4:b6:25:e9:9b:6b:00:60:92:60:ff:4f:21:49: + 18:f7:67:90:ab:61:06:9c:8f:f2:ba:e9:b4:e9:92: + 32:6b:b5:f3:57:e8:5d:1b:cd:8c:1d:ab:95:04:95: + 49:f3:35:2d:96:e3:49:6d:dd:77:e3:fb:49:4b:b4: + ac:55:07:a9:8f:95:b3:b4:23:bb:4c:6d:45:f0:f6: + a9:b2:95:30:b4:fd:4c:55:8c:27:4a:57:14:7c:82: + 9d:cd:73:92:d3:16:4a:06:0c:8c:50:d1:8f:1e:09: + be:17:a1:e6:21:ca:fd:83:e5:10:bc:83:a5:0a:c4: + 67:28:f6:73:14:14:3d:46:76:c3:87:14:89:21:34: + 4d:af:0f:45:0c:a6:49:a1:ba:bb:9c:c5:b1:33:83: + 29:85 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 4E:22:54:20:18:95:E6:E3:6E:E6:0F:FA:FA:B9:12:ED:06:17:8F:39 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 60:67:28:94:6f:0e:48:63:eb:31:dd:ea:67:18:d5:89:7d:3c: + c5:8b:4a:7f:e9:be:db:2b:17:df:b0:5f:73:77:2a:32:13:39: + 81:67:42:84:23:f2:45:67:35:ec:88:bf:f8:8f:b0:61:0c:34: + a4:ae:20:4c:84:c6:db:f8:35:e1:76:d9:df:a6:42:bb:c7:44: + 08:86:7f:36:74:24:5a:da:6c:0d:14:59:35:bd:f2:49:dd:b6: + 1f:c9:b3:0d:47:2a:3d:99:2f:bb:5c:bb:b5:d4:20:e1:99:5f: + 53:46:15:db:68:9b:f0:f3:30:d5:3e:31:e2:8d:84:9e:e3:8a: + da:da:96:3e:35:13:a5:5f:f0:f9:70:50:70:47:41:11:57:19: + 4e:c0:8f:ae:06:c4:95:13:17:2f:1b:25:9f:75:f2:b1:8e:99: + a1:6f:13:b1:41:71:fe:88:2a:c8:4f:10:20:55:d7:f3:14:45: + e5:e0:44:f4:ea:87:95:32:93:0e:fe:53:46:fa:2c:9d:ff:8b: + 22:b9:4b:d9:09:45:a4:de:a4:b8:9a:58:dd:1b:7d:52:9f:8e: + 59:43:88:81:a4:9e:26:d5:6f:ad:dd:0d:c6:37:7d:ed:03:92: + 1b:e5:77:5f:76:ee:3c:8d:c4:5d:56:5b:a2:d9:66:6e:b3:35: + 37:e5:32:b6 +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- From 44a8195c3763829c0efd41a32a434e3d2b8aa142 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 9 Jan 2024 23:01:22 +0100 Subject: [PATCH 1774/2612] doc/netwatch-dns: use new certificate for Cloudflare --- doc/netwatch-dns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 70b766a..88d4878 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -55,7 +55,7 @@ manually! Importing a certificate automatically is possible, at least if available in the repository (see `certs` sub directory). - /tool/netwatch/add comment="doh, doh-cert=DigiCert TLS Hybrid ECC SHA384 2020 CA1" host=1.1.1.1; + /tool/netwatch/add comment="doh, doh-cert=DigiCert Global G2 TLS RSA SHA256 2020 CA1" host=1.1.1.1; /tool/netwatch/add comment="doh, doh-cert=DigiCert TLS Hybrid ECC SHA384 2020 CA1" host=9.9.9.9; /tool/netwatch/add comment="doh, doh-cert=GTS CA 1C3" host=8.8.8.8; From 80db12a3e9c4f7fe14865d329de115068501b5a4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Jan 2024 09:22:32 +0100 Subject: [PATCH 1775/2612] netwatch-dns: enable DoH certificate verification... ... if a certificate is named in configuration. --- netwatch-dns.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index bf0b24e..7709ce8 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -59,6 +59,7 @@ $ScriptLock $0; :local DohServer ""; :local DohCert ""; +:local DohCertVerify [ /ip/dns/get verify-doh-cert ]; :local DohCurrent [ /ip/dns/get use-doh-server ]; :foreach Host in=[ /tool/netwatch/find where comment~"\\bdoh\\b" status="up" ] do={ @@ -81,12 +82,13 @@ $ScriptLock $0; :if ($DohServer != $DohCurrent) do={ $LogPrintExit2 info $0 ("Updating DoH server: " . $DohServer) false; :if ([ :len $DohCert ] > 0) do={ + :set DohCertVerify true; /ip/dns/set use-doh-server=""; :if ([ $CertificateAvailable $DohCert ] = false) do={ $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; } } - /ip/dns/set use-doh-server=$DohServer; + /ip/dns/set use-doh-server=$DohServer verify-doh-cert=$DohCertVerify; /ip/dns/cache/flush; } } else={ From 85aeeadcee6d6ae38768dac41b6e41cba3289b04 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Jan 2024 11:06:20 +0100 Subject: [PATCH 1776/2612] netwatch-dns: check DoH server functionality... ... and try all servers one after another. --- netwatch-dns.rsc | 56 ++++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 7709ce8..a7c75e8 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -12,6 +12,7 @@ :global CertificateAvailable; :global EitherOr; +:global IsDNSResolving; :global LogPrintExit2; :global ParseKeyValueStore; :global ScriptLock; @@ -57,10 +58,9 @@ $ScriptLock $0; } } -:local DohServer ""; -:local DohCert ""; :local DohCertVerify [ /ip/dns/get verify-doh-cert ]; :local DohCurrent [ /ip/dns/get use-doh-server ]; +:local DohServers ({}); :foreach Host in=[ /tool/netwatch/find where comment~"\\bdoh\\b" status="up" ] do={ :local HostVal [ /tool/netwatch/get $Host ]; @@ -71,30 +71,40 @@ $ScriptLock $0; :set HostName [ /ip/dns/static/get ($HostName->0) name ]; } - :if ($HostInfo->"doh" = true && $HostInfo->"disabled" != true && $DohServer = "") do={ - :set DohServer [ $EitherOr ($HostInfo->"doh-url") \ - ("https://" . [ $EitherOr $HostName ($HostVal->"host") ] . "/dns-query") ]; - :set DohCert ($HostInfo->"doh-cert"); + :if ($HostInfo->"doh" = true && $HostInfo->"disabled" != true) do={ + :if ([ :len ($HostInfo->"doh-url") ] = 0) do={ + :set ($HostInfo->"doh-url") ("https://" . [ $EitherOr $HostName ($HostVal->"host") ] . "/dns-query"); + } + + :if ($DohCurrent = $HostInfo->"doh-url") do={ + $LogPrintExit2 debug $0 ("Current DoH server is still up.") true; + } + + :set ($DohServers->[ :len $DohServers ]) $HostInfo; } } -:if ($DohServer != "") do={ - :if ($DohServer != $DohCurrent) do={ - $LogPrintExit2 info $0 ("Updating DoH server: " . $DohServer) false; - :if ([ :len $DohCert ] > 0) do={ - :set DohCertVerify true; - /ip/dns/set use-doh-server=""; - :if ([ $CertificateAvailable $DohCert ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; - } - } - /ip/dns/set use-doh-server=$DohServer verify-doh-cert=$DohCertVerify; - /ip/dns/cache/flush; - } -} else={ - :if ($DohCurrent != "") do={ - $LogPrintExit2 info $0 ("DoH server (" . $DohCurrent . ") is down, disabling.") false; +:if ([ :len $DohCurrent ] > 0 && [ :len $DohServers ] = 0) do={ + $LogPrintExit2 info $0 ("DoH server (" . $DohCurrent . ") is down, disabling.") false; + /ip/dns/set use-doh-server=""; + /ip/dns/cache/flush; +} + +:foreach DohServer in=$DohServers do={ + $LogPrintExit2 info $0 ("Updating DoH server: " . ($DohServer->"doh-url")) false; + :if ([ :len ($DohServer->"doh-cert") ] > 0) do={ + :set DohCertVerify true; /ip/dns/set use-doh-server=""; - /ip/dns/cache/flush; + :if ([ $CertificateAvailable ($DohServer->"doh-cert") ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; + } + } + /ip/dns/set use-doh-server=($DohServer->"doh-url") verify-doh-cert=$DohCertVerify; + /ip/dns/cache/flush; + :if ([ $IsDNSResolving ] = true) do={ + $LogPrintExit2 debug $0 ("DoH server is functional.") true; + } else={ + /ip/dns/set use-doh-server=""; + $LogPrintExit2 warning $0 ("DoH server not functional, trying next.") false; } } From 5fd8c8a760c332ff4858e0e0f2cdab2ff3a3ddb7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 14 Jan 2024 22:36:21 +0100 Subject: [PATCH 1777/2612] netwatch-dns: check DoH server with fetch This way we do not have to configure possibly non-functional servers to check. The query is for doh-check.eworm.de of type TXT, the expected answer is 'doh-check-OK'. % dig TXT doh-check.eworm.de +https @1.1.1.1 ; <<>> DiG 9.18.21 <<>> TXT doh-check.eworm.de +https @1.1.1.1 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42226 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 1232 ;; QUESTION SECTION: ;doh-check.eworm.de. IN TXT ;; ANSWER SECTION: doh-check.eworm.de. 63791 IN TXT "doh-check-OK" ;; Query time: 16 msec ;; SERVER: 1.1.1.1#443(1.1.1.1) (HTTPS) ;; WHEN: Mon Jan 15 13:55:36 CET 2024 ;; MSG SIZE rcvd: 72 --- netwatch-dns.rsc | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index a7c75e8..de69f75 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -12,7 +12,6 @@ :global CertificateAvailable; :global EitherOr; -:global IsDNSResolving; :global LogPrintExit2; :global ParseKeyValueStore; :global ScriptLock; @@ -58,7 +57,6 @@ $ScriptLock $0; } } -:local DohCertVerify [ /ip/dns/get verify-doh-cert ]; :local DohCurrent [ /ip/dns/get use-doh-server ]; :local DohServers ({}); @@ -77,34 +75,46 @@ $ScriptLock $0; } :if ($DohCurrent = $HostInfo->"doh-url") do={ - $LogPrintExit2 debug $0 ("Current DoH server is still up.") true; + $LogPrintExit2 debug $0 ("Current DoH server is still up: " . $DohCurrent) true; } :set ($DohServers->[ :len $DohServers ]) $HostInfo; } } -:if ([ :len $DohCurrent ] > 0 && [ :len $DohServers ] = 0) do={ - $LogPrintExit2 info $0 ("DoH server (" . $DohCurrent . ") is down, disabling.") false; +:if ([ :len $DohCurrent ] > 0) do={ + $LogPrintExit2 info $0 ("Current DoH server is down, disabling: " . $DohCurrent) false; /ip/dns/set use-doh-server=""; /ip/dns/cache/flush; } :foreach DohServer in=$DohServers do={ - $LogPrintExit2 info $0 ("Updating DoH server: " . ($DohServer->"doh-url")) false; :if ([ :len ($DohServer->"doh-cert") ] > 0) do={ - :set DohCertVerify true; - /ip/dns/set use-doh-server=""; :if ([ $CertificateAvailable ($DohServer->"doh-cert") ] = false) do={ $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; } } - /ip/dns/set use-doh-server=($DohServer->"doh-url") verify-doh-cert=$DohCertVerify; - /ip/dns/cache/flush; - :if ([ $IsDNSResolving ] = true) do={ - $LogPrintExit2 debug $0 ("DoH server is functional.") true; - } else={ - /ip/dns/set use-doh-server=""; - $LogPrintExit2 warning $0 ("DoH server not functional, trying next.") false; + + :local Data false; + :do { + :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ + http-header-field=({ "accept: application/dns-message" }) \ + url=(($DohServer->"doh-url") . "?dns=" . [ :convert to=base64 ([ :rndstr length=2 ] . \ + "\01\00" . "\00\01" . "\00\00" . "\00\00" . "\00\00" . "\09doh-check\05eworm\02de\00" . \ + "\00\10" . "\00\01") ]) as-value ]->"data"); + } on-error={ + $LogPrintExit2 warning $0 ("Request to DoH server failed (network or certificate issue): " . \ + ($DohServer->"doh-url")) false; + } + + :if ($Data != false) do={ + :if ([ :typeof [ :find $Data "doh-check-OK" ] ] = "num") do={ + /ip/dns/set use-doh-server=($DohServer->"doh-url") verify-doh-cert=yes; + /ip/dns/cache/flush; + $LogPrintExit2 info $0 ("Setting DoH server: " . ($DohServer->"doh-url")) true; + } else={ + $LogPrintExit2 warning $0 ("Received unexpected response from DoH server: " . \ + ($DohServer->"doh-url")) false; + } } } From 60bd9d1abca707a5acb441b7d352c7526e58b2f8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Jan 2024 22:00:13 +0100 Subject: [PATCH 1778/2612] README: set script owner on initial creation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ad3d2f..3f597d5 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ date and time is set correctly! Now let's download the main scripts and add them in configuration on the fly. - :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ /system/script/add name=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . ".rsc") output=user as-value]->"data"); }; + :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ /system/script/add name=$Script owner=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . ".rsc") output=user as-value]->"data"); }; ![screenshot: import scripts](README.d/04-import-scripts.avif) From be4221264ca6dd2f69f3d8cea8a2aaa65cf5580b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Jan 2024 22:01:04 +0100 Subject: [PATCH 1779/2612] INITIAL-COMMANDS: set script owner on initial creation --- INITIAL-COMMANDS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index da951aa..dfdcddc 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -19,7 +19,7 @@ Run the complete base installation: /file/remove "letsencrypt-E1.pem"; :delay 1s; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ - /system/script/add name=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . ".rsc") output=user as-value]->"data"); + /system/script/add name=$Script owner=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . ".rsc") output=user as-value]->"data"); }; /system/script { run global-config; run global-functions; }; /system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }"; From 29623a46ea1658cc8c9fcb4832f0810612addde5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Jan 2024 22:20:19 +0100 Subject: [PATCH 1780/2612] global-functions: $HexToNum: use :tonum --- global-functions.rsc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 8dd1f07..af82fa8 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -488,16 +488,14 @@ # convert from hex (string) to num :set HexToNum do={ :local Input [ :tostr $1 ]; - :local Hex "0123456789abcdef0123456789ABCDEF"; - :local Multi 1; - :local Return 0; - :for I from=([ :len $Input ] - 1) to=0 do={ - :set Return ($Return + (([ :find $Hex [ :pick $Input $I ] ] % 16) * $Multi)); - :set Multi ($Multi * 16); + :global HexToNum; + + :if ([ :pick $Input 0 ] = "*") do={ + :return [ $HexToNum [ :pick $Input 1 [ :len $Input ] ] ]; } - :return $Return; + :return [ :tonum ("0x" . $Input) ]; } # return human readable number From abd1edcdc34d6c243b00ecc5f9da7a5848190f20 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 17 Jan 2024 14:54:03 +0100 Subject: [PATCH 1781/2612] doc/hotspot-to-wpa: fix property name --- doc/hotspot-to-wpa.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index f0ffce9..06b1e87 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -90,9 +90,9 @@ Additional information is not available, including the password. Additionally templates can be created to give more options for access list: * `action`: set to `reject` to ignore logins on that hotspot -* `private-passphrase`: do **not** use passphrase from hotspot's user - credentials, but given one - or unset (use default passphrase) with - special word `ignore` +* `passphrase` or `private-passphrase`: do **not** use passphrase from + hotspot's user credentials, but given one - or unset (use default + passphrase) with special word `ignore` * `ssid-regexp`: set a different SSID regular expression to match * `vlan-id`: connect device to specific VLAN * `vlan-mode`: set the VLAN mode for device @@ -100,11 +100,11 @@ Additionally templates can be created to give more options for access list: For a hotspot called `example` the template could look like this. For `wifi` (RouterOS 7.13 and later): - /interface/wifi/access-list/add comment="hotspot-to-wpa template example" disabled=yes private-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 private-passphrase="ignore" ssid-regexp="^example\$" vlan-id=10; + /interface/wifiwave2/access-list/add comment="hotspot-to-wpa template example" disabled=yes passphrase="ignore" ssid-regexp="^example\$" vlan-id=10; For legacy CAPsMAN: From 306269f9191415b6e7fe83029d671613145f5f13 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Jan 2024 10:04:24 +0100 Subject: [PATCH 1782/2612] doc/hotspot-to-wpa: reference as WPA only... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... as this works with WPA3 as well. 😜 --- README.md | 2 +- doc/hotspot-to-wpa.md | 12 ++++++------ doc/lease-script.md | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3f597d5..db1138b 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,7 @@ Available scripts * [Download, import and update firewall address-lists](doc/fw-addr-lists.md) * [Wait for global functions und modules](doc/global-wait.md) * [Send GPS position to server](doc/gps-track.md) -* [Use WPA2 network with hotspot credentials](doc/hotspot-to-wpa.md) +* [Use WPA network with hotspot credentials](doc/hotspot-to-wpa.md) * [Create DNS records for IPSec peers](doc/ipsec-to-dns.md) * [Update configuration on IPv6 prefix change](doc/ipv6-update.md) * [Manage IP addresses with bridge status](doc/ip-addr-bridge.md) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index 06b1e87..c35bef7 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -1,5 +1,5 @@ -Use WPA2 network with hotspot credentials -========================================= +Use WPA network with hotspot credentials +======================================== [âŦ…ī¸ Go back to main README](../README.md) @@ -10,13 +10,13 @@ Description ----------- RouterOS supports an unlimited number of MAC address specific passphrases -for WPA2 encrypted wifi networks via access list. The idea of this script -is to transfer hotspot credentials to MAC address specific WPA2 passphrase. +for WPA encrypted wifi networks via access list. The idea of this script +is to transfer hotspot credentials to MAC address specific WPA passphrase. Requirements and installation ----------------------------- -You need a properly configured hotspot on one (open) SSID and a WP2 enabled +You need a properly configured hotspot on one (open) SSID and a WPA enabled SSID with suffix "`-wpa`". Then install the script. @@ -119,7 +119,7 @@ Usage and invocation -------------------- Now let the users connect and login to the hotspot. After that the devices -(identified by MAC address) can connect to the WPA2 network, using the +(identified by MAC address) can connect to the WPA network, using the passphrase from hotspot credentials. See also diff --git a/doc/lease-script.md b/doc/lease-script.md index 55928fc..c4ff20e 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -40,7 +40,7 @@ See also * [Collect MAC addresses in wireless access list](collect-wireless-mac.md) * [Comment DHCP leases with info from access list](dhcp-lease-comment.md) * [Create DNS records for DHCP leases](dhcp-to-dns.md) -* [Use WPA2 network with hotspot credentials](hotspot-to-wpa.md) +* [Use WPA network with hotspot credentials](hotspot-to-wpa.md) --- [âŦ…ī¸ Go back to main README](../README.md) From a7619a51195effef1f4c2f8aa8e8151c6e0e1094 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Jan 2024 10:13:53 +0100 Subject: [PATCH 1783/2612] global-functions: $LogPrintOnce: support exit --- dhcp-to-dns.rsc | 4 ++-- fw-addr-lists.rsc | 2 +- global-functions.rsc | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 78e7639..38e8c79 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -56,7 +56,7 @@ $ScriptLock $0 false 10; :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") . "!"); + $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; @@ -112,7 +112,7 @@ $ScriptLock $0 false 10; } :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!"); + $LogPrintOnce warning $0 ("The name '" . $FullA . "' appeared in more than one A record!") false; } } else={ $LogPrintExit2 debug $0 ("No address available... Ignoring.") false; diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 35f9a00..fec3729 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -74,7 +74,7 @@ $WaitFullyConnected; } :if ([ :len $Data ] > 63000) do={ - $LogPrintOnce warning $0 ("The list is huge and may be truncated: " . $List->"url"); + $LogPrintOnce warning $0 ("The list is huge and may be truncated: " . $List->"url") false; } :while ([ :len $Data ] != 0) do={ diff --git a/global-functions.rsc b/global-functions.rsc index af82fa8..3d66259 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -681,6 +681,7 @@ :local Severity [ :tostr $1 ]; :local Name [ :tostr $2 ]; :local Message [ :tostr $3 ]; + :local Exit [ :tostr $4 ]; :global LogPrintExit2; @@ -695,7 +696,7 @@ } :set ($LogPrintOnceMessages->$Message) 1; - $LogPrintExit2 $Severity $Name $Message false; + $LogPrintExit2 $Severity $Name $Message $Exit; } # get max value From bb0c82adb365a0ce04e83b2bebd1cc39b8ee3542 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Jan 2024 10:07:29 +0100 Subject: [PATCH 1784/2612] sms-forward: log warning just once --- sms-forward.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sms-forward.rsc b/sms-forward.rsc index 3249654..fb4d73c 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -16,6 +16,7 @@ :global IfThenElse; :global LogPrintExit2; +:global LogPrintOnce; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -25,7 +26,7 @@ $ScriptLock $0; :if ([ /tool/sms/get receive-enabled ] = false) do={ - $LogPrintExit2 warning $0 ("Receiving of SMS is not enabled.") true; + $LogPrintOnce warning $0 ("Receiving of SMS is not enabled.") true; } $WaitFullyConnected; From 8a0a4c355b4804913fa117917e8ac3686db91fc2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Jan 2024 12:53:17 +0100 Subject: [PATCH 1785/2612] global-functions: log successful loading --- global-functions.rsc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 3d66259..adfea2e 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1500,5 +1500,10 @@ } } +# Log success +:local Resource [ /system/resource/get ]; +$LogPrintOnce info $0 ("Loaded on " . $Resource->"board-name" . \ + " with RouterOS " . $Resource->"version" . ".") false; + # signal we are ready :set GlobalFunctionsReady true; From 0ad1a79d677ad26ad586238efcff59cf58d703ec Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Jan 2024 21:07:52 +0100 Subject: [PATCH 1786/2612] netwatch-dns: be move verbose on time to settle --- netwatch-dns.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index de69f75..86d59c7 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -18,8 +18,9 @@ $ScriptLock $0; -:if ([ /system/resource/get uptime ] < 5m30s) do={ - $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; +:local SettleTime (5m30s - [ /system/resource/get uptime ]); +:if ($SettleTime > 0s) do={ + $LogPrintExit2 info $0 ("System just booted, giving netwatch " . $SettleTime . " to settle.") true; } :local DnsServers ({}); From a2749b276003a90b95b9723e287542be56c0d0c1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 19 Jan 2024 13:23:52 +0100 Subject: [PATCH 1787/2612] check-certificates: use prepared user-agent string with fetch --- check-certificates.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 5f2c710..715a6b7 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -17,6 +17,7 @@ :global CertificateAvailable :global EscapeForRegEx; +:global FetchUserAgent; :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; @@ -43,7 +44,7 @@ :foreach Type in={ ".pem"; ".p12" } do={ :local CertFileName ([ $UrlEncode $Name ] . $Type); :do { - /tool/fetch check-certificate=yes-without-crl \ + /tool/fetch check-certificate=yes-without-crl http-header-field=({ $FetchUserAgent }) \ ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; $WaitForFile $CertFileName; From 4b8854946dca65b63633d9ef0647cd15ba3155c3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 19 Jan 2024 13:25:22 +0100 Subject: [PATCH 1788/2612] fw-addr-lists: use prepared user-agent string with fetch --- fw-addr-lists.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index fec3729..50fe41c 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -10,6 +10,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:global FetchUserAgent; :global FwAddrLists; :global FwAddrListTimeOut; @@ -57,7 +58,7 @@ $WaitFullyConnected; :if ($Data = false) do={ :do { :set Data ([ /tool/fetch check-certificate=$CheckCertificate output=user \ - ($List->"url") as-value ]->"data"); + http-header-field=({ $FetchUserAgent }) ($List->"url") as-value ]->"data"); } on-error={ :if ($I < 4) do={ $LogPrintExit2 debug $0 ("Failed downloading, " . $I . ". try: " . $List->"url") false; From 21cf6d49bbc0c3aebba6faa200a1ac125679c236 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 19 Jan 2024 17:08:55 +0100 Subject: [PATCH 1789/2612] backup-upload: fix the upload symbol... ... which broke with commit 080bef89a934980271a50eed25a494a0bc33d007. --- backup-upload.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index fc438d6..063cfb2 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -138,7 +138,7 @@ $WaitFullyConnected; $SendNotification2 ({ origin=$0; \ subject=[ $IfThenElse ($Failed > 0) \ ([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Backup & Config upload with failure") \ - ([ $SymbolForNotification "floppy-disk,up-arrow" ] . "Backup & Config upload") ]; \ + ([ $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" . \ From 86a0700efd926d0481b8518c62b217972fca4045 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 20 Jan 2024 00:09:54 +0100 Subject: [PATCH 1790/2612] global-functions: $SymbolByUnicodeName: name the parameter --- global-functions.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index adfea2e..8552502 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1293,6 +1293,8 @@ # return UTF-8 symbol for unicode name :set SymbolByUnicodeName do={ + :local Name [ :tostr $1 ]; + :local Symbols { "abacus"="\F0\9F\A7\AE"; "alarm-clock"="\E2\8F\B0"; @@ -1326,7 +1328,7 @@ "white-heavy-check-mark"="\E2\9C\85" } - :return (($Symbols->$1) . "\EF\B8\8F"); + :return (($Symbols->$Name) . "\EF\B8\8F"); } # return symbol for notification From 75a39ffaf1d8fb13e56d790d3902e2dbd0cabba6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 19 Jan 2024 23:57:09 +0100 Subject: [PATCH 1791/2612] global-functions: $SymbolByUnicodeName: log warning on missing name --- global-functions.rsc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 8552502..1109043 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1295,6 +1295,8 @@ :set SymbolByUnicodeName do={ :local Name [ :tostr $1 ]; + :global LogPrintOnce; + :local Symbols { "abacus"="\F0\9F\A7\AE"; "alarm-clock"="\E2\8F\B0"; @@ -1328,6 +1330,11 @@ "white-heavy-check-mark"="\E2\9C\85" } + :if ([ :len ($Symbols->$Name) ] = 0) do={ + $LogPrintOnce warning $0 ("No symbol available for name '" . $Name . "'!") false; + :return ""; + } + :return (($Symbols->$Name) . "\EF\B8\8F"); } From c2fe7e4cd73de957679f644cf489a3fe6a3f5949 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 22 Jan 2024 16:08:34 +0100 Subject: [PATCH 1792/2612] mod/notification-matrix: drop declaration of unused function --- mod/notification-matrix.rsc | 1 - 1 file changed, 1 deletion(-) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 5c6169d..8884b08 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -186,7 +186,6 @@ :global CharacterReplace; :global LogPrintExit2; :global ParseJson; - :global UrlEncode; :global MatrixAccessToken; :global MatrixHomeServer; From f015f5f0123ca222e9a85ed051c4ae2141634f9f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 22 Jan 2024 16:10:48 +0100 Subject: [PATCH 1793/2612] mod/notification-telegram: apply url encoding when sending --- mod/notification-telegram.rsc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index e778506..5b79135 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -20,6 +20,7 @@ :global IsFullyConnected; :global LogPrintExit2; :global ParseJson; + :global UrlEncode; :if ([ $IsFullyConnected ] = false) do={ $LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false; @@ -40,7 +41,7 @@ ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ http-data=("chat_id=" . ($Message->"chatid") . "&disable_notification=" . ($Message->"silent") . \ "&reply_to_message_id=" . ($Message->"replyto") . "&disable_web_page_preview=true" . \ - "&parse_mode=MarkdownV2&text=" . ($Message->"text")) as-value ]->"data"); + "&parse_mode=MarkdownV2&text=" . [ $UrlEncode ($Message->"text") ]) as-value ]->"data"); :set ($TelegramQueue->$Id); :set ($TelegramMessageIDs->([ $ParseJson ([ $ParseJson $Data ]->"result") ]->"message_id")) 1; } on-error={ @@ -132,7 +133,6 @@ [ $EscapeMD ("The message was too long and has been truncated, cut off " . \ (($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%!") "plain" ]); } - :set Text [ $UrlEncode $Text ]; :do { :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ @@ -142,7 +142,7 @@ ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ "&reply_to_message_id=" . ($Notification->"replyto") . "&disable_web_page_preview=true" . \ - "&parse_mode=MarkdownV2&text=" . $Text) as-value ]->"data"); + "&parse_mode=MarkdownV2&text=" . [ $UrlEncode $Text ]) as-value ]->"data"); :set ($TelegramMessageIDs->([ $ParseJson ([ $ParseJson $Data ]->"result") ]->"message_id")) 1; } on-error={ $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; @@ -150,9 +150,9 @@ :if ([ :typeof $TelegramQueue ] = "nothing") do={ :set TelegramQueue ({}); } - :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ + :set Text ($Text . "\n" . [ $SymbolForNotification "alarm-clock" ] . \ [ $EscapeMD ("This message was queued since " . [ /system/clock/get date ] . \ - " " . [ /system/clock/get time ] . " and may be obsolete.") "plain" ]) ]); + " " . [ /system/clock/get time ] . " and may be obsolete.") "plain" ]); :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; text=$Text; silent=($Notification->"silent"); replyto=($Notification->"replyto") }; :if ([ :len [ /system/scheduler/find where name="_FlushTelegramQueue" ] ] = 0) do={ From 49a83682c352b7f31a0f5ff502ee9fc62246773d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jan 2024 11:47:26 +0100 Subject: [PATCH 1794/2612] INITIAL-COMMANDS: remove before adding... ... to make sure it does not fail on (partly) installed scripts. This should work to fix borked base installation now. --- INITIAL-COMMANDS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index dfdcddc..ba182eb 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -19,9 +19,11 @@ Run the complete base installation: /file/remove "letsencrypt-E1.pem"; :delay 1s; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ + /system/script/remove [ find where name=$Script ]; /system/script/add name=$Script owner=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . ".rsc") output=user as-value]->"data"); }; /system/script { run global-config; run global-functions; }; + /system/scheduler/remove [ find where name="global-scripts" ]; /system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }"; :global CertificateNameByCN; $CertificateNameByCN "E1"; From 20c337d6ba241ff6ac1eee70107001af3a03a581 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jan 2024 15:52:58 +0100 Subject: [PATCH 1795/2612] INITIAL-COMMANDS: ... but rename the configuration overlay! This should not ultimately destroy user's configuration. --- INITIAL-COMMANDS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index ba182eb..ee7cef8 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -18,6 +18,7 @@ Run the complete base installation: }; /file/remove "letsencrypt-E1.pem"; :delay 1s; + /system/script/set name=("global-config-overlay-" . [ /system/clock/get date ] . "-" . [ /system/clock/get time ]) [ find where name="global-config-overlay" ]; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ /system/script/remove [ find where name=$Script ]; /system/script/add name=$Script owner=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . ".rsc") output=user as-value]->"data"); From 468b5a18f314ca3e3c280b6401626a767e9d8a69 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jan 2024 16:13:44 +0100 Subject: [PATCH 1796/2612] check-certificates: unbreak certificate download MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was borked with a2749b276003a90b95b9723e287542be56c0d0c1. đŸ˜ŗ --- check-certificates.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 715a6b7..af0f9b4 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -17,7 +17,6 @@ :global CertificateAvailable :global EscapeForRegEx; -:global FetchUserAgent; :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; @@ -35,6 +34,7 @@ :global CertificateNameByCN; :global EscapeForRegEx; + :global FetchUserAgent; :global LogPrintExit2; :global UrlEncode; :global WaitForFile; From 7baf69e67cf66d76cc37c3afec6219f86e2c2279 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jan 2024 17:14:25 +0100 Subject: [PATCH 1797/2612] doc/check-certificates: add paragraph --- doc/check-certificates.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 95ff534..e9a533f 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -63,6 +63,8 @@ Just run the script: Tips & Tricks ------------- +### Schedule at startup + The script checks for full connectivity before acting, so scheduling at startup is perfectly valid: From 7db94b5f3fd3365991ccdae2c7edde099dac95b2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 24 Jan 2024 17:22:13 +0100 Subject: [PATCH 1798/2612] doc/check-certificates: initial certificate import --- doc/check-certificates.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/check-certificates.md b/doc/check-certificates.md index e9a533f..186702c 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -70,6 +70,16 @@ startup is perfectly valid: /system/scheduler/add name=check-certificates@startup on-event="/system/script/run check-certificates;" start-time=startup; +### Initial import + +Given you have a certificate on you server, you can use `check-certificates` +for the initial import. Just create a *dummy* certificate with short lifetime +that matches criteria to be renewed: + + /certificate/add name=example.com common-name=example.com days-valid=1; + /certificate/sign example.com; + /system/script/run check-certificates; + See also -------- From 3ca51f4699f7079e5be7f1e28be16fc4d97a49f1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Jan 2024 09:35:40 +0100 Subject: [PATCH 1799/2612] INITIAL-COMMANDS: fix existing installation --- INITIAL-COMMANDS.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index ee7cef8..9d49851 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -35,6 +35,13 @@ Then continue setup with [scheduled automatic updates](README.md#scheduled-automatic-updates) or [editing configuration](README.md#editing-configuration). +## Fix existing installation + +The commands above allow to fix an existing installation in case it ever +breaks. If `global-config-overlay` did exist before it is renamed with a +date and time suffix (like `global-config-overlay-2024-01-25-09:33:12`). +Make sure to restore the configuration overlay if required. + --- [âŦ…ī¸ Go back to main README](README.md) [âŦ†ī¸ Go back to top](#top) From 64abe7430aced959d0817f4922afd2d1d219b539 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Jan 2024 09:37:20 +0100 Subject: [PATCH 1800/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 39fc8a9..6d64e67 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -32,6 +32,7 @@ Add yourself to the list, * Harold Schoemaker * Hugo BV * Klaus Michael RÃŧbsam +* Leonardo Valeri Manera * Linux-Schmie.de Michael Gisbers * Manuel Kuhn * Marek ÄŒÃĄbÃĄk From e636d4194c44a916792da58944d89820035d9287 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Jan 2024 21:34:08 +0100 Subject: [PATCH 1801/2612] global-functions: $RandomDelay: name the parameters --- global-functions.rsc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 1109043..8411fc5 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -873,10 +873,13 @@ # delay a random amount of seconds :set RandomDelay do={ + :local Time [ :tonum $1 ]; + :local Unit [ :tostr $2 ]; + :global EitherOr; :global GetRandomNumber; - :delay ([ $GetRandomNumber $1 ] . [ $EitherOr $2 "s" ]); + :delay ([ $GetRandomNumber $Time ] . [ $EitherOr $Unit "s" ]); } # check for required RouterOS version From 16898ae997df8ff9c165f54944a85b5f3d07d2dc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Jan 2024 21:36:14 +0100 Subject: [PATCH 1802/2612] global-functions: $RandomDelay: allow zero time, return immediately --- global-functions.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 8411fc5..a2c50a5 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -879,6 +879,10 @@ :global EitherOr; :global GetRandomNumber; + :if ($Time = 0) do={ + :return false; + } + :delay ([ $GetRandomNumber $Time ] . [ $EitherOr $Unit "s" ]); } From a1abfedccd62251e9540afa882ed9e47e357e486 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Jan 2024 22:32:57 +0100 Subject: [PATCH 1803/2612] global-functions: $RandomDelay: always scale to ms... ... to randomize in friction of unit. This requires :tonsec from RouterOS 7.12. --- README.md | 2 +- global-functions.rsc | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index db1138b..b23310a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ RouterOS Scripts [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.10-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/global-functions.rsc b/global-functions.rsc index a2c50a5..9be7893 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.10beta5 +# requires RouterOS, version=7.12 # # global functions # https://git.eworm.de/cgit/routeros-scripts/about/ @@ -878,12 +878,13 @@ :global EitherOr; :global GetRandomNumber; + :global MAX; :if ($Time = 0) do={ :return false; } - :delay ([ $GetRandomNumber $Time ] . [ $EitherOr $Unit "s" ]); + :delay ([ $MAX 10 [ $GetRandomNumber ([ :tonsec [ :totime ($Time . [ $EitherOr $Unit "s" ]) ] ] / 1000000) ] ] . "ms"); } # check for required RouterOS version From b6367b5df35a23365c8a2086e8f90a372845db4c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Jan 2024 21:19:36 +0100 Subject: [PATCH 1804/2612] telegram-chat: fix concatenation (and retry with delay) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ups... đŸ˜ŗ --- telegram-chat.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 3361978..292ae5b 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -57,7 +57,7 @@ $WaitFullyConnected; } on-error={ :if ($I < 4) do={ $LogPrintExit2 debug $0 ("Fetch failed, " . $I . ". try.") false; - :delay (($I * $I) "s"); + :delay (($I * $I) . "s"); } } } From abfc8e9191b23731c2ff8977cf7a46c9ca34a62b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Jan 2024 21:50:32 +0100 Subject: [PATCH 1805/2612] telegram-chat: add (and increase) random delay on error Chances are that two devices schedule the script (nearly) simultaneously. Causing a lot of failures from fetch. Instead of forcing a retry on *every* invocating we add (and increase) a random delay, that is slowly decreasd on success. This should minimize failures... --- telegram-chat.rsc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 292ae5b..986df03 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -18,6 +18,7 @@ :global TelegramChatOffset; :global TelegramChatRunTime; :global TelegramMessageIDs; +:global TelegramRandomDelay; :global TelegramTokenId; :global CertificateAvailable; @@ -26,8 +27,11 @@ :global GetRandom20CharAlNum; :global IfThenElse; :global LogPrintExit2; +:global MAX; +:global MIN; :global MkDir; :global ParseJson; +:global RandomDelay; :global ScriptLock; :global SendTelegram2; :global SymbolForNotification; @@ -42,11 +46,16 @@ $WaitFullyConnected; :if ([ :typeof $TelegramChatOffset ] != "array") do={ :set TelegramChatOffset { 0; 0; 0 }; } +:if ([ :typeof $TelegramRandomDelay ] != "num") do={ + :set TelegramRandomDelay 0; +} :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; } +$RandomDelay $TelegramRandomDelay; + :local Data false; :for I from=1 to=4 do={ :if ($Data = false) do={ @@ -54,9 +63,11 @@ $WaitFullyConnected; :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=" . \ $TelegramChatOffset->0 . "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); + :set TelegramRandomDelay [ $MAX 0 ($TelegramRandomDelay - 1) ]; } on-error={ :if ($I < 4) do={ $LogPrintExit2 debug $0 ("Fetch failed, " . $I . ". try.") false; + :set TelegramRandomDelay [ $MIN 15 ($TelegramRandomDelay + 5) ]; :delay (($I * $I) . "s"); } } From 98f26989f5f625ad918aed900b7888fa69c78248 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Jan 2024 08:54:08 +0100 Subject: [PATCH 1806/2612] packages-update: schedule from local function --- packages-update.rsc | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index 68574bd..b67346d 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -18,6 +18,17 @@ :global ScriptLock; :global VersionToNum; +:local Schedule do={ + :global RebootForUpdate do={ + :global RandomDelay; + $RandomDelay 3600; + /system/reboot; + } + /system/scheduler/add name="_RebootForUpdate" start-time=03:00:00 interval=1d \ + on-event=("/system/scheduler/remove \"_RebootForUpdate\"; " . \ + ":global RebootForUpdate; \$RebootForUpdate;"); +} + $ScriptLock $0; :local Update [ /system/package/update/get ]; @@ -95,14 +106,7 @@ $ScriptLock $0; :if ([ $ScriptFromTerminal $0 ] = true) do={ :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; :if (([ /terminal/inkey timeout=60 ] % 32) = 19) do={ - :global RebootForUpdate do={ - :global RandomDelay; - $RandomDelay 3600; - /system/reboot; - } - /system/scheduler/add name="_RebootForUpdate" start-time=03:00:00 interval=1d \ - on-event=("/system/scheduler/remove \"_RebootForUpdate\"; " . \ - ":global RebootForUpdate; \$RebootForUpdate;"); + $Schedule; $LogPrintExit2 info $0 ("Scheduled reboot for update between 03:00 and 04:00.") true; } } From 62f33d7b19792fded8366d57ff8756c5952da990 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Jan 2024 09:11:17 +0100 Subject: [PATCH 1807/2612] packages-update: support deferred reboot on auto-update Closes #56 --- doc/packages-update.md | 12 ++++++++++++ global-config.rsc | 3 +++ global-functions.rsc | 2 +- news-and-changes.rsc | 1 + packages-update.rsc | 7 +++++++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/doc/packages-update.md b/doc/packages-update.md index 653d233..280c420 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -34,6 +34,18 @@ Just install the script: It is automatically run by [check-routeros-update](check-routeros-update.md) if available. +Configuration +------------- + +The configuration goes to `global-config-overlay`, this is the only parameter: + +* `PackagesUpdateDeferReboot`: defer the reboot for night (between 3 AM + and 4 AM) + +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + Usage and invocation -------------------- diff --git a/global-config.rsc b/global-config.rsc index 6066fef..983eedb 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -135,6 +135,9 @@ # Set to all upper-case "Yes, please!" to enable. :global SafeUpdateAll "no"; +# Defer the reboot for night on automatic (non-interactive) update +:global PackagesUpdateDeferReboot false; + # These thresholds control when to send health notification # on temperature and voltage. :global CheckHealthTemperature { diff --git a/global-functions.rsc b/global-functions.rsc index 9be7893..306a2cc 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 116; +:global ExpectedConfigVersion 117; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 0c81628..5186420 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -36,6 +36,7 @@ 116=("... and also please keep in mind that it takes a huge amount of time maintaining these scripts. " . [ $IfThenElse ($IDonate != true) \ ("Following the donation hint " . [ $SymbolForNotification "arrow-down" "below" ] . "to keep me motivated is much appreciated. Thanks!") \ ("Looks like you did donate already. " . [ $SymbolForNotification "heart" "<3" ] . "Much appreciated, thanks!") ]); + 117="Enhanced 'packages-update' to support deferred reboot on automatically installed updates."; }; # Migration steps to be applied on script updates diff --git a/packages-update.rsc b/packages-update.rsc index b67346d..552a682 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -18,6 +18,8 @@ :global ScriptLock; :global VersionToNum; +:global PackagesUpdateDeferReboot; + :local Schedule do={ :global RebootForUpdate do={ :global RandomDelay; @@ -109,6 +111,11 @@ $ScriptLock $0; $Schedule; $LogPrintExit2 info $0 ("Scheduled reboot for update between 03:00 and 04:00.") true; } +} else={ + :if ($PackagesUpdateDeferReboot = true) do={ + $Schedule; + $LogPrintExit2 info $0 ("Scheduled reboot for update between 03:00 and 04:00.") true; + } } $LogPrintExit2 info $0 ("Rebooting for update.") false; From 2a4e2e0c075b5dfee095683a65755d8b384ecb72 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Jan 2024 17:55:30 +0100 Subject: [PATCH 1808/2612] send a warning on storage size --- global-functions.rsc | 2 +- news-and-changes.rsc | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 306a2cc..36fde6c 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 117; +:global ExpectedConfigVersion 118; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 5186420..b6f5169 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -8,6 +8,8 @@ :global RequiredRouterOS; :global SymbolForNotification; +:local Resource [ /system/resource/get ]; + # News, changes and migration up to change 95: # https://git.eworm.de/cgit/routeros-scripts/plain/global-config.changes?h=change-95 @@ -37,6 +39,10 @@ ("Following the donation hint " . [ $SymbolForNotification "arrow-down" "below" ] . "to keep me motivated is much appreciated. Thanks!") \ ("Looks like you did donate already. " . [ $SymbolForNotification "heart" "<3" ] . "Much appreciated, thanks!") ]); 117="Enhanced 'packages-update' to support deferred reboot on automatically installed updates."; + 118=("RouterOS packages increase in size with each release. This becomes a problem for devices with 16MB storage and below. " . \ + [ $IfThenElse ($Resource->"total-hdd-space" < 16000000) ("Your " . $Resource->"board-name" . " is specifically affected! ") \ + [ $IfThenElse ($Resource->"free-hdd-space" > 4000000) ("(Your " . $Resource->"board-name" . " does not suffer this issue.) ") ] ] . \ + "Huge configuration and lots of scripts give an extra risk. Take care!"); }; # Migration steps to be applied on script updates From 693b2034574583f8020728fe21d67d62babb1f34 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Jan 2024 18:30:13 +0100 Subject: [PATCH 1809/2612] README: make required software a paragraph --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b23310a..711455c 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ to manage RouterOS devices or extend their functionality. Requirements ------------ +### Software (RouterOS) + Latest version of the scripts require recent RouterOS to function properly. Make sure to install latest updates before you begin. If new functionality or a breaking change in RouterOS `7.n` is used in my scripts I push my From ccd7e6d1ed39b6e0d05cfe1cf367442e5ac90313 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Jan 2024 18:33:58 +0100 Subject: [PATCH 1810/2612] README: note on required hardware and limitations by storage --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 711455c..1af718c 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,14 @@ Specific scripts may require even newer RouterOS version. > â„šī¸ **Info**: The `main` branch is now RouterOS v7 only. If you are still > running RouterOS v6 switch to `routeros-v6` branch! +### Hardware + +RouterOS packages increase in size with each release. This becomes a +problem for devices with 16MB storage and below, those with an ARM CPU +are specifically affected. + +Huge configuration and lots of scripts give an extra risk. **Take care!** + Initial setup ------------- From 6ad7ca2c1a424395fdb22b62a80591ed23ea602e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Oct 2023 23:37:54 +0200 Subject: [PATCH 1811/2612] mod/notification-email: drop support for old property name --- mod/notification-email.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 93cb941..16d2b86 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # send notifications via e-mail # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-email.md @@ -43,7 +45,7 @@ } :local EMailSettings [ /tool/e-mail/get ]; - :if ([ :typeof [ :toip [ $EitherOr ($EMailSettings->"server") ($EMailSettings->"address") ] ] ] != "ip" && [ $IsDNSResolving ] = false) do={ + :if ([ :typeof [ :toip ($EMailSettings->"server") ] ] != "ip" && [ $IsDNSResolving ] = false) do={ $LogPrintExit2 debug $0 ("Server address is a DNS name and resolving fails, not flushing.") false; :return false; } @@ -138,7 +140,7 @@ :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; :local EMailSettings [ /tool/e-mail/get ]; - :if ([ :len $To ] = 0 || [ $EitherOr ($EMailSettings->"server") ($EMailSettings->"address") ] = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={ + :if ([ :len $To ] = 0 || ($EMailSettings->"server") = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={ :return false; } From 1bebac2a64bdf966b1af946ce6150c91d78ce09b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 29 Aug 2023 09:08:35 +0200 Subject: [PATCH 1812/2612] hotspot-to-wpa-cleanup: bump RouterOS version dependency --- hotspot-to-wpa-cleanup.template.rsc | 2 +- hotspot-to-wpa-cleanup.wifi.rsc | 2 +- hotspot-to-wpa-cleanup.wifiwave2.rsc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 45cf06c..a6ee028 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -5,7 +5,7 @@ # # provides: lease-script, order=80 # NOT /caps-man/ # -# requires RouterOS, version=7.12beta3 +# requires RouterOS, version=7.12 # NOT /caps-man/ # # # manage and clean up private WPA passphrase after hotspot login diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index f61f418..79031e9 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 -# requires RouterOS, version=7.12beta3 +# requires RouterOS, version=7.12 # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa-cleanup.wifiwave2.rsc b/hotspot-to-wpa-cleanup.wifiwave2.rsc index 0ff3c3f..fba67ca 100644 --- a/hotspot-to-wpa-cleanup.wifiwave2.rsc +++ b/hotspot-to-wpa-cleanup.wifiwave2.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 -# requires RouterOS, version=7.12beta3 +# requires RouterOS, version=7.12 # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md From f6f557d80fa48dceba8be1ae7ffc5ab5738038cf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Jan 2024 22:42:49 +0100 Subject: [PATCH 1813/2612] accesslist-duplicates: bump RouterOS version dependency --- accesslist-duplicates.capsman.rsc | 2 +- accesslist-duplicates.local.rsc | 2 +- accesslist-duplicates.template.rsc | 2 +- accesslist-duplicates.wifi.rsc | 2 +- accesslist-duplicates.wifiwave2.rsc | 2 +- doc/accesslist-duplicates.md | 2 -- 6 files changed, 5 insertions(+), 7 deletions(-) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index d5b55ad..72ce90c 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12beta1 +# requires RouterOS, version=7.12 # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index 2904437..7b031f8 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12beta1 +# requires RouterOS, version=7.12 # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index a2cb3a2..9e21d2d 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12beta1 +# requires RouterOS, version=7.12 # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc index 0035119..3f8fba7 100644 --- a/accesslist-duplicates.wifi.rsc +++ b/accesslist-duplicates.wifi.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12beta1 +# requires RouterOS, version=7.12 # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.wifiwave2.rsc b/accesslist-duplicates.wifiwave2.rsc index 4dfda12..7cc0bf9 100644 --- a/accesslist-duplicates.wifiwave2.rsc +++ b/accesslist-duplicates.wifiwave2.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12beta1 +# requires RouterOS, version=7.12 # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index 7cb0bc2..090298e 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -3,8 +3,6 @@ Find and remove access list duplicates [âŦ…ī¸ Go back to main README](../README.md) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) - > â„šī¸ī¸ **Info**: This script can not be used on its own but requires the base > installation. See [main README](../README.md) for details. From 5ac89bad04c338224ab4e71597c7062dfead8225 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Jan 2024 22:43:57 +0100 Subject: [PATCH 1814/2612] mod/ssh-keys-import: bump RouterOS version dependency --- doc/mod/ssh-keys-import.md | 2 -- mod/ssh-keys-import.rsc | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md index 5fd95af..1d00882 100644 --- a/doc/mod/ssh-keys-import.md +++ b/doc/mod/ssh-keys-import.md @@ -3,8 +3,6 @@ Import ssh keys for public key authentication [âŦ…ī¸ Go back to main README](../../README.md) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) - > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base > installation. See [main README](../../README.md) for details. diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 7f3ed06..b88ef9a 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12beta1 +# requires RouterOS, version=7.12 # # import ssh keys for public key authentication # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ssh-keys-import.md From 1d4f4d0017b849582fb9b61a97e8219626141cbf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1815/2612] accesslist-duplicates: use :jobname to get script name --- accesslist-duplicates.capsman.rsc | 2 +- accesslist-duplicates.local.rsc | 2 +- accesslist-duplicates.template.rsc | 2 +- accesslist-duplicates.wifi.rsc | 2 +- accesslist-duplicates.wifiwave2.rsc | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index 72ce90c..a20c05d 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -10,7 +10,7 @@ # # !! Do not edit this file, it is generated from template! -:local 0 "accesslist-duplicates.capsman"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index 7b031f8..0feb9f7 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -10,7 +10,7 @@ # # !! Do not edit this file, it is generated from template! -:local 0 "accesslist-duplicates.local"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index 9e21d2d..f350d0c 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -11,7 +11,7 @@ # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 "accesslist-duplicates%TEMPL%"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc index 3f8fba7..d5f13f0 100644 --- a/accesslist-duplicates.wifi.rsc +++ b/accesslist-duplicates.wifi.rsc @@ -10,7 +10,7 @@ # # !! Do not edit this file, it is generated from template! -:local 0 "accesslist-duplicates.wifi"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/accesslist-duplicates.wifiwave2.rsc b/accesslist-duplicates.wifiwave2.rsc index 7cc0bf9..24f5967 100644 --- a/accesslist-duplicates.wifiwave2.rsc +++ b/accesslist-duplicates.wifiwave2.rsc @@ -10,7 +10,7 @@ # # !! Do not edit this file, it is generated from template! -:local 0 "accesslist-duplicates.wifiwave2"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 72a03c4dbbc4ba1447864047626a046ff1333b71 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1816/2612] backup-cloud: use :jobname to get script name --- backup-cloud.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 155ba5c..58fd37a 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -4,11 +4,12 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=40 +# requires RouterOS, version=7.12 # # upload backup to MikroTik cloud # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md -:local 0 "backup-cloud"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 26dd16d3b9b512c0bba7adf1a25ae25058cfef2d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1817/2612] backup-email: use :jobname to get script name --- backup-email.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backup-email.rsc b/backup-email.rsc index b087f35..214c067 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -4,11 +4,12 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=20 +# requires RouterOS, version=7.12 # # create and email backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md -:local 0 "backup-email"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 994d3ef05abed9f7da5b3d0d56f2f8cfe5db0bc3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1818/2612] backup-partition: use :jobname to get script name --- backup-partition.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index fe1fa66..e67a001 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -4,11 +4,12 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=70 +# requires RouterOS, version=7.12 # # save configuration to fallback partition # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md -:local 0 "backup-partition"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From b4ac193789ec715da824e31a260d87f8be32e4fe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1819/2612] backup-upload: use :jobname to get script name --- backup-upload.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 063cfb2..34fda2b 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -4,11 +4,12 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=50 +# requires RouterOS, version=7.12 # # create and upload backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md -:local 0 "backup-upload"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 111cb59509608e18e084a307cbd07c3821331e20 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1820/2612] capsman-download-packages: use :jobname to get script name --- capsman-download-packages.capsman.rsc | 4 +++- capsman-download-packages.template.rsc | 4 +++- capsman-download-packages.wifi.rsc | 4 +++- capsman-download-packages.wifiwave2.rsc | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index 58b2f1f..82849f8 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -4,12 +4,14 @@ # Michael Gisbers # 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 "capsman-download-packages.capsman"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 90af59c..3eaa377 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -4,13 +4,15 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # download and cleanup packages for CAP installation from CAPsMAN # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md # # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 "capsman-download-packages%TEMPL%"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 93caeb9..021521e 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -4,12 +4,14 @@ # Michael Gisbers # 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 "capsman-download-packages.wifi"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/capsman-download-packages.wifiwave2.rsc b/capsman-download-packages.wifiwave2.rsc index 49ef625..29dca8a 100644 --- a/capsman-download-packages.wifiwave2.rsc +++ b/capsman-download-packages.wifiwave2.rsc @@ -4,12 +4,14 @@ # Michael Gisbers # 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 "capsman-download-packages.wifiwave2"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From dfeb6b6d614e4e657367dc6753117227990ebd9b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1821/2612] capsman-rolling-upgrade: use :jobname to get script name --- capsman-rolling-upgrade.capsman.rsc | 3 ++- capsman-rolling-upgrade.template.rsc | 3 ++- capsman-rolling-upgrade.wifi.rsc | 3 ++- capsman-rolling-upgrade.wifiwave2.rsc | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc index 1445d4d..7aa20aa 100644 --- a/capsman-rolling-upgrade.capsman.rsc +++ b/capsman-rolling-upgrade.capsman.rsc @@ -5,13 +5,14 @@ # 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 "capsman-rolling-upgrade.capsman"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index 569cdc1..de0b4d1 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -5,6 +5,7 @@ # 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 @@ -12,7 +13,7 @@ # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 "capsman-rolling-upgrade%TEMPL%"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc index 426193d..c17c5a1 100644 --- a/capsman-rolling-upgrade.wifi.rsc +++ b/capsman-rolling-upgrade.wifi.rsc @@ -5,13 +5,14 @@ # 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 "capsman-rolling-upgrade.wifi"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/capsman-rolling-upgrade.wifiwave2.rsc b/capsman-rolling-upgrade.wifiwave2.rsc index a362bae..aff47e4 100644 --- a/capsman-rolling-upgrade.wifiwave2.rsc +++ b/capsman-rolling-upgrade.wifiwave2.rsc @@ -5,13 +5,14 @@ # 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 "capsman-rolling-upgrade.wifiwave2"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 60b218628769a03805a71a60bc31d1d7a002ee89 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1822/2612] certificate-renew-issued: use :jobname to get script name --- certificate-renew-issued.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc index c3b4bdb..c6a819a 100644 --- a/certificate-renew-issued.rsc +++ b/certificate-renew-issued.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # renew locally issued certificates # https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md -:local 0 "certificate-renew-issued"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From a43202326bf17eb2a14a5d9949c6025d940b4547 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1823/2612] check-certificates: use :jobname to get script name --- check-certificates.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index af0f9b4..00a25b3 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # check for certificate validity # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md -:local 0 "check-certificates"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 531957703542471a39f8df04d8d180d34ab47d1f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1824/2612] check-health: use :jobname to get script name --- check-health.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/check-health.rsc b/check-health.rsc index 52c22ca..5c28d73 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # check for RouterOS health state # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md -:local 0 "check-health"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 08bd884810f04d64391a5d52dbada17b8c127e3a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1825/2612] check-lte-firmware-upgrade: use :jobname to get script name --- check-lte-firmware-upgrade.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index d6bda72..6a9074a 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # check for LTE firmware upgrade, send notification # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md -:local 0 "check-lte-firmware-upgrade"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 3412ab771f62e757ae62f48626e0ad0c4255c74d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1826/2612] check-routeros-update: use :jobname to get script name --- check-routeros-update.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 3f7813a..204a0d3 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # check for RouterOS update, send notification and/or install # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md -:local 0 "check-routeros-update"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 02d8455a8709eb219b097bf1c0aed97495cfe92c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1827/2612] collect-wireless-mac: use :jobname to get script name --- collect-wireless-mac.capsman.rsc | 3 ++- collect-wireless-mac.local.rsc | 3 ++- collect-wireless-mac.template.rsc | 3 ++- collect-wireless-mac.wifi.rsc | 3 ++- collect-wireless-mac.wifiwave2.rsc | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index 9868733..937d8ce 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -4,13 +4,14 @@ # 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 "collect-wireless-mac.capsman"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index 5252d9f..17f969b 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -4,13 +4,14 @@ # 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 "collect-wireless-mac.local"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index df95f52..c5420f1 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -4,6 +4,7 @@ # 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 @@ -11,7 +12,7 @@ # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 "collect-wireless-mac%TEMPL%"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc index 40d2a9c..7bc442a 100644 --- a/collect-wireless-mac.wifi.rsc +++ b/collect-wireless-mac.wifi.rsc @@ -4,13 +4,14 @@ # 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 "collect-wireless-mac.wifi"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/collect-wireless-mac.wifiwave2.rsc b/collect-wireless-mac.wifiwave2.rsc index 32e88d5..d2b0e6b 100644 --- a/collect-wireless-mac.wifiwave2.rsc +++ b/collect-wireless-mac.wifiwave2.rsc @@ -4,13 +4,14 @@ # 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 "collect-wireless-mac.wifiwave2"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 3f8d680fe8dfeea8d04ce6b67c74163306326b89 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1828/2612] daily-psk.capsman: use :jobname to get script name --- daily-psk.capsman.rsc | 4 +++- daily-psk.local.rsc | 4 +++- daily-psk.template.rsc | 4 +++- daily-psk.wifi.rsc | 4 +++- daily-psk.wifiwave2.rsc | 4 +++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index 2260588..f576d1d 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -4,12 +4,14 @@ # Michael Gisbers # 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 "daily-psk.capsman"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 5478534..da12038 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -4,12 +4,14 @@ # Michael Gisbers # 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 "daily-psk.local"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 1111b64..d1abce2 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -4,13 +4,15 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md # # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 "daily-psk%TEMPL%"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index 6a621e4..488d921 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -4,12 +4,14 @@ # Michael Gisbers # 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 "daily-psk.wifi"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/daily-psk.wifiwave2.rsc b/daily-psk.wifiwave2.rsc index e769a6c..89c5c25 100644 --- a/daily-psk.wifiwave2.rsc +++ b/daily-psk.wifiwave2.rsc @@ -4,12 +4,14 @@ # Michael Gisbers # 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 "daily-psk.wifiwave2"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 492d3a65a7670a354ee05ccbc37b6c77f0e34ebb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1829/2612] dhcp-lease-comment: use :jobname to get script name --- dhcp-lease-comment.capsman.rsc | 3 ++- dhcp-lease-comment.local.rsc | 3 ++- dhcp-lease-comment.template.rsc | 3 ++- dhcp-lease-comment.wifi.rsc | 3 ++- dhcp-lease-comment.wifiwave2.rsc | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc index 802063a..a3df2ef 100644 --- a/dhcp-lease-comment.capsman.rsc +++ b/dhcp-lease-comment.capsman.rsc @@ -4,13 +4,14 @@ # 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 "dhcp-lease-comment.capsman"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc index 9ab2d8c..5ccb916 100644 --- a/dhcp-lease-comment.local.rsc +++ b/dhcp-lease-comment.local.rsc @@ -4,13 +4,14 @@ # 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 "dhcp-lease-comment.local"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index 8916282..02bc18c 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -4,6 +4,7 @@ # 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 @@ -11,7 +12,7 @@ # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 "dhcp-lease-comment%TEMPL%"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc index 214e2d5..337f282 100644 --- a/dhcp-lease-comment.wifi.rsc +++ b/dhcp-lease-comment.wifi.rsc @@ -4,13 +4,14 @@ # 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 "dhcp-lease-comment.wifi"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/dhcp-lease-comment.wifiwave2.rsc b/dhcp-lease-comment.wifiwave2.rsc index 3860c9a..5c0c513 100644 --- a/dhcp-lease-comment.wifiwave2.rsc +++ b/dhcp-lease-comment.wifiwave2.rsc @@ -4,13 +4,14 @@ # 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 "dhcp-lease-comment.wifiwave2"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 6c52bd692b3892634275ac4b57e98fba3c146e18 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1830/2612] dhcp-to-dns: use :jobname to get script name --- dhcp-to-dns.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 38e8c79..8dccf35 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -4,11 +4,12 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=20 +# requires RouterOS, version=7.12 # # check DHCP leases and add/remove/update DNS entries # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md -:local 0 "dhcp-to-dns"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From c9fcd3419f19f93f98744a5cfb9890a3201a4e0c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1831/2612] firmware-upgrade-reboot: use :jobname to get script name --- firmware-upgrade-reboot.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc index 5c5c14f..adcea73 100644 --- a/firmware-upgrade-reboot.rsc +++ b/firmware-upgrade-reboot.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2022-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # install firmware upgrade, and reboot # https://git.eworm.de/cgit/routeros-scripts/about/doc/firmware-upgrade-reboot.md -:local 0 "firmware-upgrade-reboot"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From afd779c0bb21e47691998372a0316d0122a11035 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1832/2612] fw-addr-lists: use :jobname to get script name --- fw-addr-lists.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 50fe41c..bc294d1 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2023-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # download, import and update firewall address-lists # https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md -:local 0 "fw-addr-lists"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 4b791b7769c2e2949a38ba1b1d4ee34c9e97a3e8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1833/2612] global-functions: use :jobname to get script name --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 36fde6c..314ea6e 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -9,7 +9,7 @@ # global functions # https://git.eworm.de/cgit/routeros-scripts/about/ -:local 0 "global-functions"; +:local 0 [ :jobname ]; # expected configuration version :global ExpectedConfigVersion 118; From 8afbd5bff54be4f9a7f018589e952893c466e4b5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1834/2612] global-wait: use :jobname to get script name --- global-wait.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-wait.rsc b/global-wait.rsc index 448643c..9564a12 100644 --- a/global-wait.rsc +++ b/global-wait.rsc @@ -3,9 +3,11 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # wait for global-functions to finish # https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md -:local 0 "global-wait"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 7d47963c7a6335dfe1847766e67eeef28378b64b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1835/2612] gps-track: use :jobname to get script name --- gps-track.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gps-track.rsc b/gps-track.rsc index cd66250..2e6d50f 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # track gps data by sending json data to http server # https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md -:local 0 "gps-track"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 9cf536f89172565a112c629f257bb5ab06e37aac Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1836/2612] hotspot-to-wpa: use :jobname to get script name --- hotspot-to-wpa.capsman.rsc | 4 +++- hotspot-to-wpa.template.rsc | 4 +++- hotspot-to-wpa.wifi.rsc | 4 +++- hotspot-to-wpa.wifiwave2.rsc | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index 8ea2e6b..db3f430 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -3,12 +3,14 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # add private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md # # !! Do not edit this file, it is generated from template! -:local 0 "hotspot-to-wpa.capsman"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index b6ce561..98369a7 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -3,13 +3,15 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # add private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md # # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 "hotspot-to-wpa%TEMPL%"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index 77afad1..5e07eac 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -3,12 +3,14 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # add private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md # # !! Do not edit this file, it is generated from template! -:local 0 "hotspot-to-wpa.wifi"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/hotspot-to-wpa.wifiwave2.rsc b/hotspot-to-wpa.wifiwave2.rsc index 0c12d39..751c1bf 100644 --- a/hotspot-to-wpa.wifiwave2.rsc +++ b/hotspot-to-wpa.wifiwave2.rsc @@ -3,12 +3,14 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # add private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md # # !! Do not edit this file, it is generated from template! -:local 0 "hotspot-to-wpa.wifiwave2"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 79660f10dbc7ed6881b6f4b98bb368e2048b5ea3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1837/2612] hotspot-to-wpa-cleanup: use :jobname to get script name --- hotspot-to-wpa-cleanup.capsman.rsc | 3 ++- hotspot-to-wpa-cleanup.template.rsc | 4 +--- hotspot-to-wpa-cleanup.wifi.rsc | 2 +- hotspot-to-wpa-cleanup.wifiwave2.rsc | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index 95ae531..7e8749d 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -4,13 +4,14 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 +# requires RouterOS, version=7.12 # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md # # !! Do not edit this file, it is generated from template! -:local 0 "hotspot-to-wpa-cleanup.capsman"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index a6ee028..b7b4d9c 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -4,9 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 -# NOT /caps-man/ # # requires RouterOS, version=7.12 -# NOT /caps-man/ # # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md @@ -14,7 +12,7 @@ # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 "hotspot-to-wpa-cleanup%TEMPL%"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index 79031e9..4e9eda2 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -11,7 +11,7 @@ # # !! Do not edit this file, it is generated from template! -:local 0 "hotspot-to-wpa-cleanup.wifi"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/hotspot-to-wpa-cleanup.wifiwave2.rsc b/hotspot-to-wpa-cleanup.wifiwave2.rsc index fba67ca..afa0c2d 100644 --- a/hotspot-to-wpa-cleanup.wifiwave2.rsc +++ b/hotspot-to-wpa-cleanup.wifiwave2.rsc @@ -11,7 +11,7 @@ # # !! Do not edit this file, it is generated from template! -:local 0 "hotspot-to-wpa-cleanup.wifiwave2"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From aca18f9cc25247d8edfe33675e7891fbfe020977 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1838/2612] ipsec-to-dns: use :jobname to get script name --- ipsec-to-dns.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index aed7e56..512ef68 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2021-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # and add/remove/update DNS entries from IPSec mode-config # https://git.eworm.de/cgit/routeros-scripts/about/doc/ipsec-to-dns.md -:local 0 "ipsec-to-dns"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 19e759d8fb4cf9de2ac6fa9989e01259ddb05609 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1839/2612] ipv6-update: use :jobname to get script name --- ipv6-update.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ipv6-update.rsc b/ipv6-update.rsc index 2e905e4..1d7207b 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # update firewall and dns settings on IPv6 prefix change # https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md -:local 0 "ipv6-update"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From b4d666ef1d20dc833230245e09cd9c18a840a2cf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1840/2612] lease-script: use :jobname to get script name --- lease-script.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lease-script.rsc b/lease-script.rsc index 35fa7b4..aae74f8 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # run scripts on DHCP lease # https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md -:local 0 "lease-script"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 4653c94f3f735d439b9ce9448644392aaa41a48b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1841/2612] log-forward: use :jobname to get script name --- log-forward.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/log-forward.rsc b/log-forward.rsc index 1067184..a789f25 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # forward log messages via notification # https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md -:local 0 "log-forward"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 5d40075e442993ad2bed2f646b91bfa987906469 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:18 +0100 Subject: [PATCH 1842/2612] mode-button: use :jobname to get script name --- mode-button.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mode-button.rsc b/mode-button.rsc index 3c3e37e..372b2de 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # act on multiple mode and reset button presses # https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md -:local 0 "mode-button"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 80f587ddb555267bfe5f4344dc4e10cc268e2bc3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:19 +0100 Subject: [PATCH 1843/2612] netwatch-dns: use :jobname to get script name --- netwatch-dns.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 86d59c7..3b98a32 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2022-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # monitor and manage dns/doh with netwatch # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-dns.md -:local 0 "netwatch-dns"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 45fda69d3be56ba7d7b320125a9d2613ff7a1b0f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:19 +0100 Subject: [PATCH 1844/2612] netwatch-notify: use :jobname to get script name --- netwatch-notify.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 2586c09..ae9c8a8 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # monitor netwatch and send notifications # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md -:local 0 "netwatch-notify"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From cbdfa98576195969b8b6284127ab120b84859f13 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:19 +0100 Subject: [PATCH 1845/2612] ospf-to-leds: use :jobname to get script name --- ospf-to-leds.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc index 416fc0e..47e1d41 100644 --- a/ospf-to-leds.rsc +++ b/ospf-to-leds.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # visualize ospf instance state via leds # https://git.eworm.de/cgit/routeros-scripts/about/doc/ospf-to-leds.md -:local 0 "ospf-to-leds"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 322466fd00c54410f34f1f370b038ba182cf3833 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:19 +0100 Subject: [PATCH 1846/2612] packages-update: use :jobname to get script name --- packages-update.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages-update.rsc b/packages-update.rsc index 552a682..a7ddc19 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # download packages and reboot for installation # https://git.eworm.de/cgit/routeros-scripts/about/doc/packages-update.md -:local 0 "packages-update"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 791b04bbe4deefe51274eea010465c9805637910 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:19 +0100 Subject: [PATCH 1847/2612] ppp-on-up: use :jobname to get script name --- ppp-on-up.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc index ad19fc6..ad09fdc 100644 --- a/ppp-on-up.rsc +++ b/ppp-on-up.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # run scripts on ppp up # https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md -:local 0 "ppp-on-up"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 58748eea3c62f77e2090ccc937b4a2d240a17213 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:19 +0100 Subject: [PATCH 1848/2612] sms-action: use :jobname to get script name --- sms-action.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sms-action.rsc b/sms-action.rsc index b553762..49b6cd5 100644 --- a/sms-action.rsc +++ b/sms-action.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # run action on received SMS # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-action.md -:local 0 "sms-action"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 6e54c7c30be20d027065ffc35e852cf9383d11b7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:19 +0100 Subject: [PATCH 1849/2612] sms-forward: use :jobname to get script name --- sms-forward.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sms-forward.rsc b/sms-forward.rsc index fb4d73c..f6d8e12 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -4,10 +4,12 @@ # Anatoly Bubenkov # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # forward SMS to e-mail # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md -:local 0 "sms-forward"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 24b681761b3f29b30fcaf0672f293c77972931b1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:19 +0100 Subject: [PATCH 1850/2612] telegram-chat: use :jobname to get script name --- telegram-chat.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 986df03..d8f917b 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -3,10 +3,12 @@ # Copyright (c) 2023-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # use Telegram to chat with your Router and send commands # https://git.eworm.de/cgit/routeros-scripts/about/doc/telegram-chat.md -:local 0 "telegram-chat"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From af7031cc5689d38f19fdc0db4eef5802421b7ba1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:19 +0100 Subject: [PATCH 1851/2612] update-gre-address: use :jobname to get script name --- update-gre-address.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/update-gre-address.rsc b/update-gre-address.rsc index 5a5fd45..c5c699b 100644 --- a/update-gre-address.rsc +++ b/update-gre-address.rsc @@ -3,11 +3,13 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # update gre interface remote address with dynamic address from # ipsec remote peer # https://git.eworm.de/cgit/routeros-scripts/about/doc/update-gre-address.md -:local 0 "update-gre-address"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From b679eefcf73a8901c44a61494b419969ff4ee468 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Nov 2023 21:31:19 +0100 Subject: [PATCH 1852/2612] update-tunnelbroker: use :jobname to get script name --- update-tunnelbroker.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index bfe0bfc..4d4379a 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -5,11 +5,12 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: ppp-on-up +# requires RouterOS, version=7.12 # # update local address of tunnelbroker interface # https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md -:local 0 "update-tunnelbroker"; +:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 07cdeadf43009a82be0f8cfc5e09fc450e0df26d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 30 Jan 2024 07:10:51 +0100 Subject: [PATCH 1853/2612] log-forward: use $MAX --- log-forward.rsc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/log-forward.rsc b/log-forward.rsc index a789f25..69fa1f1 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -25,6 +25,7 @@ :global IfThenElse; :global LogForwardFilterLogForwarding; :global LogPrintExit2; +:global MAX; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -91,7 +92,5 @@ $ScriptLock $0; :set LogForwardLast ($MessageVal->".id"); } else={ - :if ($LogForwardRateLimit > 0) do={ - :set LogForwardRateLimit ($LogForwardRateLimit - 1); - } + :set LogForwardRateLimit [ $MAX 0 ($LogForwardRateLimit - 1) ]; } From 5b6ed4216e20df9c3d188d72ddab93d490a881db Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 30 Jan 2024 07:18:38 +0100 Subject: [PATCH 1854/2612] global-functions: $ScriptInstallUpdate: warn just once... ... for every script on required RouterOS version. --- global-functions.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 314ea6e..d8d688c 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -951,6 +951,7 @@ :global Grep; :global IfThenElse; :global LogPrintExit2; + :global LogPrintOnce; :global ParseKeyValueStore; :global RequiredRouterOS; :global SendNotification2; @@ -1026,7 +1027,7 @@ "' failed! Ignoring!") false; } } else={ - $LogPrintExit2 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; } } else={ From fb463419fe19f9451a1ebb8d70669407c45ca1cd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 30 Jan 2024 15:00:31 +0100 Subject: [PATCH 1855/2612] check-certificates: always quote the certificate name --- check-certificates.rsc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 00a25b3..1487a3e 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -60,7 +60,7 @@ /file/remove [ find where name=$CertFileName ]; :if ($DecryptionFailed = true) do={ - $LogPrintExit2 warning $0 ("Decryption failed for certificate file " . $CertFileName) false; + $LogPrintExit2 warning $0 ("Decryption failed for certificate file '" . $CertFileName . "'.") false; } :foreach CertInChain in=[ /certificate/find where name~("^" . [ $EscapeForRegEx $CertFileName ] . "_[0-9]+\$") \ @@ -70,7 +70,7 @@ :set Return true; } on-error={ - $LogPrintExit2 debug $0 ("Could not download certificate file " . $CertFileName) false; + $LogPrintExit2 debug $0 ("Could not download certificate file '" . $CertFileName . "'.") false; } } @@ -137,7 +137,7 @@ $WaitFullyConnected; :if ([ :len $CertRenewUrl ] = 0) do={ $LogPrintExit2 info $0 ("No CertRenewUrl given.") true; } - $LogPrintExit2 info $0 ("Attempting to renew certificate " . ($CertVal->"name") . ".") false; + $LogPrintExit2 info $0 ("Attempting to renew certificate '" . ($CertVal->"name") . "'.") false; :local ImportSuccess false; :set LastName ($CertVal->"common-name"); @@ -185,9 +185,9 @@ $WaitFullyConnected; $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; + $LogPrintExit2 info $0 ("The certificate '" . ($CertVal->"name") . "' has been renewed.") false; } on-error={ - $LogPrintExit2 debug $0 ("Could not renew certificate " . ($CertVal->"name") . ".") false; + $LogPrintExit2 debug $0 ("Could not renew certificate '" . ($CertVal->"name") . "'.") false; } } @@ -196,14 +196,14 @@ $WaitFullyConnected; :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; + $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 . \ + $LogPrintExit2 info $0 ("The certificate '" . ($CertVal->"name") . "' " . $State . \ ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; } } From ed28ade712e6ba3e699aacdce42a2c7f98a04245 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 Jan 2024 15:32:35 +0100 Subject: [PATCH 1856/2612] global-functions: $IsDNSResolving: drop declaration of unused function --- global-functions.rsc | 2 -- 1 file changed, 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index d8d688c..66dc9fa 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -546,8 +546,6 @@ # check if DNS is resolving :set IsDNSResolving do={ - :global CharacterReplace; - :do { :resolve "low-ttl.eworm.de"; } on-error={ From b548ffee5943d077ec3db352f7a08f075850ce26 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 Jan 2024 15:34:40 +0100 Subject: [PATCH 1857/2612] global-functions: $MkDir: drop declaration of unused functions --- global-functions.rsc | 2 -- 1 file changed, 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 66dc9fa..452b9d1 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -713,9 +713,7 @@ :set MkDir do={ :local Path [ :tostr $1 ]; - :global CharacterReplace; :global CleanFilePath; - :global GetRandom20CharAlNum; :global LogPrintExit2; :global WaitForFile; From 09988d9892dd3c5894f13b3e9dd3cd63b107c5eb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 Jan 2024 15:27:13 +0100 Subject: [PATCH 1858/2612] global-functions: introduce $CleanName --- global-functions.rsc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 452b9d1..3c3e2e1 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -27,6 +27,7 @@ :global CharacterMultiply; :global CharacterReplace; :global CleanFilePath; +:global CleanName; :global DeviceInfo; :global Dos2Unix; :global DownloadPackage; @@ -222,6 +223,24 @@ :return $Path; } +# clean name for DNS, file and more +:set CleanName do={ + :local Input [ :tostr $1 ]; + + :local Return ""; + + :for I from=0 to=([ :len $Input ] - 1) do={ + :local Char [ :pick $Input $I ]; + :if ([ :typeof [ find "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-" $Char ] ] = "nil") do={ + :set Char "-"; + } + :if ($Char != "-" || [ :pick $Return ([ :len $Return ] - 1) ] != "-") do={ + :set Return ($Return . $Char); + } + } + :return $Return; +} + # get readable device info :set DeviceInfo do={ :global ExpectedConfigVersion; From 821dd02e5e5c5274ee5d80a742859447c2f79d17 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 Jan 2024 15:31:07 +0100 Subject: [PATCH 1859/2612] global-functions: $CertificateNameByCN: use $CleanName --- global-functions.rsc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 3c3e2e1..d37b34b 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -168,11 +168,10 @@ :set CertificateNameByCN do={ :local CommonName [ :tostr $1 ]; - :global CharacterReplace; + :global CleanName; :local Cert [ /certificate/find where common-name=$CommonName ]; - /certificate/set $Cert \ - name=[ $CharacterReplace [ $CharacterReplace [ $CharacterReplace $CommonName "'" "-" ] " " "-" ] "---" "-" ]; + /certificate/set $Cert name=[ $CleanName $CommonName ]; } # multiply given character(s) From c5714e5dc819ce00d550a749d46b023cbf37fef0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 Jan 2024 15:29:54 +0100 Subject: [PATCH 1860/2612] dhcp-to-dns: use $CleanName --- dhcp-to-dns.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 8dccf35..a8ae466 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -16,7 +16,7 @@ :global Domain; :global Identity; -:global CharacterReplace; +:global CleanName; :global EitherOr; :global IfThenElse; :global LogPrintExit2; @@ -65,8 +65,8 @@ $ScriptLock $0 false 10; :if ([ :len ($LeaseVal->"active-address") ] > 0) do={ :local Comment ($CommentPrefix . ", macaddress=" . $LeaseVal->"active-mac-address" . ", server=" . $LeaseVal->"server"); - :local MacDash [ $CharacterReplace ($LeaseVal->"active-mac-address") ":" "-" ]; - :local HostName [ $CharacterReplace [ $EitherOr ([ $ParseKeyValueStore ($LeaseVal->"comment") ]->"hostname") ($LeaseVal->"host-name") ] " " "" ]; + :local MacDash [ $CleanName ($LeaseVal->"active-mac-address") ]; + :local HostName [ $CleanName [ $EitherOr ([ $ParseKeyValueStore ($LeaseVal->"comment") ]->"hostname") ($LeaseVal->"host-name") ] ]; :local Network [ /ip/dhcp-server/network/find where ($LeaseVal->"active-address") in address ]; :local NetworkVal; :if ([ :len $Network ] > 0) do={ From d0ff07b3cc64450c0a0f33d7e532cfd189936799 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 Jan 2024 15:37:01 +0100 Subject: [PATCH 1861/2612] backup-email: use $CleanName --- backup-email.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backup-email.rsc b/backup-email.rsc index 214c067..86f9003 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -21,7 +21,7 @@ :global Domain; :global Identity; -:global CharacterReplace; +:global CleanName; :global DeviceInfo; :global FormatLine; :global LogPrintExit2; @@ -52,7 +52,7 @@ $WaitFullyConnected; # filename based on identity :local DirName ("tmpfs/" . $0); -:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; +:local FileName [ $CleanName ($Identity . "." . $Domain) ]; :local FilePath ($DirName . "/" . $FileName); :local BackupFile "none"; :local ExportFile "none"; From c1568a33ddb848f958ac748923484887b743a0e7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 Jan 2024 15:37:41 +0100 Subject: [PATCH 1862/2612] backup-upload: use $CleanName --- backup-upload.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 34fda2b..05bc3ff 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -24,7 +24,7 @@ :global Domain; :global Identity; -:global CharacterReplace; +:global CleanName; :global DeviceInfo; :global IfThenElse; :global LogPrintExit2; @@ -51,7 +51,7 @@ $WaitFullyConnected; # filename based on identity :local DirName ("tmpfs/" . $0); -:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; +:local FileName [ $CleanName ($Identity . "." . $Domain) ]; :local FilePath ($DirName . "/" . $FileName); :local BackupFile "none"; :local ExportFile "none"; From 237dcd7261a33a4c222df486a8b895a496ef0ef3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 Jan 2024 14:33:00 +0100 Subject: [PATCH 1863/2612] packages-update: prepare message and mention time zone --- packages-update.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index a7ddc19..3e18413 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -107,16 +107,18 @@ $ScriptLock $0; /system/package/downgrade; } +:local Message ("Scheduled reboot for update between 3 AM and 4 AM local time (" . \ + [ /system/clock/get time-zone-name ] . ")."); :if ([ $ScriptFromTerminal $0 ] = true) do={ :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; :if (([ /terminal/inkey timeout=60 ] % 32) = 19) do={ $Schedule; - $LogPrintExit2 info $0 ("Scheduled reboot for update between 03:00 and 04:00.") true; + $LogPrintExit2 info $0 $Message true; } } else={ :if ($PackagesUpdateDeferReboot = true) do={ $Schedule; - $LogPrintExit2 info $0 ("Scheduled reboot for update between 03:00 and 04:00.") true; + $LogPrintExit2 info $0 $Message true; } } From 461f7b6e76c39c941a3b38a6633df46c3d13a278 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 Jan 2024 17:46:31 +0100 Subject: [PATCH 1864/2612] packages-update: move output and logging to local function... ... and pass script name for clean logging. --- packages-update.rsc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index 3e18413..8b7d617 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -23,14 +23,19 @@ :global PackagesUpdateDeferReboot; :local Schedule do={ + :global LogPrintExit2; + :global RebootForUpdate do={ :global RandomDelay; $RandomDelay 3600; /system/reboot; } + /system/scheduler/add name="_RebootForUpdate" start-time=03:00:00 interval=1d \ on-event=("/system/scheduler/remove \"_RebootForUpdate\"; " . \ ":global RebootForUpdate; \$RebootForUpdate;"); + $LogPrintExit2 info $1 ("Scheduled reboot for update between 3 AM and 4 AM local time (" . \ + [ /system/clock/get time-zone-name ] . ").") true; } $ScriptLock $0; @@ -107,18 +112,14 @@ $ScriptLock $0; /system/package/downgrade; } -:local Message ("Scheduled reboot for update between 3 AM and 4 AM local time (" . \ - [ /system/clock/get time-zone-name ] . ")."); :if ([ $ScriptFromTerminal $0 ] = true) do={ :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; :if (([ /terminal/inkey timeout=60 ] % 32) = 19) do={ - $Schedule; - $LogPrintExit2 info $0 $Message true; + $Schedule $0; } } else={ :if ($PackagesUpdateDeferReboot = true) do={ - $Schedule; - $LogPrintExit2 info $0 $Message true; + $Schedule $0; } } From 64e53a7d32106e334cedeab48e5d9fc4499cd9f0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 Jan 2024 17:52:48 +0100 Subject: [PATCH 1865/2612] packages-update: schedule reboot at pre-calculated time --- doc/packages-update.md | 5 ++++- packages-update.rsc | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/doc/packages-update.md b/doc/packages-update.md index 280c420..b3acf89 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -40,7 +40,10 @@ Configuration The configuration goes to `global-config-overlay`, this is the only parameter: * `PackagesUpdateDeferReboot`: defer the reboot for night (between 3 AM - and 4 AM) + and 5 AM) + +By modifying the scheduler's `start-time` you can force the reboot at +different time. > â„šī¸ **Info**: Copy relevant configuration from > [`global-config`](../global-config.rsc) (the one without `-overlay`) to diff --git a/packages-update.rsc b/packages-update.rsc index 8b7d617..863d273 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -23,19 +23,19 @@ :global PackagesUpdateDeferReboot; :local Schedule do={ + :global GetRandomNumber; :global LogPrintExit2; :global RebootForUpdate do={ - :global RandomDelay; - $RandomDelay 3600; /system/reboot; } - /system/scheduler/add name="_RebootForUpdate" start-time=03:00:00 interval=1d \ + :local StartTime [ :tostr [ :totime (10800 + [ $GetRandomNumber 7200 ]) ] ]; + /system/scheduler/add name="_RebootForUpdate" start-time=$StartTime interval=1d \ on-event=("/system/scheduler/remove \"_RebootForUpdate\"; " . \ ":global RebootForUpdate; \$RebootForUpdate;"); - $LogPrintExit2 info $1 ("Scheduled reboot for update between 3 AM and 4 AM local time (" . \ - [ /system/clock/get time-zone-name ] . ").") true; + $LogPrintExit2 info $1 ("Scheduled reboot for update at " . $StartTime . \ + " local time (" . [ /system/clock/get time-zone-name ] . ").") true; } $ScriptLock $0; From ed00c0877f18c7e551ffa6082c62262081f8e81a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 1 Feb 2024 15:39:39 +0100 Subject: [PATCH 1866/2612] INITIAL-COMMANDS: link initial commands above --- INITIAL-COMMANDS.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 9d49851..c58662b 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -37,10 +37,11 @@ Then continue setup with ## Fix existing installation -The commands above allow to fix an existing installation in case it ever -breaks. If `global-config-overlay` did exist before it is renamed with a -date and time suffix (like `global-config-overlay-2024-01-25-09:33:12`). -Make sure to restore the configuration overlay if required. +The [initial commands](#initial-commands) above allow to fix an existing +installation in case it ever breaks. If `global-config-overlay` did exist +before it is renamed with a date and time suffix (like +`global-config-overlay-2024-01-25-09:33:12`). Make sure to restore the +configuration overlay if required. --- [âŦ…ī¸ Go back to main README](README.md) From 77ef9b2c9593b88b11bc3f2616b8ac9d1f8f2d4c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 2 Feb 2024 10:40:59 +0100 Subject: [PATCH 1867/2612] backup-partition: use plain variable for name --- backup-partition.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index e67a001..075ca95 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -28,13 +28,13 @@ $ScriptLock $0; $LogPrintExit2 error $0 ("Device is not running from active partition.") true; } -:local ActiveRunningVar [ /partitions/get $ActiveRunning ]; +:local FallbackTo [ /partitions/get $ActiveRunning fallback-to ]; :do { - /partitions/save-config-to ($ActiveRunningVar->"fallback-to"); + /partitions/save-config-to $FallbackTo; $LogPrintExit2 info $0 ("Saved configuration to partition '" . \ - ($ActiveRunningVar->"fallback-to") . "'.") false; + $FallbackTo . "'.") false; } on-error={ $LogPrintExit2 error $0 ("Failed saving configuration to partition '" . \ - ($ActiveRunningVar->"fallback-to") . "'!") true; + $FallbackTo . "'!") true; } From 0694d9af3ec5d7fdee7aad25ec132c4e3f9b2faf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 2 Feb 2024 10:43:15 +0100 Subject: [PATCH 1868/2612] backup-partition: add a scheduler in backup... ... that logs a warning when backup is booted. --- backup-partition.rsc | 4 ++++ doc/backup-partition.md | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/backup-partition.rsc b/backup-partition.rsc index 075ca95..5d131c9 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -31,7 +31,11 @@ $ScriptLock $0; :local FallbackTo [ /partitions/get $ActiveRunning fallback-to ]; :do { + /system/scheduler/add start-time=startup \ + name=("running-from-" . $FallbackTo) \ + on-event=(":log warning \"Running from partition '" . $FallbackTo . "'!"); /partitions/save-config-to $FallbackTo; + /system/scheduler/remove ("running-from-" . $FallbackTo); $LogPrintExit2 info $0 ("Saved configuration to partition '" . \ $FallbackTo . "'.") false; } on-error={ diff --git a/doc/backup-partition.md b/doc/backup-partition.md index e95422c..0c64647 100644 --- a/doc/backup-partition.md +++ b/doc/backup-partition.md @@ -15,6 +15,10 @@ This script saves the current configuration to fallback For this to work you need a device with sufficient flash storage that is properly partitioned. +To make you aware of a possible issue a scheduler logging a warning is +added in the backup partition's configuration. You may want to use +[log-forward](log-forward.md) to be notified. + Requirements and installation ----------------------------- @@ -39,6 +43,7 @@ See also * [Upload backup to Mikrotik cloud](backup-cloud.md) * [Send backup via e-mail](backup-email.md) * [Upload backup to server](backup-upload.md) +* [Forward log messages via notification](log-forward.md) --- [âŦ…ī¸ Go back to main README](../README.md) From 7b30af90b707e6b0fe8629722bd17605e1e09b93 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 2 Feb 2024 10:53:31 +0100 Subject: [PATCH 1869/2612] backup-partition: get the actual real name... ... to prevent confusion after restore. --- backup-partition.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index 5d131c9..0eaf166 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -31,11 +31,11 @@ $ScriptLock $0; :local FallbackTo [ /partitions/get $ActiveRunning fallback-to ]; :do { - /system/scheduler/add start-time=startup \ - name=("running-from-" . $FallbackTo) \ - on-event=(":log warning \"Running from partition '" . $FallbackTo . "'!"); + /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-" . $FallbackTo); + /system/scheduler/remove "running-from-backup-partition"; $LogPrintExit2 info $0 ("Saved configuration to partition '" . \ $FallbackTo . "'.") false; } on-error={ From c21da0454b60b45e5e8619c3327c3b4101d89e0c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 2 Feb 2024 11:07:36 +0100 Subject: [PATCH 1870/2612] backup-partition: make sure to remove the scheduler on failure --- backup-partition.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/backup-partition.rsc b/backup-partition.rsc index 0eaf166..1db5e1d 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -39,6 +39,7 @@ $ScriptLock $0; $LogPrintExit2 info $0 ("Saved configuration to partition '" . \ $FallbackTo . "'.") false; } on-error={ + /system/scheduler/remove [ find where name="running-from-backup-partition" ]; $LogPrintExit2 error $0 ("Failed saving configuration to partition '" . \ $FallbackTo . "'!") true; } From 53b09529a85613e42e9010064856e6b352d34ea1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 2 Feb 2024 12:01:09 +0100 Subject: [PATCH 1871/2612] doc/backup-partition: add warning about RouterOS version --- doc/backup-partition.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/backup-partition.md b/doc/backup-partition.md index 0c64647..18edc0c 100644 --- a/doc/backup-partition.md +++ b/doc/backup-partition.md @@ -19,6 +19,10 @@ To make you aware of a possible issue a scheduler logging a warning is added in the backup partition's configuration. You may want to use [log-forward](log-forward.md) to be notified. +> âš ī¸ **Warning**: Only the configuration is saved to backup partition. +> Every now and then you should copy your installation over for a recent +> RouterOS version! + Requirements and installation ----------------------------- From 643f15a0b9d55a8d7dbce2f0cd6280cf7ecdfddb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 Jan 2024 20:52:16 +0100 Subject: [PATCH 1872/2612] introduce BRANCHES info --- BRANCHES.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 BRANCHES.md diff --git a/BRANCHES.md b/BRANCHES.md new file mode 100644 index 0000000..c431711 --- /dev/null +++ b/BRANCHES.md @@ -0,0 +1,43 @@ +Installing from branches +======================== + +[âŦ…ī¸ Go back to main README](README.md) + +> âš ī¸ **Warning**: Living on the edge? Great, read on! +> If not: Please use the `main` branch and leave this page! + +These scripts are developed in a [git](https://git-scm.com/) repository. +Development and experimental branches are used to provide early access +for specific changes. You can install scripts from these branches +for testing. + +## Install single script + +To install a single script from `next` branch: + + $ScriptInstallUpdate script-name "url-suffix=?h=next"; + +## Switch existing script + +Alternatively switch an existing script to update from `next` branch: + + /system/script/set comment="url-suffix=?h=next" script-name; + $ScriptInstallUpdate; + +## Switch installation + +Last but not least - to switch the complete installation to the `next` +branch edit `global-config-overlay` and add: + + :global ScriptUpdatesUrlSuffix "?h=next"; + +... then reload the configuration and update: + + /system/script/run global-config; + $ScriptInstallUpdate; + +> â„šī¸ **Info**: Replace `next` with *whatever* to use another specific branch. + +--- +[âŦ…ī¸ Go back to main README](README.md) +[âŦ†ī¸ Go back to top](#top) From e83154c9c3e54d8ff4b1cb04bd288cddf1af4606 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Feb 2024 20:54:02 +0100 Subject: [PATCH 1873/2612] check-lte-firmware-upgrade: give more detailed infos on modem --- check-lte-firmware-upgrade.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index 6a9074a..40a8568 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -29,8 +29,8 @@ $ScriptLock $0; :global Identity; :global SentLteFirmwareUpgradeNotification; - :global CharacterReplace; :global FormatLine; + :global IfThenElse; :global LogPrintExit2; :global ScriptFromTerminal; :global SendNotification2; @@ -84,7 +84,9 @@ $ScriptLock $0; subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \ message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \ "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ - [ $FormatLine "Interface" [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] ] . "\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 }); From 860acffbdb679a0ce378513e7b0bd9a5805accfd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Feb 2024 20:56:35 +0100 Subject: [PATCH 1874/2612] unattended-lte-firmware-upgrade: add error handling --- unattended-lte-firmware-upgrade.rsc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/unattended-lte-firmware-upgrade.rsc b/unattended-lte-firmware-upgrade.rsc index 1cbdbfb..904f952 100644 --- a/unattended-lte-firmware-upgrade.rsc +++ b/unattended-lte-firmware-upgrade.rsc @@ -24,13 +24,17 @@ :set LTEFirmwareUpgrade; /system/scheduler/remove ($1 . "-firmware-upgrade"); - /interface/lte/firmware-upgrade $1 upgrade=yes; - :log info ("LTE firmware upgrade on '" . $1 . "' finished, waiting for reset."); - :delay 240s; - :local Firmware [ /interface/lte/firmware-upgrade $1 once as-value ]; - :if (($Firmware->"installed") != ($Firmware->"latest")) do={ - :log warning ("LTE firmware versions still differ. Resetting again..."); - /interface/lte/at-chat $1 input="AT+RESET"; + :do { + /interface/lte/firmware-upgrade $1 upgrade=yes; + :log info ("LTE firmware upgrade on '" . $1 . "' finished, waiting for reset."); + :delay 240s; + :local Firmware [ /interface/lte/firmware-upgrade $1 once as-value ]; + :if (($Firmware->"installed") != ($Firmware->"latest")) do={ + :log warning ("LTE firmware versions still differ. Resetting again..."); + /interface/lte/at-chat $1 input="AT+RESET"; + } + } on-error={ + :log error ("LTE firmware upgrade on '" . $1 . "' failed."); } } From 872abbea7d147a8c6291270ba9389731e998b1e0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Feb 2024 20:58:46 +0100 Subject: [PATCH 1875/2612] doc/unattended-lte-firmware-upgrade: more devices supported... --- doc/unattended-lte-firmware-upgrade.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/unattended-lte-firmware-upgrade.md b/doc/unattended-lte-firmware-upgrade.md index 8bc9e71..a9c9b7c 100644 --- a/doc/unattended-lte-firmware-upgrade.md +++ b/doc/unattended-lte-firmware-upgrade.md @@ -12,6 +12,7 @@ This script upgrades LTE firmware on compatible devices: * R11e-LTE-US * R11e-4G * R11e-LTE6 +* ... and more - probably what ever Mikrotik builds into their devices A temporary scheduler is created to be independent from terminal. Thus starting the upgrade process over the broadband connection is supported. From b286cb680326ff31ad3592aeace5962cf0377072 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 19 Feb 2024 11:03:17 +0100 Subject: [PATCH 1876/2612] netwatch-notify: do not update with record in cache Using `:resolve` we have just one address, but chances are several records do exist. These end up in cache, so we are happy to find them there - no need to update then. --- netwatch-notify.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index ae9c8a8..77b0e69 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -79,7 +79,8 @@ $ScriptLock $0; :if ([ $IsDNSResolving ] = true) do={ :do { :local Resolve [ :resolve ($HostInfo->"resolve") ]; - :if ($Resolve != $HostVal->"host") do={ + :if ($Resolve != $HostVal->"host" and \ + [ :len [ /ip/dns/cache/find where name=($HostInfo->"resolve") data=[ :tostr ($HostVal->"host") ] ] ] = 0) do={ $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ From 471e0ead051117f9c4de71f05d9af0f8d6750931 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Feb 2024 22:56:43 +0100 Subject: [PATCH 1877/2612] doc/netwatch-notify: update for multiple records --- doc/netwatch-notify.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index b673af8..6925ca5 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -83,9 +83,9 @@ with a resolvable name: /tool/netwatch/add comment="notify, name=example.com, resolve=example.com"; -But be warned: Dynamic updates will probably cause issues if the name has -more than one record in dns - a high rate of configuration changes (and flash -writes) at least. +This supports multiple A or AAAA records for a name just fine, but be +warned: A CNAME to multiple records will cause a high rate of configuration +changes (and flash writes)! ### No notification on host down From 1c2048628d68a94e08bfcae98f33bb0bce53a25c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 26 Feb 2024 08:13:34 +0100 Subject: [PATCH 1878/2612] netwatch-notify: use logical operator, no literal "and" Just like we do everywhere else. --- netwatch-notify.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 77b0e69..d2a18ca 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -79,7 +79,7 @@ $ScriptLock $0; :if ([ $IsDNSResolving ] = true) do={ :do { :local Resolve [ :resolve ($HostInfo->"resolve") ]; - :if ($Resolve != $HostVal->"host" and \ + :if ($Resolve != $HostVal->"host" && \ [ :len [ /ip/dns/cache/find where name=($HostInfo->"resolve") data=[ :tostr ($HostVal->"host") ] ] ] = 0) do={ $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ From 1344694708eba29f02864f9c5016e835084a0788 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 21 Feb 2024 09:05:29 +0100 Subject: [PATCH 1879/2612] 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!) --- netwatch-notify.rsc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index d2a18ca..a562c85 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -125,7 +125,9 @@ $ScriptLock $0; :set ($Metric->"notified") false; :set ($Metric->"parent") ($HostInfo->"parent"); :set ($Metric->"since"); - } else={ + } + + :if ($HostVal->"status" = "down") do={ :set ($Metric->"count-down") ($Metric->"count-down" + 1); :set ($Metric->"count-up") 0; :set ($Metric->"parent") ($HostInfo->"parent"); @@ -178,6 +180,7 @@ $ScriptLock $0; :set ($Metric->"notified") true; } } + :set ($NetwatchNotify->$Name) { "count-down"=($Metric->"count-down"); "count-up"=($Metric->"count-up"); From b1199ca50a16c9accb9a49ae334c4620a69993cc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 21 Feb 2024 09:05:52 +0100 Subject: [PATCH 1880/2612] netwatch-notify: ... and switch state to "unknown" on host update --- netwatch-notify.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index a562c85..186ac0a 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -87,6 +87,7 @@ $ScriptLock $0; ", updating.") false; /tool/netwatch/set host=$Resolve $Host; :set ($Metric->"resolve-failcnt") 0; + :set ($HostVal->"status") "unknown"; } } on-error={ :set ($Metric->"resolve-failcnt") ($Metric->"resolve-failcnt" + 1); From 45875ad68e4898d5c66ee08335e0c32fe04a95a6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 26 Feb 2024 23:17:07 +0100 Subject: [PATCH 1881/2612] netwatch-notify: simplify the check --- netwatch-notify.rsc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 186ac0a..53ea7e3 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -79,8 +79,7 @@ $ScriptLock $0; :if ([ $IsDNSResolving ] = true) do={ :do { :local Resolve [ :resolve ($HostInfo->"resolve") ]; - :if ($Resolve != $HostVal->"host" && \ - [ :len [ /ip/dns/cache/find where name=($HostInfo->"resolve") data=[ :tostr ($HostVal->"host") ] ] ] = 0) do={ + :if ([ :len [ /ip/dns/cache/find where name=($HostInfo->"resolve") data=[ :tostr ($HostVal->"host") ] ] ] = 0) do={ $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ From c2f5272f18c2161150481b9569ee17bc2c3d2289 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Feb 2024 17:56:08 +0100 Subject: [PATCH 1882/2612] =?UTF-8?q?netwatch-notify:=20restore=20the=20ch?= =?UTF-8?q?eck=20=F0=9F=A5=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 28da1da49e275fef6089a103edf6c158bbff317f. 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? 🤨 --- netwatch-notify.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 53ea7e3..186ac0a 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -79,7 +79,8 @@ $ScriptLock $0; :if ([ $IsDNSResolving ] = true) do={ :do { :local Resolve [ :resolve ($HostInfo->"resolve") ]; - :if ([ :len [ /ip/dns/cache/find where name=($HostInfo->"resolve") data=[ :tostr ($HostVal->"host") ] ] ] = 0) do={ + :if ($Resolve != $HostVal->"host" && \ + [ :len [ /ip/dns/cache/find where name=($HostInfo->"resolve") data=[ :tostr ($HostVal->"host") ] ] ] = 0) do={ $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ From 93bed1b081bb23624b988627d2db6e71d55e796a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 26 Feb 2024 23:18:02 +0100 Subject: [PATCH 1883/2612] 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. --- netwatch-notify.rsc | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 186ac0a..c8de7e1 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -80,14 +80,18 @@ $ScriptLock $0; :do { :local Resolve [ :resolve ($HostInfo->"resolve") ]; :if ($Resolve != $HostVal->"host" && \ - [ :len [ /ip/dns/cache/find where name=($HostInfo->"resolve") data=[ :tostr ($HostVal->"host") ] ] ] = 0) do={ - $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ - ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ - $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ - ", updating.") false; - /tool/netwatch/set host=$Resolve $Host; - :set ($Metric->"resolve-failcnt") 0; - :set ($HostVal->"status") "unknown"; + [ :len [ /ip/dns/cache/find where name=($HostInfo->"resolve") data=[ :tostr ($HostVal->"host") ] ttl>0s ] ] = 0) do={ + :delay 1500ms; + :resolve ($HostInfo->"resolve"); + :if ([ :len [ /ip/dns/cache/find where name=($HostInfo->"resolve") data=[ :tostr ($HostVal->"host") ] ] ] = 0) do={ + $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ + ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ + $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ + ", updating.") false; + /tool/netwatch/set host=$Resolve $Host; + :set ($Metric->"resolve-failcnt") 0; + :set ($HostVal->"status") "unknown"; + } } } on-error={ :set ($Metric->"resolve-failcnt") ($Metric->"resolve-failcnt" + 1); From 01d2c3ea7e3b00a3020705120d896fd6689fab1a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Feb 2024 23:18:31 +0100 Subject: [PATCH 1884/2612] netwatch-notify: try another workaround The last one did not make it... Perhaps the cache just needs a moment to settle? --- netwatch-notify.rsc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index c8de7e1..5c6ae40 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -79,10 +79,8 @@ $ScriptLock $0; :if ([ $IsDNSResolving ] = true) do={ :do { :local Resolve [ :resolve ($HostInfo->"resolve") ]; - :if ($Resolve != $HostVal->"host" && \ - [ :len [ /ip/dns/cache/find where name=($HostInfo->"resolve") data=[ :tostr ($HostVal->"host") ] ttl>0s ] ] = 0) do={ - :delay 1500ms; - :resolve ($HostInfo->"resolve"); + :if ($Resolve != $HostVal->"host") do={ + :delay 100ms; :if ([ :len [ /ip/dns/cache/find where name=($HostInfo->"resolve") data=[ :tostr ($HostVal->"host") ] ] ] = 0) do={ $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ From 6f29c640e4e63b6a5e0d986b63dafa54dc2cc3fa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Feb 2024 22:19:26 +0100 Subject: [PATCH 1885/2612] netwatch-notify: move check in DNS cache to local function --- netwatch-notify.rsc | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 5c6ae40..1b6a005 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -52,6 +52,19 @@ :return ("Ran hook:\n" . $Hook); } +:local ResolveExpected do={ + :local Name [ :tostr $1 ]; + :local Expected [ :tostr $2 ]; + + :delay 100ms; + + :if ([ :len [ /ip/dns/cache/find where name=$Name data=$Expected ] ] > 0) do={ + :return true; + } + + :return false; +} + $ScriptLock $0; :local ScriptFromTerminalCached [ $ScriptFromTerminal $0 ]; @@ -80,8 +93,7 @@ $ScriptLock $0; :do { :local Resolve [ :resolve ($HostInfo->"resolve") ]; :if ($Resolve != $HostVal->"host") do={ - :delay 100ms; - :if ([ :len [ /ip/dns/cache/find where name=($HostInfo->"resolve") data=[ :tostr ($HostVal->"host") ] ] ] = 0) do={ + :if ([ $ResolveExpected ($HostInfo->"resolve") ($HostVal->"host") ] = false) do={ $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ From a924de274c482b79777d9c1ca9d2e1d1919155cb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Feb 2024 22:29:55 +0100 Subject: [PATCH 1886/2612] netwatch-notify: handle CNAME to multiple records --- doc/netwatch-notify.md | 6 +++--- netwatch-notify.rsc | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 6925ca5..a7cc2d6 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -83,9 +83,9 @@ with a resolvable name: /tool/netwatch/add comment="notify, name=example.com, resolve=example.com"; -This supports multiple A or AAAA records for a name just fine, but be -warned: A CNAME to multiple records will cause a high rate of configuration -changes (and flash writes)! +This supports multiple A or AAAA records for a name just fine, even a CNAME +to those. But be warned: CNAME chains to multiple records will cause a high +rate of configuration changes (and flash writes)! ### No notification on host down diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 1b6a005..cd4fc0d 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -62,6 +62,15 @@ :return true; } + :local Cname [ /ip/dns/cache/find where name=$Name type="CNAME" ]; + :if ([ :len $Cname ] > 0) do={ + :set Cname [ /ip/dns/cache/get $Cname data ]; + :set Cname [ :pick $Cname 0 ([ :len $Cname ] - 1) ]; + :if ([ :len [ /ip/dns/cache/find where name=$Cname data=$Expected ] ] > 0) do={ + :return true; + } + } + :return false; } From 1687e2780fb8a10c84b8ca829a536b4030703418 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 24 Feb 2024 23:21:42 +0100 Subject: [PATCH 1887/2612] fw-addr-lists: get timeout from loop --- fw-addr-lists.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index bc294d1..7845b8a 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -107,10 +107,10 @@ $WaitFullyConnected; } } - :foreach Address,Ignore in=$Addresses do={ - $LogPrintExit2 debug $0 ("Adding for " . ($Addresses->$Address) . ": " . $Address) false; + :foreach Address,Timeout in=$Addresses do={ + $LogPrintExit2 debug $0 ("Adding for " . $Timeout . ": " . $Address) false; :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 CntAdd ($CntAdd + 1); } on-error={ From 31966479dc9c5b58bb46e3bb9f85dcc6433a94ed Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 24 Feb 2024 23:23:05 +0100 Subject: [PATCH 1888/2612] fw-addr-lists: update wording --- fw-addr-lists.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 7845b8a..7ab575c 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -94,13 +94,13 @@ $WaitFullyConnected; :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; + $LogPrintExit2 debug $0 ("Renewing address 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; + $LogPrintExit2 debug $0 ("Removing address: " . $Address) false; /ip/firewall/address-list/remove $Entry; :set CntRemove ($CntRemove + 1); } @@ -108,7 +108,7 @@ $WaitFullyConnected; } :foreach Address,Timeout in=$Addresses do={ - $LogPrintExit2 debug $0 ("Adding for " . $Timeout . ": " . $Address) false; + $LogPrintExit2 debug $0 ("Adding address for " . $Timeout . ": " . $Address) false; :do { /ip/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout; :set ($Addresses->$Address); From 0125f102b4f420ed86e9eb968d088576e1fb4c3e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Feb 2024 11:15:46 +0100 Subject: [PATCH 1889/2612] fw-addr-lists: rename variable --- fw-addr-lists.rsc | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 7ab575c..c0212c6 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -38,10 +38,10 @@ $WaitFullyConnected; :local ListComment ("managed by " . $0); :foreach FwListName,FwList in=$FwAddrLists do={ - :local Addresses ({}); :local CntAdd 0; :local CntRenew 0; :local CntRemove 0; + :local IPv4Addresses ({}); :local Failure false; :foreach List in=$FwList do={ @@ -85,7 +85,7 @@ $WaitFullyConnected; :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 ($IPv4Addresses->$Address) $TimeOut; } :set Data [ :pick $Data ([ :len $Line ] + 1) [ :len $Data ] ]; } @@ -93,28 +93,28 @@ $WaitFullyConnected; :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 address for " . ($Addresses->$Address) . ": " . $Address) false; - /ip/firewall/address-list/set $Entry timeout=($Addresses->$Address); - :set ($Addresses->$Address); + :if ([ :typeof ($IPv4Addresses->$Address) ] = "time") do={ + $LogPrintExit2 debug $0 ("Renewing IPv4 address for " . ($IPv4Addresses->$Address) . ": " . $Address) false; + /ip/firewall/address-list/set $Entry timeout=($IPv4Addresses->$Address); + :set ($IPv4Addresses->$Address); :set CntRenew ($CntRenew + 1); } else={ :if ($Failure = false) do={ - $LogPrintExit2 debug $0 ("Removing address: " . $Address) false; + $LogPrintExit2 debug $0 ("Removing IPv4 address: " . $Address) false; /ip/firewall/address-list/remove $Entry; :set CntRemove ($CntRemove + 1); } } } - :foreach Address,Timeout in=$Addresses do={ - $LogPrintExit2 debug $0 ("Adding address for " . $Timeout . ": " . $Address) false; + :foreach Address,Timeout in=$IPv4Addresses do={ + $LogPrintExit2 debug $0 ("Adding IPv4 address for " . $Timeout . ": " . $Address) false; :do { /ip/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout; - :set ($Addresses->$Address); + :set ($IPv4Addresses->$Address); :set CntAdd ($CntAdd + 1); } on-error={ - $LogPrintExit2 warning $0 ("Failed to add address " . $Address . " to list '" . $FwListName . "'.") false; + $LogPrintExit2 warning $0 ("Failed to add IPv4 address " . $Address . " to list '" . $FwListName . "'.") false; } } From 62790ae091e167a1aea4c5a5fec128ee5c41ca4c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Feb 2024 11:19:56 +0100 Subject: [PATCH 1890/2612] fw-addr-lists: add support for IPv6 --- doc/fw-addr-lists.md | 35 +++++++++++++++++++++++++++++++++-- fw-addr-lists.rsc | 34 +++++++++++++++++++++++++++++++++- global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 4 files changed, 68 insertions(+), 4 deletions(-) diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md index 5805905..6dc6b66 100644 --- a/doc/fw-addr-lists.md +++ b/doc/fw-addr-lists.md @@ -56,8 +56,12 @@ available in my repository and downloaded automatically. Import it manually (menu `/certificate/`) if missing. Create firewall rules to process the packets that are related to addresses -from address-lists. This rejects the packets from and to ip addresses listed -in address-list `block`. +from address-lists. + +### IPv4 rules + +This rejects the packets from and to IPv4 addresses listed in +address-list `block`. /ip/firewall/filter/add chain=input src-address-list=block action=reject reject-with=icmp-admin-prohibited; /ip/firewall/filter/add chain=forward src-address-list=block action=reject reject-with=icmp-admin-prohibited; @@ -85,6 +89,33 @@ Alternatively handle the packets in firewall's raw section if you prefer: > âš ī¸ **Warning**: Just again... The order of firewall rules is important. Make > sure they actually take effect as expected! +### IPv6 rules + +These are the same rules, but for IPv6. + +Reject packets in address-list `block`: + + /ipv6/firewall/filter/add chain=input src-address-list=block action=reject reject-with=icmp-admin-prohibited; + /ipv6/firewall/filter/add chain=forward src-address-list=block action=reject reject-with=icmp-admin-prohibited; + /ipv6/firewall/filter/add chain=forward dst-address-list=block action=reject reject-with=icmp-admin-prohibited; + /ipv6/firewall/filter/add chain=output dst-address-list=block action=reject reject-with=icmp-admin-prohibited; + +Allow packets in address-list `allow`: + + /ipv6/firewall/filter/add chain=input src-address-list=allow action=accept; + /ipv6/firewall/filter/add chain=forward src-address-list=allow action=accept; + /ipv6/firewall/filter/add chain=forward dst-address-list=allow action=accept; + /ipv6/firewall/filter/add chain=output dst-address-list=allow action=accept; + +Drop packets in firewall's raw section: + + /ipv6/firewall/raw/add chain=prerouting src-address-list=block action=drop; + /ipv6/firewall/raw/add chain=prerouting dst-address-list=block action=drop; + /ipv6/firewall/raw/add chain=output dst-address-list=block action=drop; + +> âš ī¸ **Warning**: Just again... The order of firewall rules is important. Make +> sure they actually take effect as expected! + --- [âŦ…ī¸ Go back to main README](../README.md) [âŦ†ī¸ Go back to top](#top) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index c0212c6..14da2e2 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -24,7 +24,7 @@ :global WaitFullyConnected; :local FindDelim do={ - :local ValidChars "0123456789./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"; + :local ValidChars "0123456789.:/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"; :for I from=0 to=[ :len $1 ] do={ :if ([ :typeof [ :find $ValidChars [ :pick ($1 . " ") $I ] ] ] != "num") do={ :return $I; @@ -42,6 +42,7 @@ $WaitFullyConnected; :local CntRenew 0; :local CntRemove 0; :local IPv4Addresses ({}); + :local IPv6Addresses ({}); :local Failure false; :foreach List in=$FwList do={ @@ -87,6 +88,10 @@ $WaitFullyConnected; $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 ] ]; } } @@ -107,6 +112,22 @@ $WaitFullyConnected; } } + :foreach Entry in=[ /ipv6/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={ + :local Address [ /ipv6/firewall/address-list/get $Entry address ]; + :if ([ :typeof ($IPv6Addresses->$Address) ] = "time") do={ + $LogPrintExit2 debug $0 ("Renewing IPv6 address for " . ($IPv6Addresses->$Address) . ": " . $Address) false; + /ipv6/firewall/address-list/set $Entry timeout=($IPv6Addresses->$Address); + :set ($IPv6Addresses->$Address); + :set CntRenew ($CntRenew + 1); + } else={ + :if ($Failure = false) do={ + $LogPrintExit2 debug $0 ("Removing: " . $Address) false; + /ipv6/firewall/address-list/remove $Entry; + :set CntRemove ($CntRemove + 1); + } + } + } + :foreach Address,Timeout in=$IPv4Addresses do={ $LogPrintExit2 debug $0 ("Adding IPv4 address for " . $Timeout . ": " . $Address) false; :do { @@ -118,5 +139,16 @@ $WaitFullyConnected; } } + :foreach Address,Timeout in=$IPv6Addresses do={ + $LogPrintExit2 debug $0 ("Adding IPv6 address for " . $Timeout . ": " . $Address) false; + :do { + /ipv6/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout; + :set ($IPv6Addresses->$Address); + :set CntAdd ($CntAdd + 1); + } on-error={ + $LogPrintExit2 warning $0 ("Failed to add IPv6 address " . $Address . " to list '" . $FwListName . "'.") false; + } + } + $LogPrintExit2 info $0 ("list: " . $FwListName . " -- added: " . $CntAdd . " - renewed: " . $CntRenew . " - removed: " . $CntRemove) false; } diff --git a/global-functions.rsc b/global-functions.rsc index d37b34b..92fabff 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 118; +:global ExpectedConfigVersion 119; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index b6f5169..d0e9938 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -43,6 +43,7 @@ [ $IfThenElse ($Resource->"total-hdd-space" < 16000000) ("Your " . $Resource->"board-name" . " is specifically affected! ") \ [ $IfThenElse ($Resource->"free-hdd-space" > 4000000) ("(Your " . $Resource->"board-name" . " does not suffer this issue.) ") ] ] . \ "Huge configuration and lots of scripts give an extra risk. Take care!"); + 119="Added support for IPv6 to script 'fw-addr-lists'."; }; # Migration steps to be applied on script updates From 50a69149072be4f66cbd05362fef9ec68f293323 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 1 Mar 2024 12:09:29 +0100 Subject: [PATCH 1891/2612] netwatch-notify: (mis-)use firewall address-list for lookup... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... and drop the racy code querying dns cache. 😁 --- doc/netwatch-notify.md | 4 ++-- netwatch-notify.rsc | 16 +++++----------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index a7cc2d6..e252d39 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -84,8 +84,8 @@ with a resolvable name: /tool/netwatch/add comment="notify, name=example.com, resolve=example.com"; This supports multiple A or AAAA records for a name just fine, even a CNAME -to those. But be warned: CNAME chains to multiple records will cause a high -rate of configuration changes (and flash writes)! +to those. An update happens only if no more record with the configured host +address is found. ### No notification on host down diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index cd4fc0d..6501ea9 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -56,21 +56,15 @@ :local Name [ :tostr $1 ]; :local Expected [ :tostr $2 ]; - :delay 100ms; + :global GetRandom20CharAlNum; - :if ([ :len [ /ip/dns/cache/find where name=$Name data=$Expected ] ] > 0) do={ + :local FwAddrList ($0 . "-" . [ $GetRandom20CharAlNum ]); + /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s; + :delay 20ms; + :if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ :return true; } - :local Cname [ /ip/dns/cache/find where name=$Name type="CNAME" ]; - :if ([ :len $Cname ] > 0) do={ - :set Cname [ /ip/dns/cache/get $Cname data ]; - :set Cname [ :pick $Cname 0 ([ :len $Cname ] - 1) ]; - :if ([ :len [ /ip/dns/cache/find where name=$Cname data=$Expected ] ] > 0) do={ - :return true; - } - } - :return false; } From 4869d74edf055de1d7a8304a8ac3c29fe11ae3e3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 1 Mar 2024 21:02:46 +0100 Subject: [PATCH 1892/2612] netwatch-notify: handle IPv6 / AAAA resolving --- netwatch-notify.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 6501ea9..5fde355 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -60,8 +60,10 @@ :local FwAddrList ($0 . "-" . [ $GetRandom20CharAlNum ]); /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s; + /ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s; :delay 20ms; - :if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ + :if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0 || \ + [ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ :return true; } From 64aa6ef1249be378f02b8c211f53a7f12da4f695 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 3 Mar 2024 20:32:23 +0100 Subject: [PATCH 1893/2612] netwatch-notify: check one after another This can bring an extra delay, but saves a check in most cases. --- netwatch-notify.rsc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 5fde355..8c59af8 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -60,10 +60,13 @@ :local FwAddrList ($0 . "-" . [ $GetRandom20CharAlNum ]); /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s; + :delay 20ms; + :if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ + :return true; + } /ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s; :delay 20ms; - :if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0 || \ - [ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ + :if ([ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ :return true; } From efc2e75f019227274cb934a5907b3782fb8d5d71 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1894/2612] accesslist-duplicates: move code into function --- accesslist-duplicates.capsman.rsc | 27 ++++++++------- accesslist-duplicates.local.rsc | 27 ++++++++------- accesslist-duplicates.template.rsc | 51 ++++++++++++++++------------- accesslist-duplicates.wifi.rsc | 27 ++++++++------- accesslist-duplicates.wifiwave2.rsc | 27 ++++++++------- 5 files changed, 92 insertions(+), 67 deletions(-) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index a20c05d..f781eb3 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -10,22 +10,27 @@ # # !! Do not edit this file, it is generated from template! -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Seen ({}); +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ - :local Mac [ /caps-man/access-list/get $AccList mac-address ]; - :if ($Seen->$Mac = 1) do={ - /caps-man/access-list/print where mac-address=$Mac; - :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; + :local Seen ({}); - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /caps-man/access-list/remove $Remove; + :foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ + :local Mac [ /caps-man/access-list/get $AccList mac-address ]; + :if ($Seen->$Mac = 1) do={ + /caps-man/access-list/print where mac-address=$Mac; + :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; + + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /caps-man/access-list/remove $Remove; + } } + :set ($Seen->$Mac) 1; } - :set ($Seen->$Mac) 1; } + +$Main [ :jobname ]; diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index 0feb9f7..b235cd1 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -10,22 +10,27 @@ # # !! Do not edit this file, it is generated from template! -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Seen ({}); +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ - :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; - :if ($Seen->$Mac = 1) do={ - /interface/wireless/access-list/print where mac-address=$Mac; - :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; + :local Seen ({}); - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /interface/wireless/access-list/remove $Remove; + :foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ + :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; + :if ($Seen->$Mac = 1) do={ + /interface/wireless/access-list/print where mac-address=$Mac; + :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; + + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /interface/wireless/access-list/remove $Remove; + } } + :set ($Seen->$Mac) 1; } - :set ($Seen->$Mac) 1; } + +$Main [ :jobname ]; diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index f350d0c..97f6138 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -11,34 +11,39 @@ # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Seen ({}); +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ -:foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ -:foreach AccList in=[ /interface/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!" ] ]; + :local Seen ({}); - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /caps-man/access-list/remove $Remove; - /interface/wifi/access-list/remove $Remove; - /interface/wifiwave2/access-list/remove $Remove; - /interface/wireless/access-list/remove $Remove; + :foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ + :foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ + :foreach AccList in=[ /interface/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={ + :put ("Removing numeric id " . $Remove . "...\n"); + /caps-man/access-list/remove $Remove; + /interface/wifi/access-list/remove $Remove; + /interface/wifiwave2/access-list/remove $Remove; + /interface/wireless/access-list/remove $Remove; + } } + :set ($Seen->$Mac) 1; } - :set ($Seen->$Mac) 1; } + +$Main [ :jobname ]; diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc index d5f13f0..04ac19c 100644 --- a/accesslist-duplicates.wifi.rsc +++ b/accesslist-duplicates.wifi.rsc @@ -10,22 +10,27 @@ # # !! Do not edit this file, it is generated from template! -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Seen ({}); +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ - :local Mac [ /interface/wifi/access-list/get $AccList mac-address ]; - :if ($Seen->$Mac = 1) do={ - /interface/wifi/access-list/print where mac-address=$Mac; - :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; + :local Seen ({}); - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /interface/wifi/access-list/remove $Remove; + :foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ + :local Mac [ /interface/wifi/access-list/get $AccList mac-address ]; + :if ($Seen->$Mac = 1) do={ + /interface/wifi/access-list/print where mac-address=$Mac; + :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; + + :if ([ :typeof $Remove ] = "num") do={ + :put ("Removing numeric id " . $Remove . "...\n"); + /interface/wifi/access-list/remove $Remove; + } } + :set ($Seen->$Mac) 1; } - :set ($Seen->$Mac) 1; } + +$Main [ :jobname ]; diff --git a/accesslist-duplicates.wifiwave2.rsc b/accesslist-duplicates.wifiwave2.rsc index 24f5967..232d941 100644 --- a/accesslist-duplicates.wifiwave2.rsc +++ b/accesslist-duplicates.wifiwave2.rsc @@ -10,22 +10,27 @@ # # !! Do not edit this file, it is generated from template! -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Seen ({}); +:local Main do={ + :local ScriptName [ :tostr $1 ]; -: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!" ] ]; + :local Seen ({}); - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /interface/wifiwave2/access-list/remove $Remove; + :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; } - :set ($Seen->$Mac) 1; } + +$Main [ :jobname ]; From 33d129496c1a6d3092231d707ae5e12fa56315ea Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1895/2612] backup-cloud: move code into function --- backup-cloud.rsc | 89 +++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 42 deletions(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 58fd37a..94966c5 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -9,55 +9,60 @@ # upload backup to MikroTik cloud # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global BackupPassword; -:global BackupRandomDelay; -:global Identity; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global DeviceInfo; -:global FormatLine; -:global HumanReadableNum; -:global LogPrintExit2; -:global RandomDelay; -:global ScriptFromTerminal; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; -:global WaitFullyConnected; + :global BackupPassword; + :global BackupRandomDelay; + :global Identity; -$ScriptLock $0; -$WaitFullyConnected; + :global DeviceInfo; + :global FormatLine; + :global HumanReadableNum; + :global LogPrintExit2; + :global RandomDelay; + :global ScriptFromTerminal; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; + :global WaitFullyConnected; -:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ - $RandomDelay $BackupRandomDelay; -} + $ScriptLock $ScriptName; + $WaitFullyConnected; -:do { - # we are not interested in output, but print is - # required to fetch information from cloud - /system/backup/cloud/print as-value; - :if ([ :len [ /system/backup/cloud/find ] ] > 0) do={ - /system/backup/cloud/upload-file action=create-and-upload \ - password=$BackupPassword replace=[ get ([ find ]->0) name ]; - } else={ - /system/backup/cloud/upload-file action=create-and-upload \ - password=$BackupPassword; + :if ([ $ScriptFromTerminal $ScriptName ] = false && $BackupRandomDelay > 0) do={ + $RandomDelay $BackupRandomDelay; } - :local Cloud [ /system/backup/cloud/get ([ find ]->0) ]; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "floppy-disk,cloud" ] . "Cloud backup"); \ - message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - [ $FormatLine "Name" ($Cloud->"name") ] . "\n" . \ - [ $FormatLine "Size" ([ $HumanReadableNum ($Cloud->"size") 1024 ] . "iB") ] . "\n" . \ - [ $FormatLine "Download key" ($Cloud->"secret-download-key") ]); silent=true }); -} on-error={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Cloud backup failed"); \ - message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); - $LogPrintExit2 error $0 ("Failed uploading backup for " . $Identity . " to cloud!") true; + :do { + # we are not interested in output, but print is + # required to fetch information from cloud + /system/backup/cloud/print as-value; + :if ([ :len [ /system/backup/cloud/find ] ] > 0) do={ + /system/backup/cloud/upload-file action=create-and-upload \ + password=$BackupPassword replace=[ get ([ find ]->0) name ]; + } else={ + /system/backup/cloud/upload-file action=create-and-upload \ + password=$BackupPassword; + } + :local Cloud [ /system/backup/cloud/get ([ find ]->0) ]; + + $SendNotification2 ({ origin=$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 }); + } on-error={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Cloud backup failed"); \ + message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); + $LogPrintExit2 error $ScriptName ("Failed uploading backup for " . $Identity . " to cloud!") true; + } } + +$Main [ :jobname ]; From 19fb7b61ea4c92fe61db5cbfa34fe0a932acea39 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1896/2612] backup-email: move code into function --- backup-email.rsc | 191 ++++++++++++++++++++++++----------------------- 1 file changed, 98 insertions(+), 93 deletions(-) diff --git a/backup-email.rsc b/backup-email.rsc index 86f9003..7380a5d 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -9,104 +9,109 @@ # create and email backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global BackupPassword; -:global BackupRandomDelay; -:global BackupSendBinary; -:global BackupSendExport; -:global BackupSendGlobalConfig; -:global Domain; -:global Identity; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global CleanName; -:global DeviceInfo; -:global FormatLine; -:global LogPrintExit2; -:global MkDir; -:global RandomDelay; -:global ScriptFromTerminal; -:global ScriptLock; -:global SendEMail2; -:global SymbolForNotification; -:global WaitForFile; -:global WaitFullyConnected; + :global BackupPassword; + :global BackupRandomDelay; + :global BackupSendBinary; + :global BackupSendExport; + :global BackupSendGlobalConfig; + :global Domain; + :global Identity; -:if ([ :typeof $SendEMail2 ] = "nothing") do={ - $LogPrintExit2 error $0 ("The module for sending notifications via e-mail is not installed.") true; -} + :global CleanName; + :global DeviceInfo; + :global FormatLine; + :global LogPrintExit2; + :global MkDir; + :global RandomDelay; + :global ScriptFromTerminal; + :global ScriptLock; + :global SendEMail2; + :global SymbolForNotification; + :global WaitForFile; + :global WaitFullyConnected; -:if ($BackupSendBinary != true && \ - $BackupSendExport != true) do={ - $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; -} - -$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; + :if ([ :typeof $SendEMail2 ] = "nothing") do={ + $LogPrintExit2 error $ScriptName ("The module for sending notifications via e-mail is not installed.") true; + } + + :if ($BackupSendBinary != true && \ + $BackupSendExport != true) do={ + $LogPrintExit2 error $ScriptName ("Configured to send neither backup nor config export.") true; + } + + $ScriptLock $ScriptName; + $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={ + $LogPrintExit2 error $ScriptName ("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=$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={ + $LogPrintExit2 warning $ScriptName ("Files are still available, sending e-mail failed.") true; + } + :delay 1s; + :set I ($I + 1); } - :delay 1s; - :set I ($I + 1); } + +$Main [ :jobname ]; From 0ded98c9e2329e7ea20f296cc818e67803860cd3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1897/2612] backup-partition: move code into function --- backup-partition.rsc | 59 ++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index 1db5e1d..4793f12 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -9,37 +9,42 @@ # save configuration to fallback partition # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit2; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global LogPrintExit2; + :global ScriptLock; -:if ([ :len [ /partitions/find ] ] < 2) do={ - $LogPrintExit2 error $0 ("Device does not have a fallback partition.") true; + $ScriptLock $ScriptName; + + :if ([ :len [ /partitions/find ] ] < 2) do={ + $LogPrintExit2 error $ScriptName ("Device does not have a fallback partition.") true; + } + + :local ActiveRunning [ /partitions/find where active running ]; + + :if ([ :len $ActiveRunning ] < 1) do={ + $LogPrintExit2 error $ScriptName ("Device is not running from active partition.") true; + } + + :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"; + $LogPrintExit2 info $ScriptName ("Saved configuration to partition '" . \ + $FallbackTo . "'.") false; + } on-error={ + /system/scheduler/remove [ find where name="running-from-backup-partition" ]; + $LogPrintExit2 error $ScriptName ("Failed saving configuration to partition '" . \ + $FallbackTo . "'!") 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 { - /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"; - $LogPrintExit2 info $0 ("Saved configuration to partition '" . \ - $FallbackTo . "'.") false; -} on-error={ - /system/scheduler/remove [ find where name="running-from-backup-partition" ]; - $LogPrintExit2 error $0 ("Failed saving configuration to partition '" . \ - $FallbackTo . "'!") true; -} +$Main [ :jobname ]; From 1c26dde356222817a3a562bd3d27f3e45382c748 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1898/2612] backup-upload: move code into function --- backup-upload.rsc | 267 +++++++++++++++++++++++----------------------- 1 file changed, 136 insertions(+), 131 deletions(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 05bc3ff..dfba15e 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -9,143 +9,148 @@ # create and upload backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global BackupPassword; -:global BackupRandomDelay; -:global BackupSendBinary; -:global BackupSendExport; -:global BackupSendGlobalConfig; -:global BackupUploadPass; -:global BackupUploadUrl; -:global BackupUploadUser; -:global Domain; -:global Identity; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global CleanName; -:global DeviceInfo; -:global IfThenElse; -:global LogPrintExit2; -:global MkDir; -:global RandomDelay; -:global ScriptFromTerminal; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; -:global WaitForFile; -:global WaitFullyConnected; + :global BackupPassword; + :global BackupRandomDelay; + :global BackupSendBinary; + :global BackupSendExport; + :global BackupSendGlobalConfig; + :global BackupUploadPass; + :global BackupUploadUrl; + :global BackupUploadUser; + :global Domain; + :global Identity; -:if ($BackupSendBinary != true && \ - $BackupSendExport != true) do={ - $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 CleanName; + :global DeviceInfo; :global IfThenElse; + :global LogPrintExit2; + :global MkDir; + :global RandomDelay; + :global ScriptFromTerminal; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; + :global WaitForFile; + :global WaitFullyConnected; - :return \ - [ $IfThenElse ([ :typeof $File ] = "array") \ - ($Name . ":\n" . [ $FormatLine " name" ($File->"name") ] . "\n" . \ - [ $FormatLine " size" ([ $HumanReadableNum ($File->"size") 1024 ] . "iB") ]) \ - [ $FormatLine $Name $File ] ]; + :if ($BackupSendBinary != true && \ + $BackupSendExport != true) do={ + $LogPrintExit2 error $ScriptName ("Configured to send neither backup nor config export.") true; + } + + $ScriptLock $ScriptName; + $WaitFullyConnected; + + :if ([ $ScriptFromTerminal $ScriptName ] = false && $BackupRandomDelay > 0) do={ + $RandomDelay $BackupRandomDelay; + } + + # filename based on identity + :local DirName ("tmpfs/" . $ScriptName); + :local FileName [ $CleanName ($Identity . "." . $Domain) ]; + :local FilePath ($DirName . "/" . $FileName); + :local BackupFile "none"; + :local ExportFile "none"; + :local ConfigFile "none"; + :local Failed 0; + + :if ([ $MkDir $DirName ] = false) do={ + $LogPrintExit2 error $ScriptName ("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 $ScriptName ("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 $ScriptName ("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 $ScriptName ("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; + + :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={ + :error "An error occured!"; + } } -$SendNotification2 ({ origin=$0; \ - 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={ - :error "An error occured!"; -} +$Main [ :jobname ]; From c2df671d6f31c0e652542f731d66cbccace43f85 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1899/2612] capsman-download-packages: move code into function --- capsman-download-packages.capsman.rsc | 99 ++++++++++---------- capsman-download-packages.template.rsc | 117 ++++++++++++------------ capsman-download-packages.wifi.rsc | 103 +++++++++++---------- capsman-download-packages.wifiwave2.rsc | 99 ++++++++++---------- 4 files changed, 219 insertions(+), 199 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index 82849f8..18ecf57 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -11,66 +11,71 @@ # # !! 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; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; -$WaitFullyConnected; + :global CleanFilePath; + :global DownloadPackage; + :global LogPrintExit2; + :global MkDir; + :global ScriptLock; + :global WaitFullyConnected; -:local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; -:local InstalledVersion [ /system/package/update/get installed-version ]; -:local Updated false; + $ScriptLock $ScriptName; + $WaitFullyConnected; -:if ([ :len $PackagePath ] = 0) do={ - $LogPrintExit2 warning $0 ("The CAPsMAN package path is not defined, can not download packages.") true; -} + :local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; + :local InstalledVersion [ /system/package/update/get installed-version ]; + :local Updated false; -:if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ - :if ([ $MkDir $PackagePath ] = false) do={ - $LogPrintExit2 warning $0 ("Creating directory at CAPsMAN package path (" . \ - $PackagePath . ") failed!") true; + :if ([ :len $PackagePath ] = 0) do={ + $LogPrintExit2 warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages.") 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 ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ + :if ([ $MkDir $PackagePath ] = false) do={ + $LogPrintExit2 warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ + $PackagePath . ") failed!") true; + } + $LogPrintExit2 info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ + "). Please place your packages!") false; } - :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"; "mipsbe" } do={ - :foreach Package in={ "routeros"; "wireless" } do={ - :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ - :set Updated true; + :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 $ScriptName ("No packages available, downloading default set.") false; + :foreach Arch in={ "arm"; "mipsbe" } do={ + :foreach Package in={ "routeros"; "wireless" } do={ + :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ + :set Updated true; + } } } } + + :if ($Updated = true) do={ + :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); + :if ([ :len $Script ] > 0) do={ + /system/script/run $Script; + } else={ + /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; + } + } } -:if ($Updated = true) do={ - :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); - :if ([ :len $Script ] > 0) do={ - /system/script/run $Script; - } else={ - /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; - } -} +$Main [ :jobname ]; diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 3eaa377..8cc7b2d 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -12,85 +12,90 @@ # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global CleanFilePath; -:global DownloadPackage; -:global LogPrintExit2; -:global MkDir; -:global ScriptLock; -:global WaitFullyConnected; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; -$WaitFullyConnected; + :global CleanFilePath; + :global DownloadPackage; + :global LogPrintExit2; + :global MkDir; + :global ScriptLock; + :global WaitFullyConnected; -:local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; -:local PackagePath [ $CleanFilePath [ /interface/wifi/capsman/get package-path ] ]; -:local PackagePath [ $CleanFilePath [ /interface/wifiwave2/capsman/get package-path ] ]; -:local InstalledVersion [ /system/package/update/get installed-version ]; -:local Updated false; + $ScriptLock $ScriptName; + $WaitFullyConnected; -:if ([ :len $PackagePath ] = 0) do={ - $LogPrintExit2 warning $0 ("The CAPsMAN package path is not defined, can not download packages.") true; -} + :local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; + :local PackagePath [ $CleanFilePath [ /interface/wifi/capsman/get package-path ] ]; + :local PackagePath [ $CleanFilePath [ /interface/wifiwave2/capsman/get package-path ] ]; + :local InstalledVersion [ /system/package/update/get installed-version ]; + :local Updated false; -:if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ - :if ([ $MkDir $PackagePath ] = false) do={ - $LogPrintExit2 warning $0 ("Creating directory at CAPsMAN package path (" . \ - $PackagePath . ") failed!") true; + :if ([ :len $PackagePath ] = 0) do={ + $LogPrintExit2 warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages.") 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 ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ + :if ([ $MkDir $PackagePath ] = false) do={ + $LogPrintExit2 warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ + $PackagePath . ") failed!") true; + } + $LogPrintExit2 info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ + "). Please place your packages!") false; } - :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 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 $ScriptName ("No packages available, downloading default set.") false; # NOT /interface/wifi/ # # NOT /interface/wifiwave2/ # - :foreach Arch in={ "arm"; "mipsbe" } do={ - :foreach Package in={ "routeros"; "wireless" } do={ + :foreach Arch in={ "arm"; "mipsbe" } do={ + :foreach Package in={ "routeros"; "wireless" } do={ # NOT /interface/wifi/ # # NOT /interface/wifiwave2/ # # NOT /caps-man/ # - :foreach Arch in={ "arm"; "arm64" } do={ + :foreach Arch in={ "arm"; "arm64" } do={ # NOT /interface/wifi/ # - :foreach Package in={ "routeros"; "wifiwave2" } do={ + :foreach Package in={ "routeros"; "wifiwave2" } do={ # NOT /interface/wifi/ # # NOT /interface/wifiwave2/ # - :local Packages { "arm"={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" }; - "arm64"={ "routeros"; "wifi-qcom" } }; - :foreach Package in=($Packages->$Arch) do={ + :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/ # - :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ - :set Updated true; + :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ + :set Updated true; + } } } } + + :if ($Updated = true) do={ + :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); + :if ([ :len $Script ] > 0) do={ + /system/script/run $Script; + } else={ + /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; + /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; + /interface/wifiwave2/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; + } + } } -:if ($Updated = true) do={ - :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); - :if ([ :len $Script ] > 0) do={ - /system/script/run $Script; - } else={ - /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; - /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; - /interface/wifiwave2/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; - } -} +$Main [ :jobname ]; diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 021521e..6f62c54 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -11,68 +11,73 @@ # # !! 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; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; -$WaitFullyConnected; + :global CleanFilePath; + :global DownloadPackage; + :global LogPrintExit2; + :global MkDir; + :global ScriptLock; + :global WaitFullyConnected; -:local PackagePath [ $CleanFilePath [ /interface/wifi/capsman/get package-path ] ]; -:local InstalledVersion [ /system/package/update/get installed-version ]; -:local Updated false; + $ScriptLock $ScriptName; + $WaitFullyConnected; -:if ([ :len $PackagePath ] = 0) do={ - $LogPrintExit2 warning $0 ("The CAPsMAN package path is not defined, can not download packages.") true; -} + :local PackagePath [ $CleanFilePath [ /interface/wifi/capsman/get package-path ] ]; + :local InstalledVersion [ /system/package/update/get installed-version ]; + :local Updated false; -:if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ - :if ([ $MkDir $PackagePath ] = false) do={ - $LogPrintExit2 warning $0 ("Creating directory at CAPsMAN package path (" . \ - $PackagePath . ") failed!") true; + :if ([ :len $PackagePath ] = 0) do={ + $LogPrintExit2 warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages.") 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 ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ + :if ([ $MkDir $PackagePath ] = false) do={ + $LogPrintExit2 warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ + $PackagePath . ") failed!") true; + } + $LogPrintExit2 info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ + "). Please place your packages!") false; } - :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={ - :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; + :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 $ScriptName ("No packages available, downloading default set.") false; + :foreach Arch in={ "arm"; "arm64" } do={ + :local Packages { "arm"={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" }; + "arm64"={ "routeros"; "wifi-qcom" } }; + :foreach Package in=($Packages->$Arch) do={ + :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ + :set Updated true; + } } } } + + :if ($Updated = true) do={ + :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); + :if ([ :len $Script ] > 0) do={ + /system/script/run $Script; + } else={ + /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; + } + } } -:if ($Updated = true) do={ - :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); - :if ([ :len $Script ] > 0) do={ - /system/script/run $Script; - } else={ - /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; - } -} +$Main [ :jobname ]; diff --git a/capsman-download-packages.wifiwave2.rsc b/capsman-download-packages.wifiwave2.rsc index 29dca8a..705da70 100644 --- a/capsman-download-packages.wifiwave2.rsc +++ b/capsman-download-packages.wifiwave2.rsc @@ -11,66 +11,71 @@ # # !! 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; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; -$WaitFullyConnected; + :global CleanFilePath; + :global DownloadPackage; + :global LogPrintExit2; + :global MkDir; + :global ScriptLock; + :global WaitFullyConnected; -:local PackagePath [ $CleanFilePath [ /interface/wifiwave2/capsman/get package-path ] ]; -:local InstalledVersion [ /system/package/update/get installed-version ]; -:local Updated false; + $ScriptLock $ScriptName; + $WaitFullyConnected; -:if ([ :len $PackagePath ] = 0) do={ - $LogPrintExit2 warning $0 ("The CAPsMAN package path is not defined, can not download packages.") true; -} + :local PackagePath [ $CleanFilePath [ /interface/wifiwave2/capsman/get package-path ] ]; + :local InstalledVersion [ /system/package/update/get installed-version ]; + :local Updated false; -:if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ - :if ([ $MkDir $PackagePath ] = false) do={ - $LogPrintExit2 warning $0 ("Creating directory at CAPsMAN package path (" . \ - $PackagePath . ") failed!") true; + :if ([ :len $PackagePath ] = 0) do={ + $LogPrintExit2 warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages.") 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 ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ + :if ([ $MkDir $PackagePath ] = false) do={ + $LogPrintExit2 warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ + $PackagePath . ") failed!") true; + } + $LogPrintExit2 info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ + "). Please place your packages!") false; } - :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; + :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 $ScriptName ("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 ]; + } + } } -: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 ]; - } -} +$Main [ :jobname ]; From 4cbf9fab746e9ce62e3cb66c794aad3e2601dc06 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1900/2612] capsman-rolling-upgrade: move code into function --- capsman-rolling-upgrade.capsman.rsc | 41 +++++++++++-------- capsman-rolling-upgrade.template.rsc | 59 +++++++++++++++------------ capsman-rolling-upgrade.wifi.rsc | 43 ++++++++++--------- capsman-rolling-upgrade.wifiwave2.rsc | 43 ++++++++++--------- 4 files changed, 103 insertions(+), 83 deletions(-) diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc index 7aa20aa..fb0904d 100644 --- a/capsman-rolling-upgrade.capsman.rsc +++ b/capsman-rolling-upgrade.capsman.rsc @@ -12,30 +12,35 @@ # # !! 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; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global LogPrintExit2; + :global ScriptLock; -:local InstalledVersion [ /system/package/update/get installed-version ]; + $ScriptLock $ScriptName; -: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; + :local InstalledVersion [ /system/package/update/get installed-version ]; + + :local RemoteCapCount [ :len [ /caps-man/remote-cap/find ] ]; + :if ($RemoteCapCount > 0) do={ + :local Delay (600 / $RemoteCapCount); + :if ($Delay > 120) do={ :set Delay 120; } + :foreach RemoteCap in=[ /caps-man/remote-cap/find where version!=$InstalledVersion ] do={ + :local RemoteCapVal [ /caps-man/remote-cap/get $RemoteCap ]; + :if ([ :len $RemoteCapVal ] > 1) do={ + $LogPrintExit2 info $ScriptName ("Starting upgrade for " . $RemoteCapVal->"name" . \ + " (" . $RemoteCapVal->"identity" . ")...") false; + /caps-man/remote-cap/upgrade $RemoteCap; + } else={ + $LogPrintExit2 warning $ScriptName ("Remote CAP vanished, skipping upgrade.") false; + } + :delay ($Delay . "s"); } - :delay ($Delay . "s"); } } + +$Main [ :jobname ]; diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index de0b4d1..6ea9ac0 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -13,41 +13,46 @@ # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit2; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global LogPrintExit2; + :global ScriptLock; -:local InstalledVersion [ /system/package/update/get installed-version ]; + $ScriptLock $ScriptName; -: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={ + :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 ] ]; + :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"); + :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; + $LogPrintExit2 info $ScriptName ("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 $ScriptName ("Remote CAP vanished, skipping upgrade.") false; + } + :delay ($Delay . "s"); } - :delay ($Delay . "s"); } } + +$Main [ :jobname ]; diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc index c17c5a1..d788c29 100644 --- a/capsman-rolling-upgrade.wifi.rsc +++ b/capsman-rolling-upgrade.wifi.rsc @@ -12,31 +12,36 @@ # # !! 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; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global LogPrintExit2; + :global ScriptLock; -:local InstalledVersion [ /system/package/update/get installed-version ]; + $ScriptLock $ScriptName; -: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; + :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"); + $LogPrintExit2 info $ScriptName ("Starting upgrade for " . $RemoteCapVal->"name" . \ + " (" . $RemoteCapVal->"identity" . ")...") false; + /interface/wifi/capsman/remote-cap/upgrade $RemoteCap; + } else={ + $LogPrintExit2 warning $ScriptName ("Remote CAP vanished, skipping upgrade.") false; + } + :delay ($Delay . "s"); } - :delay ($Delay . "s"); } } + +$Main [ :jobname ]; diff --git a/capsman-rolling-upgrade.wifiwave2.rsc b/capsman-rolling-upgrade.wifiwave2.rsc index aff47e4..78e348d 100644 --- a/capsman-rolling-upgrade.wifiwave2.rsc +++ b/capsman-rolling-upgrade.wifiwave2.rsc @@ -12,31 +12,36 @@ # # !! 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; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global LogPrintExit2; + :global ScriptLock; -:local InstalledVersion [ /system/package/update/get installed-version ]; + $ScriptLock $ScriptName; -: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; + :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 $ScriptName ("Starting upgrade for " . $RemoteCapVal->"name" . \ + " (" . $RemoteCapVal->"identity" . ")...") false; + /interface/wifiwave2/capsman/remote-cap/upgrade $RemoteCap; + } else={ + $LogPrintExit2 warning $ScriptName ("Remote CAP vanished, skipping upgrade.") false; + } + :delay ($Delay . "s"); } - :delay ($Delay . "s"); } } + +$Main [ :jobname ]; From 2d112c0b3313f1a1d1e830035602d94c81cbc20c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1901/2612] certificate-renew-issued: move code into function --- certificate-renew-issued.rsc | 51 ++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc index c6a819a..79ed0ba 100644 --- a/certificate-renew-issued.rsc +++ b/certificate-renew-issued.rsc @@ -8,36 +8,41 @@ # renew locally issued certificates # https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global CertIssuedExportPass; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global LogPrintExit2; -:global MkDir; -:global ScriptLock; + :global CertIssuedExportPass; -$ScriptLock $0; + :global LogPrintExit2; + :global MkDir; + :global ScriptLock; -:foreach Cert in=[ /certificate/find where issued expires-after<3w ] do={ - :local CertVal [ /certificate/get $Cert ]; - /certificate/issued-revoke $Cert; - /certificate/set name=($CertVal->"name" . "-revoked-" . [ /system/clock/get date ]) $Cert; - /certificate/add name=($CertVal->"name") common-name=($CertVal->"common-name") \ - key-usage=($CertVal->"key-usage") subject-alt-name=($CertVal->"subject-alt-name"); - /certificate/sign ($CertVal->"name") ca=($CertVal->"ca"); - :if ([ :typeof ($CertIssuedExportPass->($CertVal->"common-name")) ] = "str") do={ - :if ([ $MkDir "cert-issued" ] = true) do={ - /certificate/export-certificate ($CertVal->"name") type=pkcs12 \ - file-name=("cert-issued/" . $CertVal->"common-name") \ - export-passphrase=($CertIssuedExportPass->($CertVal->"common-name")); - $LogPrintExit2 info $0 ("Issued a new certificate for \"" . $CertVal->"common-name" . \ - "\", exported to \"cert-issued/" . $CertVal->"common-name" . ".p12\".") false; + $ScriptLock $ScriptName; + + :foreach Cert in=[ /certificate/find where issued expires-after<3w ] do={ + :local CertVal [ /certificate/get $Cert ]; + /certificate/issued-revoke $Cert; + /certificate/set name=($CertVal->"name" . "-revoked-" . [ /system/clock/get date ]) $Cert; + /certificate/add name=($CertVal->"name") common-name=($CertVal->"common-name") \ + key-usage=($CertVal->"key-usage") subject-alt-name=($CertVal->"subject-alt-name"); + /certificate/sign ($CertVal->"name") ca=($CertVal->"ca"); + :if ([ :typeof ($CertIssuedExportPass->($CertVal->"common-name")) ] = "str") do={ + :if ([ $MkDir "cert-issued" ] = true) do={ + /certificate/export-certificate ($CertVal->"name") type=pkcs12 \ + file-name=("cert-issued/" . $CertVal->"common-name") \ + export-passphrase=($CertIssuedExportPass->($CertVal->"common-name")); + $LogPrintExit2 info $ScriptName ("Issued a new certificate for \"" . $CertVal->"common-name" . \ + "\", exported to \"cert-issued/" . $CertVal->"common-name" . ".p12\".") false; + } else={ + $LogPrintExit2 warning $ScriptName ("Failed creating directory, not exporting certificate.") false; + } } else={ - $LogPrintExit2 warning $0 ("Failed creating directory, not exporting certificate.") false; + $LogPrintExit2 info $ScriptName ("Issued a new certificate for \"" . $CertVal->"common-name" . "\".") false; } - } else={ - $LogPrintExit2 info $0 ("Issued a new certificate for \"" . $CertVal->"common-name" . "\".") false; } } + +$Main [ :jobname ]; From fc3fad5e87884d73f00fa6900f16280969c3c18d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1902/2612] check-certificates: move code into function --- check-certificates.rsc | 347 +++++++++++++++++++++-------------------- 1 file changed, 176 insertions(+), 171 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 1487a3e..f15f145 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -8,202 +8,207 @@ # check for certificate validity # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global CertRenewTime; -:global CertRenewUrl; -: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 ]; +:local Main do={ + :local ScriptName [ :tostr $1 ]; + :global CertRenewTime; :global CertRenewUrl; - :global CertRenewPass; + :global CertWarnTime; + :global Identity; - :global CertificateNameByCN; + :global CertificateAvailable :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 LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; + :global UrlEncode; + :global WaitFullyConnected; - :local FormatExpire do={ - :global CharacterReplace; - :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; + :local CheckCertificatesDownloadImport do={ + :local Name [ :tostr $1 ]; + + :global CertRenewUrl; + :global CertRenewPass; + + :global CertificateNameByCN; + :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 FormatCertChain do={ + :local FormatInfo do={ :local Cert $1; - :global EitherOr; - :global ParseKeyValueStore; + :global FormatLine; + :global FormatMultiLines; + :global IfThenElse; + + :local FormatExpire do={ + :global CharacterReplace; + :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; + } + + :local FormatCertChain do={ + :local Cert $1; + + :global EitherOr; + :global ParseKeyValueStore; + + :local CertVal [ /certificate/get $Cert ]; + :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 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 . "..."); + :return ( \ + [ $FormatLine "Name" ($CertVal->"name") ] . "\n" . \ + [ $IfThenElse ([ :len ($CertVal->"common-name") ] > 0) ([ $FormatLine "CommonName" ($CertVal->"common-name") ] . "\n") ] . \ + [ $IfThenElse ([ :len ($CertVal->"subject-alt-name") ] > 0) ([ $FormatMultiLines "SubjectAltNames" ($CertVal->"subject-alt-name") ] . "\n") ] . \ + [ $FormatLine "Private key" [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] ] . "\n" . \ + [ $FormatLine "Fingerprint" ($CertVal->"fingerprint") ] . "\n" . \ + [ $IfThenElse ([ :len ($CertVal->"ca") ] > 0) [ $FormatLine "Issuer" ($CertVal->"ca") ] [ $FormatLine "Issuer chain" [ $FormatCertChain $Cert ] ] ] . "\n" . \ + "Validity:\n" . \ + [ $FormatLine " from" ($CertVal->"invalid-before") ] . "\n" . \ + [ $FormatLine " to" ($CertVal->"invalid-after") ] . "\n" . \ + [ $FormatLine "Expires in" [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ] ]); } - :local CertVal [ /certificate/get $Cert ]; + $ScriptLock $ScriptName; + $WaitFullyConnected; - :return ( \ - [ $FormatLine "Name" ($CertVal->"name") ] . "\n" . \ - [ $IfThenElse ([ :len ($CertVal->"common-name") ] > 0) ([ $FormatLine "CommonName" ($CertVal->"common-name") ] . "\n") ] . \ - [ $IfThenElse ([ :len ($CertVal->"subject-alt-name") ] > 0) ([ $FormatMultiLines "SubjectAltNames" ($CertVal->"subject-alt-name") ] . "\n") ] . \ - [ $FormatLine "Private key" [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] ] . "\n" . \ - [ $FormatLine "Fingerprint" ($CertVal->"fingerprint") ] . "\n" . \ - [ $IfThenElse ([ :len ($CertVal->"ca") ] > 0) [ $FormatLine "Issuer" ($CertVal->"ca") ] [ $FormatLine "Issuer chain" [ $FormatCertChain $Cert ] ] ] . "\n" . \ - "Validity:\n" . \ - [ $FormatLine " from" ($CertVal->"invalid-before") ] . "\n" . \ - [ $FormatLine " to" ($CertVal->"invalid-after") ] . "\n" . \ - [ $FormatLine "Expires in" [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ] ]); -} + :foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ + :local CertVal [ /certificate/get $Cert ]; + :local CertNew; + :local LastName; -$ScriptLock $0; -$WaitFullyConnected; - -:foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ - :local CertVal [ /certificate/get $Cert ]; - :local CertNew; - :local LastName; - - :do { - :if ([ :len $CertRenewUrl ] = 0) do={ - $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 ]; + :do { + :if ([ :len $CertRenewUrl ] = 0) do={ + $LogPrintExit2 info $ScriptName ("No CertRenewUrl given.") true; } - } + $LogPrintExit2 info $ScriptName ("Attempting to renew certificate '" . ($CertVal->"name") . "'.") false; - :if ([ :len ($CertVal->"fingerprint") ] > 0 && $CertVal->"fingerprint" != [ /certificate/get $Cert fingerprint ]) do={ - $LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was updated in place.") false; - :set CertVal [ /certificate/get $Cert ]; + :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 ]; + } + } + + :if ([ :len ($CertVal->"fingerprint") ] > 0 && $CertVal->"fingerprint" != [ /certificate/get $Cert fingerprint ]) do={ + $LogPrintExit2 debug $ScriptName ("Certificate '" . $CertVal->"name" . "' was updated in place.") false; + :set CertVal [ /certificate/get $Cert ]; + } else={ + $LogPrintExit2 debug $ScriptName ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; + + :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={ + $LogPrintExit2 warning $ScriptName ("The certificate chain is not available!") false; + } + + :if (($CertVal->"private-key") = true && ($CertVal->"private-key") != ($CertNewVal->"private-key")) do={ + /certificate/remove $CertNew; + $LogPrintExit2 warning $ScriptName ("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=$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 ]) }); + $LogPrintExit2 info $ScriptName ("The certificate '" . ($CertVal->"name") . "' has been renewed.") false; + } on-error={ + $LogPrintExit2 debug $ScriptName ("Could not renew certificate '" . ($CertVal->"name") . "'.") false; + } + } + + :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 $ScriptName ("Certificate '" . ($CertVal->"name") . "' is handled by SCEP, skipping.") false; } 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]+\$") \ - (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={ - $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=$ScriptName; \ + subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning: " . ($CertVal->"name")); \ + message=("A certificate on " . $Identity . " " . $State . ".\n\n" . [ $FormatInfo $Cert ]) }); + $LogPrintExit2 info $ScriptName ("The certificate '" . ($CertVal->"name") . "' " . $State . \ + ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; } - - $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; } } -: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; - } -} +$Main [ :jobname ]; From 80180b432d2dcd0cad6595c5757926bb6ec7305c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1903/2612] check-health: move code into function --- check-health.rsc | 289 ++++++++++++++++++++++++----------------------- 1 file changed, 147 insertions(+), 142 deletions(-) diff --git a/check-health.rsc b/check-health.rsc index 5c28d73..b819665 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -8,165 +8,170 @@ # check for RouterOS health state # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global CheckHealthCPUUtilization; -:global CheckHealthCPUUtilizationNotified; -:global CheckHealthLast; -:global CheckHealthRAMUtilizationNotified; -:global CheckHealthTemperature; -:global CheckHealthTemperatureDeviation; -:global CheckHealthTemperatureNotified; -:global CheckHealthVoltageLow; -:global CheckHealthVoltagePercent; -:global Identity; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global FormatLine; -:global HumanReadableNum; -:global IfThenElse; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; + :global CheckHealthCPUUtilization; + :global CheckHealthCPUUtilizationNotified; + :global CheckHealthLast; + :global CheckHealthRAMUtilizationNotified; + :global CheckHealthTemperature; + :global CheckHealthTemperatureDeviation; + :global CheckHealthTemperatureNotified; + :global CheckHealthVoltageLow; + :global CheckHealthVoltagePercent; + :global Identity; -:local TempToNum do={ - :global CharacterReplace; - :local T [ :toarray [ $CharacterReplace $1 "." "," ] ]; - :return ($T->0 * 10 + $T->1); -} + :global FormatLine; + :global HumanReadableNum; + :global IfThenElse; + :global LogPrintExit2; + :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 ]; + $ScriptLock $ScriptName; -:set CheckHealthCPUUtilization (($CheckHealthCPUUtilization * 4 + ($Resource->"cpu-load") * 10) / 5); -: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 Resource [ /system/resource/get ]; -:local CheckHealthRAMUtilization (($Resource->"total-memory" - $Resource->"free-memory") * 100 / $Resource->"total-memory"); -:if ($CheckHealthRAMUtilization >=80 && $CheckHealthRAMUtilizationNotified != true) do={ - $SendNotification2 ({ origin=$0; \ - 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=$0; \ - subject=([ $SymbolForNotification "card-file-box,chart-decreasing" ] . "Health recovery: RAM utilization"); \ - message=("The RAM utilization on " . $Identity . " decreased to " . $CheckHealthRAMUtilization . "%.") }); - :set CheckHealthRAMUtilizationNotified false; -} + :set CheckHealthCPUUtilization (($CheckHealthCPUUtilization * 4 + ($Resource->"cpu-load") * 10) / 5); + :if ($CheckHealthCPUUtilization > 750 && $CheckHealthCPUUtilizationNotified != true) do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "abacus,chart-increasing" ] . "Health warning: CPU utilization"); \ + message=("The average CPU utilization on " . $Identity . " is at " . ($CheckHealthCPUUtilization / 10) . "%!") }); + :set CheckHealthCPUUtilizationNotified true; + } + :if ($CheckHealthCPUUtilization < 650 && $CheckHealthCPUUtilizationNotified = true) do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "abacus,chart-decreasing" ] . "Health recovery: CPU utilization"); \ + message=("The average CPU utilization on " . $Identity . " decreased to " . ($CheckHealthCPUUtilization / 10) . "%.") }); + :set CheckHealthCPUUtilizationNotified false; + } -:if ([ :len [ /system/health/find ] ] = 0) do={ - $LogPrintExit2 debug $0 ("Your device does not provide any health values.") true; -} + :local CheckHealthRAMUtilization (($Resource->"total-memory" - $Resource->"free-memory") * 100 / $Resource->"total-memory"); + :if ($CheckHealthRAMUtilization >=80 && $CheckHealthRAMUtilizationNotified != true) do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "card-file-box,chart-increasing" ] . "Health warning: RAM utilization"); \ + message=("The RAM utilization on " . $Identity . " is at " . $CheckHealthRAMUtilization . "%!\n\n" . \ + [ $FormatLine "total" ([ $HumanReadableNum ($Resource->"total-memory") 1024 ] . "iB") 8 ] . "\n" . \ + [ $FormatLine "used" ([ $HumanReadableNum ($Resource->"total-memory" - $Resource->"free-memory") 1024 ] . "iB") 8 ] . "\n" . \ + [ $FormatLine "free" ([ $HumanReadableNum ($Resource->"free-memory") 1024 ] . "iB") 8 ]) }); + :set CheckHealthRAMUtilizationNotified true; + } + :if ($CheckHealthRAMUtilization < 70 && $CheckHealthRAMUtilizationNotified = true) do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "card-file-box,chart-decreasing" ] . "Health recovery: RAM utilization"); \ + message=("The RAM utilization on " . $Identity . " decreased to " . $CheckHealthRAMUtilization . "%.") }); + :set CheckHealthRAMUtilizationNotified false; + } -:if ([ :typeof $CheckHealthLast ] != "array") do={ - :set CheckHealthLast ({}); -} -:if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ - :set CheckHealthTemperatureNotified ({}); -} + :if ([ :len [ /system/health/find ] ] = 0) do={ + $LogPrintExit2 debug $ScriptName ("Your device does not provide any health values.") true; + } + + :if ([ :typeof $CheckHealthLast ] != "array") do={ + :set CheckHealthLast ({}); + } + :if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ + :set CheckHealthTemperatureNotified ({}); + } -:foreach Voltage in=[ /system/health/find where type="V" ] do={ - :local Name [ /system/health/get $Voltage name ]; - :local Value [ /system/health/get $Voltage value ]; + :foreach Voltage in=[ /system/health/find where type="V" ] do={ + :local Name [ /system/health/get $Voltage name ]; + :local Value [ /system/health/get $Voltage value ]; - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :local NumCurr [ $TempToNum $Value ]; - :local NumLast [ $TempToNum ($CheckHealthLast->$Name) ]; + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ + :local NumCurr [ $TempToNum $Value ]; + :local NumLast [ $TempToNum ($CheckHealthLast->$Name) ]; - :if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \ - $NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \ - $NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ - [ $FormatLine "old value" ($CheckHealthLast->$Name . " V") 12 ] . "\n" . \ - [ $FormatLine "new value" ($Value . " V") 12 ]) }); - } else={ - :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \ - message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") }); - } - :if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ - message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") }); + :if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \ + $NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \ + $NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ + message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ + [ $FormatLine "old value" ($CheckHealthLast->$Name . " V") 12 ] . "\n" . \ + [ $FormatLine "new value" ($Value . " V") 12 ]) }); + } else={ + :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \ + message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") }); + } + :if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ + message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") }); + } } } + :set ($CheckHealthLast->$Name) $Value; + } + + :foreach PSU in=[ /system/health/find where name~"^psu.*-state\$" ] do={ + :local Name [ /system/health/get $PSU name ]; + :local Value [ /system/health/get $PSU value ]; + + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ + :if ($CheckHealthLast->$Name = "ok" && \ + $Value != "ok") do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ + message=("The power supply unit '" . $Name . "' on " . $Identity . " failed!") }); + } + :if ($CheckHealthLast->$Name != "ok" && \ + $Value = "ok") do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ + message=("The power supply unit '" . $Name . "' on " . $Identity . " recovered!") }); + } + } + :set ($CheckHealthLast->$Name) $Value; + } + + :foreach Temperature in=[ /system/health/find where type="C" ] do={ + :local Name [ /system/health/get $Temperature name ]; + :local Value [ /system/health/get $Temperature value ]; + + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ + :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ + $LogPrintExit2 info $ScriptName ("No threshold given for " . $Name . ", assuming 50C.") false; + :set ($CheckHealthTemperature->$Name) 50; + } + :local Validate [ /system/health/get [ find where name=$Name ] value ]; + :while ($Value != $Validate) do={ + :set Value $Validate; + :set Validate [ /system/health/get [ find where name=$Name ] value ]; + } + :if ($Value > $CheckHealthTemperature->$Name && \ + $CheckHealthTemperatureNotified->$Name != true) do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ + message=("The " . $Name . " on " . $Identity . " is above threshold: " . \ + $Value . "\C2\B0" . "C") }); + :set ($CheckHealthTemperatureNotified->$Name) true; + } + :if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ + $CheckHealthTemperatureNotified->$Name = true) do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ + message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ + $Value . "\C2\B0" . "C") }); + :set ($CheckHealthTemperatureNotified->$Name) false; + } + } + :set ($CheckHealthLast->$Name) $Value; } - :set ($CheckHealthLast->$Name) $Value; } -:foreach PSU in=[ /system/health/find where name~"^psu.*-state\$" ] do={ - :local Name [ /system/health/get $PSU name ]; - :local Value [ /system/health/get $PSU value ]; - - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :if ($CheckHealthLast->$Name = "ok" && \ - $Value != "ok") do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ - message=("The power supply unit '" . $Name . "' on " . $Identity . " failed!") }); - } - :if ($CheckHealthLast->$Name != "ok" && \ - $Value = "ok") do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ - message=("The power supply unit '" . $Name . "' on " . $Identity . " recovered!") }); - } - } - :set ($CheckHealthLast->$Name) $Value; -} - -:foreach Temperature in=[ /system/health/find where type="C" ] do={ - :local Name [ /system/health/get $Temperature name ]; - :local Value [ /system/health/get $Temperature value ]; - - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ - $LogPrintExit2 info $0 ("No threshold given for " . $Name . ", assuming 50C.") false; - :set ($CheckHealthTemperature->$Name) 50; - } - :local Validate [ /system/health/get [ find where name=$Name ] value ]; - :while ($Value != $Validate) do={ - :set Value $Validate; - :set Validate [ /system/health/get [ find where name=$Name ] value ]; - } - :if ($Value > $CheckHealthTemperature->$Name && \ - $CheckHealthTemperatureNotified->$Name != true) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " is above threshold: " . \ - $Value . "\C2\B0" . "C") }); - :set ($CheckHealthTemperatureNotified->$Name) true; - } - :if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ - $CheckHealthTemperatureNotified->$Name = true) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ - $Value . "\C2\B0" . "C") }); - :set ($CheckHealthTemperatureNotified->$Name) false; - } - } - :set ($CheckHealthLast->$Name) $Value; -} +$Main [ :jobname ]; From 450ea2fa48583868ccaafe51afeaafbdd2c90df5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1904/2612] check-lte-firmware-upgrade: move code into function --- check-lte-firmware-upgrade.rsc | 143 +++++++++++++++++---------------- 1 file changed, 74 insertions(+), 69 deletions(-) diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index 40a8568..12d2dd4 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -8,91 +8,96 @@ # check for LTE firmware upgrade, send notification # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global SentLteFirmwareUpgradeNotification; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -: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 FormatLine; - :global IfThenElse; - :global LogPrintExit2; - :global ScriptFromTerminal; - :global SendNotification2; - :global SymbolForNotification; + :global ScriptLock; - :local IntName [ /interface/lte/get $Interface name ]; - :local Firmware; - :local Info; - :do { - :set Firmware [ /interface/lte/firmware-upgrade $Interface once as-value ]; - :set Info [ /interface/lte/monitor $Interface once as-value ]; - } on-error={ - $LogPrintExit2 debug $0 ("Could not get latest LTE firmware version for interface " . \ - $IntName . ".") false; - :return false; + $ScriptLock $ScriptName; + + :if ([ :typeof $SentLteFirmwareUpgradeNotification ] != "array") do={ + :global SentLteFirmwareUpgradeNotification ({}); } - :if ([ :len ($Firmware->"latest") ] = 0) do={ - $LogPrintExit2 info $0 ("An empty string is not a valid version.") false; - :return false; - } + :local CheckInterface do={ + :local ScriptName $1; + :local Interface $2; - :if (($Firmware->"installed") = ($Firmware->"latest")) do={ - :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ - $LogPrintExit2 info $0 ("No firmware upgrade available for LTE interface " . $IntName . ".") false; + :global Identity; + :global SentLteFirmwareUpgradeNotification; + + :global FormatLine; + :global IfThenElse; + :global LogPrintExit2; + :global ScriptFromTerminal; + :global SendNotification2; + :global SymbolForNotification; + + :local IntName [ /interface/lte/get $Interface name ]; + :local Firmware; + :local Info; + :do { + :set Firmware [ /interface/lte/firmware-upgrade $Interface once as-value ]; + :set Info [ /interface/lte/monitor $Interface once as-value ]; + } on-error={ + $LogPrintExit2 debug $ScriptName ("Could not get latest LTE firmware version for interface " . \ + $IntName . ".") false; + :return false; } - :return true; - } - :if ([ $ScriptFromTerminal $ScriptName ] = true && \ - [ :len [ /system/script/find where name="unattended-lte-firmware-upgrade" ] ] > 0) do={ - :put ("Do you want to start unattended lte firmware upgrade for interface " . $IntName . "? [y/N]"); - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - /system/script/run unattended-lte-firmware-upgrade; - $LogPrintExit2 info $0 ("Scheduled lte firmware upgrade for interface " . $IntName . "...") false; + :if ([ :len ($Firmware->"latest") ] = 0) do={ + $LogPrintExit2 info $ScriptName ("An empty string is not a valid version.") false; + :return false; + } + + :if (($Firmware->"installed") = ($Firmware->"latest")) do={ + :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ + $LogPrintExit2 info $ScriptName ("No firmware upgrade available for LTE interface " . $IntName . ".") false; + } :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; + $LogPrintExit2 info $ScriptName ("Scheduled lte firmware upgrade for interface " . $IntName . "...") false; + :return true; + } else={ + :put "Canceled..."; + } + } + + :if (($SentLteFirmwareUpgradeNotification->$IntName) = ($Firmware->"latest")) do={ + $LogPrintExit2 debug $ScriptName ("Already sent the LTE firmware upgrade notification for version " . \ + ($Firmware->"latest") . ".") false; + :return false; + } + + $LogPrintExit2 info $ScriptName ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ + "LTE interface " . $IntName . ".") false; + $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={ - $LogPrintExit2 debug $0 ("Already sent the LTE firmware upgrade notification for version " . \ - ($Firmware->"latest") . ".") false; - :return false; + :foreach Interface in=[ /interface/lte/find ] do={ + $CheckInterface $ScriptName $Interface; } - - $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; -} +$Main [ :jobname ]; From 22eb74cb3a4238ab0eebda8ae013721f7da129dd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1905/2612] check-routeros-update: move code into function --- check-routeros-update.rsc | 246 +++++++++++++++++++------------------- 1 file changed, 125 insertions(+), 121 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 204a0d3..519c2d4 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -8,149 +8,153 @@ # check for RouterOS update, send notification and/or install # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Identity; -:global SafeUpdateAll; -:global SafeUpdateNeighbor; -:global SafeUpdateNeighborIdentity; -:global SafeUpdatePatch; -:global SafeUpdateUrl; -:global SentRouterosUpdateNotification; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global DeviceInfo; -:global EscapeForRegEx; -:global LogPrintExit2; -:global ScriptFromTerminal; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; -:global VersionToNum; -:global WaitFullyConnected; + :global Identity; + :global SafeUpdateAll; + :global SafeUpdateNeighbor; + :global SafeUpdateNeighborIdentity; + :global SafeUpdatePatch; + :global SafeUpdateUrl; + :global SentRouterosUpdateNotification; -:local DoUpdate do={ - :if ([ :len [ /system/script/find where name="packages-update" ] ] > 0) do={ - /system/script/run packages-update; - } else={ - /system/package/update/install without-paging; - } - :error "Waiting for system to reboot."; -} + :global DeviceInfo; + :global EscapeForRegEx; + :global LogPrintExit2; + :global ScriptFromTerminal; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; + :global VersionToNum; + :global WaitFullyConnected; -$ScriptLock $0; - -$WaitFullyConnected; - -:if ([ :len [ /system/scheduler/find where name="_RebootForUpdate" ] ] > 0) do={ - :error "A reboot for update is already scheduled."; -} - -$LogPrintExit2 debug $0 ("Checking for updates...") false; -/system/package/update/check-for-updates without-paging as-value; -:local Update [ /system/package/update/get ]; - -:if ([ $ScriptFromTerminal $0 ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={ - $LogPrintExit2 info $0 ("System is already up to date.") true; -} - -:local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; -:local NumLatest [ $VersionToNum ($Update->"latest-version") ]; -:local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); - -:if ($NumLatest < 117505792) do={ - $LogPrintExit2 info $0 ("The version '" . ($Update->"latest-version") . "' is not a valid version.") true; -} - -:if ($NumInstalled < $NumLatest) do={ - :if ($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; + :local DoUpdate do={ + :if ([ :len [ /system/script/find where name="packages-update" ] ] > 0) do={ + /system/script/run packages-update; + } else={ + /system/package/update/install without-paging; + } + :error "Waiting for system to reboot."; } - :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ - $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ - message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ - ", updating on " . $Identity . "..."); link=$Link; silent=true }); - $DoUpdate; + $ScriptLock $ScriptName; + $WaitFullyConnected; + + :if ([ :len [ /system/scheduler/find where name="_RebootForUpdate" ] ] > 0) do={ + :error "A reboot for update is already scheduled."; } - :if ($SafeUpdateNeighbor = true) do={ - :local Neighbors [ /ip/neighbor/find where platform="MikroTik" identity~$SafeUpdateNeighborIdentity \ - version~("^" . [ $EscapeForRegEx ($Update->"latest-version") ] . "\\b") ]; - :if ([ :len $Neighbors ] > 0) do={ - :local Neighbor [ /ip/neighbor/get ($Neighbors->0) identity ]; - $LogPrintExit2 info $0 ("Seen a neighbor (" . $Neighbor . ") running version " . \ - $Update->"latest-version" . " from " . $Update->"channel" . ", updating...") false; - $SendNotification2 ({ origin=$0; \ + $LogPrintExit2 debug $ScriptName ("Checking for updates...") false; + /system/package/update/check-for-updates without-paging as-value; + :local Update [ /system/package/update/get ]; + + :if ([ $ScriptFromTerminal $ScriptName ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={ + $LogPrintExit2 info $ScriptName ("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 $ScriptName ("The version '" . ($Update->"latest-version") . "' is not a valid version.") true; + } + + :if ($NumInstalled < $NumLatest) do={ + :if ($SafeUpdateAll ~ "^YES,? ?PLEASE!?\$") do={ + $LogPrintExit2 info $ScriptName ("Installing ALL versions automatically, including " . \ + $Update->"latest-version" . "...") false; + $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 }); + message=("Installing ALL versions automatically, including " . $Update->"latest-version" . \ + "... Updating on " . $Identity . "..."); link=$Link; silent=true }); $DoUpdate; } - } - :if ([ :len $SafeUpdateUrl ] > 0) do={ - :local Result; - :do { - :set Result [ /tool/fetch check-certificate=yes-without-crl \ - ($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \ - "&latest=" . $Update->"latest-version") output=user as-value ]; - } on-error={ - $LogPrintExit2 warning $0 ("Failed receiving safe version for " . $Update->"channel" . ".") false; - } - :if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={ - $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; - $SendNotification2 ({ origin=$0; \ + :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ + $LogPrintExit2 info $ScriptName ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; + $SendNotification2 ({ origin=$ScriptName; \ 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 }); $DoUpdate; } - } - :if ([ $ScriptFromTerminal $0 ] = true) do={ - :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - $DoUpdate; - } else={ - :put "Canceled..."; + :if ($SafeUpdateNeighbor = true) do={ + :local Neighbors [ /ip/neighbor/find where platform="MikroTik" identity~$SafeUpdateNeighborIdentity \ + version~("^" . [ $EscapeForRegEx ($Update->"latest-version") ] . "\\b") ]; + :if ([ :len $Neighbors ] > 0) do={ + :local Neighbor [ /ip/neighbor/get ($Neighbors->0) identity ]; + $LogPrintExit2 info $ScriptName ("Seen a neighbor (" . $Neighbor . ") running version " . \ + $Update->"latest-version" . " from " . $Update->"channel" . ", updating...") false; + $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={ + $LogPrintExit2 warning $ScriptName ("Failed receiving safe version for " . $Update->"channel" . ".") false; + } + :if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={ + $LogPrintExit2 info $ScriptName ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; + $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={ + $LogPrintExit2 info $ScriptName ("Already sent the RouterOS update notification for version " . \ + $Update->"latest-version" . ".") 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={ - $LogPrintExit2 info $0 ("Already sent the RouterOS update notification for version " . \ - $Update->"latest-version" . ".") true; - } + :if ($NumInstalled > $NumLatest) do={ + :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ + $LogPrintExit2 info $ScriptName ("Already sent the RouterOS downgrade notification for version " . \ + $Update->"latest-version" . ".") true; + } - $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"); + $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 }); + $LogPrintExit2 info $ScriptName ("A different RouterOS version " . ($Update->"latest-version") . \ + " is available for downgrade.") false; + :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"); -} +$Main [ :jobname ]; From e2b87c8634e12fe1fae22d15f2ca2e6ae365c789 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1906/2612] collect-wireless-mac: move code into function --- collect-wireless-mac.capsman.rsc | 127 +++++++++++---------- collect-wireless-mac.local.rsc | 129 +++++++++++---------- collect-wireless-mac.template.rsc | 177 +++++++++++++++-------------- collect-wireless-mac.wifi.rsc | 127 +++++++++++---------- collect-wireless-mac.wifiwave2.rsc | 127 +++++++++++---------- 5 files changed, 356 insertions(+), 331 deletions(-) diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index 937d8ce..0ae15ee 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -11,81 +11,86 @@ # # !! Do not edit this file, it is generated from template! -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Identity; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global EitherOr; -:global FormatLine; -:global FormatMultiLines; -:global GetMacVendor; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; + :global Identity; -$ScriptLock $0 false 10; + :global EitherOr; + :global FormatLine; + :global FormatMultiLines; + :global GetMacVendor; + :global LogPrintExit2; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; -:if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - /caps-man/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false; -} -:local PlaceBefore ([ /caps-man/access-list/find where comment="--- collected above ---" disabled ]->0); + $ScriptLock $ScriptName false 10; -: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 [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ + /caps-man/access-list/add comment="--- collected above ---" disabled=yes; + $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'.") false; } + :local PlaceBefore ([ /caps-man/access-list/find where comment="--- collected above ---" disabled ]->0); - :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /caps-man/access-list/get $AccessList comment ]) false; + :foreach Reg in=[ /caps-man/registration-table/find ] do={ + :local RegVal; + :do { + :set RegVal [ /caps-man/registration-table/get $Reg ]; + } on-error={ + $LogPrintExit2 debug $ScriptName ("Device already gone... Ignoring.") 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 ]); + :if ([ :len ($RegVal->"mac-address") ] > 0) do={ + :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + $LogPrintExit2 debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ + [ /caps-man/access-list/get $AccessList comment ]) false; + } + + :if ([ :len $AccessList ] = 0) do={ + :local Address "no dhcp lease"; + :local DnsName "no dhcp lease"; + :local HostName "no dhcp lease"; + :local Lease ([ /ip/dhcp-server/lease/find where 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 $ScriptName $Message false; + /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 ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrintExit2 info $0 $Message false; - /caps-man/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - [ $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 $ScriptName ("No mac address available... Ignoring.") false; } - } else={ - $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; } } + +$Main [ :jobname ]; diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index 17f969b..0353ddb 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -11,82 +11,87 @@ # # !! Do not edit this file, it is generated from template! -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Identity; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global EitherOr; -:global FormatLine; -:global FormatMultiLines; -:global GetMacVendor; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; + :global Identity; -$ScriptLock $0 false 10; + :global EitherOr; + :global FormatLine; + :global FormatMultiLines; + :global GetMacVendor; + :global LogPrintExit2; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; -:if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - /interface/wireless/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false; -} -:local PlaceBefore ([ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ]->0); + $ScriptLock $ScriptName false 10; -: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 [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ + /interface/wireless/access-list/add comment="--- collected above ---" disabled=yes; + $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'.") false; } + :local PlaceBefore ([ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ]->0); - :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /interface/wireless/access-list/get $AccessList comment ]) false; + :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 $ScriptName ("Device already gone... Ignoring.") 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 ]); + :if ([ :len ($RegVal->"mac-address") ] > 0) do={ + :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + $LogPrintExit2 debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ + [ /interface/wireless/access-list/get $AccessList comment ]) false; + } + + :if ([ :len $AccessList ] = 0) do={ + :local Address "no dhcp lease"; + :local DnsName "no dhcp lease"; + :local HostName "no dhcp lease"; + :local Lease ([ /ip/dhcp-server/lease/find where 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"); + $LogPrintExit2 info $ScriptName $Message false; + /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 ]; - :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrintExit2 info $0 $Message false; - /interface/wireless/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - [ $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 $ScriptName ("No mac address available... Ignoring.") false; } - } else={ - $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; } } + +$Main [ :jobname ]; diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index c5420f1..71f5679 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -12,106 +12,111 @@ # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Identity; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global EitherOr; -:global FormatLine; -:global FormatMultiLines; -:global GetMacVendor; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; + :global Identity; -$ScriptLock $0 false 10; + :global EitherOr; + :global FormatLine; + :global FormatMultiLines; + :global GetMacVendor; + :global LogPrintExit2; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; -:if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ -:if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ -:if ([ :len [ /interface/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); + $ScriptLock $ScriptName false 10; -: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 [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ + :if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ + :if ([ :len [ /interface/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 $ScriptName ("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); - :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :local AccessList ([ /interface/wifi/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :local AccessList ([ /interface/wifiwave2/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /caps-man/access-list/get $AccessList comment ]) false; - [ /interface/wifi/access-list/get $AccessList comment ]) false; - [ /interface/wifiwave2/access-list/get $AccessList comment ]) false; - [ /interface/wireless/access-list/get $AccessList comment ]) false; + :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 $ScriptName ("Device already gone... Ignoring.") 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 ]); + :if ([ :len ($RegVal->"mac-address") ] > 0) do={ + :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); + :local AccessList ([ /interface/wifi/access-list/find where mac-address=($RegVal->"mac-address") ]->0); + :local AccessList ([ /interface/wifiwave2/access-list/find where mac-address=($RegVal->"mac-address") ]->0); + :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + $LogPrintExit2 debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ + [ /caps-man/access-list/get $AccessList comment ]) false; + [ /interface/wifi/access-list/get $AccessList comment ]) false; + [ /interface/wifiwave2/access-list/get $AccessList comment ]) false; + [ /interface/wireless/access-list/get $AccessList comment ]) false; + } + + :if ([ :len $AccessList ] = 0) do={ + :local Address "no dhcp lease"; + :local DnsName "no dhcp lease"; + :local HostName "no dhcp lease"; + :local Lease ([ /ip/dhcp-server/lease/find where 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"); + $LogPrintExit2 info $ScriptName $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=$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 ]; - :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrintExit2 info $0 $Message false; - /caps-man/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - /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 $ScriptName ("No mac address available... Ignoring.") false; } - } else={ - $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; } } + +$Main [ :jobname ]; diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc index 7bc442a..f35cdad 100644 --- a/collect-wireless-mac.wifi.rsc +++ b/collect-wireless-mac.wifi.rsc @@ -11,81 +11,86 @@ # # !! Do not edit this file, it is generated from template! -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Identity; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global EitherOr; -:global FormatLine; -:global FormatMultiLines; -:global GetMacVendor; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; + :global Identity; -$ScriptLock $0 false 10; + :global EitherOr; + :global FormatLine; + :global FormatMultiLines; + :global GetMacVendor; + :global LogPrintExit2; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; -:if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - /interface/wifi/access-list/add comment="--- collected above ---" disabled=yes; - $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); + $ScriptLock $ScriptName false 10; -: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 [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ + /interface/wifi/access-list/add comment="--- collected above ---" disabled=yes; + $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'.") false; } + :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ]->0); - :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ /interface/wifi/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /interface/wifi/access-list/get $AccessList comment ]) false; + :foreach Reg in=[ /interface/wifi/registration-table/find ] do={ + :local RegVal; + :do { + :set RegVal [ /interface/wifi/registration-table/get $Reg ]; + } on-error={ + $LogPrintExit2 debug $ScriptName ("Device already gone... Ignoring.") 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 ]); + :if ([ :len ($RegVal->"mac-address") ] > 0) do={ + :local AccessList ([ /interface/wifi/access-list/find where mac-address=($RegVal->"mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + $LogPrintExit2 debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ + [ /interface/wifi/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 $ScriptName $Message false; + /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 ]); - :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/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 $ScriptName ("No mac address available... Ignoring.") false; } - } else={ - $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; } } + +$Main [ :jobname ]; diff --git a/collect-wireless-mac.wifiwave2.rsc b/collect-wireless-mac.wifiwave2.rsc index d2b0e6b..86aef65 100644 --- a/collect-wireless-mac.wifiwave2.rsc +++ b/collect-wireless-mac.wifiwave2.rsc @@ -11,81 +11,86 @@ # # !! Do not edit this file, it is generated from template! -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Identity; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global EitherOr; -:global FormatLine; -:global FormatMultiLines; -:global GetMacVendor; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; + :global Identity; -$ScriptLock $0 false 10; + :global EitherOr; + :global FormatLine; + :global FormatMultiLines; + :global GetMacVendor; + :global LogPrintExit2; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; -: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); + $ScriptLock $ScriptName false 10; -: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 [ /interface/wifiwave2/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ + /interface/wifiwave2/access-list/add comment="--- collected above ---" disabled=yes; + $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'.") false; } + :local PlaceBefore ([ /interface/wifiwave2/access-list/find where comment="--- collected above ---" disabled ]->0); - :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; + :foreach Reg in=[ /interface/wifiwave2/registration-table/find ] do={ + :local RegVal; + :do { + :set RegVal [ /interface/wifiwave2/registration-table/get $Reg ]; + } on-error={ + $LogPrintExit2 debug $ScriptName ("Device already gone... Ignoring.") 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 ]); + :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 $ScriptName ("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 $ScriptName $Message false; + /interface/wifiwave2/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 ]); - :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 $ScriptName ("No mac address available... Ignoring.") false; } - } else={ - $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; } } + +$Main [ :jobname ]; From 31da6b8bd50e4e47713c4d603cb2ae6276ed1ff5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1907/2612] daily-psk: move code into function --- daily-psk.capsman.rsc | 115 +++++++++++++++-------------- daily-psk.local.rsc | 113 +++++++++++++++-------------- daily-psk.template.rsc | 157 +++++++++++++++++++++------------------- daily-psk.wifi.rsc | 115 +++++++++++++++-------------- daily-psk.wifiwave2.rsc | 115 +++++++++++++++-------------- 5 files changed, 320 insertions(+), 295 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index f576d1d..b47ae14 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -11,77 +11,82 @@ # # !! 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; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global FormatLine; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; -:global UrlEncode; -:global WaitForFile; -:global WaitFullyConnected; + :global DailyPskMatchComment; + :global DailyPskQrCodeUrl; + :global Identity; -$ScriptLock $0; -$WaitFullyConnected; + :global FormatLine; + :global LogPrintExit2; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; + :global UrlEncode; + :global WaitForFile; + :global WaitFullyConnected; -# return pseudo-random string for PSK -:local GeneratePSK do={ - :local Date [ :tostr $1 ]; + $ScriptLock $ScriptName; + $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); - :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)); + :set Date [ $ParseDate $Date ]; - :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ - ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); -} + :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)); -:local Seen ({}); -:local Date [ /system/clock/get date ]; -:local NewPsk [ $GeneratePSK $Date ]; + :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ + ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ + ($DailyPskSecrets->2->$WeekDay)); + } -:foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ - :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; - :local Configuration ([ /caps-man/configuration/find where ssid~$SsidRegExp ]->0); - :local Ssid [ /caps-man/configuration/get $Configuration ssid ]; - :local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ]; - :local Skip 0; + :local Seen ({}); + :local Date [ /system/clock/get date ]; + :local NewPsk [ $GeneratePSK $Date ]; - :if ($NewPsk != $OldPsk) do={ - $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; - /caps-man/access-list/set $AccList private-passphrase=$NewPsk; + :foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ + :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; + :local Configuration ([ /caps-man/configuration/find where ssid~$SsidRegExp ]->0); + :local Ssid [ /caps-man/configuration/get $Configuration ssid ]; + :local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ]; + :local Skip 0; - :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 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; + :if ($NewPsk != $OldPsk) do={ + $LogPrintExit2 info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + /caps-man/access-list/set $AccList private-passphrase=$NewPsk; + + :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ + :if ($Seen->$Ssid = 1) do={ + $LogPrintExit2 debug $ScriptName ("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=$ScriptName; \ + subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ + message=("This is the daily PSK on " . $Identity . ":\n\n" . \ + [ $FormatLine "SSID" $Ssid ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk ] . "\n" . \ + [ $FormatLine "Date" $Date ] . "\n\n" . \ + "A client device specific rule must not exist!"); link=$Link }); + :set ($Seen->$Ssid) 1; + } } } } } + +$Main [ :jobname ]; diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index da12038..72e20ef 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -11,76 +11,81 @@ # # !! 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; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global FormatLine; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; -:global UrlEncode; -:global WaitForFile; -:global WaitFullyConnected; + :global DailyPskMatchComment; + :global DailyPskQrCodeUrl; + :global Identity; -$ScriptLock $0; -$WaitFullyConnected; + :global FormatLine; + :global LogPrintExit2; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; + :global UrlEncode; + :global WaitForFile; + :global WaitFullyConnected; -# return pseudo-random string for PSK -:local GeneratePSK do={ - :local Date [ :tostr $1 ]; + $ScriptLock $ScriptName; + $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); - :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)); + :set Date [ $ParseDate $Date ]; - :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ - ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); -} + :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)); -:local Seen ({}); -:local Date [ /system/clock/get date ]; -:local NewPsk [ $GeneratePSK $Date ]; + :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ + ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ + ($DailyPskSecrets->2->$WeekDay)); + } -:foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ - :local IntName [ /interface/wireless/access-list/get $AccList interface ]; - :local Ssid [ /interface/wireless/get $IntName ssid ]; - :local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ]; - :local Skip 0; + :local Seen ({}); + :local Date [ /system/clock/get date ]; + :local NewPsk [ $GeneratePSK $Date ]; - :if ($NewPsk != $OldPsk) do={ - $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; - /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; + :foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ + :local IntName [ /interface/wireless/access-list/get $AccList interface ]; + :local Ssid [ /interface/wireless/get $IntName ssid ]; + :local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ]; + :local Skip 0; - :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) 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; + :if ($NewPsk != $OldPsk) do={ + $LogPrintExit2 info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; + + :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ + :if ($Seen->$Ssid = 1) do={ + $LogPrintExit2 debug $ScriptName ("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=$ScriptName; \ + subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ + message=("This is the daily PSK on " . $Identity . ":\n\n" . \ + [ $FormatLine "SSID" $Ssid ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk ] . "\n" . \ + [ $FormatLine "Date" $Date ] . "\n\n" . \ + "A client device specific rule must not exist!"); link=$Link }); + :set ($Seen->$Ssid) 1; + } } } } } + +$Main [ :jobname ]; diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index d1abce2..2f2838e 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -12,98 +12,103 @@ # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global DailyPskMatchComment; -:global DailyPskQrCodeUrl; -:global Identity; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global FormatLine; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; -:global UrlEncode; -:global WaitForFile; -:global WaitFullyConnected; + :global DailyPskMatchComment; + :global DailyPskQrCodeUrl; + :global Identity; -$ScriptLock $0; -$WaitFullyConnected; + :global FormatLine; + :global LogPrintExit2; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; + :global UrlEncode; + :global WaitForFile; + :global WaitFullyConnected; -# return pseudo-random string for PSK -:local GeneratePSK do={ - :local Date [ :tostr $1 ]; + $ScriptLock $ScriptName; + $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); - :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)); + :set Date [ $ParseDate $Date ]; - :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ - ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); -} + :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)); -:local Seen ({}); -:local Date [ /system/clock/get date ]; -:local NewPsk [ $GeneratePSK $Date ]; + :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ + ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ + ($DailyPskSecrets->2->$WeekDay)); + } -:foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ -:foreach AccList in=[ /interface/wifi/access-list/find where comment~$DailyPskMatchComment ] do={ -:foreach AccList in=[ /interface/wifiwave2/access-list/find where comment~$DailyPskMatchComment ] do={ -:foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ - :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; - :local SsidRegExp [ /interface/wifi/access-list/get $AccList ssid-regexp ]; - :local 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; + :local Seen ({}); + :local Date [ /system/clock/get date ]; + :local NewPsk [ $GeneratePSK $Date ]; - :if ($NewPsk != $OldPsk) do={ - $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; - /caps-man/access-list/set $AccList private-passphrase=$NewPsk; - /interface/wifi/access-list/set $AccList passphrase=$NewPsk; - /interface/wifiwave2/access-list/set $AccList passphrase=$NewPsk; - /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; + :foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ + :foreach AccList in=[ /interface/wifi/access-list/find where comment~$DailyPskMatchComment ] do={ + :foreach AccList in=[ /interface/wifiwave2/access-list/find where comment~$DailyPskMatchComment ] do={ + :foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ + :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; + :local SsidRegExp [ /interface/wifi/access-list/get $AccList ssid-regexp ]; + :local 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 ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ - :if ([ :len [ /interface/wifi/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ - :if ([ :len [ /interface/wifiwave2/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ - :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ - :if ($Seen->$Ssid = 1) do={ - $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; + :if ($NewPsk != $OldPsk) do={ + $LogPrintExit2 info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + /caps-man/access-list/set $AccList private-passphrase=$NewPsk; + /interface/wifi/access-list/set $AccList passphrase=$NewPsk; + /interface/wifiwave2/access-list/set $AccList passphrase=$NewPsk; + /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; + + :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ + :if ([ :len [ /interface/wifi/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ + :if ([ :len [ /interface/wifiwave2/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ + :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ + :if ($Seen->$Ssid = 1) do={ + $LogPrintExit2 debug $ScriptName ("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=$ScriptName; \ + subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ + message=("This is the daily PSK on " . $Identity . ":\n\n" . \ + [ $FormatLine "SSID" $Ssid ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk ] . "\n" . \ + [ $FormatLine "Date" $Date ] . "\n\n" . \ + "A client device specific rule must not exist!"); link=$Link }); + :set ($Seen->$Ssid) 1; + } } } } } + +$Main [ :jobname ]; diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index 488d921..e013dd1 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -11,77 +11,82 @@ # # !! 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; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global FormatLine; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; -:global UrlEncode; -:global WaitForFile; -:global WaitFullyConnected; + :global DailyPskMatchComment; + :global DailyPskQrCodeUrl; + :global Identity; -$ScriptLock $0; -$WaitFullyConnected; + :global FormatLine; + :global LogPrintExit2; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; + :global UrlEncode; + :global WaitForFile; + :global WaitFullyConnected; -# return pseudo-random string for PSK -:local GeneratePSK do={ - :local Date [ :tostr $1 ]; + $ScriptLock $ScriptName; + $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); - :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)); + :set Date [ $ParseDate $Date ]; - :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ - ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); -} + :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)); -:local Seen ({}); -:local Date [ /system/clock/get date ]; -:local NewPsk [ $GeneratePSK $Date ]; + :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ + ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ + ($DailyPskSecrets->2->$WeekDay)); + } -:foreach AccList in=[ /interface/wifi/access-list/find where comment~$DailyPskMatchComment ] do={ - :local SsidRegExp [ /interface/wifi/access-list/get $AccList ssid-regexp ]; - :local Configuration ([ /interface/wifi/configuration/find where ssid~$SsidRegExp ]->0); - :local Ssid [ /interface/wifi/configuration/get $Configuration ssid ]; - :local OldPsk [ /interface/wifi/access-list/get $AccList passphrase ]; - :local Skip 0; + :local Seen ({}); + :local Date [ /system/clock/get date ]; + :local NewPsk [ $GeneratePSK $Date ]; - :if ($NewPsk != $OldPsk) do={ - $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; - /interface/wifi/access-list/set $AccList passphrase=$NewPsk; + :foreach AccList in=[ /interface/wifi/access-list/find where comment~$DailyPskMatchComment ] do={ + :local SsidRegExp [ /interface/wifi/access-list/get $AccList ssid-regexp ]; + :local Configuration ([ /interface/wifi/configuration/find where ssid~$SsidRegExp ]->0); + :local Ssid [ /interface/wifi/configuration/get $Configuration ssid ]; + :local OldPsk [ /interface/wifi/access-list/get $AccList passphrase ]; + :local Skip 0; - :if ([ :len [ /interface/wifi/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; + :if ($NewPsk != $OldPsk) do={ + $LogPrintExit2 info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + /interface/wifi/access-list/set $AccList passphrase=$NewPsk; + + :if ([ :len [ /interface/wifi/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ + :if ($Seen->$Ssid = 1) do={ + $LogPrintExit2 debug $ScriptName ("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=$ScriptName; \ + subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ + message=("This is the daily PSK on " . $Identity . ":\n\n" . \ + [ $FormatLine "SSID" $Ssid ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk ] . "\n" . \ + [ $FormatLine "Date" $Date ] . "\n\n" . \ + "A client device specific rule must not exist!"); link=$Link }); + :set ($Seen->$Ssid) 1; + } } } } } + +$Main [ :jobname ]; diff --git a/daily-psk.wifiwave2.rsc b/daily-psk.wifiwave2.rsc index 89c5c25..75cfb7a 100644 --- a/daily-psk.wifiwave2.rsc +++ b/daily-psk.wifiwave2.rsc @@ -11,77 +11,82 @@ # # !! 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; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global FormatLine; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; -:global UrlEncode; -:global WaitForFile; -:global WaitFullyConnected; + :global DailyPskMatchComment; + :global DailyPskQrCodeUrl; + :global Identity; -$ScriptLock $0; -$WaitFullyConnected; + :global FormatLine; + :global LogPrintExit2; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; + :global UrlEncode; + :global WaitForFile; + :global WaitFullyConnected; -# return pseudo-random string for PSK -:local GeneratePSK do={ - :local Date [ :tostr $1 ]; + $ScriptLock $ScriptName; + $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); - :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)); + :set Date [ $ParseDate $Date ]; - :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ - ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); -} + :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)); -:local Seen ({}); -:local Date [ /system/clock/get date ]; -:local NewPsk [ $GeneratePSK $Date ]; + :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ + ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ + ($DailyPskSecrets->2->$WeekDay)); + } -: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; + :local Seen ({}); + :local Date [ /system/clock/get date ]; + :local NewPsk [ $GeneratePSK $Date ]; - :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; + :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 ([ :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; + :if ($NewPsk != $OldPsk) do={ + $LogPrintExit2 info $ScriptName ("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 $ScriptName ("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=$ScriptName; \ + subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ + message=("This is the daily PSK on " . $Identity . ":\n\n" . \ + [ $FormatLine "SSID" $Ssid ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk ] . "\n" . \ + [ $FormatLine "Date" $Date ] . "\n\n" . \ + "A client device specific rule must not exist!"); link=$Link }); + :set ($Seen->$Ssid) 1; + } } } } } + +$Main [ :jobname ]; From 82ec11f2fcc57b6842e0e1f6b92078dac15d6289 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:00 +0100 Subject: [PATCH 1908/2612] dhcp-lease-comment: move code into function --- dhcp-lease-comment.capsman.rsc | 33 +++++++++++++---------- dhcp-lease-comment.local.rsc | 33 +++++++++++++---------- dhcp-lease-comment.template.rsc | 45 ++++++++++++++++++-------------- dhcp-lease-comment.wifi.rsc | 33 +++++++++++++---------- dhcp-lease-comment.wifiwave2.rsc | 33 +++++++++++++---------- 5 files changed, 101 insertions(+), 76 deletions(-) diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc index a3df2ef..825077a 100644 --- a/dhcp-lease-comment.capsman.rsc +++ b/dhcp-lease-comment.capsman.rsc @@ -11,24 +11,29 @@ # # !! 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; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global LogPrintExit2; + :global ScriptLock; -:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local NewComment; - :local AccessList ([ /caps-man/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - :set NewComment [ /caps-man/access-list/get $AccessList comment ]; - } - :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; - /ip/dhcp-server/lease/set comment=$NewComment $Lease; + $ScriptLock $ScriptName; + + :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + :local NewComment; + :local AccessList ([ /caps-man/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + :set NewComment [ /caps-man/access-list/get $AccessList comment ]; + } + :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ + $LogPrintExit2 info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; + /ip/dhcp-server/lease/set comment=$NewComment $Lease; + } } } + +$Main [ :jobname ]; diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc index 5ccb916..13c04a7 100644 --- a/dhcp-lease-comment.local.rsc +++ b/dhcp-lease-comment.local.rsc @@ -11,24 +11,29 @@ # # !! 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; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global LogPrintExit2; + :global ScriptLock; -:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local NewComment; - :local AccessList ([ /interface/wireless/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - :set NewComment [ /interface/wireless/access-list/get $AccessList comment ]; - } - :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; - /ip/dhcp-server/lease/set comment=$NewComment $Lease; + $ScriptLock $ScriptName; + + :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + :local NewComment; + :local AccessList ([ /interface/wireless/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + :set NewComment [ /interface/wireless/access-list/get $AccessList comment ]; + } + :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ + $LogPrintExit2 info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; + /ip/dhcp-server/lease/set comment=$NewComment $Lease; + } } } + +$Main [ :jobname ]; diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index 02bc18c..9f79d06 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -12,30 +12,35 @@ # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit2; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global LogPrintExit2; + :global ScriptLock; -:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local NewComment; - :local AccessList ([ /caps-man/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); - :local AccessList ([ /interface/wifi/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); - :local AccessList ([ /interface/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; - /ip/dhcp-server/lease/set comment=$NewComment $Lease; + $ScriptLock $ScriptName; + + :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + :local NewComment; + :local AccessList ([ /caps-man/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); + :local AccessList ([ /interface/wifi/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); + :local AccessList ([ /interface/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 $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; + /ip/dhcp-server/lease/set comment=$NewComment $Lease; + } } } + +$Main [ :jobname ]; diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc index 337f282..cba1d6c 100644 --- a/dhcp-lease-comment.wifi.rsc +++ b/dhcp-lease-comment.wifi.rsc @@ -11,24 +11,29 @@ # # !! 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; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global LogPrintExit2; + :global ScriptLock; -:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local NewComment; - :local AccessList ([ /interface/wifi/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - :set NewComment [ /interface/wifi/access-list/get $AccessList comment ]; - } - :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; - /ip/dhcp-server/lease/set comment=$NewComment $Lease; + $ScriptLock $ScriptName; + + :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + :local NewComment; + :local AccessList ([ /interface/wifi/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + :set NewComment [ /interface/wifi/access-list/get $AccessList comment ]; + } + :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ + $LogPrintExit2 info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; + /ip/dhcp-server/lease/set comment=$NewComment $Lease; + } } } + +$Main [ :jobname ]; diff --git a/dhcp-lease-comment.wifiwave2.rsc b/dhcp-lease-comment.wifiwave2.rsc index 5c0c513..137ac6d 100644 --- a/dhcp-lease-comment.wifiwave2.rsc +++ b/dhcp-lease-comment.wifiwave2.rsc @@ -11,24 +11,29 @@ # # !! 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; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global LogPrintExit2; + :global ScriptLock; -: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; + $ScriptLock $ScriptName; + + :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 $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; + /ip/dhcp-server/lease/set comment=$NewComment $Lease; + } } } + +$Main [ :jobname ]; From 29f544d18d00fcc5e79909c3451c718cf65b718e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1909/2612] dhcp-to-dns: move code into function --- dhcp-to-dns.rsc | 181 +++++++++++++++++++++++++----------------------- 1 file changed, 93 insertions(+), 88 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index a8ae466..1cdd86e 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -9,113 +9,118 @@ # check DHCP leases and add/remove/update DNS entries # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Domain; -:global Identity; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global CleanName; -:global EitherOr; -:global IfThenElse; -:global LogPrintExit2; -:global LogPrintOnce; -:global ParseKeyValueStore; -:global ScriptLock; + :global Domain; + :global Identity; -$ScriptLock $0 false 10; + :global CleanName; + :global EitherOr; + :global IfThenElse; + :global LogPrintExit2; + :global LogPrintOnce; + :global ParseKeyValueStore; + :global ScriptLock; -:local Ttl 5m; -:local CommentPrefix ("managed by " . $0); -:local CommentString ("--- " . $0 . " above ---"); + $ScriptLock $ScriptName false 10; -: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); + :local Ttl 5m; + :local CommentPrefix ("managed by " . $ScriptName); + :local CommentString ("--- " . $ScriptName . " above ---"); -: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") ]; + :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 $ScriptName ("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 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; + :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 $ScriptName ("Lease for " . $MacInServer . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting record.") false; + } else={ + :local Found false; + $LogPrintExit2 info $ScriptName ("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") ]; } - } on-error={ - $LogPrintExit2 debug $0 ("A lease just vanished, ignoring.") false; } - :if ([ :len ($LeaseVal->"active-address") ] > 0) do={ - :local Comment ($CommentPrefix . ", macaddress=" . $LeaseVal->"active-mac-address" . ", server=" . $LeaseVal->"server"); - :local MacDash [ $CleanName ($LeaseVal->"active-mac-address") ]; - :local HostName [ $CleanName [ $EitherOr ([ $ParseKeyValueStore ($LeaseVal->"comment") ]->"hostname") ($LeaseVal->"host-name") ] ]; - :local Network [ /ip/dhcp-server/network/find where ($LeaseVal->"active-address") in address ]; - :local NetworkVal; - :if ([ :len $Network ] > 0) do={ - :set NetworkVal [ /ip/dhcp-server/network/get ($Network->0) ]; - } - :local NetworkInfo [ $ParseKeyValueStore ($NetworkVal->"comment") ]; - :local NetDomain ([ $IfThenElse ([ :len ($NetworkInfo->"name-extra") ] > 0) ($NetworkInfo->"name-extra" . ".") ] . \ - [ $EitherOr [ $EitherOr ($NetworkInfo->"domain") ($NetworkVal->"domain") ] $Domain ]); - :local FullA ($MacDash . "." . $NetDomain); - :local FullCN ($HostName . "." . $NetDomain); - :local MacInServer ($LeaseVal->"active-mac-address" . " in " . $LeaseVal->"server"); - - :local DnsRecord [ /ip/dns/static/find where comment=$Comment (!type or type=A) ]; - :if ([ :len $DnsRecord ] > 0) do={ - :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; - - :if ($DnsRecordVal->"address" = $LeaseVal->"active-address" && $DnsRecordVal->"name" = $FullA) do={ - $LogPrintExit2 debug $0 ("The A record for " . $MacInServer . " (" . $FullA . ") does not need updating.") false; - } 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; + :foreach Lease in=[ /ip/dhcp-server/lease/find where status=bound ] do={ + :local LeaseVal; + :do { + :set LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + :if ([ :len [ /ip/dhcp-server/lease/find where active-mac-address=($LeaseVal->"active-mac-address") status=bound ] ] > 1) do={ + $LogPrintOnce info $ScriptName ("Multiple bound leases found for mac-address " . ($LeaseVal->"active-mac-address") . "!") false; } + } on-error={ + $LogPrintExit2 debug $ScriptName ("A lease just vanished, ignoring.") false; + } - :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={ - $LogPrintExit2 info $0 ("Deleting CNAME record with wrong data for " . $MacInServer . ".") false; - /ip/dns/static/remove $CName; + :if ([ :len ($LeaseVal->"active-address") ] > 0) do={ + :local Comment ($CommentPrefix . ", macaddress=" . $LeaseVal->"active-mac-address" . ", server=" . $LeaseVal->"server"); + :local MacDash [ $CleanName ($LeaseVal->"active-mac-address") ]; + :local HostName [ $CleanName [ $EitherOr ([ $ParseKeyValueStore ($LeaseVal->"comment") ]->"hostname") ($LeaseVal->"host-name") ] ]; + :local Network [ /ip/dhcp-server/network/find where ($LeaseVal->"active-address") in address ]; + :local NetworkVal; + :if ([ :len $Network ] > 0) do={ + :set NetworkVal [ /ip/dhcp-server/network/get ($Network->0) ]; + } + :local NetworkInfo [ $ParseKeyValueStore ($NetworkVal->"comment") ]; + :local NetDomain ([ $IfThenElse ([ :len ($NetworkInfo->"name-extra") ] > 0) ($NetworkInfo->"name-extra" . ".") ] . \ + [ $EitherOr [ $EitherOr ($NetworkInfo->"domain") ($NetworkVal->"domain") ] $Domain ]); + :local FullA ($MacDash . "." . $NetDomain); + :local FullCN ($HostName . "." . $NetDomain); + :local MacInServer ($LeaseVal->"active-mac-address" . " in " . $LeaseVal->"server"); + + :local DnsRecord [ /ip/dns/static/find where comment=$Comment (!type or type=A) ]; + :if ([ :len $DnsRecord ] > 0) do={ + :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; + + :if ($DnsRecordVal->"address" = $LeaseVal->"active-address" && $DnsRecordVal->"name" = $FullA) do={ + $LogPrintExit2 debug $ScriptName ("The A record for " . $MacInServer . " (" . $FullA . ") does not need updating.") false; + } else={ + $LogPrintExit2 info $ScriptName ("Updating A record for " . $MacInServer . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ").") false; + /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={ + $LogPrintExit2 info $ScriptName ("Deleting CNAME record with wrong data for " . $MacInServer . ".") false; + /ip/dns/static/remove $CName; + } + } + :if ([ :len $HostName ] > 0 && [ :len [ /ip/dns/static/find where name=$FullCN type=CNAME ] ] = 0) do={ + $LogPrintExit2 info $ScriptName ("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; + } + + } else={ + $LogPrintExit2 info $ScriptName ("Adding A record for " . $MacInServer . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ").") false; + /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 $ScriptName ("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 $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!") false; + } } else={ - $LogPrintExit2 info $0 ("Adding A record for " . $MacInServer . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ").") false; - /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; - } + $LogPrintExit2 debug $ScriptName ("No address available... Ignoring.") false; } - - :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; } } + +$Main [ :jobname ]; From cf986caf8d1b2eda83fad2b6c6daecbf0e93a8c7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1910/2612] firmware-upgrade-reboot: move code into function --- firmware-upgrade-reboot.rsc | 65 ++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc index adcea73..efe22ae 100644 --- a/firmware-upgrade-reboot.rsc +++ b/firmware-upgrade-reboot.rsc @@ -8,40 +8,45 @@ # install firmware upgrade, and reboot # https://git.eworm.de/cgit/routeros-scripts/about/doc/firmware-upgrade-reboot.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit2; -:global ScriptLock; -:global VersionToNum; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global LogPrintExit2; + :global ScriptLock; + :global VersionToNum; -:local RouterBoard [ /system/routerboard/get ]; -:if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ - $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; + $ScriptLock $ScriptName; + + :local RouterBoard [ /system/routerboard/get ]; + :if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ + $LogPrintExit2 info $ScriptName ("Current and upgrade firmware match with version " . \ + $RouterBoard->"current-firmware" . ".") true; + } + :if ([ $VersionToNum ($RouterBoard->"current-firmware") ] > [ $VersionToNum ($RouterBoard->"upgrade-firmware") ]) do={ + $LogPrintExit2 info $ScriptName ("Different firmware version is available, but it is a downgrade. Ignoring.") true; + } + + :if ([ /system/routerboard/settings/get auto-upgrade ] = false) do={ + $LogPrintExit2 info $ScriptName ("Firmware version " . $RouterBoard->"upgrade-firmware" . \ + " is available, upgrading.") false; + /system/routerboard/upgrade; + } + + :while ([ :len [ /log/find where topics=({"system";"info";"critical"}) \ + message="Firmware upgraded successfully, please reboot for changes to take effect!" ] ] = 0) do={ + :delay 1s; + } + + :local Uptime [ /system/resource/get uptime ]; + :if ($Uptime < 1m) do={ + :delay $Uptime; + } + + $LogPrintExit2 info $ScriptName ("Firmware upgrade successful, rebooting.") false; + /system/reboot; } -:if ([ /system/routerboard/settings/get auto-upgrade ] = false) do={ - $LogPrintExit2 info $0 ("Firmware version " . $RouterBoard->"upgrade-firmware" . \ - " is available, upgrading.") false; - /system/routerboard/upgrade; -} - -:while ([ :len [ /log/find where topics=({"system";"info";"critical"}) \ - message="Firmware upgraded successfully, please reboot for changes to take effect!" ] ] = 0) do={ - :delay 1s; -} - -:local Uptime [ /system/resource/get uptime ]; -:if ($Uptime < 1m) do={ - :delay $Uptime; -} - -$LogPrintExit2 info $0 ("Firmware upgrade successful, rebooting.") false; -/system/reboot; +$Main [ :jobname ]; From 480ad0c196f7edd0abbf376af2802446c23e78e1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1911/2612] fw-addr-lists: move code into function --- fw-addr-lists.rsc | 235 +++++++++++++++++++++++----------------------- 1 file changed, 120 insertions(+), 115 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 14da2e2..d4ac519 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -8,147 +8,152 @@ # download, import and update firewall address-lists # https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global FetchUserAgent; -:global FwAddrLists; -:global FwAddrListTimeOut; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global CertificateAvailable; -:global EitherOr; -:global LogPrintExit2; -:global LogPrintOnce; -:global ScriptLock; -:global WaitFullyConnected; + :global FetchUserAgent; + :global FwAddrLists; + :global FwAddrListTimeOut; -: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; + :global CertificateAvailable; + :global EitherOr; + :global LogPrintExit2; + :global LogPrintOnce; + :global ScriptLock; + :global WaitFullyConnected; + + :local FindDelim do={ + :local ValidChars "0123456789.:/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"; + :for I from=0 to=[ :len $1 ] do={ + :if ([ :typeof [ :find $ValidChars [ :pick ($1 . " ") $I ] ] ] != "num") do={ + :return $I; + } } } -} -$ScriptLock $0; -$WaitFullyConnected; + $ScriptLock $ScriptName; + $WaitFullyConnected; -:local ListComment ("managed by " . $0); + :local ListComment ("managed by " . $ScriptName); -:foreach FwListName,FwList in=$FwAddrLists do={ - :local CntAdd 0; - :local CntRenew 0; - :local CntRemove 0; - :local IPv4Addresses ({}); - :local IPv6Addresses ({}); - :local Failure false; + :foreach FwListName,FwList in=$FwAddrLists do={ + :local CntAdd 0; + :local CntRenew 0; + :local CntRemove 0; + :local IPv4Addresses ({}); + :local IPv6Addresses ({}); + :local Failure false; - :foreach List in=$FwList do={ - :local CheckCertificate "no"; - :local Data false; - :local TimeOut [ $EitherOr [ :totime ($List->"timeout") ] $FwAddrListTimeOut ]; + :foreach List in=$FwList do={ + :local CheckCertificate "no"; + :local Data false; + :local TimeOut [ $EitherOr [ :totime ($List->"timeout") ] $FwAddrListTimeOut ]; - :if ([ :len ($List->"cert") ] > 0) do={ - :set CheckCertificate "yes-without-crl"; - :if ([ $CertificateAvailable ($List->"cert") ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading required certificate failed, trying anyway.") false; + :if ([ :len ($List->"cert") ] > 0) do={ + :set CheckCertificate "yes-without-crl"; + :if ([ $CertificateAvailable ($List->"cert") ] = false) do={ + $LogPrintExit2 warning $ScriptName ("Downloading required certificate failed, trying anyway.") false; + } + } + + :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={ + $LogPrintExit2 debug $ScriptName ("Failed downloading, " . $I . ". try: " . $List->"url") false; + :delay (($I * $I) . "s"); + } + } + } + } + + :if ($Data = false) do={ + :set Data ""; + :set Failure true; + $LogPrintExit2 warning $ScriptName ("Failed downloading list from: " . $List->"url") false; + } + + :if ([ :len $Data ] > 63000) do={ + $LogPrintOnce warning $ScriptName ("The list is huge and may be truncated: " . $List->"url") false; + } + + :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={ - :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={ - $LogPrintExit2 debug $0 ("Failed downloading, " . $I . ". try: " . $List->"url") false; - :delay (($I * $I) . "s"); - } + :foreach Entry in=[ /ip/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={ + :local Address [ /ip/firewall/address-list/get $Entry address ]; + :if ([ :typeof ($IPv4Addresses->$Address) ] = "time") do={ + $LogPrintExit2 debug $ScriptName ("Renewing IPv4 address for " . ($IPv4Addresses->$Address) . ": " . $Address) false; + /ip/firewall/address-list/set $Entry timeout=($IPv4Addresses->$Address); + :set ($IPv4Addresses->$Address); + :set CntRenew ($CntRenew + 1); + } else={ + :if ($Failure = false) do={ + $LogPrintExit2 debug $ScriptName ("Removing IPv4 address: " . $Address) false; + /ip/firewall/address-list/remove $Entry; + :set CntRemove ($CntRemove + 1); } } } - :if ($Data = false) do={ - :set Data ""; - :set Failure true; - $LogPrintExit2 warning $0 ("Failed downloading list from: " . $List->"url") false; - } - - :if ([ :len $Data ] > 63000) do={ - $LogPrintOnce warning $0 ("The list is huge and may be truncated: " . $List->"url") false; - } - - :while ([ :len $Data ] != 0) do={ - :local Line [ :pick $Data 0 [ :find $Data "\n" ] ]; - :local Address ([ :pick $Line 0 [ $FindDelim $Line ] ] . ($List->"cidr")); - :if ($Address ~ "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(/[0-9]{1,2})?\$" || \ - $Address ~ "^[\\.a-zA-Z0-9-]+\\.[a-zA-Z]{2,}\$") do={ - :set ($IPv4Addresses->$Address) $TimeOut; - } - :if ($Address ~ "^[0-9a-zA-Z]*:[0-9a-zA-Z:\\.]+(/[0-9]{1,3})?\$" || \ - $Address ~ "^[\\.a-zA-Z0-9-]+\\.[a-zA-Z]{2,}\$") do={ - :set ($IPv6Addresses->$Address) $TimeOut; - } - :set Data [ :pick $Data ([ :len $Line ] + 1) [ :len $Data ] ]; - } - } - - :foreach Entry in=[ /ip/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={ - :local Address [ /ip/firewall/address-list/get $Entry address ]; - :if ([ :typeof ($IPv4Addresses->$Address) ] = "time") do={ - $LogPrintExit2 debug $0 ("Renewing IPv4 address for " . ($IPv4Addresses->$Address) . ": " . $Address) false; - /ip/firewall/address-list/set $Entry timeout=($IPv4Addresses->$Address); - :set ($IPv4Addresses->$Address); - :set CntRenew ($CntRenew + 1); - } else={ - :if ($Failure = false) do={ - $LogPrintExit2 debug $0 ("Removing IPv4 address: " . $Address) false; - /ip/firewall/address-list/remove $Entry; - :set CntRemove ($CntRemove + 1); + :foreach Entry in=[ /ipv6/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={ + :local Address [ /ipv6/firewall/address-list/get $Entry address ]; + :if ([ :typeof ($IPv6Addresses->$Address) ] = "time") do={ + $LogPrintExit2 debug $ScriptName ("Renewing IPv6 address for " . ($IPv6Addresses->$Address) . ": " . $Address) false; + /ipv6/firewall/address-list/set $Entry timeout=($IPv6Addresses->$Address); + :set ($IPv6Addresses->$Address); + :set CntRenew ($CntRenew + 1); + } else={ + :if ($Failure = false) do={ + $LogPrintExit2 debug $ScriptName ("Removing: " . $Address) false; + /ipv6/firewall/address-list/remove $Entry; + :set CntRemove ($CntRemove + 1); + } } } - } - :foreach Entry in=[ /ipv6/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={ - :local Address [ /ipv6/firewall/address-list/get $Entry address ]; - :if ([ :typeof ($IPv6Addresses->$Address) ] = "time") do={ - $LogPrintExit2 debug $0 ("Renewing IPv6 address for " . ($IPv6Addresses->$Address) . ": " . $Address) false; - /ipv6/firewall/address-list/set $Entry timeout=($IPv6Addresses->$Address); - :set ($IPv6Addresses->$Address); - :set CntRenew ($CntRenew + 1); - } else={ - :if ($Failure = false) do={ - $LogPrintExit2 debug $0 ("Removing: " . $Address) false; - /ipv6/firewall/address-list/remove $Entry; - :set CntRemove ($CntRemove + 1); + :foreach Address,Timeout in=$IPv4Addresses do={ + $LogPrintExit2 debug $ScriptName ("Adding IPv4 address for " . $Timeout . ": " . $Address) false; + :do { + /ip/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout; + :set ($IPv4Addresses->$Address); + :set CntAdd ($CntAdd + 1); + } on-error={ + $LogPrintExit2 warning $ScriptName ("Failed to add IPv4 address " . $Address . " to list '" . $FwListName . "'.") false; } } - } - :foreach Address,Timeout in=$IPv4Addresses do={ - $LogPrintExit2 debug $0 ("Adding IPv4 address for " . $Timeout . ": " . $Address) false; - :do { - /ip/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout; - :set ($IPv4Addresses->$Address); - :set CntAdd ($CntAdd + 1); - } on-error={ - $LogPrintExit2 warning $0 ("Failed to add IPv4 address " . $Address . " to list '" . $FwListName . "'.") false; + :foreach Address,Timeout in=$IPv6Addresses do={ + $LogPrintExit2 debug $ScriptName ("Adding IPv6 address for " . $Timeout . ": " . $Address) false; + :do { + /ipv6/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout; + :set ($IPv6Addresses->$Address); + :set CntAdd ($CntAdd + 1); + } on-error={ + $LogPrintExit2 warning $ScriptName ("Failed to add IPv6 address " . $Address . " to list '" . $FwListName . "'.") false; + } } - } - :foreach Address,Timeout in=$IPv6Addresses do={ - $LogPrintExit2 debug $0 ("Adding IPv6 address for " . $Timeout . ": " . $Address) false; - :do { - /ipv6/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout; - :set ($IPv6Addresses->$Address); - :set CntAdd ($CntAdd + 1); - } on-error={ - $LogPrintExit2 warning $0 ("Failed to add IPv6 address " . $Address . " to list '" . $FwListName . "'.") false; - } + $LogPrintExit2 info $ScriptName ("list: " . $FwListName . " -- added: " . $CntAdd . " - renewed: " . $CntRenew . " - removed: " . $CntRemove) false; } - - $LogPrintExit2 info $0 ("list: " . $FwListName . " -- added: " . $CntAdd . " - renewed: " . $CntRenew . " - removed: " . $CntRemove) false; } + +$Main [ :jobname ]; From a0fc6c30ef2d47d0538cadf9c2598190e2fccb59 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1912/2612] gps-track: move code into function --- gps-track.rsc | 57 ++++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/gps-track.rsc b/gps-track.rsc index 2e6d50f..8517778 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -8,38 +8,43 @@ # track gps data by sending json data to http server # https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global GpsTrackUrl; -:global Identity; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global LogPrintExit2; -:global ScriptLock; -:global WaitFullyConnected; + :global GpsTrackUrl; + :global Identity; -$ScriptLock $0; -$WaitFullyConnected; + :global LogPrintExit2; + :global ScriptLock; + :global WaitFullyConnected; -:local CoordinateFormat [ /system/gps/get coordinate-format ]; -:local Gps [ /system/gps/monitor once as-value ]; + $ScriptLock $ScriptName; + $WaitFullyConnected; -: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; + :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; + $LogPrintExit2 debug $ScriptName ("Sending GPS data in " . $CoordinateFormat . " format: " . \ + "lat: " . ($Gps->"latitude") . " " . \ + "lon: " . ($Gps->"longitude")) false; + } on-error={ + $LogPrintExit2 warning $ScriptName ("Failed sending GPS data!") false; + } + } else={ + $LogPrintExit2 debug $ScriptName ("GPS data not valid.") false; } -} else={ - $LogPrintExit2 debug $0 ("GPS data not valid.") false; } + +$Main [ :jobname ]; From 2bf02cf0852d086a3f236d6423022ba1131e2267 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1913/2612] hotspot-to-wpa-cleanup: move code into function --- hotspot-to-wpa-cleanup.capsman.rsc | 95 +++++++++++---------- hotspot-to-wpa-cleanup.template.rsc | 119 ++++++++++++++------------- hotspot-to-wpa-cleanup.wifi.rsc | 95 +++++++++++---------- hotspot-to-wpa-cleanup.wifiwave2.rsc | 95 +++++++++++---------- 4 files changed, 212 insertions(+), 192 deletions(-) diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index 7e8749d..498e853 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -11,59 +11,64 @@ # # !! Do not edit this file, it is generated from template! -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0 false 10; + :global EitherOr; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptLock; -:local DHCPServers ({}); -:foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ - :local ServerVal [ /ip/dhcp-server/get $Server ] - :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; - :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ - :set ($DHCPServers->($ServerVal->"name")) \ - [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; + $ScriptLock $ScriptName false 10; + + :local DHCPServers ({}); + :foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ + :local ServerVal [ /ip/dhcp-server/get $Server ] + :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; + :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ + :set ($DHCPServers->($ServerVal->"name")) \ + [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; + } } -} -:foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ - :local ClientVal [ /caps-man/registration-table/get $Client ]; - :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ - mac-address=($ClientVal->"mac-address") ] do={ - :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static.") false; - /ip/dhcp-server/lease/make-static $Lease; - /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; + :foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ + :local ClientVal [ /caps-man/registration-table/get $Client ]; + :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ + mac-address=($ClientVal->"mac-address") ] do={ + :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ + $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ + " connected to WPA, making lease static.") false; + /ip/dhcp-server/lease/make-static $Lease; + /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; + } + } + } + + :foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \ + !(comment~[ /system/clock/get date ]) ] do={ + :local ClientVal [ /caps-man/access-list/get $Client ]; + :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ + mac-address=($ClientVal->"mac-address") ] ] = 0) do={ + $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ + " did not connect to WPA, removing from access list.") false; + /caps-man/access-list/remove $Client; + } + } + + :foreach Server,Timeout in=$DHCPServers do={ + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ + server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + $LogPrintExit2 info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ + " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; + /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ + mac-address=($LeaseVal->"mac-address") ]; + /ip/dhcp-server/lease/remove $Lease; } } } -:foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \ - !(comment~[ /system/clock/get date ]) ] do={ - :local ClientVal [ /caps-man/access-list/get $Client ]; - :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ - mac-address=($ClientVal->"mac-address") ] ] = 0) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " did not connect to WPA, removing from access list.") false; - /caps-man/access-list/remove $Client; - } -} - -:foreach 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 ]; - $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; - /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - mac-address=($LeaseVal->"mac-address") ]; - /ip/dhcp-server/lease/remove $Lease; - } -} +$Main [ :jobname ]; diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index b7b4d9c..9ffc6ea 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -12,71 +12,76 @@ # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0 false 10; + :global EitherOr; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptLock; -:local DHCPServers ({}); -:foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ - :local ServerVal [ /ip/dhcp-server/get $Server ] - :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; - :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ - :set ($DHCPServers->($ServerVal->"name")) \ - [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; + $ScriptLock $ScriptName false 10; + + :local DHCPServers ({}); + :foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ + :local ServerVal [ /ip/dhcp-server/get $Server ] + :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; + :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ + :set ($DHCPServers->($ServerVal->"name")) \ + [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; + } } -} -:foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ -:foreach Client in=[ /interface/wifi/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ -:foreach Client in=[ /interface/wifiwave2/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ - :local ClientVal [ /caps-man/registration-table/get $Client ]; - :local ClientVal [ /interface/wifi/registration-table/get $Client ]; - :local ClientVal [ /interface/wifiwave2/registration-table/get $Client ]; - :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ - mac-address=($ClientVal->"mac-address") ] do={ - :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static.") false; - /ip/dhcp-server/lease/make-static $Lease; - /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; + :foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ + :foreach Client in=[ /interface/wifi/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ + :foreach Client in=[ /interface/wifiwave2/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ + :local ClientVal [ /caps-man/registration-table/get $Client ]; + :local ClientVal [ /interface/wifi/registration-table/get $Client ]; + :local ClientVal [ /interface/wifiwave2/registration-table/get $Client ]; + :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ + mac-address=($ClientVal->"mac-address") ] do={ + :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ + $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ + " connected to WPA, making lease static.") false; + /ip/dhcp-server/lease/make-static $Lease; + /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; + } + } + } + + :foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \ + :foreach Client in=[ /interface/wifi/access-list/find where comment~"^hotspot-to-wpa:" \ + :foreach Client in=[ /interface/wifiwave2/access-list/find where comment~"^hotspot-to-wpa:" \ + !(comment~[ /system/clock/get date ]) ] do={ + :local ClientVal [ /caps-man/access-list/get $Client ]; + :local ClientVal [ /interface/wifi/access-list/get $Client ]; + :local ClientVal [ /interface/wifiwave2/access-list/get $Client ]; + :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ + mac-address=($ClientVal->"mac-address") ] ] = 0) do={ + $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ + " did not connect to WPA, removing from access list.") false; + /caps-man/access-list/remove $Client; + /interface/wifi/access-list/remove $Client; + /interface/wifiwave2/access-list/remove $Client; + } + } + + :foreach Server,Timeout in=$DHCPServers do={ + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ + server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + $LogPrintExit2 info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ + " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; + /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ + /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ + /interface/wifiwave2/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ + mac-address=($LeaseVal->"mac-address") ]; + /ip/dhcp-server/lease/remove $Lease; } } } -:foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \ -:foreach Client in=[ /interface/wifi/access-list/find where comment~"^hotspot-to-wpa:" \ -:foreach Client in=[ /interface/wifiwave2/access-list/find where comment~"^hotspot-to-wpa:" \ - !(comment~[ /system/clock/get date ]) ] do={ - :local ClientVal [ /caps-man/access-list/get $Client ]; - :local ClientVal [ /interface/wifi/access-list/get $Client ]; - :local ClientVal [ /interface/wifiwave2/access-list/get $Client ]; - :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ - mac-address=($ClientVal->"mac-address") ] ] = 0) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " did not connect to WPA, removing from access list.") false; - /caps-man/access-list/remove $Client; - /interface/wifi/access-list/remove $Client; - /interface/wifiwave2/access-list/remove $Client; - } -} - -:foreach Server,Timeout in=$DHCPServers do={ - :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ - server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; - /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - /interface/wifiwave2/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - mac-address=($LeaseVal->"mac-address") ]; - /ip/dhcp-server/lease/remove $Lease; - } -} +$Main [ :jobname ]; diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index 4e9eda2..cf7eaad 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -11,59 +11,64 @@ # # !! Do not edit this file, it is generated from template! -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0 false 10; + :global EitherOr; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptLock; -:local DHCPServers ({}); -:foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ - :local ServerVal [ /ip/dhcp-server/get $Server ] - :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; - :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ - :set ($DHCPServers->($ServerVal->"name")) \ - [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; + $ScriptLock $ScriptName false 10; + + :local DHCPServers ({}); + :foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ + :local ServerVal [ /ip/dhcp-server/get $Server ] + :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; + :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ + :set ($DHCPServers->($ServerVal->"name")) \ + [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; + } } -} -:foreach Client in=[ /interface/wifi/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ - :local ClientVal [ /interface/wifi/registration-table/get $Client ]; - :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ - mac-address=($ClientVal->"mac-address") ] do={ - :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static.") false; - /ip/dhcp-server/lease/make-static $Lease; - /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; + :foreach Client in=[ /interface/wifi/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ + :local ClientVal [ /interface/wifi/registration-table/get $Client ]; + :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ + mac-address=($ClientVal->"mac-address") ] do={ + :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ + $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ + " connected to WPA, making lease static.") false; + /ip/dhcp-server/lease/make-static $Lease; + /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; + } + } + } + + :foreach Client in=[ /interface/wifi/access-list/find where comment~"^hotspot-to-wpa:" \ + !(comment~[ /system/clock/get date ]) ] do={ + :local ClientVal [ /interface/wifi/access-list/get $Client ]; + :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ + mac-address=($ClientVal->"mac-address") ] ] = 0) do={ + $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ + " did not connect to WPA, removing from access list.") false; + /interface/wifi/access-list/remove $Client; + } + } + + :foreach Server,Timeout in=$DHCPServers do={ + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ + server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + $LogPrintExit2 info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ + " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; + /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ + mac-address=($LeaseVal->"mac-address") ]; + /ip/dhcp-server/lease/remove $Lease; } } } -:foreach Client in=[ /interface/wifi/access-list/find where comment~"^hotspot-to-wpa:" \ - !(comment~[ /system/clock/get date ]) ] do={ - :local ClientVal [ /interface/wifi/access-list/get $Client ]; - :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ - mac-address=($ClientVal->"mac-address") ] ] = 0) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " did not connect to WPA, removing from access list.") false; - /interface/wifi/access-list/remove $Client; - } -} - -:foreach Server,Timeout in=$DHCPServers do={ - :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ - server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; - /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - mac-address=($LeaseVal->"mac-address") ]; - /ip/dhcp-server/lease/remove $Lease; - } -} +$Main [ :jobname ]; diff --git a/hotspot-to-wpa-cleanup.wifiwave2.rsc b/hotspot-to-wpa-cleanup.wifiwave2.rsc index afa0c2d..bbb64c5 100644 --- a/hotspot-to-wpa-cleanup.wifiwave2.rsc +++ b/hotspot-to-wpa-cleanup.wifiwave2.rsc @@ -11,59 +11,64 @@ # # !! Do not edit this file, it is generated from template! -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0 false 10; + :global EitherOr; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptLock; -:local DHCPServers ({}); -:foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ - :local ServerVal [ /ip/dhcp-server/get $Server ] - :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; - :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ - :set ($DHCPServers->($ServerVal->"name")) \ - [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; + $ScriptLock $ScriptName false 10; + + :local DHCPServers ({}); + :foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ + :local ServerVal [ /ip/dhcp-server/get $Server ] + :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; + :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ + :set ($DHCPServers->($ServerVal->"name")) \ + [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; + } } -} -:foreach Client in=[ /interface/wifiwave2/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ - :local ClientVal [ /interface/wifiwave2/registration-table/get $Client ]; - :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ - mac-address=($ClientVal->"mac-address") ] do={ - :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static.") false; - /ip/dhcp-server/lease/make-static $Lease; - /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; + :foreach Client in=[ /interface/wifiwave2/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ + :local ClientVal [ /interface/wifiwave2/registration-table/get $Client ]; + :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ + mac-address=($ClientVal->"mac-address") ] do={ + :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ + $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ + " connected to WPA, making lease static.") false; + /ip/dhcp-server/lease/make-static $Lease; + /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; + } + } + } + + :foreach Client in=[ /interface/wifiwave2/access-list/find where comment~"^hotspot-to-wpa:" \ + !(comment~[ /system/clock/get date ]) ] do={ + :local ClientVal [ /interface/wifiwave2/access-list/get $Client ]; + :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ + mac-address=($ClientVal->"mac-address") ] ] = 0) do={ + $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ + " did not connect to WPA, removing from access list.") false; + /interface/wifiwave2/access-list/remove $Client; + } + } + + :foreach Server,Timeout in=$DHCPServers do={ + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ + server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; + $LogPrintExit2 info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ + " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; + /interface/wifiwave2/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ + mac-address=($LeaseVal->"mac-address") ]; + /ip/dhcp-server/lease/remove $Lease; } } } -:foreach Client in=[ /interface/wifiwave2/access-list/find where comment~"^hotspot-to-wpa:" \ - !(comment~[ /system/clock/get date ]) ] do={ - :local ClientVal [ /interface/wifiwave2/access-list/get $Client ]; - :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ - mac-address=($ClientVal->"mac-address") ] ] = 0) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " did not connect to WPA, removing from access list.") false; - /interface/wifiwave2/access-list/remove $Client; - } -} - -:foreach Server,Timeout in=$DHCPServers do={ - :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ - server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; - /interface/wifiwave2/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - mac-address=($LeaseVal->"mac-address") ]; - /ip/dhcp-server/lease/remove $Lease; - } -} +$Main [ :jobname ]; From a36ec397d6fc6e5a31c25cb58f41db62c8ba0bbe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1914/2612] hotspot-to-wpa: move code into function --- hotspot-to-wpa.capsman.rsc | 144 ++++++++++++------------ hotspot-to-wpa.template.rsc | 208 ++++++++++++++++++----------------- hotspot-to-wpa.wifi.rsc | 138 ++++++++++++----------- hotspot-to-wpa.wifiwave2.rsc | 138 ++++++++++++----------- 4 files changed, 322 insertions(+), 306 deletions(-) diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index db3f430..d903fe9 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -10,82 +10,86 @@ # # !! Do not edit this file, it is generated from template! -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; + :local MacAddress [ :tostr $2 ]; + :local UserName [ :tostr $3 ]; -$ScriptLock $0; + :global EitherOr; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptLock; -:local MacAddress $"mac-address"; -:local UserName $username; + $ScriptLock $ScriptName; -:if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from hotspot on login.") true; -} - -:local Date [ /system/clock/get date ]; -:local UserVal ({}); -:if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ - :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; -} -:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; -:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; - -:if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; -} -:local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - -:if ([ :len [ /caps-man/access-list/find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; -} -:local Template [ /caps-man/access-list/get ([ find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; - -:if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; -} - -# allow login page to load -:delay 1s; - -$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ").") false; -/caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; -/caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - action=reject place-before=$PlaceBefore; - -:local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ - comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; -:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; -:if ([ :len $PrivatePassphrase ] > 0) do={ - :if ($PrivatePassphrase = "ignore") do={ - /caps-man/access-list/set $Entry !private-passphrase; - } else={ - /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; + :if ([ :len $MacAddress ] = 0 || [ :len $UserName ] = 0) do={ + $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; } -} -:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; -:if ([ :len $SsidRegexp ] > 0) do={ - /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; -} -:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; -:if ([ :len $VlanId ] > 0) do={ - /caps-man/access-list/set $Entry vlan-id=$VlanId; -} -:local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; -:if ([ :len $VlanMode] > 0) do={ - /caps-man/access-list/set $Entry vlan-mode=$VlanMode; + + :local Date [ /system/clock/get date ]; + :local UserVal ({}); + :if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ + :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; + } + :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; + :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; + + :if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; + } + :local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + + :if ([ :len [ /caps-man/access-list/find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ + /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + $LogPrintExit2 warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; + } + :local Template [ /caps-man/access-list/get ([ find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; + + :if ($Template->"action" = "reject") do={ + $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") true; + } + + # allow login page to load + :delay 1s; + + $LogPrintExit2 info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ").") false; + /caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; + /caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + action=reject place-before=$PlaceBefore; + + :local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ + comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; + :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; + :if ([ :len $PrivatePassphrase ] > 0) do={ + :if ($PrivatePassphrase = "ignore") do={ + /caps-man/access-list/set $Entry !private-passphrase; + } else={ + /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; + } + } + :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; + :if ([ :len $SsidRegexp ] > 0) do={ + /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; + } + :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; + :if ([ :len $VlanId ] > 0) do={ + /caps-man/access-list/set $Entry vlan-id=$VlanId; + } + :local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; + :if ([ :len $VlanMode] > 0) do={ + /caps-man/access-list/set $Entry vlan-mode=$VlanMode; + } + + :delay 2s; + /caps-man/access-list/set $Entry action=accept; } -:delay 2s; -/caps-man/access-list/set $Entry action=accept; +$Main [ :jobname ] $"mac-address" $username; diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index 98369a7..1f82c28 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -11,117 +11,121 @@ # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; + :local MacAddress [ :tostr $2 ]; + :local UserName [ :tostr $3 ]; -$ScriptLock $0; + :global EitherOr; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptLock; -:local MacAddress $"mac-address"; -:local UserName $username; + $ScriptLock $ScriptName; -:if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from hotspot on login.") true; -} - -:local Date [ /system/clock/get date ]; -:local UserVal ({}); -:if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ - :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; -} -:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; -:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; - -:if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ -:if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ -:if ([ :len [ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - /interface/wifiwave2/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; -} -:local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); -:local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); -:local PlaceBefore ([ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - -:if ([ :len [ /caps-man/access-list/find where \ -:if ([ :len [ /interface/wifi/access-list/find where \ -:if ([ :len [ /interface/wifiwave2/access-list/find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - /interface/wifiwave2/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; -} -:local Template [ /caps-man/access-list/get ([ find where \ -:local Template [ /interface/wifi/access-list/get ([ find where \ -:local Template [ /interface/wifiwave2/access-list/get ([ find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; - -:if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; -} - -# allow login page to load -:delay 1s; - -$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ").") false; -/caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; -/interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; -/interface/wifiwave2/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; -/caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ -/interface/wifi/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ -/interface/wifiwave2/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - action=reject place-before=$PlaceBefore; - -:local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ -:local Entry [ /interface/wifi/access-list/find where mac-address=$MacAddress \ -:local Entry [ /interface/wifiwave2/access-list/find where mac-address=$MacAddress \ - comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; -# NOT /caps-man/ # -:set ($Template->"private-passphrase") ($Template->"passphrase"); -# NOT /caps-man/ # -:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; -:if ([ :len $PrivatePassphrase ] > 0) do={ - :if ($PrivatePassphrase = "ignore") do={ - /caps-man/access-list/set $Entry !private-passphrase; - /interface/wifi/access-list/set $Entry !passphrase; - /interface/wifiwave2/access-list/set $Entry !passphrase; - } else={ - /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; - /interface/wifi/access-list/set $Entry passphrase=$PrivatePassphrase; - /interface/wifiwave2/access-list/set $Entry passphrase=$PrivatePassphrase; + :if ([ :len $MacAddress ] = 0 || [ :len $UserName ] = 0) do={ + $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; + } + + :local Date [ /system/clock/get date ]; + :local UserVal ({}); + :if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ + :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; + } + :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; + :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; + + :if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + :if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + :if ([ :len [ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + /interface/wifiwave2/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; + } + :local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + :local PlaceBefore ([ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + + :if ([ :len [ /caps-man/access-list/find where \ + :if ([ :len [ /interface/wifi/access-list/find where \ + :if ([ :len [ /interface/wifiwave2/access-list/find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ + /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + /interface/wifiwave2/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + $LogPrintExit2 warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; + } + :local Template [ /caps-man/access-list/get ([ find where \ + :local Template [ /interface/wifi/access-list/get ([ find where \ + :local Template [ /interface/wifiwave2/access-list/get ([ find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; + + :if ($Template->"action" = "reject") do={ + $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") true; + } + + # allow login page to load + :delay 1s; + + $LogPrintExit2 info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ").") false; + /caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; + /interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; + /interface/wifiwave2/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; + /caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + /interface/wifi/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + /interface/wifiwave2/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + action=reject place-before=$PlaceBefore; + + :local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ + :local Entry [ /interface/wifi/access-list/find where mac-address=$MacAddress \ + :local Entry [ /interface/wifiwave2/access-list/find where mac-address=$MacAddress \ + comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; +# NOT /caps-man/ # + :set ($Template->"private-passphrase") ($Template->"passphrase"); +# NOT /caps-man/ # + :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; + :if ([ :len $PrivatePassphrase ] > 0) do={ + :if ($PrivatePassphrase = "ignore") do={ + /caps-man/access-list/set $Entry !private-passphrase; + /interface/wifi/access-list/set $Entry !passphrase; + /interface/wifiwave2/access-list/set $Entry !passphrase; + } else={ + /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; + /interface/wifi/access-list/set $Entry passphrase=$PrivatePassphrase; + /interface/wifiwave2/access-list/set $Entry passphrase=$PrivatePassphrase; + } + } + :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; + :if ([ :len $SsidRegexp ] > 0) do={ + /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; + /interface/wifi/access-list/set $Entry ssid-regexp=$SsidRegexp; + /interface/wifiwave2/access-list/set $Entry ssid-regexp=$SsidRegexp; + } + :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; + :if ([ :len $VlanId ] > 0) do={ + /caps-man/access-list/set $Entry vlan-id=$VlanId; + /interface/wifi/access-list/set $Entry vlan-id=$VlanId; + /interface/wifiwave2/access-list/set $Entry vlan-id=$VlanId; } -} -:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; -:if ([ :len $SsidRegexp ] > 0) do={ - /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; - /interface/wifi/access-list/set $Entry ssid-regexp=$SsidRegexp; - /interface/wifiwave2/access-list/set $Entry ssid-regexp=$SsidRegexp; -} -:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; -:if ([ :len $VlanId ] > 0) do={ - /caps-man/access-list/set $Entry vlan-id=$VlanId; - /interface/wifi/access-list/set $Entry vlan-id=$VlanId; - /interface/wifiwave2/access-list/set $Entry vlan-id=$VlanId; -} # NOT /interface/wifi/ # # NOT /interface/wifiwave2/ # -:local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; -:if ([ :len $VlanMode] > 0) do={ - /caps-man/access-list/set $Entry vlan-mode=$VlanMode; -} + :local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; + :if ([ :len $VlanMode] > 0) do={ + /caps-man/access-list/set $Entry vlan-mode=$VlanMode; + } # NOT /interface/wifiwave2/ # # NOT /interface/wifi/ # -:delay 2s; -/caps-man/access-list/set $Entry action=accept; -/interface/wifi/access-list/set $Entry action=accept; -/interface/wifiwave2/access-list/set $Entry action=accept; + :delay 2s; + /caps-man/access-list/set $Entry action=accept; + /interface/wifi/access-list/set $Entry action=accept; + /interface/wifiwave2/access-list/set $Entry action=accept; +} + +$Main [ :jobname ] $"mac-address" $username; diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index 5e07eac..cd6aa80 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -10,79 +10,83 @@ # # !! Do not edit this file, it is generated from template! -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; + :local MacAddress [ :tostr $2 ]; + :local UserName [ :tostr $3 ]; -$ScriptLock $0; + :global EitherOr; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptLock; -:local MacAddress $"mac-address"; -:local UserName $username; + $ScriptLock $ScriptName; -:if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from hotspot on login.") true; -} - -:local Date [ /system/clock/get date ]; -:local UserVal ({}); -:if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ - :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; -} -:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; -:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; - -:if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; -} -:local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - -:if ([ :len [ /interface/wifi/access-list/find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; -} -:local Template [ /interface/wifi/access-list/get ([ find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; - -:if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; -} - -# allow login page to load -:delay 1s; - -$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ").") false; -/interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; -/interface/wifi/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - action=reject place-before=$PlaceBefore; - -:local Entry [ /interface/wifi/access-list/find where mac-address=$MacAddress \ - comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; -:set ($Template->"private-passphrase") ($Template->"passphrase"); -:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; -:if ([ :len $PrivatePassphrase ] > 0) do={ - :if ($PrivatePassphrase = "ignore") do={ - /interface/wifi/access-list/set $Entry !passphrase; - } else={ - /interface/wifi/access-list/set $Entry passphrase=$PrivatePassphrase; + :if ([ :len $MacAddress ] = 0 || [ :len $UserName ] = 0) do={ + $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; } -} -:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; -:if ([ :len $SsidRegexp ] > 0) do={ - /interface/wifi/access-list/set $Entry ssid-regexp=$SsidRegexp; -} -:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; -:if ([ :len $VlanId ] > 0) do={ - /interface/wifi/access-list/set $Entry vlan-id=$VlanId; + + :local Date [ /system/clock/get date ]; + :local UserVal ({}); + :if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ + :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; + } + :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; + :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; + + :if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; + } + :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + + :if ([ :len [ /interface/wifi/access-list/find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ + /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + $LogPrintExit2 warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; + } + :local Template [ /interface/wifi/access-list/get ([ find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; + + :if ($Template->"action" = "reject") do={ + $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") true; + } + + # allow login page to load + :delay 1s; + + $LogPrintExit2 info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ").") false; + /interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; + /interface/wifi/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + action=reject place-before=$PlaceBefore; + + :local Entry [ /interface/wifi/access-list/find where mac-address=$MacAddress \ + comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; + :set ($Template->"private-passphrase") ($Template->"passphrase"); + :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; + :if ([ :len $PrivatePassphrase ] > 0) do={ + :if ($PrivatePassphrase = "ignore") do={ + /interface/wifi/access-list/set $Entry !passphrase; + } else={ + /interface/wifi/access-list/set $Entry passphrase=$PrivatePassphrase; + } + } + :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; + :if ([ :len $SsidRegexp ] > 0) do={ + /interface/wifi/access-list/set $Entry ssid-regexp=$SsidRegexp; + } + :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; + :if ([ :len $VlanId ] > 0) do={ + /interface/wifi/access-list/set $Entry vlan-id=$VlanId; + } + + :delay 2s; + /interface/wifi/access-list/set $Entry action=accept; } -:delay 2s; -/interface/wifi/access-list/set $Entry action=accept; +$Main [ :jobname ] $"mac-address" $username; diff --git a/hotspot-to-wpa.wifiwave2.rsc b/hotspot-to-wpa.wifiwave2.rsc index 751c1bf..ef068b6 100644 --- a/hotspot-to-wpa.wifiwave2.rsc +++ b/hotspot-to-wpa.wifiwave2.rsc @@ -10,79 +10,83 @@ # # !! Do not edit this file, it is generated from template! -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; + :local MacAddress [ :tostr $2 ]; + :local UserName [ :tostr $3 ]; -$ScriptLock $0; + :global EitherOr; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptLock; -:local MacAddress $"mac-address"; -:local UserName $username; + $ScriptLock $ScriptName; -:if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from hotspot on login.") true; -} - -:local Date [ /system/clock/get date ]; -:local UserVal ({}); -:if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ - :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; -} -:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; -:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; - -:if ([ :len [ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - /interface/wifiwave2/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; -} -:local PlaceBefore ([ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - -:if ([ :len [ /interface/wifiwave2/access-list/find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - /interface/wifiwave2/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; -} -:local Template [ /interface/wifiwave2/access-list/get ([ find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; - -:if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; -} - -# allow login page to load -:delay 1s; - -$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ").") false; -/interface/wifiwave2/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; -/interface/wifiwave2/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - action=reject place-before=$PlaceBefore; - -:local Entry [ /interface/wifiwave2/access-list/find where mac-address=$MacAddress \ - comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; -:set ($Template->"private-passphrase") ($Template->"passphrase"); -:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; -:if ([ :len $PrivatePassphrase ] > 0) do={ - :if ($PrivatePassphrase = "ignore") do={ - /interface/wifiwave2/access-list/set $Entry !passphrase; - } else={ - /interface/wifiwave2/access-list/set $Entry passphrase=$PrivatePassphrase; + :if ([ :len $MacAddress ] = 0 || [ :len $UserName ] = 0) do={ + $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; } -} -:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; -:if ([ :len $SsidRegexp ] > 0) do={ - /interface/wifiwave2/access-list/set $Entry ssid-regexp=$SsidRegexp; -} -:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; -:if ([ :len $VlanId ] > 0) do={ - /interface/wifiwave2/access-list/set $Entry vlan-id=$VlanId; + + :local Date [ /system/clock/get date ]; + :local UserVal ({}); + :if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ + :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; + } + :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; + :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; + + :if ([ :len [ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + /interface/wifiwave2/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; + } + :local PlaceBefore ([ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + + :if ([ :len [ /interface/wifiwave2/access-list/find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ + /interface/wifiwave2/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + $LogPrintExit2 warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; + } + :local Template [ /interface/wifiwave2/access-list/get ([ find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; + + :if ($Template->"action" = "reject") do={ + $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") true; + } + + # allow login page to load + :delay 1s; + + $LogPrintExit2 info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ").") false; + /interface/wifiwave2/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; + /interface/wifiwave2/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + action=reject place-before=$PlaceBefore; + + :local Entry [ /interface/wifiwave2/access-list/find where mac-address=$MacAddress \ + comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; + :set ($Template->"private-passphrase") ($Template->"passphrase"); + :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; + :if ([ :len $PrivatePassphrase ] > 0) do={ + :if ($PrivatePassphrase = "ignore") do={ + /interface/wifiwave2/access-list/set $Entry !passphrase; + } else={ + /interface/wifiwave2/access-list/set $Entry passphrase=$PrivatePassphrase; + } + } + :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; + :if ([ :len $SsidRegexp ] > 0) do={ + /interface/wifiwave2/access-list/set $Entry ssid-regexp=$SsidRegexp; + } + :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; + :if ([ :len $VlanId ] > 0) do={ + /interface/wifiwave2/access-list/set $Entry vlan-id=$VlanId; + } + + :delay 2s; + /interface/wifiwave2/access-list/set $Entry action=accept; } -:delay 2s; -/interface/wifiwave2/access-list/set $Entry action=accept; +$Main [ :jobname ] $"mac-address" $username; From 85dbe3a868e4522311d78ba57595356ef756e421 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1915/2612] ipsec-to-dns: move code into function --- ipsec-to-dns.rsc | 105 +++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 50 deletions(-) diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index 512ef68..ff445e6 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -8,67 +8,72 @@ # and add/remove/update DNS entries from IPSec mode-config # https://git.eworm.de/cgit/routeros-scripts/about/doc/ipsec-to-dns.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Domain; -:global HostNameInZone; -:global Identity; -:global PrefixInZone; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global CharacterReplace; -:global EscapeForRegEx; -:global IfThenElse; -:global LogPrintExit2; -:global ScriptLock; + :global Domain; + :global HostNameInZone; + :global Identity; + :global PrefixInZone; -$ScriptLock $0; + :global CharacterReplace; + :global EscapeForRegEx; + :global IfThenElse; + :global LogPrintExit2; + :global ScriptLock; -:local Zone \ - ([ $IfThenElse ($PrefixInZone = true) "ipsec." ] . \ - [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); -:local Ttl 5m; -:local CommentPrefix ("managed by " . $0 . " for "); -:local CommentString ("--- " . $0 . " above ---"); + $ScriptLock $ScriptName; -: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); + :local Zone \ + ([ $IfThenElse ($PrefixInZone = true) "ipsec." ] . \ + [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); + :local Ttl 5m; + :local CommentPrefix ("managed by " . $ScriptName . " for "); + :local CommentString ("--- " . $ScriptName . " above ---"); -:foreach DnsRecord in=[ /ip/dns/static/find where comment~("^" . $CommentPrefix) ] do={ - :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; - :local PeerId [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; - :if ([ :len [ /ip/ipsec/active-peers/find where id~("^(CN=)?" . [ $EscapeForRegEx $PeerId ] . "\$") \ - dynamic-address=($DnsRecordVal->"address") ] ] > 0) do={ - $LogPrintExit2 debug $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; - } else={ - :local Found false; - $LogPrintExit2 info $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") has gone, deleting DNS entry.") false; - /ip/dns/static/remove $DnsRecord; + :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 $ScriptName ("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 Peer in=[ /ip/ipsec/active-peers/find where !(dynamic-address=[]) ] do={ - :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; - :local PeerId [ $CharacterReplace ($PeerVal->"id") "CN=" "" ]; - :local Comment ($CommentPrefix . $PeerId); - :local HostName [ :pick $PeerId 0 [ :find ($PeerId . ".") "." ] ]; - - :local Fqdn ($HostName . "." . $Zone); - :local DnsRecord [ /ip/dns/static/find where name=$Fqdn ]; - :if ([ :len $DnsRecord ] > 0) do={ - :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; - :if ($DnsIp = $PeerVal->"dynamic-address") do={ - $LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false; + :foreach DnsRecord in=[ /ip/dns/static/find where comment~("^" . $CommentPrefix) ] do={ + :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; + :local PeerId [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; + :if ([ :len [ /ip/ipsec/active-peers/find where id~("^(CN=)?" . [ $EscapeForRegEx $PeerId ] . "\$") \ + dynamic-address=($DnsRecordVal->"address") ] ] > 0) do={ + $LogPrintExit2 debug $ScriptName ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; } else={ - $LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $PeerVal->"dynamic-address" . ".") false; - /ip/dns/static/set name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment $DnsRecord; + :local Found false; + $LogPrintExit2 info $ScriptName ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") has gone, deleting DNS entry.") false; + /ip/dns/static/remove $DnsRecord; + } + } + + :foreach Peer in=[ /ip/ipsec/active-peers/find where !(dynamic-address=[]) ] do={ + :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; + :local PeerId [ $CharacterReplace ($PeerVal->"id") "CN=" "" ]; + :local Comment ($CommentPrefix . $PeerId); + :local HostName [ :pick $PeerId 0 [ :find ($PeerId . ".") "." ] ]; + + :local Fqdn ($HostName . "." . $Zone); + :local DnsRecord [ /ip/dns/static/find where name=$Fqdn ]; + :if ([ :len $DnsRecord ] > 0) do={ + :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; + :if ($DnsIp = $PeerVal->"dynamic-address") do={ + $LogPrintExit2 debug $ScriptName ("DNS entry for " . $Fqdn . " does not need updating.") false; + } else={ + $LogPrintExit2 info $ScriptName ("Replacing DNS entry for " . $Fqdn . ", new address is " . $PeerVal->"dynamic-address" . ".") false; + /ip/dns/static/set name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment $DnsRecord; + } + } else={ + $LogPrintExit2 info $ScriptName ("Adding new DNS entry for " . $Fqdn . ", address is " . $PeerVal->"dynamic-address" . ".") false; + /ip/dns/static/add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } - } else={ - $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $PeerVal->"dynamic-address" . ".") false; - /ip/dns/static/add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } + +$Main [ :jobname ]; From d6ea66ccd3e2d943808cf001574b3cf979f6231c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1916/2612] ipv6-update: move code into function --- ipv6-update.rsc | 110 +++++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 53 deletions(-) diff --git a/ipv6-update.rsc b/ipv6-update.rsc index 1d7207b..350fc4b 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -8,74 +8,78 @@ # update firewall and dns settings on IPv6 prefix change # https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local PdPrefix $"pd-prefix"; +:local Main do={ + :local ScriptName [ :tostr $1 ]; + :local PdPrefix $2; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptLock; -$ScriptLock $0; + $ScriptLock $ScriptName; -:if ([ :typeof $PdPrefix ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from ipv6 dhcp-client.") true; -} + :if ([ :typeof $PdPrefix ] = "nothing") do={ + $LogPrintExit2 error $ScriptName ("This script is supposed to run from ipv6 dhcp-client.") true; + } -:local Pool [ /ipv6/pool/get [ find where prefix=$PdPrefix ] name ]; -:if ([ :len [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={ - /ipv6/firewall/address-list/add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool); - $LogPrintExit2 warning $0 ("Added ipv6 address list entry for ipv6-pool-" . $Pool) false; -} -:local AddrList [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ]; -:local OldPrefix [ /ipv6/firewall/address-list/get ($AddrList->0) address ]; + :local Pool [ /ipv6/pool/get [ find where prefix=$PdPrefix ] name ]; + :if ([ :len [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={ + /ipv6/firewall/address-list/add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool); + $LogPrintExit2 warning $ScriptName ("Added ipv6 address list entry for ipv6-pool-" . $Pool) false; + } + :local AddrList [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ]; + :local OldPrefix [ /ipv6/firewall/address-list/get ($AddrList->0) address ]; -:if ($OldPrefix != $PdPrefix) do={ - $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix) false; - /ipv6/firewall/address-list/set address=$PdPrefix $AddrList; + :if ($OldPrefix != $PdPrefix) do={ + $LogPrintExit2 info $ScriptName ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix) false; + /ipv6/firewall/address-list/set address=$PdPrefix $AddrList; - # give the interfaces a moment to receive their addresses - :delay 2s; + # give the interfaces a moment to receive their addresses + :delay 2s; - :foreach ListEntry in=[ /ipv6/firewall/address-list/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ - :local ListEntryVal [ /ipv6/firewall/address-list/get $ListEntry ]; - :local Comment [ $ParseKeyValueStore ($ListEntryVal->"comment") ]; + :foreach ListEntry in=[ /ipv6/firewall/address-list/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ + :local ListEntryVal [ /ipv6/firewall/address-list/get $ListEntry ]; + :local Comment [ $ParseKeyValueStore ($ListEntryVal->"comment") ]; - :local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; - :if ([ :len $Prefix ] = 1) do={ - :set Prefix [ /ipv6/address/get $Prefix address ]; + :local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; + :if ([ :len $Prefix ] = 1) do={ + :set Prefix [ /ipv6/address/get $Prefix address ]; - :if ([ :typeof [ :find ($ListEntryVal->"address") "/128" ] ] = "num" ) do={ + :if ([ :typeof [ :find ($ListEntryVal->"address") "/128" ] ] = "num" ) do={ + :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); + :local Address ($ListEntryVal->"address"); + :local Address ($Prefix | ([ :toip6 [ :pick $Address 0 [ :find $Address "/128" ] ] ] & ::ffff:ffff:ffff:ffff)); + + $LogPrintExit2 info $ScriptName ("Updating IPv6 address list with new IPv6 host address " . $Address . \ + " from interface " . ($Comment->"interface")) false; + /ipv6/firewall/address-list/set address=$Address $ListEntry; + } else={ + $LogPrintExit2 info $ScriptName ("Updating IPv6 address list with new IPv6 prefix " . $Prefix . \ + " from interface " . ($Comment->"interface")) false; + /ipv6/firewall/address-list/set address=$Prefix $ListEntry; + } + } + } + + :foreach Record in=[ /ip/dns/static/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ + :local RecordVal [ /ip/dns/static/get $Record ]; + :local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ]; + + :local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; + :if ([ :len $Prefix ] = 1) do={ + :set Prefix [ /ipv6/address/get $Prefix address ]; :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); - :local Address ($ListEntryVal->"address"); - :local Address ($Prefix | ([ :toip6 [ :pick $Address 0 [ :find $Address "/128" ] ] ] & ::ffff:ffff:ffff:ffff)); + :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); - $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 host address " . $Address . \ - " from interface " . ($Comment->"interface")) false; - /ipv6/firewall/address-list/set address=$Address $ListEntry; - } else={ - $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $Prefix . \ - " from interface " . ($Comment->"interface")) false; - /ipv6/firewall/address-list/set address=$Prefix $ListEntry; + $LogPrintExit2 info $ScriptName ("Updating DNS record for " . ($RecordVal->"name") . \ + ($RecordVal->"regexp") . " to " . $Address) false; + /ip/dns/static/set address=$Address $Record; } } } - - :foreach Record in=[ /ip/dns/static/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ - :local RecordVal [ /ip/dns/static/get $Record ]; - :local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ]; - - :local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; - :if ([ :len $Prefix ] = 1) do={ - :set Prefix [ /ipv6/address/get $Prefix address ]; - :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); - :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); - - $LogPrintExit2 info $0 ("Updating DNS record for " . ($RecordVal->"name") . \ - ($RecordVal->"regexp") . " to " . $Address) false; - /ip/dns/static/set address=$Address $Record; - } - } } + +$Main [ :jobname ] $"pd-prefix"; From 49650d8b14541f96784948e88504629fd24d53ce Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1917/2612] lease-script: move code into function --- lease-script.rsc | 69 +++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/lease-script.rsc b/lease-script.rsc index aae74f8..d9c7177 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -8,45 +8,54 @@ # run scripts on DHCP lease # https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Grep; -:global IfThenElse; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; + :local leaseActIP [ :tostr $2 ]; + :local leaseActMAC [ :tostr $2 ]; + :local leaseServerName [ :tostr $2 ]; + :local leaseBound [ :tostr $2 ]; -:if ([ :typeof $leaseActIP ] = "nothing" || \ - [ :typeof $leaseActMAC ] = "nothing" || \ - [ :typeof $leaseServerName ] = "nothing" || \ - [ :typeof $leaseBound ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from ip dhcp-server.") true; -} + :global Grep; + :global IfThenElse; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptLock; -$LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \ - "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC) false; + :if ([ :typeof $leaseActIP ] = "nothing" || \ + [ :typeof $leaseActMAC ] = "nothing" || \ + [ :typeof $leaseServerName ] = "nothing" || \ + [ :typeof $leaseBound ] = "nothing") do={ + $LogPrintExit2 error $ScriptName ("This script is supposed to run from ip dhcp-server.") true; + } -$ScriptLock $0 false 10; + $LogPrintExit2 debug $ScriptName ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \ + "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC) false; -:if ([ :len [ /system/script/job/find where script=$0 ] ] > 1) do={ - $LogPrintExit2 debug $0 ("More invocations are waiting, exiting early.") true; -} + $ScriptLock $ScriptName false 10; -:local RunOrder ({}); -:foreach Script in=[ /system/script/find where source~("\n# provides: lease-script\\b") ] do={ - :local ScriptVal [ /system/script/get $Script ]; - :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") ("\23 provides: lease-script, ") ] ]; + :if ([ :len [ /system/script/job/find where script=$ScriptName ] ] > 1) do={ + $LogPrintExit2 debug $ScriptName ("More invocations are waiting, exiting early.") true; + } - :set ($RunOrder->($Store->"order" . "-" . $ScriptVal->"name")) ($ScriptVal->"name"); -} + :local RunOrder ({}); + :foreach Script in=[ /system/script/find where source~("\n# provides: lease-script\\b") ] do={ + :local ScriptVal [ /system/script/get $Script ]; + :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") ("\23 provides: lease-script, ") ] ]; -:foreach Order,Script in=$RunOrder do={ - :do { - $LogPrintExit2 debug $0 ("Running script with order " . $Order . ": " . $Script) false; - /system/script/run $Script; - } on-error={ - $LogPrintExit2 warning $0 ("Running script '" . $Script . "' failed!") false; + :set ($RunOrder->($Store->"order" . "-" . $ScriptVal->"name")) ($ScriptVal->"name"); + } + + :foreach Order,Script in=$RunOrder do={ + :do { + $LogPrintExit2 debug $ScriptName ("Running script with order " . $Order . ": " . $Script) false; + /system/script/run $Script; + } on-error={ + $LogPrintExit2 warning $ScriptName ("Running script '" . $Script . "' failed!") false; + } } } + +$Main [ :jobname ] $leaseActIP $leaseActMAC $leaseServerName $leaseBound; From 50e1c45880d94ce1d746cc9ad8ede4db826731f6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1918/2612] log-forward: move code into function --- log-forward.rsc | 149 +++++++++++++++++++++++++----------------------- 1 file changed, 77 insertions(+), 72 deletions(-) diff --git a/log-forward.rsc b/log-forward.rsc index 69fa1f1..13b490e 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -8,89 +8,94 @@ # forward log messages via notification # https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Identity; -:global LogForwardFilter; -:global LogForwardFilterMessage; -:global LogForwardInclude; -:global LogForwardIncludeMessage; -:global LogForwardLast; -:global LogForwardRateLimit; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global EitherOr; -:global HexToNum; -:global IfThenElse; -:global LogForwardFilterLogForwarding; -:global LogPrintExit2; -:global MAX; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; + :global Identity; + :global LogForwardFilter; + :global LogForwardFilterMessage; + :global LogForwardInclude; + :global LogForwardIncludeMessage; + :global LogForwardLast; + :global LogForwardRateLimit; -$ScriptLock $0; + :global EitherOr; + :global HexToNum; + :global IfThenElse; + :global LogForwardFilterLogForwarding; + :global LogPrintExit2; + :global MAX; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; -:if ([ :typeof $LogForwardRateLimit ] = "nothing") do={ - :set LogForwardRateLimit 0; -} + $ScriptLock $ScriptName; -:if ($LogForwardRateLimit > 30) do={ - :set LogForwardRateLimit ($LogForwardRateLimit - 1); - $LogPrintExit2 info $0 ("Rate limit in action, not forwarding logs, if any!") true; -} + :if ([ :typeof $LogForwardRateLimit ] = "nothing") do={ + :set LogForwardRateLimit 0; + } -:local Count 0; -:local Duplicates false; -:local Last [ $IfThenElse ([ :len $LogForwardLast ] > 0) [ $HexToNum $LogForwardLast ] -1 ]; -:local Messages ""; -:local Warning false; -:local MessageVal; -:local MessageDups ({}); + :if ($LogForwardRateLimit > 30) do={ + :set LogForwardRateLimit ($LogForwardRateLimit - 1); + $LogPrintExit2 info $ScriptName ("Rate limit in action, not forwarding logs, if any!") true; + } -:local LogForwardFilterLogForwardingCached [ $EitherOr [ $LogForwardFilterLogForwarding ] ("\$^") ]; -:foreach Message in=[ /log/find where (!(message="") and \ - !(message~$LogForwardFilterLogForwardingCached) and \ - !(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \ - topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={ - :set MessageVal [ /log/get $Message ]; - :local Bullet "information"; + :local Count 0; + :local Duplicates false; + :local Last [ $IfThenElse ([ :len $LogForwardLast ] > 0) [ $HexToNum $LogForwardLast ] -1 ]; + :local Messages ""; + :local Warning false; + :local MessageVal; + :local MessageDups ({}); - :if ($Last < [ $HexToNum ($MessageVal->".id") ]) do={ - :local DupCount ($MessageDups->($MessageVal->"message")); - :if ($MessageVal->"topics" ~ "(warning)") do={ - :set Warning true; - :set Bullet "large-orange-circle"; + :local LogForwardFilterLogForwardingCached [ $EitherOr [ $LogForwardFilterLogForwarding ] ("\$^") ]; + :foreach Message in=[ /log/find where (!(message="") and \ + !(message~$LogForwardFilterLogForwardingCached) and \ + !(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \ + topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={ + :set MessageVal [ /log/get $Message ]; + :local Bullet "information"; + + :if ($Last < [ $HexToNum ($MessageVal->".id") ]) do={ + :local DupCount ($MessageDups->($MessageVal->"message")); + :if ($MessageVal->"topics" ~ "(warning)") do={ + :set Warning true; + :set Bullet "large-orange-circle"; + } + :if ($MessageVal->"topics" ~ "(emergency|alert|critical|error)") do={ + :set Warning true; + :set Bullet "large-red-circle"; + } + :if ($DupCount < 3) do={ + :set Messages ($Messages . "\n" . [ $SymbolForNotification $Bullet ] . \ + $MessageVal->"time" . " " . [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message"); + } else={ + :set Duplicates true; + } + :set ($MessageDups->($MessageVal->"message")) ($DupCount + 1); + :set Count ($Count + 1); } - :if ($MessageVal->"topics" ~ "(emergency|alert|critical|error)") do={ - :set Warning true; - :set Bullet "large-red-circle"; - } - :if ($DupCount < 3) do={ - :set Messages ($Messages . "\n" . [ $SymbolForNotification $Bullet ] . \ - $MessageVal->"time" . " " . [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message"); - } else={ - :set Duplicates true; - } - :set ($MessageDups->($MessageVal->"message")) ($DupCount + 1); - :set Count ($Count + 1); + } + + :if ($Count > 0) do={ + :set LogForwardRateLimit ($LogForwardRateLimit + 10); + + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification [ $IfThenElse ($Warning = true) "warning-sign" "memo" ] ] . \ + "Log Forwarding"); \ + message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) "this message" \ + ("these " . $Count . " messages") ] . " after " . [ /system/resource/get uptime ] . " uptime." . \ + [ $IfThenElse ($Duplicates = true) (" Multi-repeated messages have been skipped.") ] . \ + [ $IfThenElse ($LogForwardRateLimit > 30) ("\nRate limit in action, delaying forwarding.") ] . \ + "\n" . $Messages) }); + + :set LogForwardLast ($MessageVal->".id"); + } else={ + :set LogForwardRateLimit [ $MAX 0 ($LogForwardRateLimit - 1) ]; } } -:if ($Count > 0) do={ - :set LogForwardRateLimit ($LogForwardRateLimit + 10); - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification [ $IfThenElse ($Warning = true) "warning-sign" "memo" ] ] . \ - "Log Forwarding"); \ - message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) "this message" \ - ("these " . $Count . " messages") ] . " after " . [ /system/resource/get uptime ] . " uptime." . \ - [ $IfThenElse ($Duplicates = true) (" Multi-repeated messages have been skipped.") ] . \ - [ $IfThenElse ($LogForwardRateLimit > 30) ("\nRate limit in action, delaying forwarding.") ] . \ - "\n" . $Messages) }); - - :set LogForwardLast ($MessageVal->".id"); -} else={ - :set LogForwardRateLimit [ $MAX 0 ($LogForwardRateLimit - 1) ]; -} +$Main [ :jobname ]; From 400516295ed5187278b0e6791fc4dc98914cf840 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1919/2612] mode-button: move code into function --- mode-button.rsc | 107 +++++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 51 deletions(-) diff --git a/mode-button.rsc b/mode-button.rsc index 372b2de..0cd9167 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -8,71 +8,76 @@ # act on multiple mode and reset button presses # https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global ModeButton; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global LogPrintExit2; + :global ModeButton; -:set ($ModeButton->"count") ($ModeButton->"count" + 1); + :global LogPrintExit2; -:local Scheduler [ /system/scheduler/find where name="_ModeButtonScheduler" ]; + :set ($ModeButton->"count") ($ModeButton->"count" + 1); -:if ([ :len $Scheduler ] = 0) do={ - $LogPrintExit2 info $0 ("Creating scheduler _ModeButtonScheduler, counting presses...") false; - :global ModeButtonScheduler do={ - :global ModeButton; + :local Scheduler [ /system/scheduler/find where name="_ModeButtonScheduler" ]; - :global LogPrintExit2; - :global ModeButtonScheduler; - :global ValidateSyntax; + :if ([ :len $Scheduler ] = 0) do={ + $LogPrintExit2 info $ScriptName ("Creating scheduler _ModeButtonScheduler, counting presses...") false; + :global ModeButtonScheduler do={ + :global ModeButton; - :local LEDInvert do={ - :global ModeButtonLED; + :global LogPrintExit2; + :global ModeButtonScheduler; + :global ValidateSyntax; - :global IfThenElse; + :local LEDInvert do={ + :global ModeButtonLED; - :local LED [ /system/leds/find where leds=$ModeButtonLED type~"^(on|off)\$" interface=[] ]; - :if ([ :len $LED ] = 0) do={ - :return false; - } - /system/leds/set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED; - } + :global IfThenElse; - :local Count ($ModeButton->"count"); - :local Code ($ModeButton->[ :tostr $Count ]); - - :set ($ModeButton->"count") 0; - :set ModeButtonScheduler; - /system/scheduler/remove [ find where name="_ModeButtonScheduler" ]; - - :if ([ :len $Code ] > 0) do={ - :if ([ $ValidateSyntax $Code ] = true) do={ - $LogPrintExit2 info $0 ("Acting on " . $Count . " mode-button presses: " . $Code) false; - - :for I from=1 to=$Count do={ - $LEDInvert; - :if ([ /system/routerboard/settings/get silent-boot ] = false) do={ - :beep length=200ms; - } - :delay 200ms; - $LEDInvert; - :delay 200ms; + :local LED [ /system/leds/find where leds=$ModeButtonLED type~"^(on|off)\$" interface=[] ]; + :if ([ :len $LED ] = 0) do={ + :return false; } - - [ :parse $Code ]; - } else={ - $LogPrintExit2 warning $0 ("The code for " . $Count . " mode-button presses failed syntax validation!") false; + /system/leds/set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED; + } + + :local Count ($ModeButton->"count"); + :local Code ($ModeButton->[ :tostr $Count ]); + + :set ($ModeButton->"count") 0; + :set ModeButtonScheduler; + /system/scheduler/remove [ find where name="_ModeButtonScheduler" ]; + + :if ([ :len $Code ] > 0) do={ + :if ([ $ValidateSyntax $Code ] = true) do={ + $LogPrintExit2 info $ScriptName ("Acting on " . $Count . " mode-button presses: " . $Code) false; + + :for I from=1 to=$Count do={ + $LEDInvert; + :if ([ /system/routerboard/settings/get silent-boot ] = false) do={ + :beep length=200ms; + } + :delay 200ms; + $LEDInvert; + :delay 200ms; + } + + [ :parse $Code ]; + } else={ + $LogPrintExit2 warning $ScriptName ("The code for " . $Count . " mode-button presses failed syntax validation!") false; + } + } else={ + $LogPrintExit2 info $ScriptName ("No action defined for " . $Count . " mode-button presses.") false; } - } else={ - $LogPrintExit2 info $0 ("No action defined for " . $Count . " mode-button presses.") false; } + /system/scheduler/add name="_ModeButtonScheduler" \ + on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s; + } else={ + $LogPrintExit2 debug $ScriptName ("Updating scheduler _ModeButtonScheduler...") false; + /system/scheduler/set $Scheduler start-time=[ /system/clock/get time ]; } - /system/scheduler/add name="_ModeButtonScheduler" \ - on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s; -} else={ - $LogPrintExit2 debug $0 ("Updating scheduler _ModeButtonScheduler...") false; - /system/scheduler/set $Scheduler start-time=[ /system/clock/get time ]; } + +$Main [ :jobname ]; From 458fd1fdcd6b354d0addfd814f4e10c0443d5d53 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1920/2612] netwatch-dns: move code into function --- netwatch-dns.rsc | 191 ++++++++++++++++++++++++----------------------- 1 file changed, 98 insertions(+), 93 deletions(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 3b98a32..45c12d4 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -8,116 +8,121 @@ # monitor and manage dns/doh with netwatch # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-dns.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global CertificateAvailable; -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global CertificateAvailable; + :global EitherOr; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptLock; -:local SettleTime (5m30s - [ /system/resource/get uptime ]); -:if ($SettleTime > 0s) do={ - $LogPrintExit2 info $0 ("System just booted, giving netwatch " . $SettleTime . " to settle.") true; -} + $ScriptLock $ScriptName; -:local DnsServers ({}); -:local DnsFallback ({}); -:local DnsCurrent [ /ip/dns/get servers ]; + :local SettleTime (5m30s - [ /system/resource/get uptime ]); + :if ($SettleTime > 0s) do={ + $LogPrintExit2 info $ScriptName ("System just booted, giving netwatch " . $SettleTime . " to settle.") true; + } -:foreach Host in=[ /tool/netwatch/find where comment~"\\bdns\\b" status="up" ] do={ - :local HostVal [ /tool/netwatch/get $Host ]; - :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; + :local DnsServers ({}); + :local DnsFallback ({}); + :local DnsCurrent [ /ip/dns/get servers ]; - :if ($HostInfo->"disabled" != true) do={ - :if ($HostInfo->"dns" = true) do={ - :set DnsServers ($DnsServers, $HostVal->"host"); - } - :if ($HostInfo->"dns-fallback" = true) do={ - :set DnsFallback ($DnsFallback, $HostVal->"host"); + :foreach Host in=[ /tool/netwatch/find where comment~"\\bdns\\b" status="up" ] do={ + :local HostVal [ /tool/netwatch/get $Host ]; + :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; + + :if ($HostInfo->"disabled" != true) do={ + :if ($HostInfo->"dns" = true) do={ + :set DnsServers ($DnsServers, $HostVal->"host"); + } + :if ($HostInfo->"dns-fallback" = true) do={ + :set DnsFallback ($DnsFallback, $HostVal->"host"); + } } } -} -:if ([ :len $DnsServers ] > 0) do={ - :if ($DnsServers != $DnsCurrent) do={ - $LogPrintExit2 info $0 ("Updating DNS servers: " . [ :tostr $DnsServers ]) false; - /ip/dns/set servers=$DnsServers; + :if ([ :len $DnsServers ] > 0) do={ + :if ($DnsServers != $DnsCurrent) do={ + $LogPrintExit2 info $ScriptName ("Updating DNS servers: " . [ :tostr $DnsServers ]) false; + /ip/dns/set servers=$DnsServers; + /ip/dns/cache/flush; + } + } else={ + :if ([ :len $DnsFallback ] > 0) do={ + :if ($DnsFallback != $DnsCurrent) do={ + $LogPrintExit2 info $ScriptName ("Updating DNS servers to fallback: " . \ + [ :tostr $DnsFallback ]) false; + /ip/dns/set servers=$DnsFallback; + /ip/dns/cache/flush; + } + } + } + + :local DohCurrent [ /ip/dns/get use-doh-server ]; + :local DohServers ({}); + + :foreach Host in=[ /tool/netwatch/find where comment~"\\bdoh\\b" status="up" ] do={ + :local HostVal [ /tool/netwatch/get $Host ]; + :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; + :local HostName [ /ip/dns/static/find where name address=($HostVal->"host") \ + (!type or type="A" or type="AAAA") !disabled !dynamic ]; + :if ([ :len $HostName ] > 0) do={ + :set HostName [ /ip/dns/static/get ($HostName->0) name ]; + } + + :if ($HostInfo->"doh" = true && $HostInfo->"disabled" != true) do={ + :if ([ :len ($HostInfo->"doh-url") ] = 0) do={ + :set ($HostInfo->"doh-url") ("https://" . [ $EitherOr $HostName ($HostVal->"host") ] . "/dns-query"); + } + + :if ($DohCurrent = $HostInfo->"doh-url") do={ + $LogPrintExit2 debug $ScriptName ("Current DoH server is still up: " . $DohCurrent) true; + } + + :set ($DohServers->[ :len $DohServers ]) $HostInfo; + } + } + + :if ([ :len $DohCurrent ] > 0) do={ + $LogPrintExit2 info $ScriptName ("Current DoH server is down, disabling: " . $DohCurrent) false; + /ip/dns/set use-doh-server=""; /ip/dns/cache/flush; } -} else={ - :if ([ :len $DnsFallback ] > 0) do={ - :if ($DnsFallback != $DnsCurrent) do={ - $LogPrintExit2 info $0 ("Updating DNS servers to fallback: " . \ - [ :tostr $DnsFallback ]) false; - /ip/dns/set servers=$DnsFallback; - /ip/dns/cache/flush; - } - } -} -:local DohCurrent [ /ip/dns/get use-doh-server ]; -:local DohServers ({}); - -:foreach Host in=[ /tool/netwatch/find where comment~"\\bdoh\\b" status="up" ] do={ - :local HostVal [ /tool/netwatch/get $Host ]; - :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; - :local HostName [ /ip/dns/static/find where name address=($HostVal->"host") \ - (!type or type="A" or type="AAAA") !disabled !dynamic ]; - :if ([ :len $HostName ] > 0) do={ - :set HostName [ /ip/dns/static/get ($HostName->0) name ]; - } - - :if ($HostInfo->"doh" = true && $HostInfo->"disabled" != true) do={ - :if ([ :len ($HostInfo->"doh-url") ] = 0) do={ - :set ($HostInfo->"doh-url") ("https://" . [ $EitherOr $HostName ($HostVal->"host") ] . "/dns-query"); + :foreach DohServer in=$DohServers do={ + :if ([ :len ($DohServer->"doh-cert") ] > 0) do={ + :if ([ $CertificateAvailable ($DohServer->"doh-cert") ] = false) do={ + $LogPrintExit2 warning $ScriptName ("Downloading certificate failed, trying without.") false; + } } - :if ($DohCurrent = $HostInfo->"doh-url") do={ - $LogPrintExit2 debug $0 ("Current DoH server is still up: " . $DohCurrent) true; - } - - :set ($DohServers->[ :len $DohServers ]) $HostInfo; - } -} - -:if ([ :len $DohCurrent ] > 0) do={ - $LogPrintExit2 info $0 ("Current DoH server is down, disabling: " . $DohCurrent) false; - /ip/dns/set use-doh-server=""; - /ip/dns/cache/flush; -} - -:foreach DohServer in=$DohServers do={ - :if ([ :len ($DohServer->"doh-cert") ] > 0) do={ - :if ([ $CertificateAvailable ($DohServer->"doh-cert") ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; - } - } - - :local Data false; - :do { - :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ - http-header-field=({ "accept: application/dns-message" }) \ - url=(($DohServer->"doh-url") . "?dns=" . [ :convert to=base64 ([ :rndstr length=2 ] . \ - "\01\00" . "\00\01" . "\00\00" . "\00\00" . "\00\00" . "\09doh-check\05eworm\02de\00" . \ - "\00\10" . "\00\01") ]) as-value ]->"data"); - } on-error={ - $LogPrintExit2 warning $0 ("Request to DoH server failed (network or certificate issue): " . \ - ($DohServer->"doh-url")) false; - } - - :if ($Data != false) do={ - :if ([ :typeof [ :find $Data "doh-check-OK" ] ] = "num") do={ - /ip/dns/set use-doh-server=($DohServer->"doh-url") verify-doh-cert=yes; - /ip/dns/cache/flush; - $LogPrintExit2 info $0 ("Setting DoH server: " . ($DohServer->"doh-url")) true; - } else={ - $LogPrintExit2 warning $0 ("Received unexpected response from DoH server: " . \ + :local Data false; + :do { + :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ + http-header-field=({ "accept: application/dns-message" }) \ + url=(($DohServer->"doh-url") . "?dns=" . [ :convert to=base64 ([ :rndstr length=2 ] . \ + "\01\00" . "\00\01" . "\00\00" . "\00\00" . "\00\00" . "\09doh-check\05eworm\02de\00" . \ + "\00\10" . "\00\01") ]) as-value ]->"data"); + } on-error={ + $LogPrintExit2 warning $ScriptName ("Request to DoH server failed (network or certificate issue): " . \ ($DohServer->"doh-url")) false; } + + :if ($Data != false) do={ + :if ([ :typeof [ :find $Data "doh-check-OK" ] ] = "num") do={ + /ip/dns/set use-doh-server=($DohServer->"doh-url") verify-doh-cert=yes; + /ip/dns/cache/flush; + $LogPrintExit2 info $ScriptName ("Setting DoH server: " . ($DohServer->"doh-url")) true; + } else={ + $LogPrintExit2 warning $ScriptName ("Received unexpected response from DoH server: " . \ + ($DohServer->"doh-url")) false; + } + } } } + +$Main [ :jobname ]; From 3c7673891544637ce3086ce380a80e3396102aa4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1921/2612] netwatch-notify: move code into function --- netwatch-notify.rsc | 375 ++++++++++++++++++++++---------------------- 1 file changed, 190 insertions(+), 185 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 8c59af8..28ab229 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -8,208 +8,213 @@ # monitor netwatch and send notifications # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global NetwatchNotify; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global EitherOr; -:global IfThenElse; -:global IsDNSResolving; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptFromTerminal; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; - -:local NetwatchNotifyHook do={ - :local Name [ :tostr $1 ]; - :local Type [ :tostr $2 ]; - :local State [ :tostr $3 ]; - :local Hook [ :tostr $4 ]; + :global NetwatchNotify; + :global EitherOr; + :global IfThenElse; + :global IsDNSResolving; :global LogPrintExit2; - :global ValidateSyntax; + :global ParseKeyValueStore; + :global ScriptFromTerminal; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; - :if ([ $ValidateSyntax $Hook ] = true) do={ - :do { - [ :parse $Hook ]; - } on-error={ + :local NetwatchNotifyHook do={ + :local Name [ :tostr $1 ]; + :local Type [ :tostr $2 ]; + :local State [ :tostr $3 ]; + :local Hook [ :tostr $4 ]; + + :global LogPrintExit2; + :global ValidateSyntax; + + :if ([ $ValidateSyntax $Hook ] = true) do={ + :do { + [ :parse $Hook ]; + } on-error={ + $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . \ + "' failed to run.") false; + :return ("The hook failed to run."); + } + } else={ $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . \ - "' failed to run.") false; - :return ("The hook failed to run."); - } - } else={ - $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . \ - "' failed syntax validation.") false; - :return ("The hook failed syntax validation."); - } - - $LogPrintExit2 info $0 ("Ran hook on " . $Type . " '" . $Name . "' " . $State . ": " . \ - $Hook) false; - :return ("Ran hook:\n" . $Hook); -} - -:local ResolveExpected do={ - :local Name [ :tostr $1 ]; - :local Expected [ :tostr $2 ]; - - :global GetRandom20CharAlNum; - - :local FwAddrList ($0 . "-" . [ $GetRandom20CharAlNum ]); - /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s; - :delay 20ms; - :if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ - :return true; - } - /ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s; - :delay 20ms; - :if ([ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ - :return true; - } - - :return false; -} - -$ScriptLock $0; - -:local ScriptFromTerminalCached [ $ScriptFromTerminal $0 ]; - -:if ([ :typeof $NetwatchNotify ] = "nothing") do={ - :set NetwatchNotify ({}); -} - -:foreach Host in=[ /tool/netwatch/find where comment~"\\bnotify\\b" !disabled status!="unknown" ] do={ - :local HostVal [ /tool/netwatch/get $Host ]; - :local Type [ $IfThenElse ($HostVal->"type" ~ "^(https?-get|tcp-conn)\$") "service" "host" ]; - :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; - :local HostDetails ($HostVal->"host" . \ - [ $IfThenElse ([ :len ($HostInfo->"resolve") ] > 0) (", " . $HostInfo->"resolve") ]); - - :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ - :local Name [ $EitherOr ($HostInfo->"name") ($HostVal->"name") ]; - - :local Metric { "count-down"=0; "count-up"=0; "notified"=false; "resolve-failcnt"=0 }; - :if ([ :typeof ($NetwatchNotify->$Name) ] = "array") do={ - :set $Metric ($NetwatchNotify->$Name); + "' failed syntax validation.") false; + :return ("The hook failed syntax validation."); } - :if ([ :typeof ($HostInfo->"resolve") ] = "str") do={ - :if ([ $IsDNSResolving ] = true) do={ - :do { - :local Resolve [ :resolve ($HostInfo->"resolve") ]; - :if ($Resolve != $HostVal->"host") do={ - :if ([ $ResolveExpected ($HostInfo->"resolve") ($HostVal->"host") ] = false) do={ - $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ + $LogPrintExit2 info $0 ("Ran hook on " . $Type . " '" . $Name . "' " . $State . ": " . \ + $Hook) false; + :return ("Ran hook:\n" . $Hook); + } + + :local ResolveExpected do={ + :local Name [ :tostr $1 ]; + :local Expected [ :tostr $2 ]; + + :global GetRandom20CharAlNum; + + :local FwAddrList ($0 . "-" . [ $GetRandom20CharAlNum ]); + /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s; + :delay 20ms; + :if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ + :return true; + } + /ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s; + :delay 20ms; + :if ([ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ + :return true; + } + + :return false; + } + + $ScriptLock $ScriptName; + + :local ScriptFromTerminalCached [ $ScriptFromTerminal $ScriptName ]; + + :if ([ :typeof $NetwatchNotify ] = "nothing") do={ + :set NetwatchNotify ({}); + } + + :foreach Host in=[ /tool/netwatch/find where comment~"\\bnotify\\b" !disabled status!="unknown" ] do={ + :local HostVal [ /tool/netwatch/get $Host ]; + :local Type [ $IfThenElse ($HostVal->"type" ~ "^(https?-get|tcp-conn)\$") "service" "host" ]; + :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; + :local HostDetails ($HostVal->"host" . \ + [ $IfThenElse ([ :len ($HostInfo->"resolve") ] > 0) (", " . $HostInfo->"resolve") ]); + + :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ + :local Name [ $EitherOr ($HostInfo->"name") ($HostVal->"name") ]; + + :local Metric { "count-down"=0; "count-up"=0; "notified"=false; "resolve-failcnt"=0 }; + :if ([ :typeof ($NetwatchNotify->$Name) ] = "array") do={ + :set $Metric ($NetwatchNotify->$Name); + } + + :if ([ :typeof ($HostInfo->"resolve") ] = "str") do={ + :if ([ $IsDNSResolving ] = true) do={ + :do { + :local Resolve [ :resolve ($HostInfo->"resolve") ]; + :if ($Resolve != $HostVal->"host") do={ + :if ([ $ResolveExpected ($HostInfo->"resolve") ($HostVal->"host") ] = false) do={ + $LogPrintExit2 info $ScriptName ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ + ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ + $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ + ", updating.") false; + /tool/netwatch/set host=$Resolve $Host; + :set ($Metric->"resolve-failcnt") 0; + :set ($HostVal->"status") "unknown"; + } + } + } on-error={ + :set ($Metric->"resolve-failcnt") ($Metric->"resolve-failcnt" + 1); + :if ($Metric->"resolve-failcnt" = 3) do={ + $LogPrintExit2 warning $ScriptName ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \ ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ - $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ - ", updating.") false; - /tool/netwatch/set host=$Resolve $Host; - :set ($Metric->"resolve-failcnt") 0; - :set ($HostVal->"status") "unknown"; + $HostInfo->"name") "" ] . "' failed.") false; } } - } on-error={ - :set ($Metric->"resolve-failcnt") ($Metric->"resolve-failcnt" + 1); - :if ($Metric->"resolve-failcnt" = 3) do={ - $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \ - ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ - $HostInfo->"name") "" ] . "' failed.") false; + } + } + + :if ($HostVal->"status" = "up") do={ + :local CountDown ($Metric->"count-down"); + :if ($CountDown > 0) do={ + $LogPrintExit2 info $ScriptName \ + ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is up.") false; + :set ($Metric->"count-down") 0; + } + :set ($Metric->"count-up") ($Metric->"count-up" + 1); + :if ($Metric->"notified" = true) do={ + :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ + ") is up since " . $HostVal->"since" . ".\n" . \ + "It was down for " . $CountDown . " checks since " . ($Metric->"since") . "."); + :if ([ :typeof ($HostInfo->"note") ] = "str") do={ + :set Message ($Message . "\n\nNote:\n" . ($HostInfo->"note")); } - } - } - } - - :if ($HostVal->"status" = "up") do={ - :local CountDown ($Metric->"count-down"); - :if ($CountDown > 0) do={ - $LogPrintExit2 info $0 \ - ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is up.") false; - :set ($Metric->"count-down") 0; - } - :set ($Metric->"count-up") ($Metric->"count-up" + 1); - :if ($Metric->"notified" = true) do={ - :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ - ") is up since " . $HostVal->"since" . ".\n" . \ - "It was down for " . $CountDown . " checks since " . ($Metric->"since") . "."); - :if ([ :typeof ($HostInfo->"note") ] = "str") do={ - :set Message ($Message . "\n\nNote:\n" . ($HostInfo->"note")); - } - :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "up" \ - ($HostInfo->"up-hook") ]); - } - $SendNotification2 ({ origin=[ $EitherOr ($HostInfo->"origin") $0 ]; silent=($HostInfo->"silent"); \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $Name . " up"); \ - message=$Message }); - } - :set ($Metric->"notified") false; - :set ($Metric->"parent") ($HostInfo->"parent"); - :set ($Metric->"since"); - } - - :if ($HostVal->"status" = "down") do={ - :set ($Metric->"count-down") ($Metric->"count-down" + 1); - :set ($Metric->"count-up") 0; - :set ($Metric->"parent") ($HostInfo->"parent"); - :set ($Metric->"since") ($HostVal->"since"); - :local CountDown [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; - :local Parent ($HostInfo->"parent"); - :local ParentUp false; - :while ([ :len $Parent ] > 0) do={ - :set CountDown ($CountDown + 1); - :set Parent ($NetwatchNotify->$Parent->"parent"); - } - :set Parent ($HostInfo->"parent"); - :local ParentNotified false; - :while ($ParentNotified = false && [ :len $Parent ] > 0) do={ - :set ParentNotified [ $IfThenElse (($NetwatchNotify->$Parent->"notified") = true) \ - true false ]; - :set ParentUp ($NetwatchNotify->$Parent->"count-up"); - :if ($ParentNotified = false) do={ - :set Parent ($NetwatchNotify->$Parent->"parent"); - } - } - :if ($Metric->"notified" = false || $Metric->"count-down" % 120 = 0 || \ - $ScriptFromTerminalCached = true) do={ - $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ - ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is down for " . \ - $Metric->"count-down" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ - ($Metric->"notified" = true) ("already notified.") ($CountDown - $Metric->"count-down" . \ - " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]) false; - } - :if ((($CountDown * 2) - ($Metric->"count-down" * 3)) / 2 = 0 && \ - [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ - $NetwatchNotifyHook $Name $Type "pre-down" ($HostInfo->"pre-down-hook"); - } - :if ($ParentNotified = false && $Metric->"count-down" >= $CountDown && \ - ($ParentUp = false || $ParentUp > 2) && $Metric->"notified" != true) do={ - :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ - ") is down since " . $HostVal->"since" . "."); - :if ([ :typeof ($HostInfo->"note") ] = "str") do={ - :set Message ($Message . "\n\nNote:\n" . ($HostInfo->"note")); - } - :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "down" \ - ($HostInfo->"down-hook") ]); - } - :if ($HostInfo->"no-down-notification" != true) do={ - $SendNotification2 ({ origin=[ $EitherOr ($HostInfo->"origin") $0 ]; silent=($HostInfo->"silent"); \ - subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $Name . " down"); \ + :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "up" \ + ($HostInfo->"up-hook") ]); + } + $SendNotification2 ({ origin=[ $EitherOr ($HostInfo->"origin") $ScriptName ]; silent=($HostInfo->"silent"); \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $Name . " up"); \ message=$Message }); } - :set ($Metric->"notified") true; + :set ($Metric->"notified") false; + :set ($Metric->"parent") ($HostInfo->"parent"); + :set ($Metric->"since"); } - } - :set ($NetwatchNotify->$Name) { - "count-down"=($Metric->"count-down"); - "count-up"=($Metric->"count-up"); - "notified"=($Metric->"notified"); - "parent"=($Metric->"parent"); - "resolve-failcnt"=($Metric->"resolve-failcnt"); - "since"=($Metric->"since") }; + :if ($HostVal->"status" = "down") do={ + :set ($Metric->"count-down") ($Metric->"count-down" + 1); + :set ($Metric->"count-up") 0; + :set ($Metric->"parent") ($HostInfo->"parent"); + :set ($Metric->"since") ($HostVal->"since"); + :local CountDown [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; + :local Parent ($HostInfo->"parent"); + :local ParentUp false; + :while ([ :len $Parent ] > 0) do={ + :set CountDown ($CountDown + 1); + :set Parent ($NetwatchNotify->$Parent->"parent"); + } + :set Parent ($HostInfo->"parent"); + :local ParentNotified false; + :while ($ParentNotified = false && [ :len $Parent ] > 0) do={ + :set ParentNotified [ $IfThenElse (($NetwatchNotify->$Parent->"notified") = true) \ + true false ]; + :set ParentUp ($NetwatchNotify->$Parent->"count-up"); + :if ($ParentNotified = false) do={ + :set Parent ($NetwatchNotify->$Parent->"parent"); + } + } + :if ($Metric->"notified" = false || $Metric->"count-down" % 120 = 0 || \ + $ScriptFromTerminalCached = true) do={ + $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $ScriptName \ + ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is down for " . \ + $Metric->"count-down" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ + ($Metric->"notified" = true) ("already notified.") ($CountDown - $Metric->"count-down" . \ + " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]) false; + } + :if ((($CountDown * 2) - ($Metric->"count-down" * 3)) / 2 = 0 && \ + [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ + $NetwatchNotifyHook $Name $Type "pre-down" ($HostInfo->"pre-down-hook"); + } + :if ($ParentNotified = false && $Metric->"count-down" >= $CountDown && \ + ($ParentUp = false || $ParentUp > 2) && $Metric->"notified" != true) do={ + :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ + ") is down since " . $HostVal->"since" . "."); + :if ([ :typeof ($HostInfo->"note") ] = "str") do={ + :set Message ($Message . "\n\nNote:\n" . ($HostInfo->"note")); + } + :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "down" \ + ($HostInfo->"down-hook") ]); + } + :if ($HostInfo->"no-down-notification" != true) do={ + $SendNotification2 ({ origin=[ $EitherOr ($HostInfo->"origin") $ScriptName ]; silent=($HostInfo->"silent"); \ + subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $Name . " down"); \ + message=$Message }); + } + :set ($Metric->"notified") true; + } + } + + :set ($NetwatchNotify->$Name) { + "count-down"=($Metric->"count-down"); + "count-up"=($Metric->"count-up"); + "notified"=($Metric->"notified"); + "parent"=($Metric->"parent"); + "resolve-failcnt"=($Metric->"resolve-failcnt"); + "since"=($Metric->"since") }; + } } } + +$Main [ :jobname ]; From 09ea05d989b001edd0502789576b9e06ef66dd0e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1922/2612] ospf-to-leds: move code into function --- ospf-to-leds.rsc | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc index 47e1d41..a462d2a 100644 --- a/ospf-to-leds.rsc +++ b/ospf-to-leds.rsc @@ -8,33 +8,38 @@ # visualize ospf instance state via leds # https://git.eworm.de/cgit/routeros-scripts/about/doc/ospf-to-leds.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptLock; -:foreach Instance in=[ /routing/ospf/instance/find where comment~"^ospf-to-leds," ] do={ - :local InstanceVal [ /routing/ospf/instance/get $Instance ]; - :local LED ([ $ParseKeyValueStore ($InstanceVal->"comment") ]->"leds"); - :local LEDType [ /system/leds/get [ find where leds=$LED ] type ]; + $ScriptLock $ScriptName; - :local NeighborCount 0; - :foreach Area in=[ /routing/ospf/area/find where instance=($InstanceVal->"name") ] do={ - :local AreaName [ /routing/ospf/area/get $Area name ]; - :set NeighborCount ($NeighborCount + [ :len [ /routing/ospf/neighbor/find where area=$AreaName ] ]); - } + :foreach Instance in=[ /routing/ospf/instance/find where comment~"^ospf-to-leds," ] do={ + :local InstanceVal [ /routing/ospf/instance/get $Instance ]; + :local LED ([ $ParseKeyValueStore ($InstanceVal->"comment") ]->"leds"); + :local LEDType [ /system/leds/get [ find where leds=$LED ] type ]; - :if ($NeighborCount > 0 && $LEDType = "off") do={ - $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " has " . $NeighborCount . " neighbors, led on!") false; - /system/leds/set type=on [ find where leds=$LED ]; - } - :if ($NeighborCount = 0 && $LEDType = "on") do={ - $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " has no neighbors, led off!") false; - /system/leds/set type=off [ find where leds=$LED ]; + :local NeighborCount 0; + :foreach Area in=[ /routing/ospf/area/find where instance=($InstanceVal->"name") ] do={ + :local AreaName [ /routing/ospf/area/get $Area name ]; + :set NeighborCount ($NeighborCount + [ :len [ /routing/ospf/neighbor/find where area=$AreaName ] ]); + } + + :if ($NeighborCount > 0 && $LEDType = "off") do={ + $LogPrintExit2 info $ScriptName ("OSPF instance " . $InstanceVal->"name" . " has " . $NeighborCount . " neighbors, led on!") false; + /system/leds/set type=on [ find where leds=$LED ]; + } + :if ($NeighborCount = 0 && $LEDType = "on") do={ + $LogPrintExit2 info $ScriptName ("OSPF instance " . $InstanceVal->"name" . " has no neighbors, led off!") false; + /system/leds/set type=off [ find where leds=$LED ]; + } } } + +$Main [ :jobname ]; From 492edb4263991d02e752a8b75485a610e685cc42 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1923/2612] packages-update: move code into function --- packages-update.rsc | 191 +++++++++++++++++++++++--------------------- 1 file changed, 99 insertions(+), 92 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index 863d273..325009f 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -8,121 +8,128 @@ # download packages and reboot for installation # https://git.eworm.de/cgit/routeros-scripts/about/doc/packages-update.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global DownloadPackage; -:global Grep; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptFromTerminal; -:global ScriptLock; -:global VersionToNum; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global PackagesUpdateDeferReboot; - -:local Schedule do={ - :global GetRandomNumber; + :global DownloadPackage; + :global Grep; :global LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptFromTerminal; + :global ScriptLock; + :global VersionToNum; - :global RebootForUpdate do={ - /system/reboot; - } + :global PackagesUpdateDeferReboot; - :local StartTime [ :tostr [ :totime (10800 + [ $GetRandomNumber 7200 ]) ] ]; - /system/scheduler/add name="_RebootForUpdate" start-time=$StartTime interval=1d \ - on-event=("/system/scheduler/remove \"_RebootForUpdate\"; " . \ - ":global RebootForUpdate; \$RebootForUpdate;"); - $LogPrintExit2 info $1 ("Scheduled reboot for update at " . $StartTime . \ - " local time (" . [ /system/clock/get time-zone-name ] . ").") true; -} + :local Schedule do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global GetRandomNumber; + :global LogPrintExit2; -:local Update [ /system/package/update/get ]; - -:if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ - $LogPrintExit2 warning $0 ("Latest version is not known.") true; -} - -:if ($Update->"installed-version" = $Update->"latest-version") do={ - $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is already installed.") true; -} - -:local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; -:local NumLatest [ $VersionToNum ($Update->"latest-version") ]; - -:if ($NumInstalled < 0x070d0000 && $NumLatest > 0x070d0000) do={ - $LogPrintExit2 error $0 ("Migration to wireless/wifi package in RouterOS " . \ - ($Update->"latest-version") . " is pending. Please update manually!") true; -} - -:local DoDowngrade false; -:if ($NumInstalled > $NumLatest) do={ - :if ([ $ScriptFromTerminal $0 ] = true) do={ - :put "Latest version is older than installed one. Want to downgrade? [y/N]"; - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - :set DoDowngrade true; - } else={ - :put "Canceled..."; + :global RebootForUpdate do={ + /system/reboot; } - } else={ - $LogPrintExit2 warning $0 ("Not installing downgrade automatically.") true; + + :local StartTime [ :tostr [ :totime (10800 + [ $GetRandomNumber 7200 ]) ] ]; + /system/scheduler/add name="_RebootForUpdate" start-time=$StartTime interval=1d \ + on-event=("/system/scheduler/remove \"_RebootForUpdate\"; " . \ + ":global RebootForUpdate; \$RebootForUpdate;"); + $LogPrintExit2 info $ScriptName ("Scheduled reboot for update at " . $StartTime . \ + " local time (" . [ /system/clock/get time-zone-name ] . ").") true; } -} -:foreach Package in=[ /system/package/find where !bundle ] do={ - :local PkgName [ /system/package/get $Package name ]; - :if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ - $LogPrintExit2 error $0 ("Download for package " . $PkgName . " failed, update aborted.") true; + $ScriptLock $ScriptName; + + :local Update [ /system/package/update/get ]; + + :if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ + $LogPrintExit2 warning $ScriptName ("Latest version is not known.") true; } -} -:local RunOrder ({}); -:foreach Script in=[ /system/script/find where source~("\n# provides: backup-script\\b") ] do={ - :local ScriptVal [ /system/script/get $Script ]; - :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") ("\23 provides: backup-script, ") ] ]; + :if ($Update->"installed-version" = $Update->"latest-version") do={ + $LogPrintExit2 info $ScriptName ("Version " . $Update->"latest-version" . " is already installed.") true; + } - :set ($RunOrder->($Store->"order" . "-" . $ScriptVal->"name")) ($ScriptVal->"name"); -} + :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; + :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; -:foreach Order,Script in=$RunOrder do={ - :do { - $LogPrintExit2 info $0 ("Running backup script " . $Script . " before update.") false; - /system/script/run $Script; - } on-error={ - $LogPrintExit2 warning $0 ("Running backup script " . $Script . " before update failed!") false; - :if ([ $ScriptFromTerminal $0 ] = true) do={ - :put "Do you want to continue anyway? [y/N]"; + :if ($NumInstalled < 0x070d0000 && $NumLatest > 0x070d0000) do={ + $LogPrintExit2 error $ScriptName ("Migration to wireless/wifi package in RouterOS " . \ + ($Update->"latest-version") . " is pending. Please update manually!") true; + } + + :local DoDowngrade false; + :if ($NumInstalled > $NumLatest) do={ + :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ + :put "Latest version is older than installed one. Want to downgrade? [y/N]"; :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - $LogPrintExit2 info $0 ("User requested to continue anyway.") false; + :set DoDowngrade true; } else={ - $LogPrintExit2 info $0 ("Canceled update...") true; + :put "Canceled..."; } } else={ - $LogPrintExit2 info $0 ("Canceled non-interactive update.") true; + $LogPrintExit2 warning $ScriptName ("Not installing downgrade automatically.") true; } } -} -:if ($DoDowngrade = true) do={ - $LogPrintExit2 info $0 ("Rebooting for downgrade.") false; + :foreach Package in=[ /system/package/find where !bundle ] do={ + :local PkgName [ /system/package/get $Package name ]; + :if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ + $LogPrintExit2 error $ScriptName ("Download for package " . $PkgName . " failed, update aborted.") true; + } + } + + :local RunOrder ({}); + :foreach Script in=[ /system/script/find where source~("\n# provides: backup-script\\b") ] do={ + :local ScriptVal [ /system/script/get $Script ]; + :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") ("\23 provides: backup-script, ") ] ]; + + :set ($RunOrder->($Store->"order" . "-" . $ScriptVal->"name")) ($ScriptVal->"name"); + } + + :foreach Order,Script in=$RunOrder do={ + :do { + $LogPrintExit2 info $ScriptName ("Running backup script " . $Script . " before update.") false; + /system/script/run $Script; + } on-error={ + $LogPrintExit2 warning $ScriptName ("Running backup script " . $Script . " before update failed!") false; + :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ + :put "Do you want to continue anyway? [y/N]"; + :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ + $LogPrintExit2 info $ScriptName ("User requested to continue anyway.") false; + } else={ + $LogPrintExit2 info $ScriptName ("Canceled update...") true; + } + } else={ + $LogPrintExit2 info $ScriptName ("Canceled non-interactive update.") true; + } + } + } + + :if ($DoDowngrade = true) do={ + $LogPrintExit2 info $ScriptName ("Rebooting for downgrade.") false; + :delay 1s; + /system/package/downgrade; + } + + :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ + :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; + :if (([ /terminal/inkey timeout=60 ] % 32) = 19) do={ + $Schedule $ScriptName; + } + } else={ + :if ($PackagesUpdateDeferReboot = true) do={ + $Schedule $ScriptName; + } + } + + $LogPrintExit2 info $ScriptName ("Rebooting for update.") false; :delay 1s; - /system/package/downgrade; + /system/reboot; } -:if ([ $ScriptFromTerminal $0 ] = true) do={ - :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; - :if (([ /terminal/inkey timeout=60 ] % 32) = 19) do={ - $Schedule $0; - } -} else={ - :if ($PackagesUpdateDeferReboot = true) do={ - $Schedule $0; - } -} - -$LogPrintExit2 info $0 ("Rebooting for update.") false; -:delay 1s; -/system/reboot; +$Main [ :jobname ]; From d6077025b22a30854e3fb8eec9f1f050e86e45a2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1924/2612] ppp-on-up: move code into function --- ppp-on-up.rsc | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc index ad09fdc..ae259d7 100644 --- a/ppp-on-up.rsc +++ b/ppp-on-up.rsc @@ -8,29 +8,33 @@ # run scripts on ppp up # https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global LogPrintExit2; +:local Main do={ + :local ScriptName [ :tostr $1 ]; + :local Interface $2; -:local Interface $interface; + :global LogPrintExit2; -:if ([ :typeof $Interface ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from ppp on-up script hook.") true; -} + :if ([ :typeof $Interface ] = "nothing") do={ + $LogPrintExit2 error $ScriptName ("This script is supposed to run from ppp on-up script hook.") true; + } -:local IntName [ /interface/get $Interface name ]; -$LogPrintExit2 info $0 ("PPP interface " . $IntName . " is up.") false; + :local IntName [ /interface/get $Interface name ]; + $LogPrintExit2 info $ScriptName ("PPP interface " . $IntName . " is up.") false; -/ipv6/dhcp-client/release [ find where interface=$IntName !disabled ]; + /ipv6/dhcp-client/release [ find where interface=$IntName !disabled ]; -:foreach Script in=[ /system/script/find where source~("\n# provides: ppp-on-up\n") ] do={ - :local ScriptName [ /system/script/get $Script name ]; - :do { - $LogPrintExit2 debug $0 ("Running script: " . $ScriptName) false; - /system/script/run $Script; - } on-error={ - $LogPrintExit2 warning $0 ("Running script '" . $ScriptName . "' failed!") false; + :foreach Script in=[ /system/script/find where source~("\n# provides: ppp-on-up\n") ] do={ + :local ScriptName [ /system/script/get $Script name ]; + :do { + $LogPrintExit2 debug $ScriptName ("Running script: " . $ScriptName) false; + /system/script/run $Script; + } on-error={ + $LogPrintExit2 warning $ScriptName ("Running script '" . $ScriptName . "' failed!") false; + } } } + +$Main [ :jobname ] $interface; From 721b6c783bb492cf850874d5608214293275b4fc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1925/2612] sms-action: move code into function --- sms-action.rsc | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/sms-action.rsc b/sms-action.rsc index 49b6cd5..b78a2b2 100644 --- a/sms-action.rsc +++ b/sms-action.rsc @@ -8,26 +8,30 @@ # run action on received SMS # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-action.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global SmsAction; +:local Main do={ + :local ScriptName [ :tostr $1 ]; + :local Action [ :tostr $2 ]; -:global LogPrintExit2; -:global ValidateSyntax; + :global SmsAction; -:local Action $action; + :global LogPrintExit2; + :global ValidateSyntax; -:if ([ :typeof $Action ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from SMS hook with action=...") true; + :if ([ :len $Action ] = 0) do={ + $LogPrintExit2 error $ScriptName ("This script is supposed to run from SMS hook with action=...") true; + } + + :local Code ($SmsAction->$Action); + :if ([ $ValidateSyntax $Code ] = true) do={ + :log info ("Acting on SMS action '" . $Action . "': " . $Code); + :delay 1s; + [ :parse $Code ]; + } else={ + $LogPrintExit2 warning $ScriptName ("The code for action '" . $Action . "' failed syntax validation!") false; + } } -:local Code ($SmsAction->$Action); -:if ([ $ValidateSyntax $Code ] = true) do={ - :log info ("Acting on SMS action '" . $Action . "': " . $Code); - :delay 1s; - [ :parse $Code ]; -} else={ - $LogPrintExit2 warning $0 ("The code for action '" . $Action . "' failed syntax validation!") false; -} +$Main [ :jobname ] $action; From 6b1c6a711926e32e0cc6cf4ba8359a96f1fc79c5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1926/2612] sms-forward: move code into function --- sms-forward.rsc | 125 +++++++++++++++++++++++++----------------------- 1 file changed, 65 insertions(+), 60 deletions(-) diff --git a/sms-forward.rsc b/sms-forward.rsc index f6d8e12..fee1539 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -9,84 +9,89 @@ # forward SMS to e-mail # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Identity; -:global SmsForwardHooks; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global IfThenElse; -:global LogPrintExit2; -:global LogPrintOnce; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; -:global ValidateSyntax; -:global WaitFullyConnected; + :global Identity; + :global SmsForwardHooks; -$ScriptLock $0; + :global IfThenElse; + :global LogPrintExit2; + :global LogPrintOnce; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; + :global ValidateSyntax; + :global WaitFullyConnected; -:if ([ /tool/sms/get receive-enabled ] = false) do={ - $LogPrintOnce warning $0 ("Receiving of SMS is not enabled.") true; -} + $ScriptLock $ScriptName; -$WaitFullyConnected; + :if ([ /tool/sms/get receive-enabled ] = false) do={ + $LogPrintOnce warning $ScriptName ("Receiving of SMS is not enabled.") true; + } -:local Settings [ /tool/sms/get ]; + $WaitFullyConnected; -:if ([ /interface/lte/get ($Settings->"port") running ] != true) do={ - $LogPrintExit2 info $0 ("The LTE interface is not in running state, skipping.") true; -} + :local Settings [ /tool/sms/get ]; -# forward SMS in a loop -:while ([ :len [ /tool/sms/inbox/find ] ] > 0) do={ - :local Phone [ /tool/sms/inbox/get ([ find ]->0) phone ]; - :local Messages ""; - :local Delete ({}); + :if ([ /interface/lte/get ($Settings->"port") running ] != true) do={ + $LogPrintExit2 info $ScriptName ("The LTE interface is not in running state, skipping.") true; + } - :foreach Sms in=[ /tool/sms/inbox/find where phone=$Phone ] do={ - :local SmsVal [ /tool/sms/inbox/get $Sms ]; + # forward SMS in a loop + :while ([ :len [ /tool/sms/inbox/find ] ] > 0) do={ + :local Phone [ /tool/sms/inbox/get ([ find ]->0) phone ]; + :local Messages ""; + :local Delete ({}); - :if ($Phone = $Settings->"allowed-number" && \ - ($SmsVal->"message")~("^:cmd " . $Settings->"secret" . " script ")) do={ - $LogPrintExit2 debug $0 ("Removing SMS, which started a script.") false; - /tool/sms/inbox/remove $Sms; - } else={ - :set Messages ($Messages . "\n\nOn " . $SmsVal->"timestamp" . \ - " type " . $SmsVal->"type" . ":\n" . $SmsVal->"message"); - :foreach Hook in=$SmsForwardHooks do={ - :if ($Phone~($Hook->"allowed-number") && ($SmsVal->"message")~($Hook->"match")) do={ - :if ([ $ValidateSyntax ($Hook->"command") ] = true) do={ - $LogPrintExit2 info $0 ("Running hook '" . $Hook->"match" . "': " . \ - $Hook->"command") false; - :do { - :local Command [ :parse ($Hook->"command") ]; - $Command Phone=$Phone Message=($SmsVal->"message"); - :set Messages ($Messages . "\n\nRan hook '" . $Hook->"match" . "':\n" . \ - $Hook->"command"); - } on-error={ - $LogPrintExit2 warning $0 ("The code for hook '" . $Hook->"match" . \ - "' failed to run!") false; + :foreach Sms in=[ /tool/sms/inbox/find where phone=$Phone ] do={ + :local SmsVal [ /tool/sms/inbox/get $Sms ]; + + :if ($Phone = $Settings->"allowed-number" && \ + ($SmsVal->"message")~("^:cmd " . $Settings->"secret" . " script ")) do={ + $LogPrintExit2 debug $ScriptName ("Removing SMS, which started a script.") false; + /tool/sms/inbox/remove $Sms; + } else={ + :set Messages ($Messages . "\n\nOn " . $SmsVal->"timestamp" . \ + " type " . $SmsVal->"type" . ":\n" . $SmsVal->"message"); + :foreach Hook in=$SmsForwardHooks do={ + :if ($Phone~($Hook->"allowed-number") && ($SmsVal->"message")~($Hook->"match")) do={ + :if ([ $ValidateSyntax ($Hook->"command") ] = true) do={ + $LogPrintExit2 info $ScriptName ("Running hook '" . $Hook->"match" . "': " . \ + $Hook->"command") false; + :do { + :local Command [ :parse ($Hook->"command") ]; + $Command Phone=$Phone Message=($SmsVal->"message"); + :set Messages ($Messages . "\n\nRan hook '" . $Hook->"match" . "':\n" . \ + $Hook->"command"); + } on-error={ + $LogPrintExit2 warning $ScriptName ("The code for hook '" . $Hook->"match" . \ + "' failed to run!") false; + } + } else={ + $LogPrintExit2 warning $ScriptName ("The code for hook '" . $Hook->"match" . \ + "' failed syntax validation!") false; } - } else={ - $LogPrintExit2 warning $0 ("The code for hook '" . $Hook->"match" . \ - "' failed syntax validation!") false; } } + :set Delete ($Delete, $Sms); } - :set Delete ($Delete, $Sms); } - } - :if ([ :len $Messages ] > 0) do={ - :local Count [ :len $Delete ]; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "incoming-envelope" ] . "SMS Forwarding from " . $Phone); \ - message=("Received " . [ $IfThenElse ($Count = 1) "this message" ("these " . $Count . " messages") ] . \ - " by " . $Identity . " from " . $Phone . ":" . $Messages) }); - :foreach Sms in=$Delete do={ - /tool/sms/inbox/remove $Sms; + :if ([ :len $Messages ] > 0) do={ + :local Count [ :len $Delete ]; + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "incoming-envelope" ] . "SMS Forwarding from " . $Phone); \ + message=("Received " . [ $IfThenElse ($Count = 1) "this message" ("these " . $Count . " messages") ] . \ + " by " . $Identity . " from " . $Phone . ":" . $Messages) }); + :foreach Sms in=$Delete do={ + /tool/sms/inbox/remove $Sms; + } } } } + +$Main [ :jobname ]; From 6fd745fc0f689ce0f7b57599bf0c497dda170f93 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1927/2612] telegram-chat: move code into function --- telegram-chat.rsc | 267 +++++++++++++++++++++++----------------------- 1 file changed, 136 insertions(+), 131 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index d8f917b..197c8a3 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -8,160 +8,165 @@ # use Telegram to chat with your Router and send commands # https://git.eworm.de/cgit/routeros-scripts/about/doc/telegram-chat.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Identity; -:global TelegramChatActive; -:global TelegramChatGroups; -:global TelegramChatId; -:global TelegramChatIdsTrusted; -:global TelegramChatOffset; -:global TelegramChatRunTime; -:global TelegramMessageIDs; -:global TelegramRandomDelay; -:global TelegramTokenId; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -:global CertificateAvailable; -:global EitherOr; -:global EscapeForRegEx; -:global GetRandom20CharAlNum; -:global IfThenElse; -:global LogPrintExit2; -:global MAX; -:global MIN; -:global MkDir; -:global ParseJson; -:global RandomDelay; -:global ScriptLock; -:global SendTelegram2; -:global SymbolForNotification; -:global ValidateSyntax; -:global WaitForFile; -:global WaitFullyConnected; + :global Identity; + :global TelegramChatActive; + :global TelegramChatGroups; + :global TelegramChatId; + :global TelegramChatIdsTrusted; + :global TelegramChatOffset; + :global TelegramChatRunTime; + :global TelegramMessageIDs; + :global TelegramRandomDelay; + :global TelegramTokenId; -$ScriptLock $0; + :global CertificateAvailable; + :global EitherOr; + :global EscapeForRegEx; + :global GetRandom20CharAlNum; + :global IfThenElse; + :global LogPrintExit2; + :global MAX; + :global MIN; + :global MkDir; + :global ParseJson; + :global RandomDelay; + :global ScriptLock; + :global SendTelegram2; + :global SymbolForNotification; + :global ValidateSyntax; + :global WaitForFile; + :global WaitFullyConnected; -$WaitFullyConnected; + $ScriptLock $ScriptName; -:if ([ :typeof $TelegramChatOffset ] != "array") do={ - :set TelegramChatOffset { 0; 0; 0 }; -} -:if ([ :typeof $TelegramRandomDelay ] != "num") do={ - :set TelegramRandomDelay 0; -} + $WaitFullyConnected; -:if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; -} + :if ([ :typeof $TelegramChatOffset ] != "array") do={ + :set TelegramChatOffset { 0; 0; 0 }; + } + :if ([ :typeof $TelegramRandomDelay ] != "num") do={ + :set TelegramRandomDelay 0; + } -$RandomDelay $TelegramRandomDelay; + :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ + $LogPrintExit2 warning $ScriptName ("Downloading required certificate failed.") true; + } -:local Data false; -:for I from=1 to=4 do={ - :if ($Data = false) do={ - :do { - :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ - ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=" . \ - $TelegramChatOffset->0 . "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); - :set TelegramRandomDelay [ $MAX 0 ($TelegramRandomDelay - 1) ]; - } on-error={ - :if ($I < 4) do={ - $LogPrintExit2 debug $0 ("Fetch failed, " . $I . ". try.") false; - :set TelegramRandomDelay [ $MIN 15 ($TelegramRandomDelay + 5) ]; - :delay (($I * $I) . "s"); + $RandomDelay $TelegramRandomDelay; + + :local Data false; + :for I from=1 to=4 do={ + :if ($Data = false) do={ + :do { + :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ + ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=" . \ + $TelegramChatOffset->0 . "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); + :set TelegramRandomDelay [ $MAX 0 ($TelegramRandomDelay - 1) ]; + } on-error={ + :if ($I < 4) do={ + $LogPrintExit2 debug $ScriptName ("Fetch failed, " . $I . ". try.") false; + :set TelegramRandomDelay [ $MIN 15 ($TelegramRandomDelay + 5) ]; + :delay (($I * $I) . "s"); + } } } } -} -:if ($Data = false) do={ - $LogPrintExit2 warning $0 ("Failed getting updates from Telegram.") true; -} + :if ($Data = false) do={ + $LogPrintExit2 warning $ScriptName ("Failed getting updates from Telegram.") true; + } -:local UpdateID 0; -:local Uptime [ /system/resource/get uptime ]; -:foreach UpdateArray in=([ $ParseJson $Data ]->"result") do={ - :local Update [ $ParseJson $UpdateArray ]; - :set UpdateID ($Update->"update_id"); - :local Message [ $ParseJson ($Update->"message") ]; - :local IsReply [ :len ($Message->"reply_to_message") ]; - :local IsMyReply ($TelegramMessageIDs->([ $ParseJson ($Message->"reply_to_message") ]->"message_id")); - :if (($IsMyReply = 1 || $TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={ - :local Trusted false; - :local Chat [ $ParseJson ($Message->"chat") ]; - :local From [ $ParseJson ($Message->"from") ]; + :local UpdateID 0; + :local Uptime [ /system/resource/get uptime ]; + :foreach UpdateArray in=([ $ParseJson $Data ]->"result") do={ + :local Update [ $ParseJson $UpdateArray ]; + :set UpdateID ($Update->"update_id"); + :local Message [ $ParseJson ($Update->"message") ]; + :local IsReply [ :len ($Message->"reply_to_message") ]; + :local IsMyReply ($TelegramMessageIDs->([ $ParseJson ($Message->"reply_to_message") ]->"message_id")); + :if (($IsMyReply = 1 || $TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={ + :local Trusted false; + :local Chat [ $ParseJson ($Message->"chat") ]; + :local From [ $ParseJson ($Message->"from") ]; - :foreach IdsTrusted in=($TelegramChatId, $TelegramChatIdsTrusted) do={ - :if ($From->"id" = $IdsTrusted || $From->"username" = $IdsTrusted) do={ - :set Trusted true; - } - } - - :if ($Trusted = true) do={ - :local Done false; - :if ($Message->"text" = "?") do={ - $LogPrintExit2 info $0 ("Sending notice for update " . $UpdateID . ".") false; - $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ - subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Online, awaiting your commands!") }); - :set Done true; - } - :if ($Done = false && [ :pick ($Message->"text") 0 1 ] = "!") do={ - :if ($Message->"text" ~ ("^! *(" . [ $EscapeForRegEx $Identity ] . "|@" . $TelegramChatGroups . ")\$")) do={ - :set TelegramChatActive true; - } else={ - :set TelegramChatActive false; + :foreach IdsTrusted in=($TelegramChatId, $TelegramChatIdsTrusted) do={ + :if ($From->"id" = $IdsTrusted || $From->"username" = $IdsTrusted) do={ + :set Trusted true; } - $LogPrintExit2 info $0 ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . \ - " from update " . $UpdateID . "!") false; - :set Done true; } - :if ($Done = false && ($IsMyReply = 1 || ($IsReply = 0 && $TelegramChatActive = true)) && [ :len ($Message->"text") ] > 0) do={ - :if ([ $ValidateSyntax ($Message->"text") ] = true) do={ - :local State ""; - :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); - $MkDir "tmpfs/telegram-chat"; - $LogPrintExit2 info $0 ("Running command from update " . $UpdateID . ": " . $Message->"text") false; - :execute script=(":do {\n" . $Message->"text" . "\n} on-error={ /file/add name=\"" . $File . ".failed\" };" . \ - "/file/add name=\"" . $File . ".done\"") file=($File . "\00"); - :if ([ $WaitForFile ($File . ".done") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ - :set State "The command did not finish, still running in background.\n\n"; - } - :if ([ :len [ /file/find where name=($File . ".failed") ] ] > 0) do={ - :set State "The command failed with an error!\n\n"; - } - :local Content [ /file/get $File contents ]; - $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ + + :if ($Trusted = true) do={ + :local Done false; + :if ($Message->"text" = "?") do={ + $LogPrintExit2 info $ScriptName ("Sending notice for update " . $UpdateID . ".") false; + $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Command:\n" . $Message->"text" . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ - ("Output:\n" . $Content) [ $IfThenElse ([ /file/get $File size ] > 0) \ - ("Output exceeds file read size.") ("No output.") ] ]) }); - /file/remove "tmpfs/telegram-chat"; + message=("Online, awaiting your commands!") }); + :set Done true; + } + :if ($Done = false && [ :pick ($Message->"text") 0 1 ] = "!") do={ + :if ($Message->"text" ~ ("^! *(" . [ $EscapeForRegEx $Identity ] . "|@" . $TelegramChatGroups . ")\$")) do={ + :set TelegramChatActive true; + } else={ + :set TelegramChatActive false; + } + $LogPrintExit2 info $ScriptName ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . \ + " from update " . $UpdateID . "!") false; + :set Done true; + } + :if ($Done = false && ($IsMyReply = 1 || ($IsReply = 0 && $TelegramChatActive = true)) && [ :len ($Message->"text") ] > 0) do={ + :if ([ $ValidateSyntax ($Message->"text") ] = true) do={ + :local State ""; + :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); + $MkDir "tmpfs/telegram-chat"; + $LogPrintExit2 info $ScriptName ("Running command from update " . $UpdateID . ": " . $Message->"text") false; + :execute script=(":do {\n" . $Message->"text" . "\n} on-error={ /file/add name=\"" . $File . ".failed\" };" . \ + "/file/add name=\"" . $File . ".done\"") file=($File . "\00"); + :if ([ $WaitForFile ($File . ".done") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ + :set State "The command did not finish, still running in background.\n\n"; + } + :if ([ :len [ /file/find where name=($File . ".failed") ] ] > 0) do={ + :set State "The command failed with an error!\n\n"; + } + :local Content [ /file/get $File contents ]; + $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=("Command:\n" . $Message->"text" . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ + ("Output:\n" . $Content) [ $IfThenElse ([ /file/get $File size ] > 0) \ + ("Output exceeds file read size.") ("No output.") ] ]) }); + /file/remove "tmpfs/telegram-chat"; + } else={ + $LogPrintExit2 info $ScriptName ("The command from update " . $UpdateID . " failed syntax validation!") false; + $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=("Command:\n" . $Message->"text" . "\n\nThe command failed syntax validation!") }); + } + } + } else={ + :local MessageText ("Received a message from untrusted contact " . \ + [ $IfThenElse ([ :len ($From->"username") ] = 0) "without username" ("'" . $From->"username" . "'") ] . \ + " (ID " . $From->"id" . ") in update " . $UpdateID . "!"); + :if ($Message->"text" ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ + $LogPrintExit2 warning $ScriptName $MessageText false; + $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=("You are not trusted.") }); } else={ - $LogPrintExit2 info $0 ("The command from update " . $UpdateID . " failed syntax validation!") false; - $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ - subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Command:\n" . $Message->"text" . "\n\nThe command failed syntax validation!") }); + $LogPrintExit2 info $ScriptName $MessageText false; } } } else={ - :local MessageText ("Received a message from untrusted contact " . \ - [ $IfThenElse ([ :len ($From->"username") ] = 0) "without username" ("'" . $From->"username" . "'") ] . \ - " (ID " . $From->"id" . ") in update " . $UpdateID . "!"); - :if ($Message->"text" ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ - $LogPrintExit2 warning $0 $MessageText false; - $SendTelegram2 ({ origin=$0; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ - subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("You are not trusted.") }); - } else={ - $LogPrintExit2 info $0 $MessageText false; - } + $LogPrintExit2 debug $ScriptName ("Already handled update " . $UpdateID . ".") false; } - } else={ - $LogPrintExit2 debug $0 ("Already handled update " . $UpdateID . ".") false; } + :set TelegramChatOffset ([ :pick $TelegramChatOffset 1 3 ], \ + [ $IfThenElse ($UpdateID >= $TelegramChatOffset->2) ($UpdateID + 1) ($TelegramChatOffset->2) ]); } -:set TelegramChatOffset ([ :pick $TelegramChatOffset 1 3 ], \ - [ $IfThenElse ($UpdateID >= $TelegramChatOffset->2) ($UpdateID + 1) ($TelegramChatOffset->2) ]); + +$Main [ :jobname ]; From ad623f069e43798da6775f77fef72cd4a8fbc05e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1928/2612] update-gre-address: move code into function --- update-gre-address.rsc | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/update-gre-address.rsc b/update-gre-address.rsc index c5c699b..62cdfe1 100644 --- a/update-gre-address.rsc +++ b/update-gre-address.rsc @@ -9,29 +9,34 @@ # ipsec remote peer # https://git.eworm.de/cgit/routeros-scripts/about/doc/update-gre-address.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global CharacterReplace; -:global LogPrintExit2; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global CharacterReplace; + :global LogPrintExit2; + :global ScriptLock; -/interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; + $ScriptLock $ScriptName; -:foreach Peer in=[ /ip/ipsec/active-peers/find ] do={ - :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; - :local GreInt [ /interface/gre/find where comment=($PeerVal->"id") or comment=[ $CharacterReplace ($PeerVal->"id") "CN=" "" ] ]; - :if ([ :len $GreInt ] > 0) do={ - :local GreIntVal [ /interface/gre/get $GreInt ]; - :if ([ :typeof ($PeerVal->"dynamic-address") ] = "str" && \ - ($PeerVal->"dynamic-address" != $GreIntVal->"remote-address" || \ - $GreIntVal->"disabled" = true)) do={ - $LogPrintExit2 info $0 ("Updating remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address") false; - /interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$PeerVal->"dynamic-address" name!=$GreIntVal->"name" ]; - /interface/gre/set $GreInt remote-address=($PeerVal->"dynamic-address") disabled=no; + /interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; + + :foreach Peer in=[ /ip/ipsec/active-peers/find ] do={ + :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; + :local GreInt [ /interface/gre/find where comment=($PeerVal->"id") or comment=[ $CharacterReplace ($PeerVal->"id") "CN=" "" ] ]; + :if ([ :len $GreInt ] > 0) do={ + :local GreIntVal [ /interface/gre/get $GreInt ]; + :if ([ :typeof ($PeerVal->"dynamic-address") ] = "str" && \ + ($PeerVal->"dynamic-address" != $GreIntVal->"remote-address" || \ + $GreIntVal->"disabled" = true)) do={ + $LogPrintExit2 info $ScriptName ("Updating remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address") false; + /interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$PeerVal->"dynamic-address" name!=$GreIntVal->"name" ]; + /interface/gre/set $GreInt remote-address=($PeerVal->"dynamic-address") disabled=no; + } } } } + +$Main [ :jobname ]; From 698360f03757cefc08b27c9beac9fe16af7c1d7e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 13:48:01 +0100 Subject: [PATCH 1929/2612] update-tunnelbroker: move code into function --- update-tunnelbroker.rsc | 73 ++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index 4d4379a..c61d82e 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -10,51 +10,56 @@ # update local address of tunnelbroker interface # https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global CertificateAvailable; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; +:local Main do={ + :local ScriptName [ :tostr $1 ]; -$ScriptLock $0; + :global CertificateAvailable; + :global LogPrintExit2; + :global ParseKeyValueStore; + :global ScriptLock; -:if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ - $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; -} + $ScriptLock $ScriptName; -:foreach Interface in=[ /interface/6to4/find where comment~"^tunnelbroker" !disabled ] do={ - :local Data false; - :local InterfaceVal [ /interface/6to4/get $Interface ]; - :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; + :if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ + $LogPrintExit2 error $ScriptName ("Downloading required certificate failed.") true; + } - :for I from=2 to=0 do={ - :if ($Data = false) do={ - :do { - :set Data ([ /tool/fetch check-certificate=yes-without-crl \ - ("https://ipv4.tunnelbroker.net/nic/update?hostname=" . $Comment->"id") \ - user=($Comment->"user") password=($Comment->"pass") output=user as-value ]->"data"); - } on-error={ - $LogPrintExit2 debug $0 ("Failed downloading, " . $I . " retries pending.") false; - :delay 2s; + :foreach Interface in=[ /interface/6to4/find where comment~"^tunnelbroker" !disabled ] do={ + :local Data false; + :local InterfaceVal [ /interface/6to4/get $Interface ]; + :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; + + :for I from=2 to=0 do={ + :if ($Data = false) do={ + :do { + :set Data ([ /tool/fetch check-certificate=yes-without-crl \ + ("https://ipv4.tunnelbroker.net/nic/update?hostname=" . $Comment->"id") \ + user=($Comment->"user") password=($Comment->"pass") output=user as-value ]->"data"); + } on-error={ + $LogPrintExit2 debug $ScriptName ("Failed downloading, " . $I . " retries pending.") false; + :delay 2s; + } } } - } - :if (!($Data ~ "^(good|nochg) ")) do={ - $LogPrintExit2 error $0 ("Failed sending the local address to tunnelbroker or unexpected response!") true; - } - - :local PublicAddress [ :pick $Data ([ :find $Data " " ] + 1) [ :find $Data "\n" ] ]; - - :if ($PublicAddress != $InterfaceVal->"local-address") do={ - :if ([ :len [ /ip/address find where address~("^" . $PublicAddress . "/") ] ] < 1) do={ - $LogPrintExit2 warning $0 ("The address " . $PublicAddress . " is not configured on your device. NAT by ISP?") false; + :if (!($Data ~ "^(good|nochg) ")) do={ + $LogPrintExit2 error $ScriptName ("Failed sending the local address to tunnelbroker or unexpected response!") true; } - $LogPrintExit2 info $0 ("Local address changed, updating tunnel configuration with address: " . $PublicAddress) false; - /interface/6to4/set $Interface local-address=$PublicAddress; + :local PublicAddress [ :pick $Data ([ :find $Data " " ] + 1) [ :find $Data "\n" ] ]; + + :if ($PublicAddress != $InterfaceVal->"local-address") do={ + :if ([ :len [ /ip/address find where address~("^" . $PublicAddress . "/") ] ] < 1) do={ + $LogPrintExit2 warning $ScriptName ("The address " . $PublicAddress . " is not configured on your device. NAT by ISP?") false; + } + + $LogPrintExit2 info $ScriptName ("Local address changed, updating tunnel configuration with address: " . $PublicAddress) false; + /interface/6to4/set $Interface local-address=$PublicAddress; + } } } + +$Main [ :jobname ]; From d46156ad92322ffda1c7769d8eb9ea2b9fab6015 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 12 Mar 2024 15:19:42 +0100 Subject: [PATCH 1930/2612] global-functions: use variable name $ScriptName --- global-functions.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 92fabff..90148f8 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -9,7 +9,7 @@ # global functions # https://git.eworm.de/cgit/routeros-scripts/about/ -:local 0 [ :jobname ]; +:local ScriptName [ :jobname ]; # expected configuration version :global ExpectedConfigVersion 119; @@ -1534,7 +1534,7 @@ # Log success :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; # signal we are ready From 4f3cf3656c49360a68de1e04d0f066ba1e931415 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1931/2612] BRANCHES: add badges --- BRANCHES.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/BRANCHES.md b/BRANCHES.md index c431711..0fdbdb4 100644 --- a/BRANCHES.md +++ b/BRANCHES.md @@ -1,6 +1,13 @@ Installing from branches ======================== +[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) +[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) +[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) +[![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) + [âŦ…ī¸ Go back to main README](README.md) > âš ī¸ **Warning**: Living on the edge? Great, read on! From 120d4780fd55304473031ff67ad2f452e49ec52b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1932/2612] CONTRIBUTIONS: add badges --- CONTRIBUTIONS.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 6d64e67..dff933b 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -1,6 +1,13 @@ 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) Thanks a lot for your contributions! â¤ī¸ From 13d0075a48f5626ecf32d5a94af4cea270a5e8e0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1933/2612] INITIAL-COMMANDS: add badges --- INITIAL-COMMANDS.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index c58662b..0de50ae 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -1,6 +1,13 @@ 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) > âš ī¸ **Warning**: These command are inteneded for initial setup. If you are From f9fb61ec498a7898dbee57e53ebb43b34dc6061b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1934/2612] doc/accesslist-duplicates: add badges --- doc/accesslist-duplicates.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index 6cb40f6..109bebf 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -1,6 +1,13 @@ 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) > â„šī¸ī¸ **Info**: This script can not be used on its own but requires the base From 4af1092272c3263529eed4220ec7fa73fee409dd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1935/2612] doc/backup-cloud: add badges --- doc/backup-cloud.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index ac7edb7..03d5953 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 7b527840b1e3bdc5578f68107fd033794d8ddb45 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1936/2612] doc/backup-email: add badges --- doc/backup-email.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/backup-email.md b/doc/backup-email.md index 67564e7..56b0540 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From acc8cdf8ca4ea557ec9ed356b74e88a0051d5ab4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1937/2612] doc/backup-partition: add badges --- doc/backup-partition.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/backup-partition.md b/doc/backup-partition.md index 18edc0c..e2ca8e0 100644 --- a/doc/backup-partition.md +++ b/doc/backup-partition.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From a92715ea31f04161ffe682c8eebdefd89b3ca4fe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1938/2612] doc/backup-upload: add badges --- doc/backup-upload.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/backup-upload.md b/doc/backup-upload.md index b132e56..953ac93 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 9deaed735020694b4748ed6146684c8482901e66 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1939/2612] doc/capsman-download-packages: add badges --- doc/capsman-download-packages.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index 03e4497..20fb007 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 50694ec5122b617a9f5b96e9a51530e2a5b1feee Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1940/2612] doc/capsman-rolling-upgrade: add badges --- doc/capsman-rolling-upgrade.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index b4e342d..8362794 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 0c46668e2e350916bf4844138f563261f2a1a55d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1941/2612] doc/certificate-renew-issued: add badges --- doc/certificate-renew-issued.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/certificate-renew-issued.md b/doc/certificate-renew-issued.md index bb8e18c..2df8be3 100644 --- a/doc/certificate-renew-issued.md +++ b/doc/certificate-renew-issued.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 71ce8709ca973e2349ad667baa13432c4bb662c7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1942/2612] doc/check-certificates: add badges --- doc/check-certificates.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 186702c..62b9ceb 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From f68ee9bc00fcdd4a7bab10835faeaaf2ae2ad679 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1943/2612] doc/check-health: add badges --- doc/check-health.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/check-health.md b/doc/check-health.md index 3bde4e9..ee52b61 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From a2afb1d5dc391c50dc538baccaf54560101d242f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1944/2612] doc/check-lte-firmware-upgrade: add badges --- doc/check-lte-firmware-upgrade.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index a81ca86..bec3177 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From b9b1197c1aae47b188ee87278aed4e44dc6adf3e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1945/2612] doc/check-routeros-update: add badges --- doc/check-routeros-update.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index dbe83b8..dbb2b89 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 6737c291caf2b059b1ff576c75765034b79062e0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1946/2612] doc/collect-wireless-mac: add badges --- doc/collect-wireless-mac.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 49772e9..b0a2298 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From d1549712abbf07eff580487a99db97d4eb194325 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1947/2612] doc/daily-psk: add badges --- doc/daily-psk.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 01fb9f6..f723617 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 16b318832a3920664f78ffe782b5daac9c1f1282 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1948/2612] doc/dhcp-lease-comment: add badges --- doc/dhcp-lease-comment.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/dhcp-lease-comment.md b/doc/dhcp-lease-comment.md index d98f3fc..4831b8c 100644 --- a/doc/dhcp-lease-comment.md +++ b/doc/dhcp-lease-comment.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From b178e47d6d0bd1cf07a9af43f18b63231f1461dc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1949/2612] doc/dhcp-to-dns: add badges --- doc/dhcp-to-dns.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 772704e..e7f3b88 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From d0af9d62ea6bd3b749d717f223ee424d5962c2af Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1950/2612] accesslist-duplicates: drop main function, use :do with on-error --- accesslist-duplicates.capsman.rsc | 8 +++----- accesslist-duplicates.local.rsc | 8 +++----- accesslist-duplicates.template.rsc | 8 +++----- accesslist-duplicates.wifi.rsc | 8 +++----- 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index f781eb3..2ce8302 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -13,8 +13,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :local Seen ({}); @@ -31,6 +31,4 @@ } :set ($Seen->$Mac) 1; } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index b235cd1..51ef6f3 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -13,8 +13,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :local Seen ({}); @@ -31,6 +31,4 @@ } :set ($Seen->$Mac) 1; } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index c65e9e0..770fb30 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -14,8 +14,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :local Seen ({}); @@ -40,6 +40,4 @@ } :set ($Seen->$Mac) 1; } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc index 04ac19c..65f8aaa 100644 --- a/accesslist-duplicates.wifi.rsc +++ b/accesslist-duplicates.wifi.rsc @@ -13,8 +13,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :local Seen ({}); @@ -31,6 +31,4 @@ } :set ($Seen->$Mac) 1; } -} - -$Main [ :jobname ]; +} on-error={ } From 2bd2b9b6e36f085b26713dd121aea80460b10025 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1951/2612] doc/firmware-upgrade-reboot: add badges --- doc/firmware-upgrade-reboot.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/firmware-upgrade-reboot.md b/doc/firmware-upgrade-reboot.md index 8bf4d19..420dfe1 100644 --- a/doc/firmware-upgrade-reboot.md +++ b/doc/firmware-upgrade-reboot.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 15c68c5660ab6bc0af4c9dee4de7b74ebcf0abb8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1952/2612] backup-cloud: drop main function, use :do with on-error --- backup-cloud.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 2846d75..a3dfe0c 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -12,8 +12,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global BackupRandomDelay; :global Identity; @@ -32,7 +32,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -77,6 +77,4 @@ $LogPrintExit2 error $ScriptName ("Failed uploading backup for " . $Identity . " to cloud!") true; } /file/remove "tmpfs/backup-cloud"; -} - -$Main [ :jobname ]; +} on-error={ } From 900e868cafb57f8d4ad59abc8eb6da7e6ffa9276 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1953/2612] doc/fw-addr-lists: add badges --- doc/fw-addr-lists.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md index 6dc6b66..70ca6e9 100644 --- a/doc/fw-addr-lists.md +++ b/doc/fw-addr-lists.md @@ -1,6 +1,13 @@ Download, import and update firewall address-lists ================================================== +[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) +[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) +[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) +[![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) + [âŦ…ī¸ Go back to main README](../README.md) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 3eb8fad5ae36334b2f4c56c6641d453eee5b0136 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1954/2612] backup-email: drop main function, use :do with on-error --- backup-email.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/backup-email.rsc b/backup-email.rsc index c5b4568..9f6e31a 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -12,8 +12,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global BackupPassword; :global BackupRandomDelay; @@ -46,7 +46,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -114,6 +114,4 @@ :delay 1s; :set I ($I + 1); } -} - -$Main [ :jobname ]; +} on-error={ } From 8ab1df596043a5dc4fb7a100888025f236a2252a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1955/2612] doc/global-wait: add badges --- doc/global-wait.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/global-wait.md b/doc/global-wait.md index 39921db..a3fe6d6 100644 --- a/doc/global-wait.md +++ b/doc/global-wait.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From b8bd64bac5b9925d84d1baa0eef8dbd511b738a9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1956/2612] backup-partition: drop main function, use :do with on-error --- backup-partition.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index 74dccfe..1238fab 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -12,14 +12,14 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global LogPrintExit2; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :if ([ :len [ /partitions/find ] ] < 2) do={ @@ -47,6 +47,4 @@ $LogPrintExit2 error $ScriptName ("Failed saving configuration to partition '" . \ $FallbackTo . "'!") true; } -} - -$Main [ :jobname ]; +} on-error={ } From e2f6401a15573c9a526e2dd68a5b43bf6a2df817 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1957/2612] doc/gps-track: add badges --- doc/gps-track.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/gps-track.md b/doc/gps-track.md index 721b075..03f79a7 100644 --- a/doc/gps-track.md +++ b/doc/gps-track.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 8d020a4de84cc86f0328a79c6e27bf87a35d45ba Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1958/2612] backup-upload: drop main function, use :do with on-error --- backup-upload.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index c2b3285..2b42730 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -12,8 +12,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global BackupPassword; :global BackupRandomDelay; @@ -45,7 +45,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -153,6 +153,4 @@ :if ($Failed = 1) do={ :error "An error occured!"; } -} - -$Main [ :jobname ]; +} on-error={ } From b45b7606a9dfa75de0ef627f0b25e7cb91fdfef6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1959/2612] doc/hotspot-to-wpa: add badges --- doc/hotspot-to-wpa.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index fc784dd..6ce4421 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 03309d4fdb3542c60e81b505ee9a9dc1fd623f5d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1960/2612] capsman-download-packages: drop main function, use :do with on-error --- capsman-download-packages.capsman.rsc | 10 ++++------ capsman-download-packages.template.rsc | 10 ++++------ capsman-download-packages.wifi.rsc | 10 ++++------ 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index cb82a37..d4e900d 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -14,8 +14,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global CleanFilePath; :global DownloadPackage; @@ -25,7 +25,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -78,6 +78,4 @@ /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index a76071e..cd4a83b 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -15,8 +15,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global CleanFilePath; :global DownloadPackage; @@ -26,7 +26,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -89,6 +89,4 @@ /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 89af381..633830a 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -14,8 +14,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global CleanFilePath; :global DownloadPackage; @@ -25,7 +25,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -80,6 +80,4 @@ /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; } } -} - -$Main [ :jobname ]; +} on-error={ } From ac51956c3ff003305ec1f700e2203aa100305f3b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1961/2612] doc/ip-addr-bridge: add badges --- doc/ip-addr-bridge.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/ip-addr-bridge.md b/doc/ip-addr-bridge.md index a759829..8bb9811 100644 --- a/doc/ip-addr-bridge.md +++ b/doc/ip-addr-bridge.md @@ -1,6 +1,13 @@ 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) Description From 25c9bff6f38fa7738c21572c8f13b3a831e1e6f3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1962/2612] capsman-rolling-upgrade: drop main function, use :do with on-error --- capsman-rolling-upgrade.capsman.rsc | 10 ++++------ capsman-rolling-upgrade.template.rsc | 10 ++++------ capsman-rolling-upgrade.wifi.rsc | 10 ++++------ 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc index 9379b24..16a3498 100644 --- a/capsman-rolling-upgrade.capsman.rsc +++ b/capsman-rolling-upgrade.capsman.rsc @@ -15,14 +15,14 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global LogPrintExit2; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :local InstalledVersion [ /system/package/update/get installed-version ]; @@ -43,6 +43,4 @@ :delay ($Delay . "s"); } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index 731dbeb..45a5f8e 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -16,14 +16,14 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global LogPrintExit2; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :local InstalledVersion [ /system/package/update/get installed-version ]; @@ -51,6 +51,4 @@ :delay ($Delay . "s"); } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc index 205d1d8..63245dc 100644 --- a/capsman-rolling-upgrade.wifi.rsc +++ b/capsman-rolling-upgrade.wifi.rsc @@ -15,14 +15,14 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global LogPrintExit2; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :local InstalledVersion [ /system/package/update/get installed-version ]; @@ -44,6 +44,4 @@ :delay ($Delay . "s"); } } -} - -$Main [ :jobname ]; +} on-error={ } From c645ab5100bbde7c8c3cb386afc7cb09bcf35e96 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1963/2612] doc/ipsec-to-dns: add badges --- doc/ipsec-to-dns.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/ipsec-to-dns.md b/doc/ipsec-to-dns.md index 04500a3..ca5b86c 100644 --- a/doc/ipsec-to-dns.md +++ b/doc/ipsec-to-dns.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 78f65ead599a6ccb9161fe93a88674e28d8e95cb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1964/2612] certificate-renew-issued: drop main function, use :do with on-error --- certificate-renew-issued.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc index 7bf4128..a360a3f 100644 --- a/certificate-renew-issued.rsc +++ b/certificate-renew-issued.rsc @@ -11,8 +11,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global CertIssuedExportPass; @@ -21,7 +21,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :foreach Cert in=[ /certificate/find where issued expires-after<3w ] do={ @@ -45,6 +45,4 @@ $LogPrintExit2 info $ScriptName ("Issued a new certificate for \"" . $CertVal->"common-name" . "\".") false; } } -} - -$Main [ :jobname ]; +} on-error={ } From 8b5c919d8cb16bfabacb06e01cc5a7245923e740 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1965/2612] doc/ipv6-update: add badges --- doc/ipv6-update.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md index f49cfaa..a5661fc 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From b1e37c27346209aa523705ee7076a2480e782780 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1966/2612] check-certificates: drop main function, use :do with on-error --- check-certificates.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index e470b59..edde7f3 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -11,8 +11,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global CertRenewTime; :global CertRenewUrl; @@ -132,7 +132,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -216,6 +216,4 @@ ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; } } -} - -$Main [ :jobname ]; +} on-error={ } From fd1cb3131df0966a3b351fcd95d614a9d98628d7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1967/2612] doc/lease-script: add badges --- doc/lease-script.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/lease-script.md b/doc/lease-script.md index c4ff20e..f346621 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 7bf36fa8a5b4b568444e17aca7ccee817280ed31 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1968/2612] check-health: drop main function, use :do with on-error --- check-health.rsc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/check-health.rsc b/check-health.rsc index df76d25..91330fc 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -11,8 +11,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global CheckHealthCPUUtilization; :global CheckHealthCPUUtilizationNotified; @@ -40,7 +40,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :local Resource [ /system/resource/get ]; @@ -78,7 +78,7 @@ :if ([ :len [ /system/health/find ] ] = 0) do={ $LogPrintExit2 debug $ScriptName ("Your device does not provide any health values.") false; - :return true; + :error true; } :if ([ :typeof $CheckHealthLast ] != "array") do={ @@ -175,6 +175,4 @@ } :set ($CheckHealthLast->$Name) $Value; } -} - -$Main [ :jobname ]; +} on-error={ } From 91e94c6e385607574a7d5c27b92d2f654542acc2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1969/2612] doc/leds-mode: add badges --- doc/leds-mode.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/leds-mode.md b/doc/leds-mode.md index 5710d85..5dd5f63 100644 --- a/doc/leds-mode.md +++ b/doc/leds-mode.md @@ -1,6 +1,13 @@ 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) Description From b78556ca41c720f14c57eb84b85bcf099c06764c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1970/2612] check-lte-firmware-upgrade: drop main function, use :do with on-error --- check-lte-firmware-upgrade.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index 18109fb..f2a6e37 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -11,15 +11,15 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global SentLteFirmwareUpgradeNotification; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :if ([ :typeof $SentLteFirmwareUpgradeNotification ] != "array") do={ @@ -100,6 +100,4 @@ :foreach Interface in=[ /interface/lte/find ] do={ $CheckInterface $ScriptName $Interface; } -} - -$Main [ :jobname ]; +} on-error={ } From b6983c86154d66d683562f6a38461bbf16fc7302 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1971/2612] doc/log-forward: add badges --- doc/log-forward.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/log-forward.md b/doc/log-forward.md index 4212381..4183d7b 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 7110b29cbabdd7097c0eeebb338b4b5b42ce6aee Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1972/2612] check-routeros-update: drop main function, use :do with on-error --- check-routeros-update.rsc | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index ae0038c..a68762b 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -11,8 +11,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global Identity; :global SafeUpdateAll; @@ -42,7 +42,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -56,7 +56,7 @@ :if ([ $ScriptFromTerminal $ScriptName ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={ $LogPrintExit2 info $ScriptName ("System is already up to date.") false; - :return true; + :error true; } :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; @@ -133,7 +133,7 @@ :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ $LogPrintExit2 info $ScriptName ("Already sent the RouterOS update notification for version " . \ $Update->"latest-version" . ".") false; - :return true; + :error true; } $SendNotification2 ({ origin=$ScriptName; \ @@ -148,7 +148,7 @@ :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ $LogPrintExit2 info $ScriptName ("Already sent the RouterOS downgrade notification for version " . \ $Update->"latest-version" . ".") false; - :return true; + :error true; } $SendNotification2 ({ origin=$ScriptName; \ @@ -160,6 +160,4 @@ " is available for downgrade.") false; :set SentRouterosUpdateNotification ($Update->"latest-version"); } -} - -$Main [ :jobname ]; +} on-error={ } From 202096c610569ae19c1d678407b883ea26793a7a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1973/2612] doc/mod/bridge-port-to: add badges --- doc/mod/bridge-port-to.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/mod/bridge-port-to.md b/doc/mod/bridge-port-to.md index a956de4..838d1e0 100644 --- a/doc/mod/bridge-port-to.md +++ b/doc/mod/bridge-port-to.md @@ -1,6 +1,13 @@ 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) > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base From 4ada2e7678d43246575005a300f2baab24f019f8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1974/2612] collect-wireless-mac: drop main function, use :do with on-error --- collect-wireless-mac.capsman.rsc | 10 ++++------ collect-wireless-mac.local.rsc | 10 ++++------ collect-wireless-mac.template.rsc | 10 ++++------ collect-wireless-mac.wifi.rsc | 10 ++++------ 4 files changed, 16 insertions(+), 24 deletions(-) diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index 3a10b1f..5423624 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -14,8 +14,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global Identity; @@ -29,7 +29,7 @@ :global SymbolForNotification; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :return false; + :error false; } :if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ @@ -93,6 +93,4 @@ $LogPrintExit2 debug $ScriptName ("No mac address available... Ignoring.") false; } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index f6f898e..a4e81a3 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -14,8 +14,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global Identity; @@ -29,7 +29,7 @@ :global SymbolForNotification; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :return false; + :error false; } :if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ @@ -94,6 +94,4 @@ $LogPrintExit2 debug $ScriptName ("No mac address available... Ignoring.") false; } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index e633e03..f647eb3 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -15,8 +15,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global Identity; @@ -30,7 +30,7 @@ :global SymbolForNotification; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :return false; + :error false; } :if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ @@ -111,6 +111,4 @@ $LogPrintExit2 debug $ScriptName ("No mac address available... Ignoring.") false; } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc index c866bcc..063d6dc 100644 --- a/collect-wireless-mac.wifi.rsc +++ b/collect-wireless-mac.wifi.rsc @@ -14,8 +14,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global Identity; @@ -29,7 +29,7 @@ :global SymbolForNotification; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :return false; + :error false; } :if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ @@ -93,6 +93,4 @@ $LogPrintExit2 debug $ScriptName ("No mac address available... Ignoring.") false; } } -} - -$Main [ :jobname ]; +} on-error={ } From 9cd84ddffebf5911787fa689f5ec2fae41af8bb2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1975/2612] doc/mod/bridge-port-vlan: add badges --- doc/mod/bridge-port-vlan.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/mod/bridge-port-vlan.md b/doc/mod/bridge-port-vlan.md index 068f050..5660b9d 100644 --- a/doc/mod/bridge-port-vlan.md +++ b/doc/mod/bridge-port-vlan.md @@ -1,6 +1,13 @@ 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) > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base From 7fa03ab70e4e711dfb3ceeefa37639bf6676e27c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 15:27:03 +0100 Subject: [PATCH 1976/2612] log-forward: do not exit with error --- log-forward.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log-forward.rsc b/log-forward.rsc index 13b490e..5044d43 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -40,7 +40,8 @@ :if ($LogForwardRateLimit > 30) do={ :set LogForwardRateLimit ($LogForwardRateLimit - 1); - $LogPrintExit2 info $ScriptName ("Rate limit in action, not forwarding logs, if any!") true; + $LogPrintExit2 info $ScriptName ("Rate limit in action, not forwarding logs, if any!") false; + :return true; } :local Count 0; From f79206a9b82850c2df299158191f63d9e57c03f4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1977/2612] daily-psk: drop main function, use :do with on-error --- daily-psk.capsman.rsc | 10 ++++------ daily-psk.local.rsc | 10 ++++------ daily-psk.template.rsc | 10 ++++------ daily-psk.wifi.rsc | 10 ++++------ 4 files changed, 16 insertions(+), 24 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index 85e05b6..c9c0186 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -14,8 +14,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global DailyPskMatchComment; :global DailyPskQrCodeUrl; @@ -31,7 +31,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -89,6 +89,4 @@ } } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 108c711..228efc8 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -14,8 +14,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global DailyPskMatchComment; :global DailyPskQrCodeUrl; @@ -31,7 +31,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -88,6 +88,4 @@ } } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index c45f34a..4403fe6 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -15,8 +15,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global DailyPskMatchComment; :global DailyPskQrCodeUrl; @@ -32,7 +32,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -104,6 +104,4 @@ } } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index 0ba22ab..e9b5199 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -14,8 +14,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global DailyPskMatchComment; :global DailyPskQrCodeUrl; @@ -31,7 +31,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -89,6 +89,4 @@ } } } -} - -$Main [ :jobname ]; +} on-error={ } From 73d56b3d5f930c1f767e0d06e56f082c8ee64137 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1978/2612] doc/mod/inspectvar: add badges --- doc/mod/inspectvar.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/mod/inspectvar.md b/doc/mod/inspectvar.md index 1cc49a2..7ec74f2 100644 --- a/doc/mod/inspectvar.md +++ b/doc/mod/inspectvar.md @@ -1,6 +1,13 @@ 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) > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base From 6712cc101d57fbe47420c562ea82d36b07a5ad9c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 15:27:57 +0100 Subject: [PATCH 1979/2612] check-health: do not exit with error --- check-health.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/check-health.rsc b/check-health.rsc index b819665..9d7c68e 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -75,7 +75,8 @@ } :if ([ :len [ /system/health/find ] ] = 0) do={ - $LogPrintExit2 debug $ScriptName ("Your device does not provide any health values.") true; + $LogPrintExit2 debug $ScriptName ("Your device does not provide any health values.") false; + :return true; } :if ([ :typeof $CheckHealthLast ] != "array") do={ From 0d1c4cece27094aa529a5bf75ef5a0bae3bc6321 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1980/2612] dhcp-lease-comment: drop main function, use :do with on-error --- dhcp-lease-comment.capsman.rsc | 10 ++++------ dhcp-lease-comment.local.rsc | 10 ++++------ dhcp-lease-comment.template.rsc | 10 ++++------ dhcp-lease-comment.wifi.rsc | 10 ++++------ 4 files changed, 16 insertions(+), 24 deletions(-) diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc index 09893ce..1b61167 100644 --- a/dhcp-lease-comment.capsman.rsc +++ b/dhcp-lease-comment.capsman.rsc @@ -14,14 +14,14 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global LogPrintExit2; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ @@ -36,6 +36,4 @@ /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc index a5e9330..5401a77 100644 --- a/dhcp-lease-comment.local.rsc +++ b/dhcp-lease-comment.local.rsc @@ -14,14 +14,14 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global LogPrintExit2; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ @@ -36,6 +36,4 @@ /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index d7f36a3..6ed8fc3 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -15,14 +15,14 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global LogPrintExit2; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ @@ -41,6 +41,4 @@ /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc index 2552b5a..62ed03d 100644 --- a/dhcp-lease-comment.wifi.rsc +++ b/dhcp-lease-comment.wifi.rsc @@ -14,14 +14,14 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global LogPrintExit2; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ @@ -36,6 +36,4 @@ /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } -} - -$Main [ :jobname ]; +} on-error={ } From 732b86bb86369ce41bcd195313a2ae2de3d6516a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1981/2612] doc/mod/ipcalc: add badges --- doc/mod/ipcalc.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/mod/ipcalc.md b/doc/mod/ipcalc.md index f2f1140..5b24952 100644 --- a/doc/mod/ipcalc.md +++ b/doc/mod/ipcalc.md @@ -1,6 +1,13 @@ 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) > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base From 5af8b95444ae161bcc38565163aa4ed56a8e3f0e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 15:29:33 +0100 Subject: [PATCH 1982/2612] netwatch-dns: do not exit with error --- netwatch-dns.rsc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 45c12d4..1603427 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -24,7 +24,8 @@ :local SettleTime (5m30s - [ /system/resource/get uptime ]); :if ($SettleTime > 0s) do={ - $LogPrintExit2 info $ScriptName ("System just booted, giving netwatch " . $SettleTime . " to settle.") true; + $LogPrintExit2 info $ScriptName ("System just booted, giving netwatch " . $SettleTime . " to settle.") false; + :return true; } :local DnsServers ({}); @@ -80,7 +81,8 @@ } :if ($DohCurrent = $HostInfo->"doh-url") do={ - $LogPrintExit2 debug $ScriptName ("Current DoH server is still up: " . $DohCurrent) true; + $LogPrintExit2 debug $ScriptName ("Current DoH server is still up: " . $DohCurrent) false; + :return true; } :set ($DohServers->[ :len $DohServers ]) $HostInfo; @@ -116,7 +118,8 @@ :if ([ :typeof [ :find $Data "doh-check-OK" ] ] = "num") do={ /ip/dns/set use-doh-server=($DohServer->"doh-url") verify-doh-cert=yes; /ip/dns/cache/flush; - $LogPrintExit2 info $ScriptName ("Setting DoH server: " . ($DohServer->"doh-url")) true; + $LogPrintExit2 info $ScriptName ("Setting DoH server: " . ($DohServer->"doh-url")) false; + :return true; } else={ $LogPrintExit2 warning $ScriptName ("Received unexpected response from DoH server: " . \ ($DohServer->"doh-url")) false; From ef5972e9f09be975f0905ca8d81477bc443515cb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1983/2612] dhcp-to-dns: drop main function, use :do with on-error --- dhcp-to-dns.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index df6ae01..84a1e84 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -12,8 +12,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global Domain; :global Identity; @@ -27,7 +27,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :return false; + :error false; } :local Ttl 5m; @@ -123,6 +123,4 @@ $LogPrintExit2 debug $ScriptName ("No address available... Ignoring.") false; } } -} - -$Main [ :jobname ]; +} on-error={ } From e2823d87465e459dd70799938e604d545d45f8a4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1984/2612] doc/mod/notification-email: add badges --- doc/mod/notification-email.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/mod/notification-email.md b/doc/mod/notification-email.md index 373f8fe..76816c1 100644 --- a/doc/mod/notification-email.md +++ b/doc/mod/notification-email.md @@ -1,6 +1,13 @@ 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) > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base From 184a769eebc245be7b60f0c6e8ee4157b740c704 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 15:45:09 +0100 Subject: [PATCH 1985/2612] check-routeros-update: do not exit with error --- check-routeros-update.rsc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 519c2d4..1e3a1f4 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -53,7 +53,8 @@ :local Update [ /system/package/update/get ]; :if ([ $ScriptFromTerminal $ScriptName ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={ - $LogPrintExit2 info $ScriptName ("System is already up to date.") true; + $LogPrintExit2 info $ScriptName ("System is already up to date.") false; + :return true; } :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; @@ -129,7 +130,8 @@ :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ $LogPrintExit2 info $ScriptName ("Already sent the RouterOS update notification for version " . \ - $Update->"latest-version" . ".") true; + $Update->"latest-version" . ".") false; + :return true; } $SendNotification2 ({ origin=$ScriptName; \ @@ -143,7 +145,8 @@ :if ($NumInstalled > $NumLatest) do={ :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ $LogPrintExit2 info $ScriptName ("Already sent the RouterOS downgrade notification for version " . \ - $Update->"latest-version" . ".") true; + $Update->"latest-version" . ".") false; + :return true; } $SendNotification2 ({ origin=$ScriptName; \ From 894c36fc1583bbc6b48ecaa35c562dfcf467e4d3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1986/2612] firmware-upgrade-reboot: drop main function, use :do with on-error --- firmware-upgrade-reboot.rsc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc index bd28f12..6499d27 100644 --- a/firmware-upgrade-reboot.rsc +++ b/firmware-upgrade-reboot.rsc @@ -11,26 +11,26 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global LogPrintExit2; :global ScriptLock; :global VersionToNum; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :local RouterBoard [ /system/routerboard/get ]; :if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ $LogPrintExit2 info $ScriptName ("Current and upgrade firmware match with version " . \ $RouterBoard->"current-firmware" . ".") false; - :return true; + :error true; } :if ([ $VersionToNum ($RouterBoard->"current-firmware") ] > [ $VersionToNum ($RouterBoard->"upgrade-firmware") ]) do={ $LogPrintExit2 info $ScriptName ("Different firmware version is available, but it is a downgrade. Ignoring.") false; - :return true; + :error true; } :if ([ /system/routerboard/settings/get auto-upgrade ] = false) do={ @@ -51,6 +51,4 @@ $LogPrintExit2 info $ScriptName ("Firmware upgrade successful, rebooting.") false; /system/reboot; -} - -$Main [ :jobname ]; +} on-error={ } From 4a08c0912942a0de57ace8194e1277e2768c19b4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1987/2612] doc/mod/notification-matrix: add badges --- doc/mod/notification-matrix.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index b309d3d..c68b0aa 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -1,6 +1,13 @@ 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) > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base From ab0b2e27c3d190b627325827d0fba5808cba9137 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 15:46:46 +0100 Subject: [PATCH 1988/2612] firmware-upgrade-reboot: do not exit with error --- firmware-upgrade-reboot.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc index efe22ae..95adab0 100644 --- a/firmware-upgrade-reboot.rsc +++ b/firmware-upgrade-reboot.rsc @@ -23,10 +23,12 @@ :local RouterBoard [ /system/routerboard/get ]; :if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ $LogPrintExit2 info $ScriptName ("Current and upgrade firmware match with version " . \ - $RouterBoard->"current-firmware" . ".") true; + $RouterBoard->"current-firmware" . ".") false; + :return true; } :if ([ $VersionToNum ($RouterBoard->"current-firmware") ] > [ $VersionToNum ($RouterBoard->"upgrade-firmware") ]) do={ - $LogPrintExit2 info $ScriptName ("Different firmware version is available, but it is a downgrade. Ignoring.") true; + $LogPrintExit2 info $ScriptName ("Different firmware version is available, but it is a downgrade. Ignoring.") false; + :return true; } :if ([ /system/routerboard/settings/get auto-upgrade ] = false) do={ From c1362f54e585d2b17fac9232cbf845da34fa8707 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1989/2612] fw-addr-lists: drop main function, use :do with on-error --- fw-addr-lists.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 8ba0147..6071f7b 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -11,8 +11,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global FetchUserAgent; :global FwAddrLists; @@ -35,7 +35,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -156,6 +156,4 @@ $LogPrintExit2 info $ScriptName ("list: " . $FwListName . " -- added: " . $CntAdd . " - renewed: " . $CntRenew . " - removed: " . $CntRemove) false; } -} - -$Main [ :jobname ]; +} on-error={ } From db211a9804d1fc44b7bbd5a6795df8b5e87f217a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1990/2612] doc/mod/notification-ntfy: add badges --- doc/mod/notification-ntfy.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/mod/notification-ntfy.md b/doc/mod/notification-ntfy.md index f4cad8a..a3fdf88 100644 --- a/doc/mod/notification-ntfy.md +++ b/doc/mod/notification-ntfy.md @@ -1,6 +1,13 @@ Send notifications via Ntfy =========================== +[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) +[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) +[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) +[![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) + [âŦ…ī¸ Go back to main README](../../README.md) > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base From 3acdebad044785371208246ab74b062a32a6d09f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 15:58:32 +0100 Subject: [PATCH 1991/2612] hotspot-to-wpa: do not exit with error --- hotspot-to-wpa.capsman.rsc | 3 ++- hotspot-to-wpa.template.rsc | 3 ++- hotspot-to-wpa.wifi.rsc | 3 ++- hotspot-to-wpa.wifiwave2.rsc | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index d903fe9..f9f9324 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -52,7 +52,8 @@ comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; :if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") true; + $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") false; + :return true; } # allow login page to load diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index 1f82c28..9fa52c5 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -65,7 +65,8 @@ comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; :if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") true; + $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") false; + :return true; } # allow login page to load diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index cd6aa80..7638cf7 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -52,7 +52,8 @@ comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; :if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") true; + $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") false; + :return true; } # allow login page to load diff --git a/hotspot-to-wpa.wifiwave2.rsc b/hotspot-to-wpa.wifiwave2.rsc index ef068b6..1b60227 100644 --- a/hotspot-to-wpa.wifiwave2.rsc +++ b/hotspot-to-wpa.wifiwave2.rsc @@ -52,7 +52,8 @@ comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; :if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") true; + $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") false; + :return true; } # allow login page to load From 47b67af2266e8706f8b047477c9db84c6282360a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1992/2612] gps-track: drop main function, use :do with on-error --- gps-track.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/gps-track.rsc b/gps-track.rsc index cef95f2..c40e2e0 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -11,8 +11,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global GpsTrackUrl; :global Identity; @@ -22,7 +22,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -47,6 +47,4 @@ } else={ $LogPrintExit2 debug $ScriptName ("GPS data not valid.") false; } -} - -$Main [ :jobname ]; +} on-error={ } From 4313de6c68877e663b0517ace72fc2b649152931 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1993/2612] doc/mod/notification-telegram: add badges --- doc/mod/notification-telegram.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index 444938f..cb326f0 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -1,6 +1,13 @@ 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) > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base From c6639518bcd6689286ed63505d243369c95196e2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 16:01:00 +0100 Subject: [PATCH 1994/2612] lease-script: do not exit with error --- lease-script.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lease-script.rsc b/lease-script.rsc index d9c7177..64e7f46 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -37,7 +37,8 @@ $ScriptLock $ScriptName false 10; :if ([ :len [ /system/script/job/find where script=$ScriptName ] ] > 1) do={ - $LogPrintExit2 debug $ScriptName ("More invocations are waiting, exiting early.") true; + $LogPrintExit2 debug $ScriptName ("More invocations are waiting, exiting early.") false; + :return true; } :local RunOrder ({}); From b622f47d6566d2049f95f17c787f1b3ee2b103b4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1995/2612] hotspot-to-wpa-cleanup: drop main function, use :do with on-error --- hotspot-to-wpa-cleanup.capsman.rsc | 10 ++++------ hotspot-to-wpa-cleanup.template.rsc | 10 ++++------ hotspot-to-wpa-cleanup.wifi.rsc | 10 ++++------ 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index 62beacc..ba74260 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -14,8 +14,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global EitherOr; :global LogPrintExit2; @@ -23,7 +23,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :return false; + :error false; } :local DHCPServers ({}); @@ -71,6 +71,4 @@ /ip/dhcp-server/lease/remove $Lease; } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index bba9f0e..c46d75d 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -15,8 +15,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global EitherOr; :global LogPrintExit2; @@ -24,7 +24,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :return false; + :error false; } :local DHCPServers ({}); @@ -78,6 +78,4 @@ /ip/dhcp-server/lease/remove $Lease; } } -} - -$Main [ :jobname ]; +} on-error={ } diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index a44064f..3e5799a 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -14,8 +14,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global EitherOr; :global LogPrintExit2; @@ -23,7 +23,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :return false; + :error false; } :local DHCPServers ({}); @@ -71,6 +71,4 @@ /ip/dhcp-server/lease/remove $Lease; } } -} - -$Main [ :jobname ]; +} on-error={ } From 564a288c4ccfcba43f07f3578bbc843e99f6abc2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1996/2612] doc/mod/scriptrunonce: add badges --- doc/mod/scriptrunonce.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/mod/scriptrunonce.md b/doc/mod/scriptrunonce.md index 895c20c..6619efb 100644 --- a/doc/mod/scriptrunonce.md +++ b/doc/mod/scriptrunonce.md @@ -1,6 +1,13 @@ 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) > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base From ec90695e8ff892926e9839d29bdbf672d2b5ca90 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 16:18:29 +0100 Subject: [PATCH 1997/2612] packages-update: do not exit with error --- packages-update.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index 325009f..e6bed78 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -39,7 +39,8 @@ on-event=("/system/scheduler/remove \"_RebootForUpdate\"; " . \ ":global RebootForUpdate; \$RebootForUpdate;"); $LogPrintExit2 info $ScriptName ("Scheduled reboot for update at " . $StartTime . \ - " local time (" . [ /system/clock/get time-zone-name ] . ").") true; + " local time (" . [ /system/clock/get time-zone-name ] . ").") false; + :return true; } $ScriptLock $ScriptName; @@ -51,7 +52,8 @@ } :if ($Update->"installed-version" = $Update->"latest-version") do={ - $LogPrintExit2 info $ScriptName ("Version " . $Update->"latest-version" . " is already installed.") true; + $LogPrintExit2 info $ScriptName ("Version " . $Update->"latest-version" . " is already installed.") false; + :return true; } :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; From 54638924e4a06f926d3bdd3bbd44489acc692a75 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 1998/2612] hotspot-to-wpa: drop main function, use :do with on-error --- hotspot-to-wpa.capsman.rsc | 19 +++++++++---------- hotspot-to-wpa.template.rsc | 19 +++++++++---------- hotspot-to-wpa.wifi.rsc | 19 +++++++++---------- 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index 7498ae2..a6ad2a1 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -13,21 +13,22 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; - :local MacAddress [ :tostr $2 ]; - :local UserName [ :tostr $3 ]; +:do { + :local ScriptName [ :jobname ]; :global EitherOr; :global LogPrintExit2; :global ParseKeyValueStore; :global ScriptLock; + :local MacAddress $"mac-address"; + :local UserName $username; + :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } - :if ([ :len $MacAddress ] = 0 || [ :len $UserName ] = 0) do={ + :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; } @@ -55,7 +56,7 @@ :if ($Template->"action" = "reject") do={ $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") false; - :return true; + :error true; } # allow login page to load @@ -93,6 +94,4 @@ :delay 2s; /caps-man/access-list/set $Entry action=accept; -} - -$Main [ :jobname ] $"mac-address" $username; +} on-error={ } diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index c96096c..b7869c4 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -14,21 +14,22 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; - :local MacAddress [ :tostr $2 ]; - :local UserName [ :tostr $3 ]; +:do { + :local ScriptName [ :jobname ]; :global EitherOr; :global LogPrintExit2; :global ParseKeyValueStore; :global ScriptLock; + :local MacAddress $"mac-address"; + :local UserName $username; + :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } - :if ([ :len $MacAddress ] = 0 || [ :len $UserName ] = 0) do={ + :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; } @@ -62,7 +63,7 @@ :if ($Template->"action" = "reject") do={ $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") false; - :return true; + :error true; } # allow login page to load @@ -113,6 +114,4 @@ :delay 2s; /caps-man/access-list/set $Entry action=accept; /interface/wifi/access-list/set $Entry action=accept; -} - -$Main [ :jobname ] $"mac-address" $username; +} on-error={ } diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index 83f490d..e728d7f 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -13,21 +13,22 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; - :local MacAddress [ :tostr $2 ]; - :local UserName [ :tostr $3 ]; +:do { + :local ScriptName [ :jobname ]; :global EitherOr; :global LogPrintExit2; :global ParseKeyValueStore; :global ScriptLock; + :local MacAddress $"mac-address"; + :local UserName $username; + :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } - :if ([ :len $MacAddress ] = 0 || [ :len $UserName ] = 0) do={ + :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; } @@ -55,7 +56,7 @@ :if ($Template->"action" = "reject") do={ $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") false; - :return true; + :error true; } # allow login page to load @@ -90,6 +91,4 @@ :delay 2s; /interface/wifi/access-list/set $Entry action=accept; -} - -$Main [ :jobname ] $"mac-address" $username; +} on-error={ } From 1934c63512cbf77d2cf6d3183995e3d6af11f850 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 1999/2612] doc/mod/ssh-keys-import: add badges --- doc/mod/ssh-keys-import.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md index 1d00882..3d81566 100644 --- a/doc/mod/ssh-keys-import.md +++ b/doc/mod/ssh-keys-import.md @@ -1,6 +1,13 @@ Import ssh keys for public key authentication ============================================= +[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) +[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) +[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) +[![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) + [âŦ…ī¸ Go back to main README](../../README.md) > â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base From 4004d713aa9c9ffeb5c317a5030e0e929d668460 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 16:22:17 +0100 Subject: [PATCH 2000/2612] sms-forward: do not exit with error --- sms-forward.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sms-forward.rsc b/sms-forward.rsc index fee1539..f85dab2 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -38,7 +38,8 @@ :local Settings [ /tool/sms/get ]; :if ([ /interface/lte/get ($Settings->"port") running ] != true) do={ - $LogPrintExit2 info $ScriptName ("The LTE interface is not in running state, skipping.") true; + $LogPrintExit2 info $ScriptName ("The LTE interface is not in running state, skipping.") false; + :return true; } # forward SMS in a loop From 341e84682cd3242735a0776640901ed0b9b7bebe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2001/2612] ipsec-to-dns: drop main function, use :do with on-error --- ipsec-to-dns.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index e19a11b..03abf59 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -11,8 +11,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global Domain; :global HostNameInZone; @@ -26,7 +26,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :local Zone \ @@ -76,6 +76,4 @@ /ip/dns/static/add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } -} - -$Main [ :jobname ]; +} on-error={ } From 2170505bebb9d24e0c69a146c63868e1539c8846 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 2002/2612] doc/mode-button: add badges --- doc/mode-button.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/mode-button.md b/doc/mode-button.md index 38a4b11..22ec215 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From d799edfc17cb50b0949c6bcd3d3de8fba9914c54 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Mar 2024 11:02:45 +0100 Subject: [PATCH 2003/2612] Makefile: drop support for wifiwave2 --- Makefile | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index b18b09a..d21713c 100644 --- a/Makefile +++ b/Makefile @@ -5,39 +5,32 @@ CAPSMAN = $(wildcard *.capsman.rsc) LOCAL = $(wildcard *.local.rsc) WIFI = $(wildcard *.wifi.rsc) -WIFIWAVE2 = $(wildcard *.wifiwave2.rsc) MARKDOWN = $(wildcard *.md doc/*.md doc/mod/*.md) HTML = $(MARKDOWN:.md=.html) -all: $(CAPSMAN) $(LOCAL) $(WIFI) $(WIFIWAVE2) $(HTML) +all: $(CAPSMAN) $(LOCAL) $(WIFI) $(HTML) %.html: %.md Makefile markdown $< | sed 's/href="\([-_\./[:alnum:]]*\)\.md"/href="\1.html"/g' > $@ %.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 '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ %.local.rsc: %.template.rsc Makefile - sed -e '/\/caps-man\//d' -e '/\/interface\/wifi\//d' -e '/\/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 '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ %.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 '/^# !!/,/^# !!/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: rm -f $(HTML) From 56e97dd60c3c9603df07bb315587c44da1ff44fd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Mar 2024 15:59:22 +0100 Subject: [PATCH 2004/2612] global-functions: $DownloadPackage: do not exit from global function --- global-functions.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 90148f8..b68fbaa 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -328,7 +328,8 @@ } :if ([ $CertificateAvailable "R3" ] = false) do={ - $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; + $LogPrintExit2 error $0 ("Downloading required certificate failed.") false; + :return false; } :local Url ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile); From 6f91c97b7fe68dbfd5274259aafbc2a77dd80d3d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2005/2612] ipv6-update: drop main function, use :do with on-error --- ipv6-update.rsc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/ipv6-update.rsc b/ipv6-update.rsc index d173347..8ce1e4d 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -11,16 +11,17 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; - :local PdPrefix $2; +:do { + :local ScriptName [ :jobname ]; :global LogPrintExit2; :global ParseKeyValueStore; :global ScriptLock; + :local PdPrefix $"pd-prefix"; + :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :if ([ :typeof $PdPrefix ] = "nothing") do={ @@ -82,6 +83,4 @@ } } } -} - -$Main [ :jobname ] $"pd-prefix"; +} on-error={ } From fe83328a57c3ada51b54be1186a817341250176c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 2006/2612] doc/netwatch-dns: add badges --- doc/netwatch-dns.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 88d4878..e00ccd0 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 9ecc3c4c49cd1113e2444116e2f7ab859e5193fa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Mar 2024 11:04:20 +0100 Subject: [PATCH 2007/2612] accesslist-duplicates: drop support for wifiwave2 --- accesslist-duplicates.template.rsc | 4 ---- accesslist-duplicates.wifiwave2.rsc | 36 ----------------------------- doc/accesslist-duplicates.md | 13 ++++------- 3 files changed, 4 insertions(+), 49 deletions(-) delete mode 100644 accesslist-duplicates.wifiwave2.rsc diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index 97f6138..c65e9e0 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -21,16 +21,13 @@ :foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ - :foreach AccList in=[ /interface/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!" ] ]; @@ -38,7 +35,6 @@ :put ("Removing numeric id " . $Remove . "...\n"); /caps-man/access-list/remove $Remove; /interface/wifi/access-list/remove $Remove; - /interface/wifiwave2/access-list/remove $Remove; /interface/wireless/access-list/remove $Remove; } } diff --git a/accesslist-duplicates.wifiwave2.rsc b/accesslist-duplicates.wifiwave2.rsc deleted file mode 100644 index 232d941..0000000 --- a/accesslist-duplicates.wifiwave2.rsc +++ /dev/null @@ -1,36 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: accesslist-duplicates.wifiwave2 -# Copyright (c) 2018-2024 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# requires RouterOS, version=7.12 -# -# print duplicate antries in wireless access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local Main do={ - :local ScriptName [ :tostr $1 ]; - - :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; - } -} - -$Main [ :jobname ]; diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index 090298e..6cb40f6 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -15,19 +15,14 @@ entries in wireless access list. Requirements and installation ----------------------------- -Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` -package (`/interface/wifiwave2`), legacy wifi with CAPsMAN (`/caps-man`) -or local wireless interface (`/interface/wireless`) you need to install a -different script. +Depending on whether you use `wifi` package (`/interface/wifi`), legacy +wifi with CAPsMAN (`/caps-man`) or local wireless interface +(`/interface/wireless`) you need to install a different script. -For `wifi` (RouterOS 7.13 and later): +For `wifi`: $ScriptInstallUpdate accesslist-duplicates.wifi; -For `wifiwave2` (up to RouterOS 7.12): - - $ScriptInstallUpdate accesslist-duplicates.wifiwave2; - For legacy CAPsMAN: $ScriptInstallUpdate accesslist-duplicates.capsman; From 1e8918fdaa5a30393e2004d1f5e4dff458936b67 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Mar 2024 16:12:36 +0100 Subject: [PATCH 2008/2612] global-functions: $ScriptLock: do not exit from global function --- backup-cloud.rsc | 4 +++- backup-email.rsc | 4 +++- backup-partition.rsc | 4 +++- backup-upload.rsc | 4 +++- capsman-download-packages.capsman.rsc | 4 +++- capsman-download-packages.template.rsc | 4 +++- capsman-download-packages.wifi.rsc | 4 +++- capsman-download-packages.wifiwave2.rsc | 4 +++- capsman-rolling-upgrade.capsman.rsc | 4 +++- capsman-rolling-upgrade.template.rsc | 4 +++- capsman-rolling-upgrade.wifi.rsc | 4 +++- capsman-rolling-upgrade.wifiwave2.rsc | 4 +++- certificate-renew-issued.rsc | 4 +++- check-certificates.rsc | 4 +++- check-health.rsc | 4 +++- check-lte-firmware-upgrade.rsc | 4 +++- check-routeros-update.rsc | 4 +++- collect-wireless-mac.capsman.rsc | 4 +++- collect-wireless-mac.local.rsc | 4 +++- collect-wireless-mac.template.rsc | 4 +++- collect-wireless-mac.wifi.rsc | 4 +++- collect-wireless-mac.wifiwave2.rsc | 4 +++- daily-psk.capsman.rsc | 4 +++- daily-psk.local.rsc | 4 +++- daily-psk.template.rsc | 4 +++- daily-psk.wifi.rsc | 4 +++- daily-psk.wifiwave2.rsc | 4 +++- dhcp-lease-comment.capsman.rsc | 4 +++- dhcp-lease-comment.local.rsc | 4 +++- dhcp-lease-comment.template.rsc | 4 +++- dhcp-lease-comment.wifi.rsc | 4 +++- dhcp-lease-comment.wifiwave2.rsc | 4 +++- dhcp-to-dns.rsc | 4 +++- firmware-upgrade-reboot.rsc | 4 +++- fw-addr-lists.rsc | 4 +++- global-functions.rsc | 9 ++++----- gps-track.rsc | 4 +++- hotspot-to-wpa-cleanup.capsman.rsc | 4 +++- hotspot-to-wpa-cleanup.template.rsc | 4 +++- hotspot-to-wpa-cleanup.wifi.rsc | 4 +++- hotspot-to-wpa-cleanup.wifiwave2.rsc | 4 +++- hotspot-to-wpa.capsman.rsc | 4 +++- hotspot-to-wpa.template.rsc | 4 +++- hotspot-to-wpa.wifi.rsc | 4 +++- hotspot-to-wpa.wifiwave2.rsc | 4 +++- ipsec-to-dns.rsc | 4 +++- ipv6-update.rsc | 4 +++- lease-script.rsc | 4 +++- log-forward.rsc | 4 +++- netwatch-dns.rsc | 4 +++- netwatch-notify.rsc | 4 +++- ospf-to-leds.rsc | 4 +++- packages-update.rsc | 4 +++- sms-forward.rsc | 4 +++- telegram-chat.rsc | 4 +++- update-gre-address.rsc | 4 +++- update-tunnelbroker.rsc | 4 +++- 57 files changed, 172 insertions(+), 61 deletions(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 94966c5..418e68d 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -30,7 +30,9 @@ :global SymbolForNotification; :global WaitFullyConnected; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; :if ([ $ScriptFromTerminal $ScriptName ] = false && $BackupRandomDelay > 0) do={ diff --git a/backup-email.rsc b/backup-email.rsc index 7380a5d..c5b4568 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -45,7 +45,9 @@ $LogPrintExit2 error $ScriptName ("Configured to send neither backup nor config export.") true; } - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; :if ([ $ScriptFromTerminal $ScriptName ] = false && $BackupRandomDelay > 0) do={ diff --git a/backup-partition.rsc b/backup-partition.rsc index 4793f12..74dccfe 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -18,7 +18,9 @@ :global LogPrintExit2; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :if ([ :len [ /partitions/find ] ] < 2) do={ $LogPrintExit2 error $ScriptName ("Device does not have a fallback partition.") true; diff --git a/backup-upload.rsc b/backup-upload.rsc index dfba15e..c2b3285 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -44,7 +44,9 @@ $LogPrintExit2 error $ScriptName ("Configured to send neither backup nor config export.") true; } - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; :if ([ $ScriptFromTerminal $ScriptName ] = false && $BackupRandomDelay > 0) do={ diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index 18ecf57..cb82a37 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -24,7 +24,9 @@ :global ScriptLock; :global WaitFullyConnected; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; :local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 8cc7b2d..41d2dca 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -25,7 +25,9 @@ :global ScriptLock; :global WaitFullyConnected; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; :local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 6f62c54..89af381 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -24,7 +24,9 @@ :global ScriptLock; :global WaitFullyConnected; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; :local PackagePath [ $CleanFilePath [ /interface/wifi/capsman/get package-path ] ]; diff --git a/capsman-download-packages.wifiwave2.rsc b/capsman-download-packages.wifiwave2.rsc index 705da70..2b8ea73 100644 --- a/capsman-download-packages.wifiwave2.rsc +++ b/capsman-download-packages.wifiwave2.rsc @@ -24,7 +24,9 @@ :global ScriptLock; :global WaitFullyConnected; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; :local PackagePath [ $CleanFilePath [ /interface/wifiwave2/capsman/get package-path ] ]; diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc index fb0904d..9379b24 100644 --- a/capsman-rolling-upgrade.capsman.rsc +++ b/capsman-rolling-upgrade.capsman.rsc @@ -21,7 +21,9 @@ :global LogPrintExit2; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :local InstalledVersion [ /system/package/update/get installed-version ]; diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index 6ea9ac0..c810f43 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -22,7 +22,9 @@ :global LogPrintExit2; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :local InstalledVersion [ /system/package/update/get installed-version ]; diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc index d788c29..205d1d8 100644 --- a/capsman-rolling-upgrade.wifi.rsc +++ b/capsman-rolling-upgrade.wifi.rsc @@ -21,7 +21,9 @@ :global LogPrintExit2; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :local InstalledVersion [ /system/package/update/get installed-version ]; diff --git a/capsman-rolling-upgrade.wifiwave2.rsc b/capsman-rolling-upgrade.wifiwave2.rsc index 78e348d..4b3aba4 100644 --- a/capsman-rolling-upgrade.wifiwave2.rsc +++ b/capsman-rolling-upgrade.wifiwave2.rsc @@ -21,7 +21,9 @@ :global LogPrintExit2; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :local InstalledVersion [ /system/package/update/get installed-version ]; diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc index 79ed0ba..7bf4128 100644 --- a/certificate-renew-issued.rsc +++ b/certificate-renew-issued.rsc @@ -20,7 +20,9 @@ :global MkDir; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :foreach Cert in=[ /certificate/find where issued expires-after<3w ] do={ :local CertVal [ /certificate/get $Cert ]; diff --git a/check-certificates.rsc b/check-certificates.rsc index f15f145..69d9097 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -127,7 +127,9 @@ [ $FormatLine "Expires in" [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ] ]); } - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; :foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ diff --git a/check-health.rsc b/check-health.rsc index 9d7c68e..df76d25 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -39,7 +39,9 @@ :return ($T->0 * 10 + $T->1); } - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :local Resource [ /system/resource/get ]; diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index 12d2dd4..18109fb 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -18,7 +18,9 @@ :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :if ([ :typeof $SentLteFirmwareUpgradeNotification ] != "array") do={ :global SentLteFirmwareUpgradeNotification ({}); diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 1e3a1f4..ae0038c 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -41,7 +41,9 @@ :error "Waiting for system to reboot."; } - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; :if ([ :len [ /system/scheduler/find where name="_RebootForUpdate" ] ] > 0) do={ diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index 0ae15ee..3a10b1f 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -28,7 +28,9 @@ :global SendNotification2; :global SymbolForNotification; - $ScriptLock $ScriptName false 10; + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :return false; + } :if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ /caps-man/access-list/add comment="--- collected above ---" disabled=yes; diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index 0353ddb..f6f898e 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -28,7 +28,9 @@ :global SendNotification2; :global SymbolForNotification; - $ScriptLock $ScriptName false 10; + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :return false; + } :if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ /interface/wireless/access-list/add comment="--- collected above ---" disabled=yes; diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index 71f5679..d046fbe 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -29,7 +29,9 @@ :global SendNotification2; :global SymbolForNotification; - $ScriptLock $ScriptName false 10; + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :return false; + } :if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ :if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc index f35cdad..c866bcc 100644 --- a/collect-wireless-mac.wifi.rsc +++ b/collect-wireless-mac.wifi.rsc @@ -28,7 +28,9 @@ :global SendNotification2; :global SymbolForNotification; - $ScriptLock $ScriptName false 10; + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :return false; + } :if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ /interface/wifi/access-list/add comment="--- collected above ---" disabled=yes; diff --git a/collect-wireless-mac.wifiwave2.rsc b/collect-wireless-mac.wifiwave2.rsc index 86aef65..de8cdab 100644 --- a/collect-wireless-mac.wifiwave2.rsc +++ b/collect-wireless-mac.wifiwave2.rsc @@ -28,7 +28,9 @@ :global SendNotification2; :global SymbolForNotification; - $ScriptLock $ScriptName false 10; + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :return false; + } :if ([ :len [ /interface/wifiwave2/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ /interface/wifiwave2/access-list/add comment="--- collected above ---" disabled=yes; diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index b47ae14..85e05b6 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -30,7 +30,9 @@ :global WaitForFile; :global WaitFullyConnected; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; # return pseudo-random string for PSK diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 72e20ef..108c711 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -30,7 +30,9 @@ :global WaitForFile; :global WaitFullyConnected; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; # return pseudo-random string for PSK diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 2f2838e..93cefeb 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -31,7 +31,9 @@ :global WaitForFile; :global WaitFullyConnected; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; # return pseudo-random string for PSK diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index e013dd1..0ba22ab 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -30,7 +30,9 @@ :global WaitForFile; :global WaitFullyConnected; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; # return pseudo-random string for PSK diff --git a/daily-psk.wifiwave2.rsc b/daily-psk.wifiwave2.rsc index 75cfb7a..4e71489 100644 --- a/daily-psk.wifiwave2.rsc +++ b/daily-psk.wifiwave2.rsc @@ -30,7 +30,9 @@ :global WaitForFile; :global WaitFullyConnected; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; # return pseudo-random string for PSK diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc index 825077a..09893ce 100644 --- a/dhcp-lease-comment.capsman.rsc +++ b/dhcp-lease-comment.capsman.rsc @@ -20,7 +20,9 @@ :global LogPrintExit2; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc index 13c04a7..a5e9330 100644 --- a/dhcp-lease-comment.local.rsc +++ b/dhcp-lease-comment.local.rsc @@ -20,7 +20,9 @@ :global LogPrintExit2; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index 9f79d06..d0133c8 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -21,7 +21,9 @@ :global LogPrintExit2; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc index cba1d6c..2552b5a 100644 --- a/dhcp-lease-comment.wifi.rsc +++ b/dhcp-lease-comment.wifi.rsc @@ -20,7 +20,9 @@ :global LogPrintExit2; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; diff --git a/dhcp-lease-comment.wifiwave2.rsc b/dhcp-lease-comment.wifiwave2.rsc index 137ac6d..7cc29da 100644 --- a/dhcp-lease-comment.wifiwave2.rsc +++ b/dhcp-lease-comment.wifiwave2.rsc @@ -20,7 +20,9 @@ :global LogPrintExit2; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 1cdd86e..df6ae01 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -26,7 +26,9 @@ :global ParseKeyValueStore; :global ScriptLock; - $ScriptLock $ScriptName false 10; + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :return false; + } :local Ttl 5m; :local CommentPrefix ("managed by " . $ScriptName); diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc index 95adab0..bd28f12 100644 --- a/firmware-upgrade-reboot.rsc +++ b/firmware-upgrade-reboot.rsc @@ -18,7 +18,9 @@ :global ScriptLock; :global VersionToNum; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :local RouterBoard [ /system/routerboard/get ]; :if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index d4ac519..8ba0147 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -34,7 +34,9 @@ } } - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; :local ListComment ("managed by " . $ScriptName); diff --git a/global-functions.rsc b/global-functions.rsc index b68fbaa..1e36616 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1170,8 +1170,7 @@ # lock script against multiple invocation :set ScriptLock do={ :local Script [ :tostr $1 ]; - :local DoReturn $2; - :local WaitMax ([ :tonum $3 ] * 10); + :local WaitMax ([ :tonum $3 ] * 10); :global GetRandom20CharAlNum; :global IfThenElse; @@ -1286,13 +1285,13 @@ :if ([ $IsFirstTicket $Script $MyTicket ] = true && [ $TicketCount $Script ] = [ $JobCount $Script ]) do={ $RemoveTicket $Script $MyTicket; $CleanupTickets $Script; - :return false; + :return true; } $RemoveTicket $Script $MyTicket; $LogPrintExit2 info $0 ("Script '" . $Script . "' started more than once" . [ $IfThenElse ($WaitCount > 0) \ - " and timed out waiting for lock" "" ] . "... Aborting.") [ $IfThenElse ($DoReturn = true) false true ]; - :return true; + " and timed out waiting for lock" "" ] . "... Aborting.") false; + :return false; } # send notification via NotificationFunctions - expects at least two string arguments diff --git a/gps-track.rsc b/gps-track.rsc index 8517778..cef95f2 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -21,7 +21,9 @@ :global ScriptLock; :global WaitFullyConnected; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; :local CoordinateFormat [ /system/gps/get coordinate-format ]; diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index 498e853..62beacc 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -22,7 +22,9 @@ :global ParseKeyValueStore; :global ScriptLock; - $ScriptLock $ScriptName false 10; + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :return false; + } :local DHCPServers ({}); :foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 9ffc6ea..c393888 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -23,7 +23,9 @@ :global ParseKeyValueStore; :global ScriptLock; - $ScriptLock $ScriptName false 10; + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :return false; + } :local DHCPServers ({}); :foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index cf7eaad..a44064f 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -22,7 +22,9 @@ :global ParseKeyValueStore; :global ScriptLock; - $ScriptLock $ScriptName false 10; + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :return false; + } :local DHCPServers ({}); :foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ diff --git a/hotspot-to-wpa-cleanup.wifiwave2.rsc b/hotspot-to-wpa-cleanup.wifiwave2.rsc index bbb64c5..e5a0cf5 100644 --- a/hotspot-to-wpa-cleanup.wifiwave2.rsc +++ b/hotspot-to-wpa-cleanup.wifiwave2.rsc @@ -22,7 +22,9 @@ :global ParseKeyValueStore; :global ScriptLock; - $ScriptLock $ScriptName false 10; + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :return false; + } :local DHCPServers ({}); :foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index f9f9324..7498ae2 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -23,7 +23,9 @@ :global ParseKeyValueStore; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :if ([ :len $MacAddress ] = 0 || [ :len $UserName ] = 0) do={ $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index 9fa52c5..9038d82 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -24,7 +24,9 @@ :global ParseKeyValueStore; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :if ([ :len $MacAddress ] = 0 || [ :len $UserName ] = 0) do={ $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index 7638cf7..83f490d 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -23,7 +23,9 @@ :global ParseKeyValueStore; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :if ([ :len $MacAddress ] = 0 || [ :len $UserName ] = 0) do={ $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; diff --git a/hotspot-to-wpa.wifiwave2.rsc b/hotspot-to-wpa.wifiwave2.rsc index 1b60227..519f81f 100644 --- a/hotspot-to-wpa.wifiwave2.rsc +++ b/hotspot-to-wpa.wifiwave2.rsc @@ -23,7 +23,9 @@ :global ParseKeyValueStore; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :if ([ :len $MacAddress ] = 0 || [ :len $UserName ] = 0) do={ $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index ff445e6..e19a11b 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -25,7 +25,9 @@ :global LogPrintExit2; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :local Zone \ ([ $IfThenElse ($PrefixInZone = true) "ipsec." ] . \ diff --git a/ipv6-update.rsc b/ipv6-update.rsc index 350fc4b..d173347 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -19,7 +19,9 @@ :global ParseKeyValueStore; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :if ([ :typeof $PdPrefix ] = "nothing") do={ $LogPrintExit2 error $ScriptName ("This script is supposed to run from ipv6 dhcp-client.") true; diff --git a/lease-script.rsc b/lease-script.rsc index 64e7f46..582f8ff 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -34,7 +34,9 @@ $LogPrintExit2 debug $ScriptName ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \ "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC) false; - $ScriptLock $ScriptName false 10; + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :return false; + } :if ([ :len [ /system/script/job/find where script=$ScriptName ] ] > 1) do={ $LogPrintExit2 debug $ScriptName ("More invocations are waiting, exiting early.") false; diff --git a/log-forward.rsc b/log-forward.rsc index 5044d43..b9dbc8b 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -32,7 +32,9 @@ :global SendNotification2; :global SymbolForNotification; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :if ([ :typeof $LogForwardRateLimit ] = "nothing") do={ :set LogForwardRateLimit 0; diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 1603427..2468d35 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -20,7 +20,9 @@ :global ParseKeyValueStore; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :local SettleTime (5m30s - [ /system/resource/get uptime ]); :if ($SettleTime > 0s) do={ diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 28ab229..ce74ffa 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -75,7 +75,9 @@ :return false; } - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :local ScriptFromTerminalCached [ $ScriptFromTerminal $ScriptName ]; diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc index a462d2a..3ca16db 100644 --- a/ospf-to-leds.rsc +++ b/ospf-to-leds.rsc @@ -18,7 +18,9 @@ :global ParseKeyValueStore; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :foreach Instance in=[ /routing/ospf/instance/find where comment~"^ospf-to-leds," ] do={ :local InstanceVal [ /routing/ospf/instance/get $Instance ]; diff --git a/packages-update.rsc b/packages-update.rsc index e6bed78..5b6d158 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -43,7 +43,9 @@ :return true; } - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :local Update [ /system/package/update/get ]; diff --git a/sms-forward.rsc b/sms-forward.rsc index f85dab2..7c4488a 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -27,7 +27,9 @@ :global ValidateSyntax; :global WaitFullyConnected; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :if ([ /tool/sms/get receive-enabled ] = false) do={ $LogPrintOnce warning $ScriptName ("Receiving of SMS is not enabled.") true; diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 197c8a3..bb12042 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -43,7 +43,9 @@ :global WaitForFile; :global WaitFullyConnected; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } $WaitFullyConnected; diff --git a/update-gre-address.rsc b/update-gre-address.rsc index 62cdfe1..d9a7a55 100644 --- a/update-gre-address.rsc +++ b/update-gre-address.rsc @@ -19,7 +19,9 @@ :global LogPrintExit2; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } /interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index c61d82e..90e3f24 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -21,7 +21,9 @@ :global ParseKeyValueStore; :global ScriptLock; - $ScriptLock $ScriptName; + :if ([ $ScriptLock $ScriptName ] = false) do={ + :return false; + } :if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ $LogPrintExit2 error $ScriptName ("Downloading required certificate failed.") true; From 6546e7f085c9a5ce33c6efa0b1887d178eb4ac5a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2009/2612] lease-script: drop main function, use :do with on-error --- lease-script.rsc | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/lease-script.rsc b/lease-script.rsc index 582f8ff..0f6b7f8 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -11,12 +11,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; - :local leaseActIP [ :tostr $2 ]; - :local leaseActMAC [ :tostr $2 ]; - :local leaseServerName [ :tostr $2 ]; - :local leaseBound [ :tostr $2 ]; +:do { + :local ScriptName [ :jobname ]; :global Grep; :global IfThenElse; @@ -35,12 +31,12 @@ "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC) false; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :return false; + :error false; } :if ([ :len [ /system/script/job/find where script=$ScriptName ] ] > 1) do={ $LogPrintExit2 debug $ScriptName ("More invocations are waiting, exiting early.") false; - :return true; + :error true; } :local RunOrder ({}); @@ -59,6 +55,4 @@ $LogPrintExit2 warning $ScriptName ("Running script '" . $Script . "' failed!") false; } } -} - -$Main [ :jobname ] $leaseActIP $leaseActMAC $leaseServerName $leaseBound; +} on-error={ } From cdc0db3b814f8119649536300c604d4a31261f85 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 2010/2612] doc/netwatch-notify: add badges --- doc/netwatch-notify.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index e252d39..6f3e1ce 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 34620ba53cb5fd1e3160c0a53a36c27ba34da256 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Mar 2024 11:06:53 +0100 Subject: [PATCH 2011/2612] capsman-download-packages: drop support for wifiwave2 --- capsman-download-packages.template.rsc | 9 --- capsman-download-packages.wifiwave2.rsc | 83 ------------------------- doc/capsman-download-packages.md | 19 ++---- 3 files changed, 4 insertions(+), 107 deletions(-) delete mode 100644 capsman-download-packages.wifiwave2.rsc diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 41d2dca..a76071e 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -32,7 +32,6 @@ :local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; :local PackagePath [ $CleanFilePath [ /interface/wifi/capsman/get package-path ] ]; - :local PackagePath [ $CleanFilePath [ /interface/wifiwave2/capsman/get package-path ] ]; :local InstalledVersion [ /system/package/update/get installed-version ]; :local Updated false; @@ -65,21 +64,14 @@ :if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ $LogPrintExit2 info $ScriptName ("No packages available, downloading default set.") false; # NOT /interface/wifi/ # -# NOT /interface/wifiwave2/ # :foreach Arch in={ "arm"; "mipsbe" } do={ :foreach Package in={ "routeros"; "wireless" } do={ # NOT /interface/wifi/ # -# NOT /interface/wifiwave2/ # # NOT /caps-man/ # :foreach Arch in={ "arm"; "arm64" } do={ -# NOT /interface/wifi/ # - :foreach Package in={ "routeros"; "wifiwave2" } do={ -# NOT /interface/wifi/ # -# 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/ # :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ :set Updated true; @@ -95,7 +87,6 @@ } else={ /caps-man/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 ]; } } } diff --git a/capsman-download-packages.wifiwave2.rsc b/capsman-download-packages.wifiwave2.rsc deleted file mode 100644 index 2b8ea73..0000000 --- a/capsman-download-packages.wifiwave2.rsc +++ /dev/null @@ -1,83 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: capsman-download-packages.wifiwave2 -# Copyright (c) 2018-2024 Christian Hesse -# Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# requires RouterOS, version=7.12 -# -# download and cleanup packages for CAP installation from CAPsMAN -# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local Main do={ - :local ScriptName [ :tostr $1 ]; - - :global CleanFilePath; - :global DownloadPackage; - :global LogPrintExit2; - :global MkDir; - :global ScriptLock; - :global WaitFullyConnected; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; - } - $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 $ScriptName ("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 $ScriptName ("Creating directory at CAPsMAN package path (" . \ - $PackagePath . ") failed!") true; - } - $LogPrintExit2 info $ScriptName ("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 $ScriptName ("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 ]; - } - } -} - -$Main [ :jobname ]; diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index 5b9550d..03e4497 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -23,31 +23,21 @@ as that is where packages are downloaded to and where the system expects them. Then just install the script on CAPsMAN device. -Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` -package (`/interface/wifiwave2`) or legacy wifi with CAPsMAN (`/caps-man`) -you need to install a different script. +Depending on whether you use `wifi` package (`/interface/wifi`) or legacy +wifi with CAPsMAN (`/caps-man`) you need to install a different script. -For `wifi` (RouterOS 7.13 and later): +For `wifi`: $ScriptInstallUpdate capsman-download-packages.wifi; -For `wifiwave2` (up to RouterOS 7.12): - - $ScriptInstallUpdate capsman-download-packages.wifiwave2; - For legacy CAPsMAN: $ScriptInstallUpdate capsman-download-packages.capsman; -Optionally add a scheduler to run after startup. For `wifi` (RouterOS 7.13 -and later): +Optionally add a scheduler to run after startup. For `wifi`: /system/scheduler/add name=capsman-download-packages on-event="/system/script/run capsman-download-packages.wifi;" start-time=startup; -For `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: /system/scheduler/add name=capsman-download-packages on-event="/system/script/run capsman-download-packages.capsman;" start-time=startup; @@ -58,7 +48,6 @@ unconditionally. If no packages are found the script downloads a default set of packages: * `wifi`: `routeros` and `wifi-qcom` for *arm* and *arm64*, `wifi-qcom-ac` for *arm* - * `wifiwave2`: `routeros` and `wifiwave2` for *arm* and *arm64* * legacy CAPsMAN: `routeros` and `wireless` for *arm* and *mipsbe* > â„šī¸ **Info**: If you have packages in the directory and things go wrong for From ada91536366d72e1a30c186be9289fb455ab3149 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Mar 2024 21:48:21 +0100 Subject: [PATCH 2012/2612] global-functions: $ScriptLock: fix wording... ... as this does (no longer) abort. --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 1e36616..6ddcbd3 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1290,7 +1290,7 @@ $RemoveTicket $Script $MyTicket; $LogPrintExit2 info $0 ("Script '" . $Script . "' started more than once" . [ $IfThenElse ($WaitCount > 0) \ - " and timed out waiting for lock" "" ] . "... Aborting.") false; + " and timed out waiting for lock" "" ] . "...") false; :return false; } From 52f54baea08184294825b24a43f1c21a45de265d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2013/2612] log-forward: drop main function, use :do with on-error --- log-forward.rsc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/log-forward.rsc b/log-forward.rsc index b9dbc8b..09e3b84 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -11,8 +11,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global Identity; :global LogForwardFilter; @@ -33,7 +33,7 @@ :global SymbolForNotification; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :if ([ :typeof $LogForwardRateLimit ] = "nothing") do={ @@ -43,7 +43,7 @@ :if ($LogForwardRateLimit > 30) do={ :set LogForwardRateLimit ($LogForwardRateLimit - 1); $LogPrintExit2 info $ScriptName ("Rate limit in action, not forwarding logs, if any!") false; - :return true; + :error false; } :local Count 0; @@ -99,6 +99,4 @@ } else={ :set LogForwardRateLimit [ $MAX 0 ($LogForwardRateLimit - 1) ]; } -} - -$Main [ :jobname ]; +} on-error={ } From 6786fbb29224e26994b5f2e091fef2c979e04919 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 2014/2612] doc/ospf-to-leds: add badges --- doc/ospf-to-leds.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/ospf-to-leds.md b/doc/ospf-to-leds.md index ce7f9ff..a7d4e9a 100644 --- a/doc/ospf-to-leds.md +++ b/doc/ospf-to-leds.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From e8c5585cc7557c5785096f33c678a4d789158874 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Mar 2024 11:07:59 +0100 Subject: [PATCH 2015/2612] capsman-rolling-upgrade: drop support for wifiwave2 --- capsman-rolling-upgrade.template.rsc | 4 --- capsman-rolling-upgrade.wifiwave2.rsc | 49 --------------------------- doc/capsman-rolling-upgrade.md | 11 ++---- 3 files changed, 3 insertions(+), 61 deletions(-) delete mode 100644 capsman-rolling-upgrade.wifiwave2.rsc diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index c810f43..731dbeb 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -30,16 +30,13 @@ :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"); @@ -48,7 +45,6 @@ " (" . $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 $ScriptName ("Remote CAP vanished, skipping upgrade.") false; } diff --git a/capsman-rolling-upgrade.wifiwave2.rsc b/capsman-rolling-upgrade.wifiwave2.rsc deleted file mode 100644 index 4b3aba4..0000000 --- a/capsman-rolling-upgrade.wifiwave2.rsc +++ /dev/null @@ -1,49 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: capsman-rolling-upgrade.wifiwave2 -# Copyright (c) 2018-2024 Christian Hesse -# Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: capsman-rolling-upgrade -# requires RouterOS, version=7.12 -# -# upgrade CAPs one after another -# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local Main do={ - :local ScriptName [ :tostr $1 ]; - - :global LogPrintExit2; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; - } - - :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 $ScriptName ("Starting upgrade for " . $RemoteCapVal->"name" . \ - " (" . $RemoteCapVal->"identity" . ")...") false; - /interface/wifiwave2/capsman/remote-cap/upgrade $RemoteCap; - } else={ - $LogPrintExit2 warning $ScriptName ("Remote CAP vanished, skipping upgrade.") false; - } - :delay ($Delay . "s"); - } - } -} - -$Main [ :jobname ]; diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index bbc8e14..b4e342d 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -21,18 +21,13 @@ Requirements and installation ----------------------------- Just install the script on CAPsMAN device. -Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` -package (`/interface/wifiwave2`) or legacy wifi with CAPsMAN (`/caps-man`) -you need to install a different script. +Depending on whether you use `wifi` package (`/interface/wifi`) or legacy +wifi with CAPsMAN (`/caps-man`) you need to install a different script. -For `wifi` (RouterOS 7.13 and later): +For `wifi`: $ScriptInstallUpdate capsman-rolling-upgrade.wifi; -For `wifiwave2` (up to RouterOS 7.12): - - $ScriptInstallUpdate capsman-rolling-upgrade.wifiwave2; - For legacy CAPsMAN: $ScriptInstallUpdate capsman-rolling-upgrade.capsman; From 4dd6bdef3185d154c5b28efa7075f50cdb990682 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2016/2612] mode-button: drop main function, use :do with on-error --- mode-button.rsc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mode-button.rsc b/mode-button.rsc index 0cd9167..07788cb 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -11,8 +11,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global ModeButton; @@ -78,6 +78,4 @@ $LogPrintExit2 debug $ScriptName ("Updating scheduler _ModeButtonScheduler...") false; /system/scheduler/set $Scheduler start-time=[ /system/clock/get time ]; } -} - -$Main [ :jobname ]; +} on-error={ } From 4ff543e6296c5bf9998c32a94905d47935a93d2c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 2017/2612] doc/packages-update: add badges --- doc/packages-update.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/packages-update.md b/doc/packages-update.md index b3acf89..86eae0d 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -1,6 +1,13 @@ 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.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) +[![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) + [âŦ…ī¸ Go back to main README](../README.md) > â„šī¸ **Info**: This script can not be used on its own but requires the base From b4146083296884be88ed73652dc1ee5f3ccf0c63 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Mar 2024 11:09:06 +0100 Subject: [PATCH 2018/2612] collect-wireless-mac: drop support for wifiwave2 --- collect-wireless-mac.template.rsc | 8 --- collect-wireless-mac.wifiwave2.rsc | 98 ------------------------------ doc/collect-wireless-mac.md | 13 ++-- 3 files changed, 4 insertions(+), 115 deletions(-) delete mode 100644 collect-wireless-mac.wifiwave2.rsc diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index d046fbe..e633e03 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -35,28 +35,23 @@ :if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ :if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - :if ([ :len [ /interface/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 $ScriptName ("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 $ScriptName ("Device already gone... Ignoring.") false; @@ -65,13 +60,11 @@ :if ([ :len ($RegVal->"mac-address") ] > 0) do={ :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :local AccessList ([ /interface/wifi/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :local AccessList ([ /interface/wifiwave2/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ $LogPrintExit2 debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ [ /caps-man/access-list/get $AccessList comment ]) false; [ /interface/wifi/access-list/get $AccessList comment ]) false; - [ /interface/wifiwave2/access-list/get $AccessList comment ]) false; [ /interface/wireless/access-list/get $AccessList comment ]) false; } @@ -100,7 +93,6 @@ $LogPrintExit2 info $ScriptName $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=$ScriptName; \ subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ diff --git a/collect-wireless-mac.wifiwave2.rsc b/collect-wireless-mac.wifiwave2.rsc deleted file mode 100644 index de8cdab..0000000 --- a/collect-wireless-mac.wifiwave2.rsc +++ /dev/null @@ -1,98 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: collect-wireless-mac.wifiwave2 -# Copyright (c) 2013-2024 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: lease-script, order=40 -# requires RouterOS, version=7.12 -# -# collect wireless mac adresses in access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local Main do={ - :local ScriptName [ :tostr $1 ]; - - :global Identity; - - :global EitherOr; - :global FormatLine; - :global FormatMultiLines; - :global GetMacVendor; - :global LogPrintExit2; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - - :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :return false; - } - - :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 $ScriptName ("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 $ScriptName ("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 $ScriptName ("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 $ScriptName $Message false; - /interface/wifiwave2/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - [ $FormatLine "Controller" $Identity ] . "\n" . \ - [ $FormatLine "Interface" ($RegVal->"interface") ] . "\n" . \ - [ $FormatLine "SSID" ($RegVal->"ssid") ] . "\n" . \ - [ $FormatLine "MAC" ($RegVal->"mac-address") ] . "\n" . \ - [ $FormatLine "Vendor" $Vendor ] . "\n" . \ - [ $FormatLine "Hostname" $HostName ] . "\n" . \ - [ $FormatLine "Address" $Address ] . "\n" . \ - [ $FormatMultiLines "DNS name" $DnsName ] . "\n" . \ - [ $FormatLine "Date" $DateTime ]) }); - } - } else={ - $LogPrintExit2 debug $ScriptName ("No mac address available... Ignoring.") false; - } - } -} - -$Main [ :jobname ]; diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index e73cf58..49772e9 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -22,19 +22,14 @@ and modify it to your needs. Requirements and installation ----------------------------- -Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` -package (`/interface/wifiwave2`), legacy wifi with CAPsMAN (`/caps-man`) -or local wireless interface (`/interface/wireless`) you need to install a -different script. +Depending on whether you use `wifi` package (`/interface/wifi`), legacy +wifi with CAPsMAN (`/caps-man`) or local wireless interface +(`/interface/wireless`) you need to install a different script. -For `wifi` (RouterOS 7.13 and later): +For `wifi`: $ScriptInstallUpdate collect-wireless-mac.wifi; -For `wifiwave2` (up to RouterOS 7.12): - - $ScriptInstallUpdate collect-wireless-mac.wifiwave2; - For legacy CAPsMAN: $ScriptInstallUpdate collect-wireless-mac.capsman; From 0d35a18c7166ce85efebc6966435ce72826744ad Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 16:45:01 +0100 Subject: [PATCH 2019/2612] global-wait: drop unused variable --- global-wait.rsc | 1 - 1 file changed, 1 deletion(-) diff --git a/global-wait.rsc b/global-wait.rsc index 9564a12..f8c767b 100644 --- a/global-wait.rsc +++ b/global-wait.rsc @@ -8,6 +8,5 @@ # wait for global-functions to finish # https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md -:local 0 [ :jobname ]; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 8fcb8efbea2b377f12038f983d751c99aad07fb7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2020/2612] netwatch-dns: drop main function, use :do with on-error --- netwatch-dns.rsc | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 2468d35..76f2685 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -11,8 +11,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global CertificateAvailable; :global EitherOr; @@ -21,13 +21,13 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :local SettleTime (5m30s - [ /system/resource/get uptime ]); :if ($SettleTime > 0s) do={ $LogPrintExit2 info $ScriptName ("System just booted, giving netwatch " . $SettleTime . " to settle.") false; - :return true; + :error true; } :local DnsServers ({}); @@ -84,7 +84,7 @@ :if ($DohCurrent = $HostInfo->"doh-url") do={ $LogPrintExit2 debug $ScriptName ("Current DoH server is still up: " . $DohCurrent) false; - :return true; + :error true; } :set ($DohServers->[ :len $DohServers ]) $HostInfo; @@ -121,13 +121,11 @@ /ip/dns/set use-doh-server=($DohServer->"doh-url") verify-doh-cert=yes; /ip/dns/cache/flush; $LogPrintExit2 info $ScriptName ("Setting DoH server: " . ($DohServer->"doh-url")) false; - :return true; + :error true; } else={ $LogPrintExit2 warning $ScriptName ("Received unexpected response from DoH server: " . \ ($DohServer->"doh-url")) false; } } } -} - -$Main [ :jobname ]; +} on-error={ } From 2038480b00fb503d4e851877e420795d323e5a35 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:18 +0100 Subject: [PATCH 2021/2612] doc/ppp-on-up: add badges --- doc/ppp-on-up.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/ppp-on-up.md b/doc/ppp-on-up.md index d5d0ae5..418f05e 100644 --- a/doc/ppp-on-up.md +++ b/doc/ppp-on-up.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From decb8fb17a8530765aec82f5b5df1bffa5407024 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Mar 2024 11:10:24 +0100 Subject: [PATCH 2022/2612] daily-psk: drop support for wifiwave2 --- daily-psk.template.rsc | 9 +--- daily-psk.wifiwave2.rsc | 94 ----------------------------------------- doc/daily-psk.md | 22 +++------- 3 files changed, 7 insertions(+), 118 deletions(-) delete mode 100644 daily-psk.wifiwave2.rsc diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 93cefeb..c45f34a 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -63,21 +63,16 @@ :foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ :foreach AccList in=[ /interface/wifi/access-list/find where comment~$DailyPskMatchComment ] do={ - :foreach AccList in=[ /interface/wifiwave2/access-list/find where comment~$DailyPskMatchComment ] do={ :foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; :local SsidRegExp [ /interface/wifi/access-list/get $AccList ssid-regexp ]; - :local 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 + # /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 ]; @@ -87,12 +82,10 @@ $LogPrintExit2 info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; /caps-man/access-list/set $AccList private-passphrase=$NewPsk; /interface/wifi/access-list/set $AccList passphrase=$NewPsk; - /interface/wifiwave2/access-list/set $AccList passphrase=$NewPsk; /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ :if ([ :len [ /interface/wifi/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ - :if ([ :len [ /interface/wifiwave2/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ :if ($Seen->$Ssid = 1) do={ $LogPrintExit2 debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; diff --git a/daily-psk.wifiwave2.rsc b/daily-psk.wifiwave2.rsc deleted file mode 100644 index 4e71489..0000000 --- a/daily-psk.wifiwave2.rsc +++ /dev/null @@ -1,94 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: daily-psk.wifiwave2 -# Copyright (c) 2013-2024 Christian Hesse -# Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# requires RouterOS, version=7.12 -# -# update daily PSK (pre shared key) -# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local Main do={ - :local ScriptName [ :tostr $1 ]; - - :global DailyPskMatchComment; - :global DailyPskQrCodeUrl; - :global Identity; - - :global FormatLine; - :global LogPrintExit2; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - :global UrlEncode; - :global WaitForFile; - :global WaitFullyConnected; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; - } - $WaitFullyConnected; - - # return pseudo-random string for PSK - :local GeneratePSK do={ - :local Date [ :tostr $1 ]; - - :global DailyPskSecrets; - - :global ParseDate; - - :set Date [ $ParseDate $Date ]; - - :local A ((14 - ($Date->"month")) / 12); - :local B (($Date->"year") - $A); - :local C (($Date->"month") + 12 * $A - 2); - :local WeekDay (7000 + ($Date->"day") + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); - :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); - - :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ - ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); - } - - :local Seen ({}); - :local Date [ /system/clock/get date ]; - :local NewPsk [ $GeneratePSK $Date ]; - - :foreach AccList in=[ /interface/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 $ScriptName ("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 $ScriptName ("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=$ScriptName; \ - subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ - message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - [ $FormatLine "SSID" $Ssid ] . "\n" . \ - [ $FormatLine "PSK" $NewPsk ] . "\n" . \ - [ $FormatLine "Date" $Date ] . "\n\n" . \ - "A client device specific rule must not exist!"); link=$Link }); - :set ($Seen->$Ssid) 1; - } - } - } - } -} - -$Main [ :jobname ]; diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 6eb656c..01fb9f6 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -21,23 +21,17 @@ Requirements and installation Just install this script. -Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` -package (`/interface/wifiwave2`), legacy wifi with CAPsMAN (`/caps-man`) -or local wireless interface (`/interface/wireless`) you need to install a -different script and add schedulers to run the script: +Depending on whether you use `wifi` package (`/interface/wifi`), legacy +wifi with CAPsMAN (`/caps-man`) or local wireless interface +(`/interface/wireless`) you need to install a different script and add +schedulers to run the script: -For `wifi` (RouterOS 7.13 and later): +For `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 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: $ScriptInstallUpdate daily-psk.capsman; @@ -64,14 +58,10 @@ The configuration goes to `global-config-overlay`, these are the parameters: > [`global-config`](../global-config.rsc) (the one without `-overlay`) to > your local `global-config-overlay` and modify it to your specific needs. -Then add an access list entry. For `wifi` (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"; -For `wifiwave2` (up to RouterOS 7.12): - - /interface/wifiwave2/access-list/add comment="Daily PSK" ssid-regexp="-guest\$" passphrase="ToBeChangedDaily"; - For legacy CAPsMAN: /caps-man/access-list/add comment="Daily PSK" ssid-regexp="-guest\$" private-passphrase="ToBeChangedDaily"; From 4e1362aacc103c2aa6de86eebf7aa4fc9317c624 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 20:40:35 +0100 Subject: [PATCH 2023/2612] mod/inspectvar: remove extra spaces --- mod/inspectvar.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/inspectvar.rsc b/mod/inspectvar.rsc index c6c8bdd..577abf3 100644 --- a/mod/inspectvar.rsc +++ b/mod/inspectvar.rsc @@ -39,7 +39,7 @@ :local TypeOf [ :typeof $Input ]; :local Return [ $IndentReturn "type" $TypeOf $Level ]; - + :if ($TypeOf = "array") do={ :foreach Key,Value in=$Input do={ :set $Return ($Return . "\n" . \ From 18ed12e3f7ced88d30b53ab1e4c557d25a2df755 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2024/2612] netwatch-notify: drop main function, use :do with on-error --- netwatch-notify.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index ce74ffa..90d26f1 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -11,8 +11,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global NetwatchNotify; @@ -76,7 +76,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :local ScriptFromTerminalCached [ $ScriptFromTerminal $ScriptName ]; @@ -217,6 +217,4 @@ "since"=($Metric->"since") }; } } -} - -$Main [ :jobname ]; +} on-error={ } From 42d8fed577a41bbf6cbf837e1bc751784b1d5ae0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:19 +0100 Subject: [PATCH 2025/2612] doc/sms-action: add badges --- doc/sms-action.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/sms-action.md b/doc/sms-action.md index 3391902..18ca574 100644 --- a/doc/sms-action.md +++ b/doc/sms-action.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 074e70ee51ede8f5344f2750405d0502f78b0b50 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Mar 2024 11:11:15 +0100 Subject: [PATCH 2026/2612] dhcp-lease-comment: drop support for wifiwave2 --- dhcp-lease-comment.template.rsc | 2 -- dhcp-lease-comment.wifiwave2.rsc | 41 -------------------------------- doc/dhcp-lease-comment.md | 13 ++++------ 3 files changed, 4 insertions(+), 52 deletions(-) delete mode 100644 dhcp-lease-comment.wifiwave2.rsc diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index d0133c8..d7f36a3 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -30,12 +30,10 @@ :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={ diff --git a/dhcp-lease-comment.wifiwave2.rsc b/dhcp-lease-comment.wifiwave2.rsc deleted file mode 100644 index 7cc29da..0000000 --- a/dhcp-lease-comment.wifiwave2.rsc +++ /dev/null @@ -1,41 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: dhcp-lease-comment.wifiwave2 -# Copyright (c) 2013-2024 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: lease-script, order=60 -# requires RouterOS, version=7.12 -# -# update dhcp-server lease comment with infos from access-list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local Main do={ - :local ScriptName [ :tostr $1 ]; - - :global LogPrintExit2; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; - } - - :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local NewComment; - :local AccessList ([ /interface/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 $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; - /ip/dhcp-server/lease/set comment=$NewComment $Lease; - } - } -} - -$Main [ :jobname ]; diff --git a/doc/dhcp-lease-comment.md b/doc/dhcp-lease-comment.md index ae0edfb..d98f3fc 100644 --- a/doc/dhcp-lease-comment.md +++ b/doc/dhcp-lease-comment.md @@ -15,19 +15,14 @@ from wireless access list. Requirements and installation ----------------------------- -Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` -package (`/interface/wifiwave2`), legacy wifi with CAPsMAN (`/caps-man`) -or local wireless interface (`/interface/wireless`) you need to install a -different script. +Depending on whether you use `wifi` package (`/interface/wifi`), legacy +wifi with CAPsMAN (`/caps-man`) or local wireless interface +(`/interface/wireless`) you need to install a different script. -For `wifi` (RouterOS 7.13 and later): +For `wifi`: $ScriptInstallUpdate dhcp-lease-comment.wifi; -For `wifiwave2` (up to RouterOS 7.12): - - $ScriptInstallUpdate dhcp-lease-comment.wifiwave2; - For legacy CAPsMAN: $ScriptInstallUpdate dhcp-lease-comment.capsman; From ed790dea6e7ac48f6f0901b44f7137cc3874403d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 20:40:53 +0100 Subject: [PATCH 2027/2612] mod/notification-email: remove extra spaces --- mod/notification-email.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 16d2b86..88bfdac 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -29,7 +29,7 @@ :local AllDone true; :local QueueLen [ :len $EmailQueue ]; :local Scheduler [ /system/scheduler/find where name="_FlushEmailQueue" ]; - + :if ([ :len $Scheduler ] > 0 && [ /system/scheduler/get $Scheduler interval ] < 1m) do={ /system/scheduler/set interval=1m comment="Doing initial checks..." $Scheduler; } From 850e8db9752aa62746183a639da60a0a26b66217 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2028/2612] ospf-to-leds: drop main function, use :do with on-error --- ospf-to-leds.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc index 3ca16db..73c9922 100644 --- a/ospf-to-leds.rsc +++ b/ospf-to-leds.rsc @@ -11,15 +11,15 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global LogPrintExit2; :global ParseKeyValueStore; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :foreach Instance in=[ /routing/ospf/instance/find where comment~"^ospf-to-leds," ] do={ @@ -42,6 +42,4 @@ /system/leds/set type=off [ find where leds=$LED ]; } } -} - -$Main [ :jobname ]; +} on-error={ } From 3995e85ccf4f032d538305db4a095003f713e3cf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:19 +0100 Subject: [PATCH 2029/2612] doc/sms-forward: add badges --- doc/sms-forward.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 823805e..2fe9486 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 0385c032e270a581a999657919e159a8d58c802e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Mar 2024 11:20:06 +0100 Subject: [PATCH 2030/2612] hotspot-to-wpa: drop support for wifiwave2 --- doc/hotspot-to-wpa.md | 22 +++------ hotspot-to-wpa.template.rsc | 16 ------ hotspot-to-wpa.wifiwave2.rsc | 95 ------------------------------------ 3 files changed, 6 insertions(+), 127 deletions(-) delete mode 100644 hotspot-to-wpa.wifiwave2.rsc diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index c35bef7..c2a5cc6 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -20,21 +20,15 @@ You need a properly configured hotspot on one (open) SSID and a WPA enabled SSID with suffix "`-wpa`". Then install the script. -Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` -package (`/interface/wifiwave2`) or legacy wifi with CAPsMAN (`/caps-man`) -you need to install a different script and set it as `on-login` script in -hotspot. +Depending on whether you use `wifi` package (`/interface/wifi`)or legacy +wifi with CAPsMAN (`/caps-man`) you need to install a different script and +set it as `on-login` script in hotspot. -For `wifi` (RouterOS 7.13 and later): +For `wifi`: $ScriptInstallUpdate hotspot-to-wpa.wifi; /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: $ScriptInstallUpdate hotspot-to-wpa.capsman; @@ -97,15 +91,11 @@ Additionally templates can be created to give more options for access list: * `vlan-id`: connect device to specific VLAN * `vlan-mode`: set the VLAN mode for device -For a hotspot called `example` the template could look like this. For -`wifi` (RouterOS 7.13 and later): +For a hotspot called `example` the template could look like this. +For `wifi`: /interface/wifi/access-list/add comment="hotspot-to-wpa template example" disabled=yes passphrase="ignore" ssid-regexp="^example\$" vlan-id=10; -For `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: /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; diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index 9038d82..c96096c 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -42,28 +42,22 @@ :if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ :if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - :if ([ :len [ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - /interface/wifiwave2/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; } :local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - :local PlaceBefore ([ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); :if ([ :len [ /caps-man/access-list/find where \ :if ([ :len [ /interface/wifi/access-list/find where \ - :if ([ :len [ /interface/wifiwave2/access-list/find where \ comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - /interface/wifiwave2/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; $LogPrintExit2 warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; } :local Template [ /caps-man/access-list/get ([ find where \ :local Template [ /interface/wifi/access-list/get ([ find where \ - :local Template [ /interface/wifiwave2/access-list/get ([ find where \ comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; :if ($Template->"action" = "reject") do={ @@ -78,16 +72,13 @@ " (user " . $UserName . ").") false; /caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; /interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; - /interface/wifiwave2/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; /caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ /interface/wifi/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - /interface/wifiwave2/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ action=reject place-before=$PlaceBefore; :local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ :local Entry [ /interface/wifi/access-list/find where mac-address=$MacAddress \ - :local Entry [ /interface/wifiwave2/access-list/find where mac-address=$MacAddress \ comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; # NOT /caps-man/ # :set ($Template->"private-passphrase") ($Template->"passphrase"); @@ -97,38 +88,31 @@ :if ($PrivatePassphrase = "ignore") do={ /caps-man/access-list/set $Entry !private-passphrase; /interface/wifi/access-list/set $Entry !passphrase; - /interface/wifiwave2/access-list/set $Entry !passphrase; } else={ /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; /interface/wifi/access-list/set $Entry passphrase=$PrivatePassphrase; - /interface/wifiwave2/access-list/set $Entry passphrase=$PrivatePassphrase; } } :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; :if ([ :len $SsidRegexp ] > 0) do={ /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; /interface/wifi/access-list/set $Entry ssid-regexp=$SsidRegexp; - /interface/wifiwave2/access-list/set $Entry ssid-regexp=$SsidRegexp; } :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; :if ([ :len $VlanId ] > 0) do={ /caps-man/access-list/set $Entry vlan-id=$VlanId; /interface/wifi/access-list/set $Entry vlan-id=$VlanId; - /interface/wifiwave2/access-list/set $Entry vlan-id=$VlanId; } # NOT /interface/wifi/ # -# NOT /interface/wifiwave2/ # :local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; :if ([ :len $VlanMode] > 0) do={ /caps-man/access-list/set $Entry vlan-mode=$VlanMode; } -# NOT /interface/wifiwave2/ # # NOT /interface/wifi/ # :delay 2s; /caps-man/access-list/set $Entry action=accept; /interface/wifi/access-list/set $Entry action=accept; - /interface/wifiwave2/access-list/set $Entry action=accept; } $Main [ :jobname ] $"mac-address" $username; diff --git a/hotspot-to-wpa.wifiwave2.rsc b/hotspot-to-wpa.wifiwave2.rsc deleted file mode 100644 index 519f81f..0000000 --- a/hotspot-to-wpa.wifiwave2.rsc +++ /dev/null @@ -1,95 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: hotspot-to-wpa.wifiwave2 -# Copyright (c) 2019-2024 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# requires RouterOS, version=7.12 -# -# add private WPA passphrase after hotspot login -# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local Main do={ - :local ScriptName [ :tostr $1 ]; - :local MacAddress [ :tostr $2 ]; - :local UserName [ :tostr $3 ]; - - :global EitherOr; - :global LogPrintExit2; - :global ParseKeyValueStore; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; - } - - :if ([ :len $MacAddress ] = 0 || [ :len $UserName ] = 0) do={ - $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; - } - - :local Date [ /system/clock/get date ]; - :local UserVal ({}); - :if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ - :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; - } - :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; - :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; - - :if ([ :len [ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - /interface/wifiwave2/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; - } - :local PlaceBefore ([ /interface/wifiwave2/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - - :if ([ :len [ /interface/wifiwave2/access-list/find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - /interface/wifiwave2/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrintExit2 warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; - } - :local Template [ /interface/wifiwave2/access-list/get ([ find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; - - :if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") false; - :return true; - } - - # allow login page to load - :delay 1s; - - $LogPrintExit2 info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ").") false; - /interface/wifiwave2/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; - /interface/wifiwave2/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - action=reject place-before=$PlaceBefore; - - :local Entry [ /interface/wifiwave2/access-list/find where mac-address=$MacAddress \ - comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; - :set ($Template->"private-passphrase") ($Template->"passphrase"); - :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; - :if ([ :len $PrivatePassphrase ] > 0) do={ - :if ($PrivatePassphrase = "ignore") do={ - /interface/wifiwave2/access-list/set $Entry !passphrase; - } else={ - /interface/wifiwave2/access-list/set $Entry passphrase=$PrivatePassphrase; - } - } - :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; - :if ([ :len $SsidRegexp ] > 0) do={ - /interface/wifiwave2/access-list/set $Entry ssid-regexp=$SsidRegexp; - } - :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; - :if ([ :len $VlanId ] > 0) do={ - /interface/wifiwave2/access-list/set $Entry vlan-id=$VlanId; - } - - :delay 2s; - /interface/wifiwave2/access-list/set $Entry action=accept; -} - -$Main [ :jobname ] $"mac-address" $username; From 010bea56dca6b501978f57ef4a830a7dad497833 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 20:49:44 +0100 Subject: [PATCH 2031/2612] telegram-chat: error when making directory fails --- telegram-chat.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index bb12042..528d99c 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -126,7 +126,9 @@ :if ([ $ValidateSyntax ($Message->"text") ] = true) do={ :local State ""; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); - $MkDir "tmpfs/telegram-chat"; + :if ([ $MkDir "tmpfs/telegram-chat" ] = false) do={ + $LogPrintExit2 error $ScriptName ("Failed creating directory!") true; + } $LogPrintExit2 info $ScriptName ("Running command from update " . $UpdateID . ": " . $Message->"text") false; :execute script=(":do {\n" . $Message->"text" . "\n} on-error={ /file/add name=\"" . $File . ".failed\" };" . \ "/file/add name=\"" . $File . ".done\"") file=($File . "\00"); From 1012d9fc51973adefff4b72885e828f2cd04149a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2032/2612] packages-update: drop main function, use :do with on-error --- packages-update.rsc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index 5b6d158..abcbfd8 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -11,8 +11,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global DownloadPackage; :global Grep; @@ -44,7 +44,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :local Update [ /system/package/update/get ]; @@ -55,7 +55,7 @@ :if ($Update->"installed-version" = $Update->"latest-version") do={ $LogPrintExit2 info $ScriptName ("Version " . $Update->"latest-version" . " is already installed.") false; - :return true; + :error true; } :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; @@ -134,6 +134,4 @@ $LogPrintExit2 info $ScriptName ("Rebooting for update.") false; :delay 1s; /system/reboot; -} - -$Main [ :jobname ]; +} on-error={ } From 8a439ea15c340c5e8b84012512178303405eacd8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:19 +0100 Subject: [PATCH 2033/2612] doc/super-mario-theme: add badges --- doc/super-mario-theme.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/super-mario-theme.md b/doc/super-mario-theme.md index b3100e8..ec59b39 100644 --- a/doc/super-mario-theme.md +++ b/doc/super-mario-theme.md @@ -1,6 +1,13 @@ 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) Description From d513ea61cf07e282903cda0685da59ee569ad2a1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Mar 2024 11:21:05 +0100 Subject: [PATCH 2034/2612] hotspot-to-wpa-cleanup: drop support for wifiwave2 --- doc/hotspot-to-wpa.md | 7 +-- hotspot-to-wpa-cleanup.template.rsc | 6 --- hotspot-to-wpa-cleanup.wifiwave2.rsc | 76 ---------------------------- 3 files changed, 1 insertion(+), 88 deletions(-) delete mode 100644 hotspot-to-wpa-cleanup.wifiwave2.rsc diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index c2a5cc6..fc784dd 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -40,16 +40,11 @@ With just `hotspot-to-wpa` installed the mac addresses will last in the access list forever. Install the optional script for automatic cleanup and add a scheduler. -For `wifi` (RouterOS 7.13 and later): +For `wifi`: $ScriptInstallUpdate hotspot-to-wpa-cleanup.wifi,lease-script; /system/scheduler/add interval=1d name=hotspot-to-wpa-cleanup on-event="/system/script/run hotspot-to-wpa-cleanup.wifi;" start-time=startup; -For `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: $ScriptInstallUpdate hotspot-to-wpa-cleanup.capsman,lease-script; diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index c393888..bba9f0e 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -39,10 +39,8 @@ :foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ :foreach Client in=[ /interface/wifi/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ - :foreach Client in=[ /interface/wifiwave2/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ :local ClientVal [ /caps-man/registration-table/get $Client ]; :local ClientVal [ /interface/wifi/registration-table/get $Client ]; - :local ClientVal [ /interface/wifiwave2/registration-table/get $Client ]; :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ mac-address=($ClientVal->"mac-address") ] do={ :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ @@ -56,18 +54,15 @@ :foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \ :foreach Client in=[ /interface/wifi/access-list/find where comment~"^hotspot-to-wpa:" \ - :foreach Client in=[ /interface/wifiwave2/access-list/find where comment~"^hotspot-to-wpa:" \ !(comment~[ /system/clock/get date ]) ] do={ :local ClientVal [ /caps-man/access-list/get $Client ]; :local ClientVal [ /interface/wifi/access-list/get $Client ]; - :local ClientVal [ /interface/wifiwave2/access-list/get $Client ]; :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ mac-address=($ClientVal->"mac-address") ] ] = 0) do={ $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ " did not connect to WPA, removing from access list.") false; /caps-man/access-list/remove $Client; /interface/wifi/access-list/remove $Client; - /interface/wifiwave2/access-list/remove $Client; } } @@ -79,7 +74,6 @@ " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - /interface/wifiwave2/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ mac-address=($LeaseVal->"mac-address") ]; /ip/dhcp-server/lease/remove $Lease; } diff --git a/hotspot-to-wpa-cleanup.wifiwave2.rsc b/hotspot-to-wpa-cleanup.wifiwave2.rsc deleted file mode 100644 index e5a0cf5..0000000 --- a/hotspot-to-wpa-cleanup.wifiwave2.rsc +++ /dev/null @@ -1,76 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: hotspot-to-wpa-cleanup.wifiwave2 -# Copyright (c) 2021-2024 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: lease-script, order=80 -# requires RouterOS, version=7.12 -# -# manage and clean up private WPA passphrase after hotspot login -# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local Main do={ - :local ScriptName [ :tostr $1 ]; - - :global EitherOr; - :global LogPrintExit2; - :global ParseKeyValueStore; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :return false; - } - - :local DHCPServers ({}); - :foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ - :local ServerVal [ /ip/dhcp-server/get $Server ] - :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; - :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ - :set ($DHCPServers->($ServerVal->"name")) \ - [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; - } - } - - :foreach Client in=[ /interface/wifiwave2/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ - :local ClientVal [ /interface/wifiwave2/registration-table/get $Client ]; - :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ - mac-address=($ClientVal->"mac-address") ] do={ - :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ - $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static.") false; - /ip/dhcp-server/lease/make-static $Lease; - /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; - } - } - } - - :foreach Client in=[ /interface/wifiwave2/access-list/find where comment~"^hotspot-to-wpa:" \ - !(comment~[ /system/clock/get date ]) ] do={ - :local ClientVal [ /interface/wifiwave2/access-list/get $Client ]; - :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ - mac-address=($ClientVal->"mac-address") ] ] = 0) do={ - $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ - " did not connect to WPA, removing from access list.") false; - /interface/wifiwave2/access-list/remove $Client; - } - } - - :foreach Server,Timeout in=$DHCPServers do={ - :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ - server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - $LogPrintExit2 info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; - /interface/wifiwave2/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - mac-address=($LeaseVal->"mac-address") ]; - /ip/dhcp-server/lease/remove $Lease; - } - } -} - -$Main [ :jobname ]; From 955ee8499b9fe63c332431c2a7fc0488bd2ac315 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 4 Mar 2024 20:57:34 +0100 Subject: [PATCH 2035/2612] backup-cloud: catch error with :execute workaround Catching a runtime error here fails... So let's try a workaround with :execute... --- backup-cloud.rsc | 17 ++++++++++++++--- doc/backup-cloud.md | 8 ++++---- global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 418e68d..5dd4bf1 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -15,7 +15,6 @@ :local Main do={ :local ScriptName [ :tostr $1 ]; - :global BackupPassword; :global BackupRandomDelay; :global Identity; @@ -23,11 +22,13 @@ :global FormatLine; :global HumanReadableNum; :global LogPrintExit2; + :global MkDir; :global RandomDelay; :global ScriptFromTerminal; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; + :global WaitForFile; :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -39,7 +40,12 @@ $RandomDelay $BackupRandomDelay; } - :do { + :if ([ $MkDir ("tmpfs/backup-cloud") ] = false) do={ + $LogPrintExit2 error $ScriptName ("Failed creating directory!") true; + } + + :execute { + :global BackupPassword; # we are not interested in output, but print is # required to fetch information from cloud /system/backup/cloud/print as-value; @@ -50,6 +56,10 @@ /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; \ @@ -59,12 +69,13 @@ [ $FormatLine "Name" ($Cloud->"name") ] . "\n" . \ [ $FormatLine "Size" ([ $HumanReadableNum ($Cloud->"size") 1024 ] . "iB") ] . "\n" . \ [ $FormatLine "Download key" ($Cloud->"secret-download-key") ]); silent=true }); - } on-error={ + } else={ $SendNotification2 ({ origin=$ScriptName; \ subject=([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Cloud backup failed"); \ message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); $LogPrintExit2 error $ScriptName ("Failed uploading backup for " . $Identity . " to cloud!") true; } + /file/remove "tmpfs/backup-cloud"; } $Main [ :jobname ]; diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index f084d5b..ac7edb7 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -12,10 +12,10 @@ Description This script uploads [binary backup to Mikrotik cloud](https://wiki.mikrotik.com/wiki/Manual:IP/Cloud#Backup). -> âš ī¸ **Warning**: The used command can hit errors that a script can not handle. -> This may result in script termination (where no notification is sent) or -> malfunction of fetch command (where all up- and downloads break) for some -> time. Failed notifications are queued then. +> âš ī¸ **Warning**: The used command can hit errors that a script can with +> workaround only. A notification *should* be sent anyway. But it can result +> in malfunction of fetch command (where all up- and downloads break) for +> some time. Failed notifications are queued then. ### Sample notification diff --git a/global-functions.rsc b/global-functions.rsc index 6ddcbd3..9b5b0b0 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 119; +:global ExpectedConfigVersion 120; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index d0e9938..c260427 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -44,6 +44,7 @@ [ $IfThenElse ($Resource->"free-hdd-space" > 4000000) ("(Your " . $Resource->"board-name" . " does not suffer this issue.) ") ] ] . \ "Huge configuration and lots of scripts give an extra risk. Take care!"); 119="Added support for IPv6 to script 'fw-addr-lists'."; + 120="Implemented a workaround in 'backup-cloud'. Now script should no longer just crash, but send notification with error."; }; # Migration steps to be applied on script updates From 1db1a943e2c802e9e869fa9222998b16d14cedba Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2036/2612] ppp-on-up: drop main function, use :do with on-error --- ppp-on-up.rsc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc index ae259d7..0cc2405 100644 --- a/ppp-on-up.rsc +++ b/ppp-on-up.rsc @@ -11,12 +11,13 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; - :local Interface $2; +:do { + :local ScriptName [ :jobname ]; :global LogPrintExit2; + :local Interface $interface; + :if ([ :typeof $Interface ] = "nothing") do={ $LogPrintExit2 error $ScriptName ("This script is supposed to run from ppp on-up script hook.") true; } @@ -35,6 +36,4 @@ $LogPrintExit2 warning $ScriptName ("Running script '" . $ScriptName . "' failed!") false; } } -} - -$Main [ :jobname ] $interface; +} on-error={ } From 2ac18b1cdfb8e56a5c6441bfb956e29e9df226cd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:19 +0100 Subject: [PATCH 2037/2612] doc/telegram-chat: add badges --- doc/telegram-chat.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index 397920a..c750042 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -1,6 +1,13 @@ Chat with your router and send commands via Telegram bot ======================================================== +[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) +[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) +[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) +[![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) + [âŦ…ī¸ Go back to main README](../README.md) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 83dbcfecd58e9f60b8d8b97a635a46cf851ae259 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 11 Mar 2024 16:32:49 +0100 Subject: [PATCH 2038/2612] news on wifiwave2 EOL --- global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 9b5b0b0..7f5ba9f 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 120; +:global ExpectedConfigVersion 121; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index c260427..c5117ca 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -45,6 +45,7 @@ "Huge configuration and lots of scripts give an extra risk. Take care!"); 119="Added support for IPv6 to script 'fw-addr-lists'."; 120="Implemented a workaround in 'backup-cloud'. Now script should no longer just crash, but send notification with error."; + 121="The 'wifiwave2' scripts are finally gone. Development continues with 'wifi' in RouterOS 7.13 and later."; }; # Migration steps to be applied on script updates From 050ccd490e423a641907065bb8711c7090898d10 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Mar 2024 10:31:33 +0100 Subject: [PATCH 2039/2612] backup-cloud: add a short delay Not sure it helps, but chances are... --- backup-cloud.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 5dd4bf1..2846d75 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -49,6 +49,7 @@ # 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 ]; From e19a48682e6d3675da75b391ef7678286177e69d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2040/2612] sms-action: drop main function, use :do with on-error --- sms-action.rsc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/sms-action.rsc b/sms-action.rsc index b78a2b2..11d3523 100644 --- a/sms-action.rsc +++ b/sms-action.rsc @@ -11,16 +11,17 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; - :local Action [ :tostr $2 ]; +:do { + :local ScriptName [ :jobname ]; :global SmsAction; :global LogPrintExit2; :global ValidateSyntax; - :if ([ :len $Action ] = 0) do={ + :local Action $action; + + :if ([ :typeof $Action ] = "nothing") do={ $LogPrintExit2 error $ScriptName ("This script is supposed to run from SMS hook with action=...") true; } @@ -32,6 +33,4 @@ } else={ $LogPrintExit2 warning $ScriptName ("The code for action '" . $Action . "' failed syntax validation!") false; } -} - -$Main [ :jobname ] $action; +} on-error={ } From 11832a7651d4bcd118420c6a0a89afe313c99430 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:19 +0100 Subject: [PATCH 2041/2612] doc/unattended-lte-firmware-upgrade: add badges --- doc/unattended-lte-firmware-upgrade.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/unattended-lte-firmware-upgrade.md b/doc/unattended-lte-firmware-upgrade.md index a9c9b7c..a6bf994 100644 --- a/doc/unattended-lte-firmware-upgrade.md +++ b/doc/unattended-lte-firmware-upgrade.md @@ -1,6 +1,13 @@ 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) Description From ac38e1694435c3fb070dabcf8e8325d931b3eb27 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2042/2612] sms-forward: drop main function, use :do with on-error --- sms-forward.rsc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sms-forward.rsc b/sms-forward.rsc index 7c4488a..2f549b1 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -12,8 +12,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global Identity; :global SmsForwardHooks; @@ -28,7 +28,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :if ([ /tool/sms/get receive-enabled ] = false) do={ @@ -41,7 +41,7 @@ :if ([ /interface/lte/get ($Settings->"port") running ] != true) do={ $LogPrintExit2 info $ScriptName ("The LTE interface is not in running state, skipping.") false; - :return true; + :error true; } # forward SMS in a loop @@ -95,6 +95,4 @@ } } } -} - -$Main [ :jobname ]; +} on-error={ } From a0a964fa185bc867047b5b61f033d6c36a180ea2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:19 +0100 Subject: [PATCH 2043/2612] doc/update-gre-address: add badges --- doc/update-gre-address.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/update-gre-address.md b/doc/update-gre-address.md index 5bf95bd..fba2a65 100644 --- a/doc/update-gre-address.md +++ b/doc/update-gre-address.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 53ff8fbf97afa63192dbc43cc3900bfd84069af0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 11:37:50 +0100 Subject: [PATCH 2044/2612] check-certificates: exit block on failed import --- check-certificates.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/check-certificates.rsc b/check-certificates.rsc index 69d9097..1968641 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -152,6 +152,7 @@ :set ImportSuccess [ $CheckCertificatesDownloadImport $LastName ]; } } + :if ($ImportSuccess = false) do={ :error false; } :if ([ :len ($CertVal->"fingerprint") ] > 0 && $CertVal->"fingerprint" != [ /certificate/get $Cert fingerprint ]) do={ $LogPrintExit2 debug $ScriptName ("Certificate '" . $CertVal->"name" . "' was updated in place.") false; From 738dd119293efe0f16235e2bcce241314393da5d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2045/2612] telegram-chat: drop main function, use :do with on-error --- telegram-chat.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 528d99c..799569f 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -11,8 +11,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global Identity; :global TelegramChatActive; @@ -44,7 +44,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } $WaitFullyConnected; @@ -171,6 +171,4 @@ } :set TelegramChatOffset ([ :pick $TelegramChatOffset 1 3 ], \ [ $IfThenElse ($UpdateID >= $TelegramChatOffset->2) ($UpdateID + 1) ($TelegramChatOffset->2) ]); -} - -$Main [ :jobname ]; +} on-error={ } From 4061661a2027a94b791760ff8b59b136d391aeb5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:30:19 +0100 Subject: [PATCH 2046/2612] doc/update-tunnelbroker: add badges --- doc/update-tunnelbroker.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/update-tunnelbroker.md b/doc/update-tunnelbroker.md index 4d6f1ba..5aca581 100644 --- a/doc/update-tunnelbroker.md +++ b/doc/update-tunnelbroker.md @@ -1,6 +1,13 @@ 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) > â„šī¸ **Info**: This script can not be used on its own but requires the base From 09393d3ef5c0b140ce5f1ddc2c3cae5b95119072 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 12:13:15 +0100 Subject: [PATCH 2047/2612] check-certificates: handle formatting of self signed cert --- check-certificates.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 1968641..e470b59 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -98,8 +98,12 @@ :global ParseKeyValueStore; :local CertVal [ /certificate/get $Cert ]; - :local Return ""; + :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") ]); From febd13af13c3bd0fff3d702364a3979d3e4221a3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2048/2612] update-gre-address: drop main function, use :do with on-error --- update-gre-address.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/update-gre-address.rsc b/update-gre-address.rsc index d9a7a55..78705c5 100644 --- a/update-gre-address.rsc +++ b/update-gre-address.rsc @@ -12,15 +12,15 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global CharacterReplace; :global LogPrintExit2; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } /interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; @@ -39,6 +39,4 @@ } } } -} - -$Main [ :jobname ]; +} on-error={ } From f0856c264e07804a229668268a457f2154cb373a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 15:28:55 +0100 Subject: [PATCH 2049/2612] update-tunnelbroker: drop main function, use :do with on-error --- update-tunnelbroker.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index 90e3f24..9f316e3 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -13,8 +13,8 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Main do={ - :local ScriptName [ :tostr $1 ]; +:do { + :local ScriptName [ :jobname ]; :global CertificateAvailable; :global LogPrintExit2; @@ -22,7 +22,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ - :return false; + :error false; } :if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ @@ -62,6 +62,4 @@ /interface/6to4/set $Interface local-address=$PublicAddress; } } -} - -$Main [ :jobname ]; +} on-error={ } From b86d6314868596dacdf422db80ef0ff27c61c644 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Mar 2024 14:38:11 +0100 Subject: [PATCH 2050/2612] doc/telegram-chat: show usage of persistent ids --- doc/telegram-chat.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index c750042..2a4af99 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -107,6 +107,14 @@ scripting capabilities. Try to print what you want to act on... /ip/address/remove [ find where interface=eth ]; +What does work is using the persistent ids: + + /ip/address/print show-ids; + +The output contains an id starting with asterisk that can be used: + + /ip/address/remove *E; + ### Mind command runtime The command is run in background while the script waits for it - about From ffa31c7ad797eb63a896d241651773423c7126aa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 10:14:26 +0100 Subject: [PATCH 2051/2612] packages-update: increate log severity on canceled non-interactive update --- packages-update.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages-update.rsc b/packages-update.rsc index abcbfd8..e0e1f6d 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -109,7 +109,7 @@ $LogPrintExit2 info $ScriptName ("Canceled update...") true; } } else={ - $LogPrintExit2 info $ScriptName ("Canceled non-interactive update.") true; + $LogPrintExit2 warning $ScriptName ("Canceled non-interactive update.") true; } } } From 3fcdd395fe93a501de297f7678d57b5c1064b05d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 09:19:43 +0100 Subject: [PATCH 2052/2612] packages-update: support passing backup failure --- packages-update.rsc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages-update.rsc b/packages-update.rsc index e0e1f6d..634b7bb 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -23,6 +23,7 @@ :global VersionToNum; :global PackagesUpdateDeferReboot; + :global PackagesUpdateBackupFailure; :local Schedule do={ :local ScriptName [ :tostr $1 ]; @@ -96,10 +97,15 @@ } :foreach Order,Script in=$RunOrder do={ + :set PackagesUpdateBackupFailure false; :do { $LogPrintExit2 info $ScriptName ("Running backup script " . $Script . " before update.") false; /system/script/run $Script; } on-error={ + :set PackagesUpdateBackupFailure true; + } + + :if ($PackagesUpdateBackupFailure = true) do={ $LogPrintExit2 warning $ScriptName ("Running backup script " . $Script . " before update failed!") false; :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ :put "Do you want to continue anyway? [y/N]"; From c82f7766326f5e24ea81c2fe4a2a745075c86984 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 09:25:56 +0100 Subject: [PATCH 2053/2612] backup-cloud: pass failure to packages-update --- backup-cloud.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index a3dfe0c..14af776 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -17,6 +17,7 @@ :global BackupRandomDelay; :global Identity; + :global PackagesUpdateBackupFailure; :global DeviceInfo; :global FormatLine; @@ -32,6 +33,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set PackagesUpdateBackupFailure true; :error false; } $WaitFullyConnected; @@ -74,7 +76,9 @@ $SendNotification2 ({ origin=$ScriptName; \ subject=([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Cloud backup failed"); \ message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); - $LogPrintExit2 error $ScriptName ("Failed uploading backup for " . $Identity . " to cloud!") true; + $LogPrintExit2 error $ScriptName ("Failed uploading backup for " . $Identity . " to cloud!") false; + :set PackagesUpdateBackupFailure true; + :error false; } /file/remove "tmpfs/backup-cloud"; } on-error={ } From 5f41bd1c1ec98bea8d7cc1760ff740ded20aa4d1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 09:26:24 +0100 Subject: [PATCH 2054/2612] backup-email: pass failure to packages-update --- backup-email.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backup-email.rsc b/backup-email.rsc index 9f6e31a..e4dec3b 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -22,6 +22,7 @@ :global BackupSendGlobalConfig; :global Domain; :global Identity; + :global PackagesUpdateBackupFailure; :global CleanName; :global DeviceInfo; @@ -46,6 +47,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ + :set PackagesUpdateBackupFailure true; :error false; } $WaitFullyConnected; @@ -109,7 +111,9 @@ :local I 0; :while ([ :len [ /file/find where name ~ ($FilePath . "\\.(backup|rsc)\$") ] ] > 0) do={ :if ($I >= 120) do={ - $LogPrintExit2 warning $ScriptName ("Files are still available, sending e-mail failed.") true; + $LogPrintExit2 warning $ScriptName ("Files are still available, sending e-mail failed.") false; + :set PackagesUpdateBackupFailure true; + :error false; } :delay 1s; :set I ($I + 1); From 51b00181cf6524f173f0464a237bdb63c3f0734a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 09:26:39 +0100 Subject: [PATCH 2055/2612] backup-partition: pass failure to packages-update --- backup-partition.rsc | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index 1238fab..13ed8b9 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -15,21 +15,28 @@ :do { :local ScriptName [ :jobname ]; + :global PackagesUpdateBackupFailure; + :global LogPrintExit2; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set PackagesUpdateBackupFailure true; :error false; } :if ([ :len [ /partitions/find ] ] < 2) do={ - $LogPrintExit2 error $ScriptName ("Device does not have a fallback partition.") true; + $LogPrintExit2 error $ScriptName ("Device does not have a fallback partition.") false; + :set PackagesUpdateBackupFailure true; + :error false; } :local ActiveRunning [ /partitions/find where active running ]; :if ([ :len $ActiveRunning ] < 1) do={ - $LogPrintExit2 error $ScriptName ("Device is not running from active partition.") true; + $LogPrintExit2 error $ScriptName ("Device is not running from active partition.") false; + :set PackagesUpdateBackupFailure true; + :error false; } :local FallbackTo [ /partitions/get $ActiveRunning fallback-to ]; @@ -45,6 +52,8 @@ } on-error={ /system/scheduler/remove [ find where name="running-from-backup-partition" ]; $LogPrintExit2 error $ScriptName ("Failed saving configuration to partition '" . \ - $FallbackTo . "'!") true; + $FallbackTo . "'!") false; + :set PackagesUpdateBackupFailure true; + :error false; } } on-error={ } From e39e8a00834192211999b89f5f163a35c2214707 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 09:26:53 +0100 Subject: [PATCH 2056/2612] backup-upload: pass failure to packages-update --- backup-upload.rsc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 2b42730..769972b 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -25,6 +25,7 @@ :global BackupUploadUser; :global Domain; :global Identity; + :global PackagesUpdateBackupFailure; :global CleanName; :global DeviceInfo; @@ -45,6 +46,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ + :set PackagesUpdateBackupFailure true; :error false; } $WaitFullyConnected; @@ -151,6 +153,7 @@ [ $FileInfo "Config file" $ConfigFile ]); silent=true }); :if ($Failed = 1) do={ - :error "An error occured!"; + :set PackagesUpdateBackupFailure true; + :error false; } } on-error={ } From a7cb3e520a86b44cb6e1bdfdf6df24856274e0e3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 09:33:17 +0100 Subject: [PATCH 2057/2612] 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. --- README.md | 5 +++++ global-config.rsc | 10 ++++++++++ global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1af718c..61b1725 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,11 @@ Save changes and exit with `Ctrl-o`. ![screenshot: edit global-config-overlay](README.d/07-edit-global-config-overlay.avif) +Additionally creating configuration snippets is supported. The script name +of these snippets has to start with `global-config-overlay.d/` to make them +being loaded automatically. This allows to split off parts of the +configuration. + To apply your changes run `global-config`, which will automatically load the overlay as well: diff --git a/global-config.rsc b/global-config.rsc index 983eedb..85731c3 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -250,3 +250,13 @@ } on-error={ :log error ("Loading configuration from overlay failed!"); } + +# configuration overlay snippets +:foreach Script in=[ /system/script/find where name ~ "^global-config-overlay.d/" ] do={ + :do { + /system/script/run $Script; + } on-error={ + :log error ("Loading configuration from overlay snippet " . \ + [ /system/script/get $Script name ] . " failed!"); + } +} diff --git a/global-functions.rsc b/global-functions.rsc index 7f5ba9f..d2386f4 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 121; +:global ExpectedConfigVersion 122; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index c5117ca..46b777a 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -46,6 +46,7 @@ 119="Added support for IPv6 to script 'fw-addr-lists'."; 120="Implemented a workaround in 'backup-cloud'. Now script should no longer just crash, but send notification with error."; 121="The 'wifiwave2' scripts are finally gone. Development continues with 'wifi' in RouterOS 7.13 and later."; + 122="The global configuration was enhanced to support loading snippets. Configuration can be split off to scripts where name starts with 'global-config-overlay.d/'."; }; # Migration steps to be applied on script updates From 1feeed145d6b63ef60fc3c0abbe0703b7bd73837 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 10:38:09 +0100 Subject: [PATCH 2058/2612] global-functions: introduce $LogPrint, deprecate $LogPrintExit2 --- global-functions.rsc | 21 +++++++++++++++++---- news-and-changes.rsc | 1 + 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index aca4cd8..1220eca 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 122; +:global ExpectedConfigVersion 123; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -53,6 +53,7 @@ :global IsFullyConnected; :global IsMacLocallyAdministered; :global IsTimeSync; +:global LogPrint; :global LogPrintExit2; :global LogPrintOnce; :global MAX; @@ -654,12 +655,11 @@ :return true; } -# log and print with same text, optionally exit -:set LogPrintExit2 do={ +# log and print with same text +:set LogPrint do={ :local Severity [ :tostr $1 ]; :local Name [ :tostr $2 ]; :local Message [ :tostr $3 ]; - :local Exit [ :tostr $4 ]; :global PrintDebug; :global PrintDebugOverride; @@ -692,6 +692,19 @@ :if ($Severity != "debug" || $Debug = true) do={ :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={ :error ("Hard error to exit."); diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 46b777a..6b0a538 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -47,6 +47,7 @@ 120="Implemented a workaround in 'backup-cloud'. Now script should no longer just crash, but send notification with error."; 121="The 'wifiwave2' scripts are finally gone. Development continues with 'wifi' in RouterOS 7.13 and later."; 122="The global configuration was enhanced to support loading snippets. Configuration can be split off to scripts where name starts with 'global-config-overlay.d/'."; + 123="Introduced new function '\$LogPrint', and deprecated '\$LogPrintExit2'. Please update custom scripts if you use it."; }; # Migration steps to be applied on script updates From ac3b755fdc630d4daa40a9ba5254d92f8a91b03f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:37 +0100 Subject: [PATCH 2059/2612] backup-cloud: switch to $LogPrint --- backup-cloud.rsc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 14af776..cccb41b 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -22,7 +22,7 @@ :global DeviceInfo; :global FormatLine; :global HumanReadableNum; - :global LogPrintExit2; + :global LogPrint; :global MkDir; :global RandomDelay; :global ScriptFromTerminal; @@ -43,7 +43,8 @@ } :if ([ $MkDir ("tmpfs/backup-cloud") ] = false) do={ - $LogPrintExit2 error $ScriptName ("Failed creating directory!") true; + $LogPrint error $ScriptName ("Failed creating directory!"); + :error false; } :execute { @@ -76,7 +77,7 @@ $SendNotification2 ({ origin=$ScriptName; \ subject=([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Cloud backup failed"); \ message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); - $LogPrintExit2 error $ScriptName ("Failed uploading backup for " . $Identity . " to cloud!") false; + $LogPrint error $ScriptName ("Failed uploading backup for " . $Identity . " to cloud!"); :set PackagesUpdateBackupFailure true; :error false; } From 4b69144ee476ada47c640f1e5a65952bce7241ec Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:37 +0100 Subject: [PATCH 2060/2612] backup-email: switch to $LogPrint --- backup-email.rsc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/backup-email.rsc b/backup-email.rsc index e4dec3b..64ca69c 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -27,7 +27,7 @@ :global CleanName; :global DeviceInfo; :global FormatLine; - :global LogPrintExit2; + :global LogPrint; :global MkDir; :global RandomDelay; :global ScriptFromTerminal; @@ -38,12 +38,14 @@ :global WaitFullyConnected; :if ([ :typeof $SendEMail2 ] = "nothing") do={ - $LogPrintExit2 error $ScriptName ("The module for sending notifications via e-mail is not installed.") true; + $LogPrint error $ScriptName ("The module for sending notifications via e-mail is not installed."); + :error false; } :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ - $LogPrintExit2 error $ScriptName ("Configured to send neither backup nor config export.") true; + $LogPrint error $ScriptName ("Configured to send neither backup nor config export."); + :error false; } :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -66,7 +68,8 @@ :local Attach ({}); :if ([ $MkDir $DirName ] = false) do={ - $LogPrintExit2 error $ScriptName ("Failed creating directory!") true; + $LogPrint error $ScriptName ("Failed creating directory!"); + :error false; } # binary backup @@ -111,7 +114,7 @@ :local I 0; :while ([ :len [ /file/find where name ~ ($FilePath . "\\.(backup|rsc)\$") ] ] > 0) do={ :if ($I >= 120) do={ - $LogPrintExit2 warning $ScriptName ("Files are still available, sending e-mail failed.") false; + $LogPrint warning $ScriptName ("Files are still available, sending e-mail failed."); :set PackagesUpdateBackupFailure true; :error false; } From b879f8fef2fac123d3929f2964c9528465ce7a42 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:37 +0100 Subject: [PATCH 2061/2612] backup-partition: switch to $LogPrint --- backup-partition.rsc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index 13ed8b9..503d382 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -17,7 +17,7 @@ :global PackagesUpdateBackupFailure; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -26,7 +26,7 @@ } :if ([ :len [ /partitions/find ] ] < 2) do={ - $LogPrintExit2 error $ScriptName ("Device does not have a fallback partition.") false; + $LogPrint error $ScriptName ("Device does not have a fallback partition."); :set PackagesUpdateBackupFailure true; :error false; } @@ -34,7 +34,7 @@ :local ActiveRunning [ /partitions/find where active running ]; :if ([ :len $ActiveRunning ] < 1) do={ - $LogPrintExit2 error $ScriptName ("Device is not running from active partition.") false; + $LogPrint error $ScriptName ("Device is not running from active partition."); :set PackagesUpdateBackupFailure true; :error false; } @@ -47,12 +47,10 @@ "[ /partitions/get [ find where running ] name ] . \"'!\")"); /partitions/save-config-to $FallbackTo; /system/scheduler/remove "running-from-backup-partition"; - $LogPrintExit2 info $ScriptName ("Saved configuration to partition '" . \ - $FallbackTo . "'.") false; + $LogPrint info $ScriptName ("Saved configuration to partition '" . $FallbackTo . "'."); } on-error={ /system/scheduler/remove [ find where name="running-from-backup-partition" ]; - $LogPrintExit2 error $ScriptName ("Failed saving configuration to partition '" . \ - $FallbackTo . "'!") false; + $LogPrint error $ScriptName ("Failed saving configuration to partition '" . $FallbackTo . "'!"); :set PackagesUpdateBackupFailure true; :error false; } From ca822e1358d59f43d2ef359e2ec3cde44c589f46 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:37 +0100 Subject: [PATCH 2062/2612] backup-upload: switch to $LogPrint --- backup-upload.rsc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 769972b..ef5b7c7 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -30,7 +30,7 @@ :global CleanName; :global DeviceInfo; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global MkDir; :global RandomDelay; :global ScriptFromTerminal; @@ -42,7 +42,8 @@ :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ - $LogPrintExit2 error $ScriptName ("Configured to send neither backup nor config export.") true; + $LogPrint error $ScriptName ("Configured to send neither backup nor config export."); + :error false; } :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -65,7 +66,8 @@ :local Failed 0; :if ([ $MkDir $DirName ] = false) do={ - $LogPrintExit2 error $ScriptName ("Failed creating directory!") true; + $LogPrint error $ScriptName ("Failed creating directory!"); + :error false; } # binary backup @@ -79,7 +81,7 @@ :set BackupFile [ /file/get ($FilePath . ".backup") ]; :set ($BackupFile->"name") ($FileName . ".backup"); } on-error={ - $LogPrintExit2 error $ScriptName ("Uploading backup file failed!") false; + $LogPrint error $ScriptName ("Uploading backup file failed!"); :set BackupFile "failed"; :set Failed 1; } @@ -98,7 +100,7 @@ :set ExportFile [ /file/get ($FilePath . ".rsc") ]; :set ($ExportFile->"name") ($FileName . ".rsc"); } on-error={ - $LogPrintExit2 error $ScriptName ("Uploading configuration export failed!") false; + $LogPrint error $ScriptName ("Uploading configuration export failed!"); :set ExportFile "failed"; :set Failed 1; } @@ -119,7 +121,7 @@ :set ConfigFile [ /file/get ($FilePath . ".conf") ]; :set ($ConfigFile->"name") ($FileName . ".conf"); } on-error={ - $LogPrintExit2 error $ScriptName ("Uploading global-config-overlay failed!") false; + $LogPrint error $ScriptName ("Uploading global-config-overlay failed!"); :set ConfigFile "failed"; :set Failed 1; } From e40da1e7e483a07592477ef82c4a665f6b2a7bde Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:37 +0100 Subject: [PATCH 2063/2612] capsman-download-packages: switch to $LogPrint --- capsman-download-packages.capsman.rsc | 16 +++++++++------- capsman-download-packages.template.rsc | 16 +++++++++------- capsman-download-packages.wifi.rsc | 16 +++++++++------- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index d4e900d..a3bd4a5 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -19,7 +19,7 @@ :global CleanFilePath; :global DownloadPackage; - :global LogPrintExit2; + :global LogPrint; :global MkDir; :global ScriptLock; :global WaitFullyConnected; @@ -34,16 +34,18 @@ :local Updated false; :if ([ :len $PackagePath ] = 0) do={ - $LogPrintExit2 warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages.") true; + $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={ - $LogPrintExit2 warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ - $PackagePath . ") failed!") true; + $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ + $PackagePath . ") failed!"); + :error false; } - $LogPrintExit2 info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ - "). Please place your packages!") false; + $LogPrint info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ + "). Please place your packages!"); } :foreach Package in=[ /file/find where type=package \ @@ -60,7 +62,7 @@ } :if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ - $LogPrintExit2 info $ScriptName ("No packages available, downloading default set.") false; + $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={ diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index cd4a83b..cad3bcb 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -20,7 +20,7 @@ :global CleanFilePath; :global DownloadPackage; - :global LogPrintExit2; + :global LogPrint; :global MkDir; :global ScriptLock; :global WaitFullyConnected; @@ -36,16 +36,18 @@ :local Updated false; :if ([ :len $PackagePath ] = 0) do={ - $LogPrintExit2 warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages.") true; + $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={ - $LogPrintExit2 warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ - $PackagePath . ") failed!") true; + $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ + $PackagePath . ") failed!"); + :error false; } - $LogPrintExit2 info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ - "). Please place your packages!") false; + $LogPrint info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ + "). Please place your packages!"); } :foreach Package in=[ /file/find where type=package \ @@ -62,7 +64,7 @@ } :if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ - $LogPrintExit2 info $ScriptName ("No packages available, downloading default set.") false; + $LogPrint info $ScriptName ("No packages available, downloading default set."); # NOT /interface/wifi/ # :foreach Arch in={ "arm"; "mipsbe" } do={ :foreach Package in={ "routeros"; "wireless" } do={ diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 633830a..909688f 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -19,7 +19,7 @@ :global CleanFilePath; :global DownloadPackage; - :global LogPrintExit2; + :global LogPrint; :global MkDir; :global ScriptLock; :global WaitFullyConnected; @@ -34,16 +34,18 @@ :local Updated false; :if ([ :len $PackagePath ] = 0) do={ - $LogPrintExit2 warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages.") true; + $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={ - $LogPrintExit2 warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ - $PackagePath . ") failed!") true; + $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ + $PackagePath . ") failed!"); + :error false; } - $LogPrintExit2 info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ - "). Please place your packages!") false; + $LogPrint info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ + "). Please place your packages!"); } :foreach Package in=[ /file/find where type=package \ @@ -60,7 +62,7 @@ } :if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ - $LogPrintExit2 info $ScriptName ("No packages available, downloading default set.") false; + $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" } }; From 12435ff1c53e7ef3b8b63b28860a3f35f8146184 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:37 +0100 Subject: [PATCH 2064/2612] capsman-rolling-upgrade: switch to $LogPrint --- capsman-rolling-upgrade.capsman.rsc | 8 ++++---- capsman-rolling-upgrade.template.rsc | 8 ++++---- capsman-rolling-upgrade.wifi.rsc | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc index 16a3498..11bfd69 100644 --- a/capsman-rolling-upgrade.capsman.rsc +++ b/capsman-rolling-upgrade.capsman.rsc @@ -18,7 +18,7 @@ :do { :local ScriptName [ :jobname ]; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -34,11 +34,11 @@ :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 $ScriptName ("Starting upgrade for " . $RemoteCapVal->"name" . \ - " (" . $RemoteCapVal->"identity" . ")...") false; + $LogPrint info $ScriptName ("Starting upgrade for " . $RemoteCapVal->"name" . \ + " (" . $RemoteCapVal->"identity" . ")..."); /caps-man/remote-cap/upgrade $RemoteCap; } else={ - $LogPrintExit2 warning $ScriptName ("Remote CAP vanished, skipping upgrade.") false; + $LogPrint warning $ScriptName ("Remote CAP vanished, skipping upgrade."); } :delay ($Delay . "s"); } diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index 45a5f8e..e0effd4 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -19,7 +19,7 @@ :do { :local ScriptName [ :jobname ]; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -41,12 +41,12 @@ # NOT /caps-man/ # :set ($RemoteCapVal->"name") ($RemoteCapVal->"common-name"); # NOT /caps-man/ # - $LogPrintExit2 info $ScriptName ("Starting upgrade for " . $RemoteCapVal->"name" . \ - " (" . $RemoteCapVal->"identity" . ")...") false; + $LogPrint info $ScriptName ("Starting upgrade for " . $RemoteCapVal->"name" . \ + " (" . $RemoteCapVal->"identity" . ")..."); /caps-man/remote-cap/upgrade $RemoteCap; /interface/wifi/capsman/remote-cap/upgrade $RemoteCap; } else={ - $LogPrintExit2 warning $ScriptName ("Remote CAP vanished, skipping upgrade.") false; + $LogPrint warning $ScriptName ("Remote CAP vanished, skipping upgrade."); } :delay ($Delay . "s"); } diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc index 63245dc..8ec6f26 100644 --- a/capsman-rolling-upgrade.wifi.rsc +++ b/capsman-rolling-upgrade.wifi.rsc @@ -18,7 +18,7 @@ :do { :local ScriptName [ :jobname ]; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -35,11 +35,11 @@ :local RemoteCapVal [ /interface/wifi/capsman/remote-cap/get $RemoteCap ]; :if ([ :len $RemoteCapVal ] > 1) do={ :set ($RemoteCapVal->"name") ($RemoteCapVal->"common-name"); - $LogPrintExit2 info $ScriptName ("Starting upgrade for " . $RemoteCapVal->"name" . \ - " (" . $RemoteCapVal->"identity" . ")...") false; + $LogPrint info $ScriptName ("Starting upgrade for " . $RemoteCapVal->"name" . \ + " (" . $RemoteCapVal->"identity" . ")..."); /interface/wifi/capsman/remote-cap/upgrade $RemoteCap; } else={ - $LogPrintExit2 warning $ScriptName ("Remote CAP vanished, skipping upgrade.") false; + $LogPrint warning $ScriptName ("Remote CAP vanished, skipping upgrade."); } :delay ($Delay . "s"); } From 7c38b9a35c972a9b65c16c581c8da1b4d456b0fe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:37 +0100 Subject: [PATCH 2065/2612] certificate-renew-issued: switch to $LogPrint --- certificate-renew-issued.rsc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc index a360a3f..45805c5 100644 --- a/certificate-renew-issued.rsc +++ b/certificate-renew-issued.rsc @@ -16,7 +16,7 @@ :global CertIssuedExportPass; - :global LogPrintExit2; + :global LogPrint; :global MkDir; :global ScriptLock; @@ -36,13 +36,13 @@ /certificate/export-certificate ($CertVal->"name") type=pkcs12 \ file-name=("cert-issued/" . $CertVal->"common-name") \ export-passphrase=($CertIssuedExportPass->($CertVal->"common-name")); - $LogPrintExit2 info $ScriptName ("Issued a new certificate for \"" . $CertVal->"common-name" . \ - "\", exported to \"cert-issued/" . $CertVal->"common-name" . ".p12\".") false; + $LogPrint info $ScriptName ("Issued a new certificate for \"" . $CertVal->"common-name" . \ + "\", exported to \"cert-issued/" . $CertVal->"common-name" . ".p12\"."); } else={ - $LogPrintExit2 warning $ScriptName ("Failed creating directory, not exporting certificate.") false; + $LogPrint warning $ScriptName ("Failed creating directory, not exporting certificate."); } } else={ - $LogPrintExit2 info $ScriptName ("Issued a new certificate for \"" . $CertVal->"common-name" . "\".") false; + $LogPrint info $ScriptName ("Issued a new certificate for \"" . $CertVal->"common-name" . "\"."); } } } on-error={ } From 36258087497df000a69cd9544595ba87d216077f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:37 +0100 Subject: [PATCH 2066/2612] check-certificates: switch to $LogPrint --- check-certificates.rsc | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index edde7f3..7504955 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -22,7 +22,7 @@ :global CertificateAvailable :global EscapeForRegEx; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global ScriptLock; :global SendNotification2; @@ -39,7 +39,7 @@ :global CertificateNameByCN; :global EscapeForRegEx; :global FetchUserAgent; - :global LogPrintExit2; + :global LogPrint; :global UrlEncode; :global WaitForFile; @@ -62,7 +62,7 @@ /file/remove [ find where name=$CertFileName ]; :if ($DecryptionFailed = true) do={ - $LogPrintExit2 warning $0 ("Decryption failed for certificate file '" . $CertFileName . "'.") false; + $LogPrint warning $0 ("Decryption failed for certificate file '" . $CertFileName . "'."); } :foreach CertInChain in=[ /certificate/find where name~("^" . [ $EscapeForRegEx $CertFileName ] . "_[0-9]+\$") \ @@ -72,7 +72,7 @@ :set Return true; } on-error={ - $LogPrintExit2 debug $0 ("Could not download certificate file '" . $CertFileName . "'.") false; + $LogPrint debug $0 ("Could not download certificate file '" . $CertFileName . "'."); } } @@ -143,9 +143,10 @@ :do { :if ([ :len $CertRenewUrl ] = 0) do={ - $LogPrintExit2 info $ScriptName ("No CertRenewUrl given.") true; + $LogPrint info $ScriptName ("No CertRenewUrl given."); + :error false; } - $LogPrintExit2 info $ScriptName ("Attempting to renew certificate '" . ($CertVal->"name") . "'.") false; + $LogPrint info $ScriptName ("Attempting to renew certificate '" . ($CertVal->"name") . "'."); :local ImportSuccess false; :set LastName ($CertVal->"common-name"); @@ -159,10 +160,10 @@ :if ($ImportSuccess = false) do={ :error false; } :if ([ :len ($CertVal->"fingerprint") ] > 0 && $CertVal->"fingerprint" != [ /certificate/get $Cert fingerprint ]) do={ - $LogPrintExit2 debug $ScriptName ("Certificate '" . $CertVal->"name" . "' was updated in place.") false; + $LogPrint debug $ScriptName ("Certificate '" . $CertVal->"name" . "' was updated in place."); :set CertVal [ /certificate/get $Cert ]; } else={ - $LogPrintExit2 debug $ScriptName ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; + $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|\$)")) \ @@ -170,12 +171,13 @@ :local CertNewVal [ /certificate/get $CertNew ]; :if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") ] = false) do={ - $LogPrintExit2 warning $ScriptName ("The certificate chain is not available!") false; + $LogPrint warning $ScriptName ("The certificate chain is not available!"); } :if (($CertVal->"private-key") = true && ($CertVal->"private-key") != ($CertNewVal->"private-key")) do={ /certificate/remove $CertNew; - $LogPrintExit2 warning $ScriptName ("Old certificate '" . ($CertVal->"name") . "' has a private key, new certificate does not. Aborting renew.") true; + $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") ]; @@ -194,9 +196,9 @@ $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 ]) }); - $LogPrintExit2 info $ScriptName ("The certificate '" . ($CertVal->"name") . "' has been renewed.") false; + $LogPrint info $ScriptName ("The certificate '" . ($CertVal->"name") . "' has been renewed."); } on-error={ - $LogPrintExit2 debug $ScriptName ("Could not renew certificate '" . ($CertVal->"name") . "'.") false; + $LogPrint debug $ScriptName ("Could not renew certificate '" . ($CertVal->"name") . "'."); } } @@ -205,15 +207,15 @@ :local CertVal [ /certificate/get $Cert ]; :if ([ :len [ /certificate/scep-server/find where ca-cert=($CertVal->"ca") ] ] > 0) do={ - $LogPrintExit2 debug $ScriptName ("Certificate '" . ($CertVal->"name") . "' is handled by SCEP, skipping.") false; + $LogPrint debug $ScriptName ("Certificate '" . ($CertVal->"name") . "' is handled by SCEP, skipping."); } else={ :local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ]; $SendNotification2 ({ origin=$ScriptName; \ subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning: " . ($CertVal->"name")); \ message=("A certificate on " . $Identity . " " . $State . ".\n\n" . [ $FormatInfo $Cert ]) }); - $LogPrintExit2 info $ScriptName ("The certificate '" . ($CertVal->"name") . "' " . $State . \ - ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; + $LogPrint info $ScriptName ("The certificate '" . ($CertVal->"name") . "' " . $State . \ + ", it is invalid after " . ($CertVal->"invalid-after") . "."); } } } on-error={ } From 463393647fc5c28faad5e9c671af8e9b441478c7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:37 +0100 Subject: [PATCH 2067/2612] check-health: switch to $LogPrint --- check-health.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/check-health.rsc b/check-health.rsc index 91330fc..2a97ad6 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -28,7 +28,7 @@ :global FormatLine; :global HumanReadableNum; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -77,7 +77,7 @@ } :if ([ :len [ /system/health/find ] ] = 0) do={ - $LogPrintExit2 debug $ScriptName ("Your device does not provide any health values.") false; + $LogPrint debug $ScriptName ("Your device does not provide any health values."); :error true; } @@ -148,7 +148,7 @@ :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ - $LogPrintExit2 info $ScriptName ("No threshold given for " . $Name . ", assuming 50C.") false; + $LogPrint info $ScriptName ("No threshold given for " . $Name . ", assuming 50C."); :set ($CheckHealthTemperature->$Name) 50; } :local Validate [ /system/health/get [ find where name=$Name ] value ]; From 7f154a178bf41a6d053cd86e339d8533c0028a51 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:37 +0100 Subject: [PATCH 2068/2612] check-lte-firmware-upgrade: switch to $LogPrint --- check-lte-firmware-upgrade.rsc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index f2a6e37..e7f06f3 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -35,7 +35,7 @@ :global FormatLine; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global ScriptFromTerminal; :global SendNotification2; :global SymbolForNotification; @@ -47,19 +47,19 @@ :set Firmware [ /interface/lte/firmware-upgrade $Interface once as-value ]; :set Info [ /interface/lte/monitor $Interface once as-value ]; } on-error={ - $LogPrintExit2 debug $ScriptName ("Could not get latest LTE firmware version for interface " . \ - $IntName . ".") false; + $LogPrint debug $ScriptName ("Could not get latest LTE firmware version for interface " . \ + $IntName . "."); :return false; } :if ([ :len ($Firmware->"latest") ] = 0) do={ - $LogPrintExit2 info $ScriptName ("An empty string is not a valid version.") false; + $LogPrint info $ScriptName ("An empty string is not a valid version."); :return false; } :if (($Firmware->"installed") = ($Firmware->"latest")) do={ :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ - $LogPrintExit2 info $ScriptName ("No firmware upgrade available for LTE interface " . $IntName . ".") false; + $LogPrint info $ScriptName ("No firmware upgrade available for LTE interface " . $IntName . "."); } :return true; } @@ -69,7 +69,7 @@ :put ("Do you want to start unattended lte firmware upgrade for interface " . $IntName . "? [y/N]"); :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ /system/script/run unattended-lte-firmware-upgrade; - $LogPrintExit2 info $ScriptName ("Scheduled lte firmware upgrade for interface " . $IntName . "...") false; + $LogPrint info $ScriptName ("Scheduled lte firmware upgrade for interface " . $IntName . "..."); :return true; } else={ :put "Canceled..."; @@ -77,13 +77,13 @@ } :if (($SentLteFirmwareUpgradeNotification->$IntName) = ($Firmware->"latest")) do={ - $LogPrintExit2 debug $ScriptName ("Already sent the LTE firmware upgrade notification for version " . \ - ($Firmware->"latest") . ".") false; + $LogPrint debug $ScriptName ("Already sent the LTE firmware upgrade notification for version " . \ + ($Firmware->"latest") . "."); :return false; } - $LogPrintExit2 info $ScriptName ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ - "LTE interface " . $IntName . ".") 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 " . \ From a996bdac2aa42728676fe2acc1f0b589aae6673c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:37 +0100 Subject: [PATCH 2069/2612] check-routeros-update: switch to $LogPrint --- check-routeros-update.rsc | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index a68762b..e209610 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -24,7 +24,7 @@ :global DeviceInfo; :global EscapeForRegEx; - :global LogPrintExit2; + :global LogPrint; :global ScriptFromTerminal; :global ScriptLock; :global SendNotification2; @@ -50,12 +50,12 @@ :error "A reboot for update is already scheduled."; } - $LogPrintExit2 debug $ScriptName ("Checking for updates...") false; + $LogPrint debug $ScriptName ("Checking for updates..."); /system/package/update/check-for-updates without-paging as-value; :local Update [ /system/package/update/get ]; :if ([ $ScriptFromTerminal $ScriptName ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={ - $LogPrintExit2 info $ScriptName ("System is already up to date.") false; + $LogPrint info $ScriptName ("System is already up to date."); :error true; } @@ -64,13 +64,14 @@ :local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); :if ($NumLatest < 117505792) do={ - $LogPrintExit2 info $ScriptName ("The version '" . ($Update->"latest-version") . "' is not a valid version.") true; + $LogPrint info $ScriptName ("The version '" . ($Update->"latest-version") . "' is not a valid version."); + :error false; } :if ($NumInstalled < $NumLatest) do={ :if ($SafeUpdateAll ~ "^YES,? ?PLEASE!?\$") do={ - $LogPrintExit2 info $ScriptName ("Installing ALL versions automatically, including " . \ - $Update->"latest-version" . "...") false; + $LogPrint info $ScriptName ("Installing ALL versions automatically, including " . \ + $Update->"latest-version" . "..."); $SendNotification2 ({ origin=$ScriptName; \ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ message=("Installing ALL versions automatically, including " . $Update->"latest-version" . \ @@ -79,7 +80,7 @@ } :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ - $LogPrintExit2 info $ScriptName ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; + $LogPrint info $ScriptName ("Version " . $Update->"latest-version" . " is a patch release, updating..."); $SendNotification2 ({ origin=$ScriptName; \ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ @@ -92,8 +93,8 @@ version~("^" . [ $EscapeForRegEx ($Update->"latest-version") ] . "\\b") ]; :if ([ :len $Neighbors ] > 0) do={ :local Neighbor [ /ip/neighbor/get ($Neighbors->0) identity ]; - $LogPrintExit2 info $ScriptName ("Seen a neighbor (" . $Neighbor . ") running version " . \ - $Update->"latest-version" . " from " . $Update->"channel" . ", updating...") false; + $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" . \ @@ -109,10 +110,10 @@ ($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \ "&latest=" . $Update->"latest-version") output=user as-value ]; } on-error={ - $LogPrintExit2 warning $ScriptName ("Failed receiving safe version for " . $Update->"channel" . ".") false; + $LogPrint warning $ScriptName ("Failed receiving safe version for " . $Update->"channel" . "."); } :if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={ - $LogPrintExit2 info $ScriptName ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; + $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" . \ @@ -131,8 +132,8 @@ } :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ - $LogPrintExit2 info $ScriptName ("Already sent the RouterOS update notification for version " . \ - $Update->"latest-version" . ".") false; + $LogPrint info $ScriptName ("Already sent the RouterOS update notification for version " . \ + $Update->"latest-version" . "."); :error true; } @@ -146,8 +147,8 @@ :if ($NumInstalled > $NumLatest) do={ :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ - $LogPrintExit2 info $ScriptName ("Already sent the RouterOS downgrade notification for version " . \ - $Update->"latest-version" . ".") false; + $LogPrint info $ScriptName ("Already sent the RouterOS downgrade notification for version " . \ + $Update->"latest-version" . "."); :error true; } @@ -156,8 +157,8 @@ 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 $ScriptName ("A different RouterOS version " . ($Update->"latest-version") . \ - " is available for downgrade.") false; + $LogPrint info $ScriptName ("A different RouterOS version " . ($Update->"latest-version") . \ + " is available for downgrade."); :set SentRouterosUpdateNotification ($Update->"latest-version"); } } on-error={ } From 5016f4d28ccef4d3b0b1ab55cacb8cf3ee9d0cea Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:37 +0100 Subject: [PATCH 2070/2612] collect-wireless-mac: switch to $LogPrint --- collect-wireless-mac.capsman.rsc | 14 +++++++------- collect-wireless-mac.local.rsc | 14 +++++++------- collect-wireless-mac.template.rsc | 18 +++++++++--------- collect-wireless-mac.wifi.rsc | 14 +++++++------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index 5423624..dcb303c 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -23,7 +23,7 @@ :global FormatLine; :global FormatMultiLines; :global GetMacVendor; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -34,7 +34,7 @@ :if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ /caps-man/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'.") false; + $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'."); } :local PlaceBefore ([ /caps-man/access-list/find where comment="--- collected above ---" disabled ]->0); @@ -43,14 +43,14 @@ :do { :set RegVal [ /caps-man/registration-table/get $Reg ]; } on-error={ - $LogPrintExit2 debug $ScriptName ("Device already gone... Ignoring.") false; + $LogPrint debug $ScriptName ("Device already gone... Ignoring."); } :if ([ :len ($RegVal->"mac-address") ] > 0) do={ :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /caps-man/access-list/get $AccessList comment ]) false; + $LogPrint debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ + [ /caps-man/access-list/get $AccessList comment ]); } :if ([ :len $AccessList ] = 0) do={ @@ -74,7 +74,7 @@ :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 $ScriptName $Message false; + $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"); \ @@ -90,7 +90,7 @@ [ $FormatLine "Date" $DateTime ]) }); } } else={ - $LogPrintExit2 debug $ScriptName ("No mac address available... Ignoring.") false; + $LogPrint debug $ScriptName ("No mac address available... Ignoring."); } } } on-error={ } diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index a4e81a3..7c1122c 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -23,7 +23,7 @@ :global FormatLine; :global FormatMultiLines; :global GetMacVendor; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -34,7 +34,7 @@ :if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ /interface/wireless/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'.") false; + $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'."); } :local PlaceBefore ([ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ]->0); @@ -43,14 +43,14 @@ :do { :set RegVal [ /interface/wireless/registration-table/get $Reg ]; } on-error={ - $LogPrintExit2 debug $ScriptName ("Device already gone... Ignoring.") false; + $LogPrint debug $ScriptName ("Device already gone... Ignoring."); } :if ([ :len ($RegVal->"mac-address") ] > 0) do={ :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /interface/wireless/access-list/get $AccessList comment ]) false; + $LogPrint debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ + [ /interface/wireless/access-list/get $AccessList comment ]); } :if ([ :len $AccessList ] = 0) do={ @@ -75,7 +75,7 @@ :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 $ScriptName $Message false; + $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"); \ @@ -91,7 +91,7 @@ [ $FormatLine "Date" $DateTime ]) }); } } else={ - $LogPrintExit2 debug $ScriptName ("No mac address available... Ignoring.") false; + $LogPrint debug $ScriptName ("No mac address available... Ignoring."); } } } on-error={ } diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index f647eb3..b8c5ff8 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -24,7 +24,7 @@ :global FormatLine; :global FormatMultiLines; :global GetMacVendor; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -39,7 +39,7 @@ /caps-man/access-list/add comment="--- collected above ---" disabled=yes; /interface/wifi/access-list/add comment="--- collected above ---" disabled=yes; /interface/wireless/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'.") false; + $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'."); } :local PlaceBefore ([ /caps-man/access-list/find where comment="--- collected above ---" disabled ]->0); :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ]->0); @@ -54,7 +54,7 @@ :set RegVal [ /interface/wifi/registration-table/get $Reg ]; :set RegVal [ /interface/wireless/registration-table/get $Reg ]; } on-error={ - $LogPrintExit2 debug $ScriptName ("Device already gone... Ignoring.") false; + $LogPrint debug $ScriptName ("Device already gone... Ignoring."); } :if ([ :len ($RegVal->"mac-address") ] > 0) do={ @@ -62,10 +62,10 @@ :local AccessList ([ /interface/wifi/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /caps-man/access-list/get $AccessList comment ]) false; - [ /interface/wifi/access-list/get $AccessList comment ]) false; - [ /interface/wireless/access-list/get $AccessList comment ]) false; + $LogPrint debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ + [ /caps-man/access-list/get $AccessList comment ]); + [ /interface/wifi/access-list/get $AccessList comment ]); + [ /interface/wireless/access-list/get $AccessList comment ]); } :if ([ :len $AccessList ] = 0) do={ @@ -90,7 +90,7 @@ :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 $ScriptName $Message false; + $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; @@ -108,7 +108,7 @@ [ $FormatLine "Date" $DateTime ]) }); } } else={ - $LogPrintExit2 debug $ScriptName ("No mac address available... Ignoring.") false; + $LogPrint debug $ScriptName ("No mac address available... Ignoring."); } } } on-error={ } diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc index 063d6dc..b8ad939 100644 --- a/collect-wireless-mac.wifi.rsc +++ b/collect-wireless-mac.wifi.rsc @@ -23,7 +23,7 @@ :global FormatLine; :global FormatMultiLines; :global GetMacVendor; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -34,7 +34,7 @@ :if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ /interface/wifi/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'.") false; + $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'."); } :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ]->0); @@ -43,14 +43,14 @@ :do { :set RegVal [ /interface/wifi/registration-table/get $Reg ]; } on-error={ - $LogPrintExit2 debug $ScriptName ("Device already gone... Ignoring.") false; + $LogPrint debug $ScriptName ("Device already gone... Ignoring."); } :if ([ :len ($RegVal->"mac-address") ] > 0) do={ :local AccessList ([ /interface/wifi/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /interface/wifi/access-list/get $AccessList comment ]) false; + $LogPrint debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ + [ /interface/wifi/access-list/get $AccessList comment ]); } :if ([ :len $AccessList ] = 0) do={ @@ -74,7 +74,7 @@ :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 $ScriptName $Message false; + $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"); \ @@ -90,7 +90,7 @@ [ $FormatLine "Date" $DateTime ]) }); } } else={ - $LogPrintExit2 debug $ScriptName ("No mac address available... Ignoring.") false; + $LogPrint debug $ScriptName ("No mac address available... Ignoring."); } } } on-error={ } From 4ab8dbd774f6d024db493359a7cb345f3bd76c8b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2071/2612] daily-psk: switch to $LogPrint --- daily-psk.capsman.rsc | 6 +++--- daily-psk.local.rsc | 6 +++--- daily-psk.template.rsc | 6 +++--- daily-psk.wifi.rsc | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index c9c0186..43651d0 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -22,7 +22,7 @@ :global Identity; :global FormatLine; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -68,12 +68,12 @@ :local Skip 0; :if ($NewPsk != $OldPsk) do={ - $LogPrintExit2 info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + $LogPrint info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")"); /caps-man/access-list/set $AccList private-passphrase=$NewPsk; :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ :if ($Seen->$Ssid = 1) do={ - $LogPrintExit2 debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; + $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping."); } else={ :local Link ($DailyPskQrCodeUrl . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 228efc8..2dbc61b 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -22,7 +22,7 @@ :global Identity; :global FormatLine; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -67,12 +67,12 @@ :local Skip 0; :if ($NewPsk != $OldPsk) do={ - $LogPrintExit2 info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + $LogPrint info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")"); /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ :if ($Seen->$Ssid = 1) do={ - $LogPrintExit2 debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; + $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping."); } else={ :local Link ($DailyPskQrCodeUrl . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 4403fe6..e190ffb 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -23,7 +23,7 @@ :global Identity; :global FormatLine; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -79,7 +79,7 @@ :local Skip 0; :if ($NewPsk != $OldPsk) do={ - $LogPrintExit2 info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + $LogPrint info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")"); /caps-man/access-list/set $AccList private-passphrase=$NewPsk; /interface/wifi/access-list/set $AccList passphrase=$NewPsk; /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; @@ -88,7 +88,7 @@ :if ([ :len [ /interface/wifi/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ :if ($Seen->$Ssid = 1) do={ - $LogPrintExit2 debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; + $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping."); } else={ :local Link ($DailyPskQrCodeUrl . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index e9b5199..ee3e1b0 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -22,7 +22,7 @@ :global Identity; :global FormatLine; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -68,12 +68,12 @@ :local Skip 0; :if ($NewPsk != $OldPsk) do={ - $LogPrintExit2 info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + $LogPrint info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")"); /interface/wifi/access-list/set $AccList passphrase=$NewPsk; :if ([ :len [ /interface/wifi/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ :if ($Seen->$Ssid = 1) do={ - $LogPrintExit2 debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; + $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping."); } else={ :local Link ($DailyPskQrCodeUrl . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); From 5638bdcc2d6a6c333c5a11df4946ff88cb3ecb43 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2072/2612] dhcp-lease-comment: switch to $LogPrint --- dhcp-lease-comment.capsman.rsc | 4 ++-- dhcp-lease-comment.local.rsc | 4 ++-- dhcp-lease-comment.template.rsc | 4 ++-- dhcp-lease-comment.wifi.rsc | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc index 1b61167..4ac228b 100644 --- a/dhcp-lease-comment.capsman.rsc +++ b/dhcp-lease-comment.capsman.rsc @@ -17,7 +17,7 @@ :do { :local ScriptName [ :jobname ]; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -32,7 +32,7 @@ :set NewComment [ /caps-man/access-list/get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit2 info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; + $LogPrint info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment); /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc index 5401a77..a49f74f 100644 --- a/dhcp-lease-comment.local.rsc +++ b/dhcp-lease-comment.local.rsc @@ -17,7 +17,7 @@ :do { :local ScriptName [ :jobname ]; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -32,7 +32,7 @@ :set NewComment [ /interface/wireless/access-list/get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit2 info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; + $LogPrint info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment); /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index 6ed8fc3..0f0975b 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -18,7 +18,7 @@ :do { :local ScriptName [ :jobname ]; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -37,7 +37,7 @@ :set NewComment [ /interface/wireless/access-list/get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit2 info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; + $LogPrint info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment); /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc index 62ed03d..c9c091b 100644 --- a/dhcp-lease-comment.wifi.rsc +++ b/dhcp-lease-comment.wifi.rsc @@ -17,7 +17,7 @@ :do { :local ScriptName [ :jobname ]; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -32,7 +32,7 @@ :set NewComment [ /interface/wifi/access-list/get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit2 info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; + $LogPrint info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment); /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } From 5c775fdb3f28aaa2f354db3dca8ae3abd29c3d9d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2073/2612] dhcp-to-dns: switch to $LogPrint --- dhcp-to-dns.rsc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index d0638c7..5b6e64a 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -21,7 +21,7 @@ :global CleanName; :global EitherOr; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global LogPrintOnce; :global ParseKeyValueStore; :global ScriptLock; @@ -36,7 +36,7 @@ :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 $ScriptName ("Added disabled static dns record with name '" . $CommentString . "'.") false; + $LogPrint warning $ScriptName ("Added disabled static dns record with name '" . $CommentString . "'."); } :local PlaceBefore ([ /ip/dns/static/find where (name=$CommentString or (comment=$CommentString and name=-)) type=NXDOMAIN disabled ]->0); @@ -47,10 +47,10 @@ :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 $ScriptName ("Lease for " . $MacInServer . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting record.") false; + $LogPrint debug $ScriptName ("Lease for " . $MacInServer . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting record."); } else={ :local Found false; - $LogPrintExit2 info $ScriptName ("Lease expired for " . $MacInServer . ", deleting record (" . $DnsRecordVal->"name" . ").") 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") ]; } @@ -64,7 +64,7 @@ $LogPrintOnce info $ScriptName ("Multiple bound leases found for mac-address " . ($LeaseVal->"active-mac-address") . "!"); } } on-error={ - $LogPrintExit2 debug $ScriptName ("A lease just vanished, ignoring.") false; + $LogPrint debug $ScriptName ("A lease just vanished, ignoring."); } :if ([ :len ($LeaseVal->"active-address") ] > 0) do={ @@ -88,9 +88,9 @@ :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; :if ($DnsRecordVal->"address" = $LeaseVal->"active-address" && $DnsRecordVal->"name" = $FullA) do={ - $LogPrintExit2 debug $ScriptName ("The A record for " . $MacInServer . " (" . $FullA . ") does not need updating.") false; + $LogPrint debug $ScriptName ("The A record for " . $MacInServer . " (" . $FullA . ") does not need updating."); } else={ - $LogPrintExit2 info $ScriptName ("Updating A record for " . $MacInServer . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ").") false; + $LogPrint info $ScriptName ("Updating A record for " . $MacInServer . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ")."); /ip/dns/static/set address=($LeaseVal->"active-address") name=$FullA $DnsRecord; } @@ -98,20 +98,20 @@ :if ([ :len $CName ] > 0) do={ :local CNameVal [ /ip/dns/static/get $CName ]; :if ($CNameVal->"name" != $FullCN || $CNameVal->"cname" != $FullA) do={ - $LogPrintExit2 info $ScriptName ("Deleting CNAME record with wrong data for " . $MacInServer . ".") false; + $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={ - $LogPrintExit2 info $ScriptName ("Adding CNAME record for " . $MacInServer . " (" . $FullCN . " -> " . $FullA . ").") false; + $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={ - $LogPrintExit2 info $ScriptName ("Adding A record for " . $MacInServer . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ").") false; + $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={ - $LogPrintExit2 info $ScriptName ("Adding CNAME record for " . $MacInServer . " (" . $FullCN . " -> " . $FullA . ").") false; + $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; } } @@ -120,7 +120,7 @@ $LogPrintOnce warning $ScriptName ("The name '" . $FullA . "' appeared in more than one A record!"); } } else={ - $LogPrintExit2 debug $ScriptName ("No address available... Ignoring.") false; + $LogPrint debug $ScriptName ("No address available... Ignoring."); } } } on-error={ } From c8e4cb05267f50ebc06d5cebc30186f0a5618252 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2074/2612] firmware-upgrade-reboot: switch to $LogPrint --- firmware-upgrade-reboot.rsc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc index 6499d27..038f74e 100644 --- a/firmware-upgrade-reboot.rsc +++ b/firmware-upgrade-reboot.rsc @@ -14,7 +14,7 @@ :do { :local ScriptName [ :jobname ]; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :global VersionToNum; @@ -24,18 +24,18 @@ :local RouterBoard [ /system/routerboard/get ]; :if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ - $LogPrintExit2 info $ScriptName ("Current and upgrade firmware match with version " . \ - $RouterBoard->"current-firmware" . ".") false; + $LogPrint info $ScriptName ("Current and upgrade firmware match with version " . \ + $RouterBoard->"current-firmware" . "."); :error true; } :if ([ $VersionToNum ($RouterBoard->"current-firmware") ] > [ $VersionToNum ($RouterBoard->"upgrade-firmware") ]) do={ - $LogPrintExit2 info $ScriptName ("Different firmware version is available, but it is a downgrade. Ignoring.") false; + $LogPrint info $ScriptName ("Different firmware version is available, but it is a downgrade. Ignoring."); :error true; } :if ([ /system/routerboard/settings/get auto-upgrade ] = false) do={ - $LogPrintExit2 info $ScriptName ("Firmware version " . $RouterBoard->"upgrade-firmware" . \ - " is available, upgrading.") false; + $LogPrint info $ScriptName ("Firmware version " . $RouterBoard->"upgrade-firmware" . \ + " is available, upgrading."); /system/routerboard/upgrade; } @@ -49,6 +49,6 @@ :delay $Uptime; } - $LogPrintExit2 info $ScriptName ("Firmware upgrade successful, rebooting.") false; + $LogPrint info $ScriptName ("Firmware upgrade successful, rebooting."); /system/reboot; } on-error={ } From 6715696ba1a4239b626e19a466cafae9e698c807 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2075/2612] fw-addr-lists: switch to $LogPrint --- fw-addr-lists.rsc | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 4ec4105..64233ac 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -20,7 +20,7 @@ :global CertificateAvailable; :global EitherOr; - :global LogPrintExit2; + :global LogPrint; :global LogPrintOnce; :global ScriptLock; :global WaitFullyConnected; @@ -57,7 +57,7 @@ :if ([ :len ($List->"cert") ] > 0) do={ :set CheckCertificate "yes-without-crl"; :if ([ $CertificateAvailable ($List->"cert") ] = false) do={ - $LogPrintExit2 warning $ScriptName ("Downloading required certificate failed, trying anyway.") false; + $LogPrint warning $ScriptName ("Downloading required certificate failed, trying anyway."); } } @@ -68,7 +68,7 @@ http-header-field=({ $FetchUserAgent }) ($List->"url") as-value ]->"data"); } on-error={ :if ($I < 4) do={ - $LogPrintExit2 debug $ScriptName ("Failed downloading, " . $I . ". try: " . $List->"url") false; + $LogPrint debug $ScriptName ("Failed downloading, " . $I . ". try: " . $List->"url"); :delay (($I * $I) . "s"); } } @@ -78,7 +78,7 @@ :if ($Data = false) do={ :set Data ""; :set Failure true; - $LogPrintExit2 warning $ScriptName ("Failed downloading list from: " . $List->"url") false; + $LogPrint warning $ScriptName ("Failed downloading list from: " . $List->"url"); } :if ([ :len $Data ] > 63000) do={ @@ -103,13 +103,13 @@ :foreach Entry in=[ /ip/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={ :local Address [ /ip/firewall/address-list/get $Entry address ]; :if ([ :typeof ($IPv4Addresses->$Address) ] = "time") do={ - $LogPrintExit2 debug $ScriptName ("Renewing IPv4 address for " . ($IPv4Addresses->$Address) . ": " . $Address) false; + $LogPrint debug $ScriptName ("Renewing IPv4 address for " . ($IPv4Addresses->$Address) . ": " . $Address); /ip/firewall/address-list/set $Entry timeout=($IPv4Addresses->$Address); :set ($IPv4Addresses->$Address); :set CntRenew ($CntRenew + 1); } else={ :if ($Failure = false) do={ - $LogPrintExit2 debug $ScriptName ("Removing IPv4 address: " . $Address) false; + $LogPrint debug $ScriptName ("Removing IPv4 address: " . $Address); /ip/firewall/address-list/remove $Entry; :set CntRemove ($CntRemove + 1); } @@ -119,13 +119,13 @@ :foreach Entry in=[ /ipv6/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={ :local Address [ /ipv6/firewall/address-list/get $Entry address ]; :if ([ :typeof ($IPv6Addresses->$Address) ] = "time") do={ - $LogPrintExit2 debug $ScriptName ("Renewing IPv6 address for " . ($IPv6Addresses->$Address) . ": " . $Address) false; + $LogPrint debug $ScriptName ("Renewing IPv6 address for " . ($IPv6Addresses->$Address) . ": " . $Address); /ipv6/firewall/address-list/set $Entry timeout=($IPv6Addresses->$Address); :set ($IPv6Addresses->$Address); :set CntRenew ($CntRenew + 1); } else={ :if ($Failure = false) do={ - $LogPrintExit2 debug $ScriptName ("Removing: " . $Address) false; + $LogPrint debug $ScriptName ("Removing: " . $Address); /ipv6/firewall/address-list/remove $Entry; :set CntRemove ($CntRemove + 1); } @@ -133,27 +133,27 @@ } :foreach Address,Timeout in=$IPv4Addresses do={ - $LogPrintExit2 debug $ScriptName ("Adding IPv4 address for " . $Timeout . ": " . $Address) false; + $LogPrint debug $ScriptName ("Adding IPv4 address for " . $Timeout . ": " . $Address); :do { /ip/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout; :set ($IPv4Addresses->$Address); :set CntAdd ($CntAdd + 1); } on-error={ - $LogPrintExit2 warning $ScriptName ("Failed to add IPv4 address " . $Address . " to list '" . $FwListName . "'.") false; + $LogPrint warning $ScriptName ("Failed to add IPv4 address " . $Address . " to list '" . $FwListName . "'."); } } :foreach Address,Timeout in=$IPv6Addresses do={ - $LogPrintExit2 debug $ScriptName ("Adding IPv6 address for " . $Timeout . ": " . $Address) false; + $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={ - $LogPrintExit2 warning $ScriptName ("Failed to add IPv6 address " . $Address . " to list '" . $FwListName . "'.") false; + $LogPrint warning $ScriptName ("Failed to add IPv6 address " . $Address . " to list '" . $FwListName . "'."); } } - $LogPrintExit2 info $ScriptName ("list: " . $FwListName . " -- added: " . $CntAdd . " - renewed: " . $CntRenew . " - removed: " . $CntRemove) false; + $LogPrint info $ScriptName ("list: " . $FwListName . " -- added: " . $CntAdd . " - renewed: " . $CntRenew . " - removed: " . $CntRemove); } } on-error={ } From 9dd1b768ee533545042b6e46fc9710bd39cc48d2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2076/2612] global-functions: switch to $LogPrint --- global-functions.rsc | 162 ++++++++++++++++++++++--------------------- 1 file changed, 82 insertions(+), 80 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 1220eca..d33e3e2 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -102,18 +102,18 @@ :local CommonName [ :tostr $1 ]; :global CertificateDownload; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :if ([ /system/resource/get free-hdd-space ] < 8388608 && \ [ /certificate/settings/get crl-download ] = true && \ [ /certificate/settings/get crl-store ] = "system") do={ - $LogPrintExit2 warning $0 ("This system has low free flash space but " . \ - "is configured to download certificate CRLs to system!") false; + $LogPrint warning $0 ("This system has low free flash space but " . \ + "is configured to download certificate CRLs to system!"); } :if ([ :len [ /certificate/find where common-name=$CommonName ] ] = 0) do={ - $LogPrintExit2 info $0 ("Certificate with CommonName \"" . $CommonName . "\" not available.") false; + $LogPrint info $0 ("Certificate with CommonName \"" . $CommonName . "\" not available."); :if ([ $CertificateDownload $CommonName ] = false) do={ :return false; } @@ -122,8 +122,8 @@ :local CertVal [ /certificate/get [ find where common-name=$CommonName ] ]; :while (($CertVal->"akid") != "" && ($CertVal->"akid") != ($CertVal->"skid")) do={ :if ([ :len [ /certificate/find where skid=($CertVal->"akid") ] ] = 0) do={ - $LogPrintExit2 info $0 ("Certificate chain for \"" . $CommonName . \ - "\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\".") false; + $LogPrint info $0 ("Certificate chain for \"" . $CommonName . \ + "\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\"."); :if ([ $CertificateDownload $CommonName ] = false) do={ :return false; } @@ -142,12 +142,12 @@ :global ScriptUpdatesUrlSuffix; :global CertificateNameByCN; - :global LogPrintExit2; + :global LogPrint; :global UrlEncode; :global WaitForFile; - $LogPrintExit2 info $0 ("Downloading and importing certificate with " . \ - "CommonName \"" . $CommonName . "\".") false; + $LogPrint info $0 ("Downloading and importing certificate with " . \ + "CommonName \"" . $CommonName . "\"."); :do { :local LocalFileName ($CommonName . ".pem"); :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); @@ -163,8 +163,7 @@ $CertificateNameByCN [ /certificate/get $Cert common-name ]; } } on-error={ - $LogPrintExit2 warning $0 ("Failed importing certificate with " . \ - "CommonName \"" . $CommonName . "\"!") false; + $LogPrint warning $0 ("Failed importing certificate with CommonName \"" . $CommonName . "\"!"); :return false; } :return true; @@ -309,7 +308,7 @@ :global CertificateAvailable; :global CleanFilePath; - :global LogPrintExit2; + :global LogPrint; :global MkDir; :global WaitForFile; @@ -324,23 +323,23 @@ :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; :if ([ $MkDir $PkgDir ] = false) do={ - $LogPrintExit2 warning $0 ("Failed creating directory, not downloading package.") false; + $LogPrint warning $0 ("Failed creating directory, not downloading package."); :return false; } :if ([ :len [ /file/find where name=$PkgDest type="package" ] ] > 0) do={ - $LogPrintExit2 info $0 ("Package file " . $PkgName . " already exists.") false; + $LogPrint info $0 ("Package file " . $PkgName . " already exists."); :return true; } :if ([ $CertificateAvailable "R3" ] = false) do={ - $LogPrintExit2 error $0 ("Downloading required certificate failed.") false; + $LogPrint error $0 ("Downloading required certificate failed."); :return false; } :local Url ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile); - $LogPrintExit2 info $0 ("Downloading package file '" . $PkgName . "'...") false; - $LogPrintExit2 debug $0 ("... from url: " . $Url) false; + $LogPrint info $0 ("Downloading package file '" . $PkgName . "'..."); + $LogPrint debug $0 ("... from url: " . $Url); :local Retry 3; :while ($Retry > 0) do={ :do { @@ -351,14 +350,14 @@ :return true; } } on-error={ - $LogPrintExit2 debug $0 ("Downloading package file failed.") false; + $LogPrint debug $0 ("Downloading package file failed."); } /file/remove [ find where name=$PkgDest ]; :set Retry ($Retry - 1); } - $LogPrintExit2 warning $0 ("Downloading package file '" . $PkgName . "' failed.") false; + $LogPrint warning $0 ("Downloading package file '" . $PkgName . "' failed."); :return false; } @@ -444,7 +443,7 @@ :global CertificateAvailable; :global IsMacLocallyAdministered; - :global LogPrintExit2; + :global LogPrint; :if ([ $IsMacLocallyAdministered $Mac ] = true) do={ :return "locally administered"; @@ -452,7 +451,8 @@ :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 \ ("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data"); @@ -461,9 +461,9 @@ :do { /tool/fetch check-certificate=yes-without-crl ("https://api.macvendors.com/") \ output=none as-value; - $LogPrintExit2 debug $0 ("The mac vendor is not known in database.") false; + $LogPrint debug $0 ("The mac vendor is not known in database."); } on-error={ - $LogPrintExit2 warning $0 ("Failed getting mac vendor.") false; + $LogPrint warning $0 ("Failed getting mac vendor."); } :return "unknown vendor"; } @@ -610,7 +610,7 @@ :global IsTimeSyncCached; :global IsTimeSyncResetNtp; - :global LogPrintExit2; + :global LogPrint; :if ($IsTimeSyncCached = true) do={ :return true; @@ -639,7 +639,7 @@ :if ([ /system/license/get ]->"level" = "free" || \ [ /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; } @@ -651,7 +651,7 @@ :return false; } - $LogPrintExit2 debug $0 ("No time source configured! Returning gracefully...") false; + $LogPrint debug $0 ("No time source configured! Returning gracefully..."); :return true; } @@ -717,7 +717,7 @@ :local Name [ :tostr $2 ]; :local Message [ :tostr $3 ]; - :global LogPrintExit2; + :global LogPrint; :global LogPrintOnceMessages; @@ -730,7 +730,7 @@ } :set ($LogPrintOnceMessages->$Message) 1; - $LogPrintExit2 $Severity $Name $Message false; + $LogPrint $Severity $Name $Message; } # get max value @@ -750,24 +750,24 @@ :local Path [ :tostr $1 ]; :global CleanFilePath; - :global LogPrintExit2; + :global LogPrint; :global WaitForFile; :local MkTmpfs do={ - :global LogPrintExit2; + :global LogPrint; :global WaitForFile; :if ([ :len [ /disk/find where slot=tmpfs type=tmpfs ] ] = 1) do={ :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" ]; :do { /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/get total-memory ] / 3); $WaitForFile "tmpfs"; } on-error={ - $LogPrintExit2 warning $0 ("Creating disk of type tmpfs failed!") false; + $LogPrint warning $0 ("Creating disk of type tmpfs failed!"); :return false; } :return true; @@ -795,7 +795,7 @@ $WaitForFile $File; /file/remove $File; } on-error={ - $LogPrintExit2 warning $0 ("Making directory '" . $Path . "' failed!") false; + $LogPrint warning $0 ("Making directory '" . $Path . "' failed!"); :return false; } @@ -926,18 +926,18 @@ :local Warn [ :tostr $3 ]; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global VersionToNum; :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; } :if ([ $VersionToNum $Required ] > [ $VersionToNum [ /system/package/update/get installed-version ] ]) do={ :if ($Warn = "true") do={ - $LogPrintExit2 warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = ("\$")) "function" "script" ] . \ - " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!") false; + $LogPrint warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = ("\$")) "function" "script" ] . \ + " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!"); } :return false; } @@ -948,7 +948,7 @@ :set ScriptFromTerminal do={ :local Script [ :tostr $1 ]; - :global LogPrintExit2; + :global LogPrint; :foreach Job in=[ /system/script/job/find where script=$Script ] do={ :set Job [ /system/script/job/get $Job ]; @@ -956,11 +956,11 @@ :set Job [ /system/script/job/get [ find where .id=($Job->"parent") ] ]; } :if (($Job->"type") = "login") do={ - $LogPrintExit2 debug $0 ("Script " . $Script . " started from terminal.") false; + $LogPrint debug $0 ("Script " . $Script . " started from terminal."); :return true; } } - $LogPrintExit2 debug $0 ("Script " . $Script . " NOT started from terminal.") false; + $LogPrint debug $0 ("Script " . $Script . " NOT started from terminal."); :return false; } @@ -982,7 +982,7 @@ :global EitherOr; :global Grep; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global LogPrintOnce; :global ParseKeyValueStore; :global RequiredRouterOS; @@ -991,12 +991,12 @@ :global ValidateSyntax; :if ([ $CertificateAvailable "E1" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; + $LogPrint warning $0 ("Downloading certificate failed, trying without."); } :foreach Script in=$Scripts do={ :if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={ - $LogPrintExit2 info $0 ("Adding new script: " . $Script) false; + $LogPrint info $0 ("Adding new script: " . $Script); /system/script/add name=$Script owner=$Script source="#!rsc by RouterOS\n" comment=$NewComment; } } @@ -1013,8 +1013,8 @@ :foreach Scheduler in=[ /system/scheduler/find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ :local SchedulerVal [ /system/scheduler/get $Scheduler ]; :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ - $LogPrintExit2 warning $0 ("Policies differ for script '" . $ScriptVal->"name" . \ - "' and its scheduler '" . $SchedulerVal->"name" . "'!") false; + $LogPrint warning $0 ("Policies differ for script '" . $ScriptVal->"name" . \ + "' and its scheduler '" . $SchedulerVal->"name" . "'!"); } } @@ -1023,7 +1023,7 @@ :local BaseUrl [ $EitherOr ($ScriptInfo->"base-url") $ScriptUpdatesBaseUrl ]; :local UrlSuffix [ $EitherOr ($ScriptInfo->"url-suffix") $ScriptUpdatesUrlSuffix ]; :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 \ http-header-field=({ $FetchUserAgent }) $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ @@ -1031,11 +1031,11 @@ } } on-error={ :if ($ScriptVal->"source" = "#!rsc by RouterOS\n") do={ - $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . \ - "', removing dummy. Typo on installation?") false; + $LogPrint warning $0 ("Failed fetching script '" . $ScriptVal->"name" . \ + "', removing dummy. Typo on installation?"); /system/script/remove $Script; } else={ - $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!") false; + $LogPrint warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!"); } } } @@ -1046,7 +1046,7 @@ :local Required ([ $ParseKeyValueStore [ $Grep $SourceNew ("\23 requires RouterOS, ") ] ]->"version"); :if ([ $RequiredRouterOS $0 [ $EitherOr $Required "0.0" ] false ] = 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; :if ($ScriptVal->"name" = "global-config") do={ :set ReloadGlobalConfig true; @@ -1055,48 +1055,48 @@ :set ReloadGlobalFunctions true; } } else={ - $LogPrintExit2 warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . \ - "' failed! Ignoring!") false; + $LogPrint warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . \ + "' failed! Ignoring!"); } } else={ $LogPrintOnce warning $0 ("The script '" . $ScriptVal->"name" . "' requires RouterOS " . \ $Required . ", which is not met by your installation. Ignoring!"); } } else={ - $LogPrintExit2 warning $0 ("Looks like new script '" . $ScriptVal->"name" . \ - "' is not valid (missing shebang). Ignoring!") false; + $LogPrint warning $0 ("Looks like new script '" . $ScriptVal->"name" . \ + "' is not valid (missing shebang). Ignoring!"); } } else={ - $LogPrintExit2 debug $0 ("Script '" . $ScriptVal->"name" . "' did not change.") false; + $LogPrint debug $0 ("Script '" . $ScriptVal->"name" . "' did not change."); } } else={ - $LogPrintExit2 debug $0 ("No update for script '" . $ScriptVal->"name" . "'.") false; + $LogPrint debug $0 ("No update for script '" . $ScriptVal->"name" . "'."); } } :if ($ReloadGlobalFunctions = true) do={ - $LogPrintExit2 info $0 ("Reloading global functions.") false; + $LogPrint info $0 ("Reloading global functions."); :do { /system/script/run global-functions; } on-error={ - $LogPrintExit2 error $0 ("Reloading global functions failed!") false; + $LogPrint error $0 ("Reloading global functions failed!"); } } :if ($ReloadGlobalConfig = true) do={ - $LogPrintExit2 info $0 ("Reloading global configuration.") false; + $LogPrint info $0 ("Reloading global configuration."); :do { /system/script/run global-config; } on-error={ - $LogPrintExit2 error $0 ("Reloading global configuration failed!" . \ - " Syntax error or missing overlay?") false; + $LogPrint error $0 ("Reloading global configuration failed!" . \ + " Syntax error or missing overlay?"); } } :if ($ExpectedConfigVersionBefore > $ExpectedConfigVersion) do={ - $LogPrintExit2 warning $0 ("The configuration version decreased from " . \ + $LogPrint warning $0 ("The configuration version decreased from " . \ $ExpectedConfigVersionBefore . " to " . $ExpectedConfigVersion . \ - ". Installed an older version?") false; + ". Installed an older version?"); } :if ($ExpectedConfigVersionBefore < $ExpectedConfigVersion) do={ @@ -1106,14 +1106,14 @@ :do { :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 \ http-header-field=({ $FetchUserAgent }) $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set ChangeLogCode ($Result->"data"); } } on-error={ - $LogPrintExit2 warning $0 ("Failed fetching news, changes and migration!") false; + $LogPrint warning $0 ("Failed fetching news, changes and migration!"); } :if ([ :len $ChangeLogCode ] > 0) do={ @@ -1121,10 +1121,10 @@ :do { [ :parse $ChangeLogCode ]; } on-error={ - $LogPrintExit2 warning $0 ("The changelog failed to run!") false; + $LogPrint warning $0 ("The changelog failed to run!"); } } else={ - $LogPrintExit2 warning $0 ("The changelog failed syntax validation!") false; + $LogPrint warning $0 ("The changelog failed syntax validation!"); } } @@ -1133,14 +1133,14 @@ :local Migration ($GlobalConfigMigration->[ :tostr $I ]); :if ([ :typeof $Migration ] = "str") do={ :if ([ $ValidateSyntax $Migration ] = true) do={ - $LogPrintExit2 info $0 ("Applying migration for change " . $I . ": " . $Migration) false; + $LogPrint info $0 ("Applying migration for change " . $I . ": " . $Migration); :do { [ :parse $Migration ]; } on-error={ - $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed to run!") false; + $LogPrint warning $0 ("Migration code for change " . $I . " failed to run!"); } } else={ - $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed syntax validation!") false; + $LogPrint warning $0 ("Migration code for change " . $I . " failed syntax validation!"); } } } @@ -1149,7 +1149,7 @@ :local NotificationMessage ("The configuration version on " . $Identity . " increased " . \ "to " . $ExpectedConfigVersion . ", current configuration may need modification. " . \ "Please review and update global-config-overlay, then re-run global-config."); - $LogPrintExit2 info $0 ($NotificationMessage) false; + $LogPrint info $0 ($NotificationMessage); :if ([ :len $GlobalConfigChanges ] > 0) do={ :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); @@ -1157,7 +1157,7 @@ :local Change ($GlobalConfigChanges->[ :tostr $I ]); :set NotificationMessage ($NotificationMessage . "\n " . \ [ $SymbolForNotification "pushpin" "*" ] . $Change); - $LogPrintExit2 info $0 ("Change " . $I . ": " . $Change) false; + $LogPrint info $0 ("Change " . $I . ": " . $Change); } } else={ :set NotificationMessage ($NotificationMessage . "\n\nNews and changes are not available."); @@ -1191,7 +1191,7 @@ :global GetRandom20CharAlNum; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global ScriptLockOrder; :if ([ :typeof $ScriptLockOrder ] = "nothing") do={ @@ -1277,15 +1277,17 @@ } :if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={ - $LogPrintExit2 error $0 ("A script named '" . $Script . "' does not exist!") true; + $LogPrint error $0 ("A script named '" . $Script . "' does not exist!"); + :error false; } :if ([ $JobCount $Script ] = 0) do={ - $LogPrintExit2 error $0 ("No script '" . $Script . "' is running!") true; + $LogPrint error $0 ("No script '" . $Script . "' is running!"); + :error false; } :if ([ $TicketCount $Script ] >= [ $JobCount $Script ]) do={ - $LogPrintExit2 error $0 ("More tickets than running scripts '" . $Script . "', resetting!") false; + $LogPrint error $0 ("More tickets than running scripts '" . $Script . "', resetting!"); :set ($ScriptLockOrder->$Script) ({}); /system/script/job/remove [ find where script=$Script ]; } @@ -1306,8 +1308,8 @@ } $RemoveTicket $Script $MyTicket; - $LogPrintExit2 info $0 ("Script '" . $Script . "' started more than once" . [ $IfThenElse ($WaitCount > 0) \ - " and timed out waiting for lock" "" ] . "...") false; + $LogPrint info $0 ("Script '" . $Script . "' started more than once" . [ $IfThenElse ($WaitCount > 0) \ + " and timed out waiting for lock" "" ] . "..."); :return false; } @@ -1542,10 +1544,10 @@ :do { /system/script/run $Script; } on-error={ - $LogPrintExit2 error $0 ("Module '" . $ScriptVal->"name" . "' failed to run.") false; + $LogPrint error $0 ("Module '" . $ScriptVal->"name" . "' failed to run."); } } else={ - $LogPrintExit2 error $0 ("Module '" . $ScriptVal->"name" . "' failed syntax validation, skipping.") false; + $LogPrint error $0 ("Module '" . $ScriptVal->"name" . "' failed syntax validation, skipping."); } } From 5c567604ff14700ee90701e2b21af07fde4bd0ce Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2077/2612] gps-track: switch to $LogPrint --- gps-track.rsc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gps-track.rsc b/gps-track.rsc index c40e2e0..1aeab84 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -17,7 +17,7 @@ :global GpsTrackUrl; :global Identity; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :global WaitFullyConnected; @@ -38,13 +38,13 @@ "\"lon\":\"" . ($Gps->"longitude") . "\"," . \ "\"identity\":\"" . $Identity . "\"" . \ "}") as-value; - $LogPrintExit2 debug $ScriptName ("Sending GPS data in " . $CoordinateFormat . " format: " . \ + $LogPrint debug $ScriptName ("Sending GPS data in " . $CoordinateFormat . " format: " . \ "lat: " . ($Gps->"latitude") . " " . \ - "lon: " . ($Gps->"longitude")) false; + "lon: " . ($Gps->"longitude")); } on-error={ - $LogPrintExit2 warning $ScriptName ("Failed sending GPS data!") false; + $LogPrint warning $ScriptName ("Failed sending GPS data!"); } } else={ - $LogPrintExit2 debug $ScriptName ("GPS data not valid.") false; + $LogPrint debug $ScriptName ("GPS data not valid."); } } on-error={ } From d93ffb9cb28843f95a970fdaae0d8296546cbb9d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2078/2612] hotspot-to-wpa-cleanup: switch to $LogPrint --- hotspot-to-wpa-cleanup.capsman.rsc | 14 +++++++------- hotspot-to-wpa-cleanup.template.rsc | 14 +++++++------- hotspot-to-wpa-cleanup.wifi.rsc | 14 +++++++------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index ba74260..0540ad5 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -18,7 +18,7 @@ :local ScriptName [ :jobname ]; :global EitherOr; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global ScriptLock; @@ -41,8 +41,8 @@ :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ mac-address=($ClientVal->"mac-address") ] do={ :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ - $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static.") false; + $LogPrint info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ + " connected to WPA, making lease static."); /ip/dhcp-server/lease/make-static $Lease; /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; } @@ -54,8 +54,8 @@ :local ClientVal [ /caps-man/access-list/get $Client ]; :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ mac-address=($ClientVal->"mac-address") ] ] = 0) do={ - $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ - " did not connect to WPA, removing from access list.") false; + $LogPrint info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ + " did not connect to WPA, removing from access list."); /caps-man/access-list/remove $Client; } } @@ -64,8 +64,8 @@ :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 ]; - $LogPrintExit2 info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; + $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; diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index c46d75d..6f3b3e1 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -19,7 +19,7 @@ :local ScriptName [ :jobname ]; :global EitherOr; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global ScriptLock; @@ -44,8 +44,8 @@ :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ mac-address=($ClientVal->"mac-address") ] do={ :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ - $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static.") false; + $LogPrint info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ + " connected to WPA, making lease static."); /ip/dhcp-server/lease/make-static $Lease; /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; } @@ -59,8 +59,8 @@ :local ClientVal [ /interface/wifi/access-list/get $Client ]; :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ mac-address=($ClientVal->"mac-address") ] ] = 0) do={ - $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ - " did not connect to WPA, removing from access list.") false; + $LogPrint info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ + " did not connect to WPA, removing from access list."); /caps-man/access-list/remove $Client; /interface/wifi/access-list/remove $Client; } @@ -70,8 +70,8 @@ :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 ]; - $LogPrintExit2 info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; + $LogPrint info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ + " was not seen for " . ($LeaseVal->"last-seen") . ", removing."); /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ mac-address=($LeaseVal->"mac-address") ]; diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index 3e5799a..9c79628 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -18,7 +18,7 @@ :local ScriptName [ :jobname ]; :global EitherOr; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global ScriptLock; @@ -41,8 +41,8 @@ :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ mac-address=($ClientVal->"mac-address") ] do={ :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ - $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static.") false; + $LogPrint info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ + " connected to WPA, making lease static."); /ip/dhcp-server/lease/make-static $Lease; /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; } @@ -54,8 +54,8 @@ :local ClientVal [ /interface/wifi/access-list/get $Client ]; :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ mac-address=($ClientVal->"mac-address") ] ] = 0) do={ - $LogPrintExit2 info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ - " did not connect to WPA, removing from access list.") false; + $LogPrint info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ + " did not connect to WPA, removing from access list."); /interface/wifi/access-list/remove $Client; } } @@ -64,8 +64,8 @@ :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 ]; - $LogPrintExit2 info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; + $LogPrint info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ + " was not seen for " . ($LeaseVal->"last-seen") . ", removing."); /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ mac-address=($LeaseVal->"mac-address") ]; /ip/dhcp-server/lease/remove $Lease; From 369af473743623fd89685cdfd8bf31b3430ed489 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2079/2612] hotspot-to-wpa: switch to $LogPrint --- hotspot-to-wpa.capsman.rsc | 15 ++++++++------- hotspot-to-wpa.template.rsc | 15 ++++++++------- hotspot-to-wpa.wifi.rsc | 15 ++++++++------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index a6ad2a1..37c8464 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -17,7 +17,7 @@ :local ScriptName [ :jobname ]; :global EitherOr; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global ScriptLock; @@ -29,7 +29,8 @@ } :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ - $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; + $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); + :error false; } :local Date [ /system/clock/get date ]; @@ -42,28 +43,28 @@ :if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; + $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'."); } :local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); :if ([ :len [ /caps-man/access-list/find where \ comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrintExit2 warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; + $LogPrint warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'."); } :local Template [ /caps-man/access-list/get ([ find where \ comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; :if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") false; + $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); :error true; } # allow login page to load :delay 1s; - $LogPrintExit2 info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ").") false; + $LogPrint info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ")."); /caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; /caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index b7869c4..cbce42a 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -18,7 +18,7 @@ :local ScriptName [ :jobname ]; :global EitherOr; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global ScriptLock; @@ -30,7 +30,8 @@ } :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ - $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; + $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); + :error false; } :local Date [ /system/clock/get date ]; @@ -45,7 +46,7 @@ :if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; + $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'."); } :local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); @@ -55,22 +56,22 @@ comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrintExit2 warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; + $LogPrint warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'."); } :local Template [ /caps-man/access-list/get ([ find where \ :local Template [ /interface/wifi/access-list/get ([ find where \ comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; :if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") false; + $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); :error true; } # allow login page to load :delay 1s; - $LogPrintExit2 info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ").") false; + $LogPrint info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ")."); /caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; /interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; /caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index e728d7f..86aeed7 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -17,7 +17,7 @@ :local ScriptName [ :jobname ]; :global EitherOr; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global ScriptLock; @@ -29,7 +29,8 @@ } :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ - $LogPrintExit2 error $ScriptName ("This script is supposed to run from hotspot on login.") true; + $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); + :error false; } :local Date [ /system/clock/get date ]; @@ -42,28 +43,28 @@ :if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrintExit2 warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; + $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'."); } :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); :if ([ :len [ /interface/wifi/access-list/find where \ comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrintExit2 warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; + $LogPrint warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'."); } :local Template [ /interface/wifi/access-list/get ([ find where \ comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; :if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'.") false; + $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); :error true; } # allow login page to load :delay 1s; - $LogPrintExit2 info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ").") false; + $LogPrint info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ")."); /interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; /interface/wifi/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ From 56e39123b92fa0c6f20ed47bcc870db6ab1a4cd1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2080/2612] ipsec-to-dns: switch to $LogPrint --- ipsec-to-dns.rsc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index 03abf59..dd40ca2 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -22,7 +22,7 @@ :global CharacterReplace; :global EscapeForRegEx; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -38,7 +38,7 @@ :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 $ScriptName ("Added disabled static dns record with name '" . $CommentString . "'.") false; + $LogPrint warning $ScriptName ("Added disabled static dns record with name '" . $CommentString . "'."); } :local PlaceBefore ([ /ip/dns/static/find where (name=$CommentString or (comment=$CommentString and name=-)) type=NXDOMAIN disabled ]->0); @@ -47,10 +47,10 @@ :local PeerId [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; :if ([ :len [ /ip/ipsec/active-peers/find where id~("^(CN=)?" . [ $EscapeForRegEx $PeerId ] . "\$") \ dynamic-address=($DnsRecordVal->"address") ] ] > 0) do={ - $LogPrintExit2 debug $ScriptName ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; + $LogPrint debug $ScriptName ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry."); } else={ :local Found false; - $LogPrintExit2 info $ScriptName ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") has gone, deleting DNS entry.") false; + $LogPrint info $ScriptName ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") has gone, deleting DNS entry."); /ip/dns/static/remove $DnsRecord; } } @@ -66,13 +66,13 @@ :if ([ :len $DnsRecord ] > 0) do={ :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; :if ($DnsIp = $PeerVal->"dynamic-address") do={ - $LogPrintExit2 debug $ScriptName ("DNS entry for " . $Fqdn . " does not need updating.") false; + $LogPrint debug $ScriptName ("DNS entry for " . $Fqdn . " does not need updating."); } else={ - $LogPrintExit2 info $ScriptName ("Replacing DNS entry for " . $Fqdn . ", new address is " . $PeerVal->"dynamic-address" . ".") false; + $LogPrint info $ScriptName ("Replacing DNS entry for " . $Fqdn . ", new address is " . $PeerVal->"dynamic-address" . "."); /ip/dns/static/set name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment $DnsRecord; } } else={ - $LogPrintExit2 info $ScriptName ("Adding new DNS entry for " . $Fqdn . ", address is " . $PeerVal->"dynamic-address" . ".") false; + $LogPrint info $ScriptName ("Adding new DNS entry for " . $Fqdn . ", address is " . $PeerVal->"dynamic-address" . "."); /ip/dns/static/add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } From 1f938efcaff3e4c67b5be25762c97dce75fa104c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2081/2612] ipv6-update: switch to $LogPrint --- ipv6-update.rsc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/ipv6-update.rsc b/ipv6-update.rsc index 8ce1e4d..65bb959 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -14,7 +14,7 @@ :do { :local ScriptName [ :jobname ]; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global ScriptLock; @@ -25,19 +25,20 @@ } :if ([ :typeof $PdPrefix ] = "nothing") do={ - $LogPrintExit2 error $ScriptName ("This script is supposed to run from ipv6 dhcp-client.") true; + $LogPrint error $ScriptName ("This script is supposed to run from ipv6 dhcp-client."); + :error false; } :local Pool [ /ipv6/pool/get [ find where prefix=$PdPrefix ] name ]; :if ([ :len [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={ /ipv6/firewall/address-list/add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool); - $LogPrintExit2 warning $ScriptName ("Added ipv6 address list entry for ipv6-pool-" . $Pool) false; + $LogPrint warning $ScriptName ("Added ipv6 address list entry for ipv6-pool-" . $Pool); } :local AddrList [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ]; :local OldPrefix [ /ipv6/firewall/address-list/get ($AddrList->0) address ]; :if ($OldPrefix != $PdPrefix) do={ - $LogPrintExit2 info $ScriptName ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix) false; + $LogPrint info $ScriptName ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix); /ipv6/firewall/address-list/set address=$PdPrefix $AddrList; # give the interfaces a moment to receive their addresses @@ -56,12 +57,12 @@ :local Address ($ListEntryVal->"address"); :local Address ($Prefix | ([ :toip6 [ :pick $Address 0 [ :find $Address "/128" ] ] ] & ::ffff:ffff:ffff:ffff)); - $LogPrintExit2 info $ScriptName ("Updating IPv6 address list with new IPv6 host address " . $Address . \ - " from interface " . ($Comment->"interface")) false; + $LogPrint info $ScriptName ("Updating IPv6 address list with new IPv6 host address " . $Address . \ + " from interface " . ($Comment->"interface")); /ipv6/firewall/address-list/set address=$Address $ListEntry; } else={ - $LogPrintExit2 info $ScriptName ("Updating IPv6 address list with new IPv6 prefix " . $Prefix . \ - " from interface " . ($Comment->"interface")) false; + $LogPrint info $ScriptName ("Updating IPv6 address list with new IPv6 prefix " . $Prefix . \ + " from interface " . ($Comment->"interface")); /ipv6/firewall/address-list/set address=$Prefix $ListEntry; } } @@ -77,8 +78,8 @@ :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); - $LogPrintExit2 info $ScriptName ("Updating DNS record for " . ($RecordVal->"name") . \ - ($RecordVal->"regexp") . " to " . $Address) false; + $LogPrint info $ScriptName ("Updating DNS record for " . ($RecordVal->"name") . \ + ($RecordVal->"regexp") . " to " . $Address); /ip/dns/static/set address=$Address $Record; } } From 29a72e54dce7ad5a65b46d5b403db1ccec3c9c3e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2082/2612] lease-script: switch to $LogPrint --- lease-script.rsc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lease-script.rsc b/lease-script.rsc index 0f6b7f8..8e1e8f6 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -16,7 +16,7 @@ :global Grep; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global ScriptLock; @@ -24,18 +24,19 @@ [ :typeof $leaseActMAC ] = "nothing" || \ [ :typeof $leaseServerName ] = "nothing" || \ [ :typeof $leaseBound ] = "nothing") do={ - $LogPrintExit2 error $ScriptName ("This script is supposed to run from ip dhcp-server.") true; + $LogPrint error $ScriptName ("This script is supposed to run from ip dhcp-server."); + :error false; } - $LogPrintExit2 debug $ScriptName ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \ - "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC) false; + $LogPrint debug $ScriptName ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \ + "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC); :if ([ $ScriptLock $ScriptName 10 ] = false) do={ :error false; } :if ([ :len [ /system/script/job/find where script=$ScriptName ] ] > 1) do={ - $LogPrintExit2 debug $ScriptName ("More invocations are waiting, exiting early.") false; + $LogPrint debug $ScriptName ("More invocations are waiting, exiting early."); :error true; } @@ -49,10 +50,10 @@ :foreach Order,Script in=$RunOrder do={ :do { - $LogPrintExit2 debug $ScriptName ("Running script with order " . $Order . ": " . $Script) false; + $LogPrint debug $ScriptName ("Running script with order " . $Order . ": " . $Script); /system/script/run $Script; } on-error={ - $LogPrintExit2 warning $ScriptName ("Running script '" . $Script . "' failed!") false; + $LogPrint warning $ScriptName ("Running script '" . $Script . "' failed!"); } } } on-error={ } From f8c79abd382a3859297f87071a0836d6d9480bdc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2083/2612] log-forward: switch to $LogPrint --- log-forward.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/log-forward.rsc b/log-forward.rsc index 09e3b84..a919d8f 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -26,7 +26,7 @@ :global HexToNum; :global IfThenElse; :global LogForwardFilterLogForwarding; - :global LogPrintExit2; + :global LogPrint; :global MAX; :global ScriptLock; :global SendNotification2; @@ -42,7 +42,7 @@ :if ($LogForwardRateLimit > 30) do={ :set LogForwardRateLimit ($LogForwardRateLimit - 1); - $LogPrintExit2 info $ScriptName ("Rate limit in action, not forwarding logs, if any!") false; + $LogPrint info $ScriptName ("Rate limit in action, not forwarding logs, if any!"); :error false; } From b7983d18c41d61746671a55ec2b9795eba8477bc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2084/2612] mod/bridge-port-to: switch to $LogPrint --- mod/bridge-port-to.rsc | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/mod/bridge-port-to.rsc b/mod/bridge-port-to.rsc index a78f31b..441094f 100644 --- a/mod/bridge-port-to.rsc +++ b/mod/bridge-port-to.rsc @@ -12,7 +12,7 @@ :local BridgePortTo [ :tostr $1 ]; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :local InterfaceReEnable ({}); @@ -24,21 +24,22 @@ :if ($BridgeDefault = "dhcp-client") do={ :if ([ :len $DHCPClient ] != 1) do={ - $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ - " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; + $LogPrint warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ + " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!"); + :error false; } :local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ]; :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ - $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; + $LogPrint info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client."); /interface/bridge/port/disable $BridgePort; :delay 200ms; /ip/dhcp-client/enable $DHCPClient; } } else={ :if ($BridgePortVal->"disabled" = true || $BridgeDefault != $BridgePortVal->"bridge") do={ - $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ - " bridge " . $BridgeDefault . ", disabling dhcp client.") false; + $LogPrint info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ + " bridge " . $BridgeDefault . ", disabling dhcp client."); :if ([ :len $DHCPClient ] = 1) do={ /ip/dhcp-client/disable $DHCPClient; :delay 200ms; @@ -50,8 +51,8 @@ } /interface/bridge/port/set disabled=no bridge=$BridgeDefault $BridgePort; } else={ - $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ - " bridge " . $BridgeDefault . ".") false; + $LogPrint debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ + " bridge " . $BridgeDefault . "."); } } } @@ -59,7 +60,7 @@ } :if ([ :len $InterfaceReEnable ] > 0) do={ :delay 5s; - $LogPrintExit2 info $0 ("Re-enabling interfaces...") false; + $LogPrint info $0 ("Re-enabling interfaces..."); /interface/ethernet/enable $InterfaceReEnable; } } From bdcf43a6f6644d0f88a1d38e4b28e90566d77d23 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2085/2612] mod/bridge-port-vlan: switch to $LogPrint --- mod/bridge-port-vlan.rsc | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/mod/bridge-port-vlan.rsc b/mod/bridge-port-vlan.rsc index 72cf772..522e9a6 100644 --- a/mod/bridge-port-vlan.rsc +++ b/mod/bridge-port-vlan.rsc @@ -12,7 +12,7 @@ :local ConfigTo [ :tostr $1 ]; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :local InterfaceReEnable ({}); @@ -24,13 +24,14 @@ :if ($Vlan = "dhcp-client") do={ :if ([ :len $DHCPClient ] != 1) do={ - $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ - " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; + $LogPrint warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ + " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!"); + :error false; } :local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ]; :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ - $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; + $LogPrint info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client."); /interface/bridge/port/disable $BridgePort; :delay 200ms; /ip/dhcp-client/enable $DHCPClient; @@ -41,12 +42,13 @@ :do { :set $Vlan ([ /interface/bridge/vlan/get [ find where comment=$Vlan ] vlan-ids ]->0); } on-error={ - $LogPrintExit2 warning $0 ("Could not find VLAN '" . $Vlan . "' for interface " . $BridgePortVal->"interface" . "!") true; + $LogPrint warning $0 ("Could not find VLAN '" . $Vlan . "' for interface " . $BridgePortVal->"interface" . "!"); + :error false; } } :if ($BridgePortVal->"disabled" = true || $Vlan != $BridgePortVal->"pvid") do={ - $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $ConfigTo . \ - " vlan " . $Vlan . [ $IfThenElse ($Vlan != $VlanName) (" (" . $VlanName . ")") ] . ", disabling dhcp client.") false; + $LogPrint info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $ConfigTo . \ + " vlan " . $Vlan . [ $IfThenElse ($Vlan != $VlanName) (" (" . $VlanName . ")") ] . ", disabling dhcp client."); :if ([ :len $DHCPClient ] = 1) do={ /ip/dhcp-client/disable $DHCPClient; :delay 200ms; @@ -58,8 +60,8 @@ } /interface/bridge/port/set disabled=no pvid=$Vlan $BridgePort; } else={ - $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \ - " vlan " . $Vlan . ".") false; + $LogPrint debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \ + " vlan " . $Vlan . "."); } } } @@ -67,7 +69,7 @@ } :if ([ :len $InterfaceReEnable ] > 0) do={ :delay 5s; - $LogPrintExit2 info $0 ("Re-enabling interfaces...") false; + $LogPrint info $0 ("Re-enabling interfaces..."); /interface/ethernet/enable $InterfaceReEnable; } } From 9b8d3f7970dbdddeb2a51db06f8358d8a195526d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2086/2612] mod/notification-email: switch to $LogPrint --- mod/notification-email.rsc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 88bfdac..78192f3 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -24,7 +24,7 @@ :global EitherOr; :global IsDNSResolving; :global IsTimeSync; - :global LogPrintExit2; + :global LogPrint; :local AllDone true; :local QueueLen [ :len $EmailQueue ]; @@ -35,23 +35,23 @@ } :if ([ /tool/e-mail/get last-status ] = "in-progress") do={ - $LogPrintExit2 debug $0 ("Sending mail is currently in progress, not flushing.") false; + $LogPrint debug $0 ("Sending mail is currently in progress, not flushing."); :return false; } :if ([ $IsTimeSync ] = false) do={ - $LogPrintExit2 debug $0 ("Time is not synced, not flushing.") false; + $LogPrint debug $0 ("Time is not synced, not flushing."); :return false; } :local EMailSettings [ /tool/e-mail/get ]; :if ([ :typeof [ :toip ($EMailSettings->"server") ] ] != "ip" && [ $IsDNSResolving ] = false) do={ - $LogPrintExit2 debug $0 ("Server address is a DNS name and resolving fails, not flushing.") false; + $LogPrint debug $0 ("Server address is a DNS name and resolving fails, not flushing."); :return false; } :if ([ :len $Scheduler ] > 0 && $QueueLen = 0) do={ - $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; + $LogPrint warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty."); } /system/scheduler/set interval=([ $EitherOr $QueueLen 1 ] . "m") comment="Sending..." $Scheduler; @@ -64,7 +64,7 @@ :if ([ :len [ /file/find where name=$File ] ] = 1) do={ :set Attach ($Attach, $File); } else={ - $LogPrintExit2 warning $0 ("File '" . $File . "' does not exist, can not attach.") false; + $LogPrint warning $0 ("File '" . $File . "' does not exist, can not attach."); } } /tool/e-mail/send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \ From 279993e965a934c6f4c2f30f4c97aa09ab03158e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2087/2612] mod/notification-matrix: switch to $LogPrint --- mod/notification-matrix.rsc | 41 +++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 8884b08..c4fe100 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -20,10 +20,10 @@ :global MatrixQueue; :global IsFullyConnected; - :global LogPrintExit2; + :global LogPrint; :if ([ $IsFullyConnected ] = false) do={ - $LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false; + $LogPrint debug $0 ("System is not fully connected, not flushing."); :return false; } @@ -31,7 +31,7 @@ :local QueueLen [ :len $MatrixQueue ]; :if ([ :len [ /system/scheduler/find where name="_FlushMatrixQueue" ] ] > 0 && $QueueLen = 0) do={ - $LogPrintExit2 warning $0 ("Flushing Matrix messages from scheduler, but queue is empty.") false; + $LogPrint warning $0 ("Flushing Matrix messages from scheduler, but queue is empty."); } :foreach Id,Message in=$MatrixQueue do={ @@ -45,7 +45,7 @@ $Message->"formatted" . "\" }") as-value; :set ($MatrixQueue->$Id); } on-error={ - $LogPrintExit2 debug $0 ("Sending queued Matrix message failed.") false; + $LogPrint debug $0 ("Sending queued Matrix message failed."); :set AllDone false; } } @@ -72,7 +72,7 @@ :global MatrixRoomOverride; :global EitherOr; - :global LogPrintExit2; + :global LogPrint; :global SymbolForNotification; :local PrepareText do={ @@ -134,7 +134,7 @@ "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ $Formatted . "\" }") as-value; } on-error={ - $LogPrintExit2 info $0 ("Failed sending Matrix notification! Queuing...") false; + $LogPrint info $0 ("Failed sending Matrix notification! Queuing..."); :if ([ :typeof $MatrixQueue ] = "nothing") do={ :set MatrixQueue ({}); @@ -184,7 +184,7 @@ :local Pass [ :tostr $2 ]; :global CharacterReplace; - :global LogPrintExit2; + :global LogPrint; :global ParseJson; :global MatrixAccessToken; @@ -195,9 +195,10 @@ :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ ("https://" . $Domain . "/.well-known/matrix/client") as-value ]->"data"); :set MatrixHomeServer ([ $ParseJson ([ $ParseJson [ $CharacterReplace $Data " " "" ] ]->"m.homeserver") ]->"base_url"); - $LogPrintExit2 debug $0 ("Home server is: " . $MatrixHomeServer) false; + $LogPrint debug $0 ("Home server is: " . $MatrixHomeServer); } on-error={ - $LogPrintExit2 error $0 ("Failed getting home server!") true; + $LogPrint error $0 ("Failed getting home server!"); + :error false; } :if ([ :pick $MatrixHomeServer 0 8 ] = "https://") do={ @@ -209,18 +210,20 @@ http-method=post http-data=("{\"type\":\"m.login.password\", \"user\":\"" . $User . "\", \"password\":\"" . $Pass . "\"}") \ ("https://" . $MatrixHomeServer . "/_matrix/client/r0/login") as-value ]->"data"); :set MatrixAccessToken ([ $ParseJson $Data ]->"access_token"); - $LogPrintExit2 debug $0 ("Access token is: " . $MatrixAccessToken) false; + $LogPrint debug $0 ("Access token is: " . $MatrixAccessToken); } on-error={ - $LogPrintExit2 error $0 ("Failed logging in (and getting access token)!") true; + $LogPrint error $0 ("Failed logging in (and getting access token)!"); + :error false; } :do { /system/script/set global-config-overlay source=([ get global-config-overlay source ] . "\n" . \ ":global MatrixHomeServer \"" . $MatrixHomeServer . "\";\n" . \ ":global MatrixAccessToken \"" . $MatrixAccessToken . "\";\n"); - $LogPrintExit2 info $0 ("Appended configuration to global-config-overlay. Now create and join a room, please!") false; + $LogPrint info $0 ("Appended configuration to global-config-overlay. Now create and join a room, please!"); } on-error={ - $LogPrintExit2 error $0 ("Failed appending configuration to global-config-overlay!") true; + $LogPrint error $0 ("Failed appending configuration to global-config-overlay!"); + :error false; } } @@ -228,7 +231,7 @@ :set SetupMatrixJoinRoom do={ :global MatrixRoom [ :tostr $1 ]; - :global LogPrintExit2; + :global LogPrint; :global UrlEncode; :global MatrixAccessToken; @@ -240,16 +243,18 @@ http-method=post http-data="" \ ("https://" . $MatrixHomeServer . "/_matrix/client/r0/rooms/" . [ $UrlEncode $MatrixRoom ] . \ "/join?access_token=" . [ $UrlEncode $MatrixAccessToken ]) as-value; - $LogPrintExit2 debug $0 ("Joined the room.") false; + $LogPrint debug $0 ("Joined the room."); } on-error={ - $LogPrintExit2 error $0 ("Failed joining the room!") true; + $LogPrint error $0 ("Failed joining the room!"); + :error false; } :do { /system/script/set global-config-overlay source=([ get global-config-overlay source ] . "\n" . \ ":global MatrixRoom \"" . $MatrixRoom . "\";\n"); - $LogPrintExit2 info $0 ("Appended configuration to global-config-overlay. Please review and cleanup!") false; + $LogPrint info $0 ("Appended configuration to global-config-overlay. Please review and cleanup!"); } on-error={ - $LogPrintExit2 error $0 ("Failed appending configuration to global-config-overlay!") true; + $LogPrint error $0 ("Failed appending configuration to global-config-overlay!"); + :error false; } } From fb88521ed5ba5012cec11824f19c92ded44c4ce1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2088/2612] mod/notification-ntfy: switch to $LogPrint --- mod/notification-ntfy.rsc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index 4dc6d84..6d48a59 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -18,10 +18,10 @@ :global NtfyMessageIDs; :global IsFullyConnected; - :global LogPrintExit2; + :global LogPrint; :if ([ $IsFullyConnected ] = false) do={ - $LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false; + $LogPrint debug $0 ("System is not fully connected, not flushing."); :return false; } @@ -29,7 +29,7 @@ :local QueueLen [ :len $NtfyQueue ]; :if ([ :len [ /system/scheduler/find where name="_FlushNtfyQueue" ] ] > 0 && $QueueLen = 0) do={ - $LogPrintExit2 warning $0 ("Flushing Ntfy messages from scheduler, but queue is empty.") false; + $LogPrint warning $0 ("Flushing Ntfy messages from scheduler, but queue is empty."); } :foreach Id,Message in=$NtfyQueue do={ @@ -39,7 +39,7 @@ ($Message->"url") http-header-field=($Message->"headers") http-data=($Message->"text") as-value; :set ($NtfyQueue->$Id); } on-error={ - $LogPrintExit2 debug $0 ("Sending queued Ntfy message failed.") false; + $LogPrint debug $0 ("Sending queued Ntfy message failed."); :set AllDone false; } } @@ -66,7 +66,7 @@ :global CertificateAvailable; :global EitherOr; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global SymbolForNotification; :global UrlEncode; @@ -88,13 +88,14 @@ :do { :if ($NtfyServer = "ntfy.sh") do={ :if ([ $CertificateAvailable "R3" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; + $LogPrint warning $0 ("Downloading required certificate failed."); + :error false; } } /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ $Url http-header-field=$Headers http-data=$Text as-value; } on-error={ - $LogPrintExit2 info $0 ("Failed sending ntfy notification! Queuing...") false; + $LogPrint info $0 ("Failed sending ntfy notification! Queuing..."); :if ([ :typeof $NtfyQueue ] = "nothing") do={ :set NtfyQueue ({}); From 699f09c2820abb156cf6ca4f45fe3a8285b11a81 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2089/2612] mod/notification-telegram: switch to $LogPrint --- mod/notification-telegram.rsc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 5b79135..506ec80 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -18,12 +18,12 @@ :global TelegramMessageIDs; :global IsFullyConnected; - :global LogPrintExit2; + :global LogPrint; :global ParseJson; :global UrlEncode; :if ([ $IsFullyConnected ] = false) do={ - $LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false; + $LogPrint debug $0 ("System is not fully connected, not flushing."); :return false; } @@ -31,7 +31,7 @@ :local QueueLen [ :len $TelegramQueue ]; :if ([ :len [ /system/scheduler/find where name="_FlushTelegramQueue" ] ] > 0 && $QueueLen = 0) do={ - $LogPrintExit2 warning $0 ("Flushing Telegram messages from scheduler, but queue is empty.") false; + $LogPrint warning $0 ("Flushing Telegram messages from scheduler, but queue is empty."); } :foreach Id,Message in=$TelegramQueue do={ @@ -45,7 +45,7 @@ :set ($TelegramQueue->$Id); :set ($TelegramMessageIDs->([ $ParseJson ([ $ParseJson $Data ]->"result") ]->"message_id")) 1; } on-error={ - $LogPrintExit2 debug $0 ("Sending queued Telegram message failed.") false; + $LogPrint debug $0 ("Sending queued Telegram message failed."); :set AllDone false; } } @@ -74,7 +74,7 @@ :global CharacterReplace; :global EitherOr; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global ParseJson; :global SymbolForNotification; :global UrlEncode; @@ -136,7 +136,8 @@ :do { :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; + $LogPrint warning $0 ("Downloading required certificate failed."); + :error false; } :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \ ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ @@ -145,7 +146,7 @@ "&parse_mode=MarkdownV2&text=" . [ $UrlEncode $Text ]) as-value ]->"data"); :set ($TelegramMessageIDs->([ $ParseJson ([ $ParseJson $Data ]->"result") ]->"message_id")) 1; } on-error={ - $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; + $LogPrint info $0 ("Failed sending telegram notification! Queuing..."); :if ([ :typeof $TelegramQueue ] = "nothing") do={ :set TelegramQueue ({}); From 8c62c31604d00bc12ddd548da4c8cbd46c0de383 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2090/2612] mod/scriptrunonce: switch to $LogPrint --- mod/scriptrunonce.rsc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index 38348a0..ffb1aff 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -15,13 +15,14 @@ :global ScriptRunOnceBaseUrl; :global ScriptRunOnceUrlSuffix; - :global LogPrintExit2; + :global LogPrint; :global ValidateSyntax; :foreach Script in=$Scripts do={ :if (!($Script ~ "^(ftp|https?|sftp)://")) do={ :if ([ :len $ScriptRunOnceBaseUrl ] = 0) do={ - $LogPrintExit2 warning $0 ("Script '" . $Script . "' is not an url and base url is not available.") true; + $LogPrint warning $0 ("Script '" . $Script . "' is not an url and base url is not available."); + :error false; } :set Script ($ScriptRunOnceBaseUrl . $Script . ".rsc" . $ScriptRunOnceUrlSuffix); } @@ -30,19 +31,19 @@ :do { :set Source ([ /tool/fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data"); } on-error={ - $LogPrintExit2 warning $0 ("Failed fetching script '" . $Script . "'!") false; + $LogPrint warning $0 ("Failed fetching script '" . $Script . "'!"); } :if ([ :len $Source ] > 0) do={ :if ([ $ValidateSyntax $Source ] = true) do={ :do { - $LogPrintExit2 info $0 ("Running script '" . $Script . "' now.") false; + $LogPrint info $0 ("Running script '" . $Script . "' now."); [ :parse $Source ]; } on-error={ - $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed to run!") false; + $LogPrint warning $0 ("The script '" . $Script . "' failed to run!"); } } else={ - $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed syntax validation!") false; + $LogPrint warning $0 ("The script '" . $Script . "' failed syntax validation!"); } } } From eedf092930992281700b591371cd2e960f1d9f0e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2091/2612] mod/ssh-keys-import: switch to $LogPrint --- mod/ssh-keys-import.rsc | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index b88ef9a..fbc667e 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -18,32 +18,36 @@ :global CharacterReplace; :global GetRandom20CharAlNum; - :global LogPrintExit2; + :global LogPrint; :global MkDir; :global WaitForFile; :if ([ :len $Key ] = 0 || [ :len $User ] = 0) do={ - $LogPrintExit2 warning $0 ("Missing argument(s), please pass key and user!") true; + $LogPrint warning $0 ("Missing argument(s), please pass key and user!"); + :error false; } :if ([ :len [ /user/find where name=$User ] ] = 0) do={ - $LogPrintExit2 warning $0 ("User '" . $User . "' does not exist.") true; + $LogPrint warning $0 ("User '" . $User . "' does not exist."); + :error false; } :local KeyVal [ :toarray [ $CharacterReplace $Key " " "," ] ]; :if (!($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa")) do={ - $LogPrintExit2 warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported.") true; + $LogPrint warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported."); + :error false; } :if ([ $MkDir "tmpfs/ssh-keys-import" ] = false) do={ - $LogPrintExit2 warning $0 ("Creating directory 'tmpfs/ssh-keys-import' failed!") true; + $LogPrint warning $0 ("Creating directory 'tmpfs/ssh-keys-import' failed!"); + :error false; } :local FingerPrintMD5 [ :convert from=base64 transform=md5 to=hex ($KeyVal->1) ]; :if ([ :len [ /user/ssh-keys/find where user=$User key-owner~("\\bmd5=" . $FingerPrintMD5 . "\\b") ] ] > 0) do={ - $LogPrintExit2 warning $0 ("The ssh public key (MD5:" . $FingerPrintMD5 . \ - ") is already available for user '" . $User . "'.") false; + $LogPrint warning $0 ("The ssh public key (MD5:" . $FingerPrintMD5 . \ + ") is already available for user '" . $User . "'."); :return false; } @@ -53,10 +57,11 @@ :do { /user/ssh-keys/import public-key-file=$FileName user=$User; - $LogPrintExit2 info $0 ("Imported ssh public key (" . $KeyVal->2 . ", " . $KeyVal->0 . ", " . \ - "MD5:" . $FingerPrintMD5 . ") for user '" . $User . "'.") false; + $LogPrint info $0 ("Imported ssh public key (" . $KeyVal->2 . ", " . $KeyVal->0 . ", " . \ + "MD5:" . $FingerPrintMD5 . ") for user '" . $User . "'."); } on-error={ - $LogPrintExit2 warning $0 ("Failed importing key.") true; + $LogPrint warning $0 ("Failed importing key."); + :error false; } } @@ -67,17 +72,19 @@ :global CharacterReplace; :global EitherOr; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global SSHKeysImport; :if ([ :len $FileName ] = 0 || [ :len $User ] = 0) do={ - $LogPrintExit2 warning $0 ("Missing argument(s), please pass file name and user!") true; + $LogPrint warning $0 ("Missing argument(s), please pass file name and user!"); + :error false; } :local File [ /file/find where name=$FileName ]; :if ([ :len $File ] = 0) do={ - $LogPrintExit2 warning $0 ("File '" . $FileName . "' does not exist.") true; + $LogPrint warning $0 ("File '" . $FileName . "' does not exist."); + :error false; } :local Keys ([ /file/get $FileName contents ] . "\n"); @@ -90,7 +97,7 @@ :do { $SSHKeysImport $Line $User; } on-error={ - $LogPrintExit2 warning $0 ("Failed importing key for user '" . $User . "'.") false; + $LogPrint warning $0 ("Failed importing key for user '" . $User . "'."); } :set Continue true; } @@ -99,7 +106,7 @@ :set Continue true; } :if ($Continue = false && [ :len ($KeyVal->0) ] > 0) do={ - $LogPrintExit2 warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported.") false; + $LogPrint warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported."); } } while=([ :len $Keys ] > 0); } From e3d55819eebfbdf1f752ec474adf28dc199ae989 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2092/2612] mode-button: switch to $LogPrint --- mode-button.rsc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mode-button.rsc b/mode-button.rsc index 07788cb..f453f11 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -16,18 +16,18 @@ :global ModeButton; - :global LogPrintExit2; + :global LogPrint; :set ($ModeButton->"count") ($ModeButton->"count" + 1); :local Scheduler [ /system/scheduler/find where name="_ModeButtonScheduler" ]; :if ([ :len $Scheduler ] = 0) do={ - $LogPrintExit2 info $ScriptName ("Creating scheduler _ModeButtonScheduler, counting presses...") false; + $LogPrint info $ScriptName ("Creating scheduler _ModeButtonScheduler, counting presses..."); :global ModeButtonScheduler do={ :global ModeButton; - :global LogPrintExit2; + :global LogPrint; :global ModeButtonScheduler; :global ValidateSyntax; @@ -52,7 +52,7 @@ :if ([ :len $Code ] > 0) do={ :if ([ $ValidateSyntax $Code ] = true) do={ - $LogPrintExit2 info $ScriptName ("Acting on " . $Count . " mode-button presses: " . $Code) false; + $LogPrint info $ScriptName ("Acting on " . $Count . " mode-button presses: " . $Code); :for I from=1 to=$Count do={ $LEDInvert; @@ -66,16 +66,16 @@ [ :parse $Code ]; } else={ - $LogPrintExit2 warning $ScriptName ("The code for " . $Count . " mode-button presses failed syntax validation!") false; + $LogPrint warning $ScriptName ("The code for " . $Count . " mode-button presses failed syntax validation!"); } } else={ - $LogPrintExit2 info $ScriptName ("No action defined for " . $Count . " mode-button presses.") false; + $LogPrint info $ScriptName ("No action defined for " . $Count . " mode-button presses."); } } /system/scheduler/add name="_ModeButtonScheduler" \ on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s; } else={ - $LogPrintExit2 debug $ScriptName ("Updating scheduler _ModeButtonScheduler...") false; + $LogPrint debug $ScriptName ("Updating scheduler _ModeButtonScheduler..."); /system/scheduler/set $Scheduler start-time=[ /system/clock/get time ]; } } on-error={ } From 8ea24540c4bd910717b33f93d07b1b60d3cd8bb6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2093/2612] netwatch-dns: switch to $LogPrint --- netwatch-dns.rsc | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 76f2685..50c2b4c 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -16,7 +16,7 @@ :global CertificateAvailable; :global EitherOr; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global ScriptLock; @@ -26,7 +26,7 @@ :local SettleTime (5m30s - [ /system/resource/get uptime ]); :if ($SettleTime > 0s) do={ - $LogPrintExit2 info $ScriptName ("System just booted, giving netwatch " . $SettleTime . " to settle.") false; + $LogPrint info $ScriptName ("System just booted, giving netwatch " . $SettleTime . " to settle."); :error true; } @@ -50,15 +50,14 @@ :if ([ :len $DnsServers ] > 0) do={ :if ($DnsServers != $DnsCurrent) do={ - $LogPrintExit2 info $ScriptName ("Updating DNS servers: " . [ :tostr $DnsServers ]) false; + $LogPrint info $ScriptName ("Updating DNS servers: " . [ :tostr $DnsServers ]); /ip/dns/set servers=$DnsServers; /ip/dns/cache/flush; } } else={ :if ([ :len $DnsFallback ] > 0) do={ :if ($DnsFallback != $DnsCurrent) do={ - $LogPrintExit2 info $ScriptName ("Updating DNS servers to fallback: " . \ - [ :tostr $DnsFallback ]) false; + $LogPrint info $ScriptName ("Updating DNS servers to fallback: " . [ :tostr $DnsFallback ]); /ip/dns/set servers=$DnsFallback; /ip/dns/cache/flush; } @@ -83,7 +82,7 @@ } :if ($DohCurrent = $HostInfo->"doh-url") do={ - $LogPrintExit2 debug $ScriptName ("Current DoH server is still up: " . $DohCurrent) false; + $LogPrint debug $ScriptName ("Current DoH server is still up: " . $DohCurrent); :error true; } @@ -92,7 +91,7 @@ } :if ([ :len $DohCurrent ] > 0) do={ - $LogPrintExit2 info $ScriptName ("Current DoH server is down, disabling: " . $DohCurrent) false; + $LogPrint info $ScriptName ("Current DoH server is down, disabling: " . $DohCurrent); /ip/dns/set use-doh-server=""; /ip/dns/cache/flush; } @@ -100,7 +99,7 @@ :foreach DohServer in=$DohServers do={ :if ([ :len ($DohServer->"doh-cert") ] > 0) do={ :if ([ $CertificateAvailable ($DohServer->"doh-cert") ] = false) do={ - $LogPrintExit2 warning $ScriptName ("Downloading certificate failed, trying without.") false; + $LogPrint warning $ScriptName ("Downloading certificate failed, trying without."); } } @@ -112,19 +111,19 @@ "\01\00" . "\00\01" . "\00\00" . "\00\00" . "\00\00" . "\09doh-check\05eworm\02de\00" . \ "\00\10" . "\00\01") ]) as-value ]->"data"); } on-error={ - $LogPrintExit2 warning $ScriptName ("Request to DoH server failed (network or certificate issue): " . \ - ($DohServer->"doh-url")) false; + $LogPrint warning $ScriptName ("Request to DoH server failed (network or certificate issue): " . \ + ($DohServer->"doh-url")); } :if ($Data != false) do={ :if ([ :typeof [ :find $Data "doh-check-OK" ] ] = "num") do={ /ip/dns/set use-doh-server=($DohServer->"doh-url") verify-doh-cert=yes; /ip/dns/cache/flush; - $LogPrintExit2 info $ScriptName ("Setting DoH server: " . ($DohServer->"doh-url")) false; + $LogPrint info $ScriptName ("Setting DoH server: " . ($DohServer->"doh-url")); :error true; } else={ - $LogPrintExit2 warning $ScriptName ("Received unexpected response from DoH server: " . \ - ($DohServer->"doh-url")) false; + $LogPrint warning $ScriptName ("Received unexpected response from DoH server: " . \ + ($DohServer->"doh-url")); } } } From 030105cc2ed46623b4628496cbd5665da245b0c9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2094/2612] netwatch-notify: switch to $LogPrint --- netwatch-notify.rsc | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 90d26f1..9536dd7 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -19,7 +19,7 @@ :global EitherOr; :global IfThenElse; :global IsDNSResolving; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global ScriptFromTerminal; :global ScriptLock; @@ -32,25 +32,22 @@ :local State [ :tostr $3 ]; :local Hook [ :tostr $4 ]; - :global LogPrintExit2; + :global LogPrint; :global ValidateSyntax; :if ([ $ValidateSyntax $Hook ] = true) do={ :do { [ :parse $Hook ]; } on-error={ - $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . \ - "' failed to run.") false; + $LogPrint warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . "' failed to run."); :return ("The hook failed to run."); } } else={ - $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . \ - "' failed syntax validation.") false; + $LogPrint warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . "' failed syntax validation."); :return ("The hook failed syntax validation."); } - $LogPrintExit2 info $0 ("Ran hook on " . $Type . " '" . $Name . "' " . $State . ": " . \ - $Hook) false; + $LogPrint info $0 ("Ran hook on " . $Type . " '" . $Name . "' " . $State . ": " . $Hook); :return ("Ran hook:\n" . $Hook); } @@ -106,10 +103,10 @@ :local Resolve [ :resolve ($HostInfo->"resolve") ]; :if ($Resolve != $HostVal->"host") do={ :if ([ $ResolveExpected ($HostInfo->"resolve") ($HostVal->"host") ] = false) do={ - $LogPrintExit2 info $ScriptName ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ + $LogPrint info $ScriptName ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ - ", updating.") false; + ", updating."); /tool/netwatch/set host=$Resolve $Host; :set ($Metric->"resolve-failcnt") 0; :set ($HostVal->"status") "unknown"; @@ -118,9 +115,9 @@ } on-error={ :set ($Metric->"resolve-failcnt") ($Metric->"resolve-failcnt" + 1); :if ($Metric->"resolve-failcnt" = 3) do={ - $LogPrintExit2 warning $ScriptName ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \ + $LogPrint warning $ScriptName ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \ ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ - $HostInfo->"name") "" ] . "' failed.") false; + $HostInfo->"name") "" ] . "' failed."); } } } @@ -129,8 +126,8 @@ :if ($HostVal->"status" = "up") do={ :local CountDown ($Metric->"count-down"); :if ($CountDown > 0) do={ - $LogPrintExit2 info $ScriptName \ - ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is up.") false; + $LogPrint info $ScriptName \ + ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is up."); :set ($Metric->"count-down") 0; } :set ($Metric->"count-up") ($Metric->"count-up" + 1); @@ -178,11 +175,11 @@ } :if ($Metric->"notified" = false || $Metric->"count-down" % 120 = 0 || \ $ScriptFromTerminalCached = true) do={ - $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $ScriptName \ + $LogPrint [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $ScriptName \ ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is down for " . \ $Metric->"count-down" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ ($Metric->"notified" = true) ("already notified.") ($CountDown - $Metric->"count-down" . \ - " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]) false; + " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]); } :if ((($CountDown * 2) - ($Metric->"count-down" * 3)) / 2 = 0 && \ [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ From ad65b62c1c0751fc3efee6221f4c32232f3302b9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2095/2612] ospf-to-leds: switch to $LogPrint --- ospf-to-leds.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc index 73c9922..a22e5a5 100644 --- a/ospf-to-leds.rsc +++ b/ospf-to-leds.rsc @@ -14,7 +14,7 @@ :do { :local ScriptName [ :jobname ]; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global ScriptLock; @@ -34,11 +34,11 @@ } :if ($NeighborCount > 0 && $LEDType = "off") do={ - $LogPrintExit2 info $ScriptName ("OSPF instance " . $InstanceVal->"name" . " has " . $NeighborCount . " neighbors, led on!") false; + $LogPrint info $ScriptName ("OSPF instance " . $InstanceVal->"name" . " has " . $NeighborCount . " neighbors, led on!"); /system/leds/set type=on [ find where leds=$LED ]; } :if ($NeighborCount = 0 && $LEDType = "on") do={ - $LogPrintExit2 info $ScriptName ("OSPF instance " . $InstanceVal->"name" . " has no neighbors, led off!") false; + $LogPrint info $ScriptName ("OSPF instance " . $InstanceVal->"name" . " has no neighbors, led off!"); /system/leds/set type=off [ find where leds=$LED ]; } } From 8444e5f2703a90ae0441281239505a670c24c152 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2096/2612] packages-update: switch to $LogPrint --- packages-update.rsc | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index 634b7bb..22ea501 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -16,7 +16,7 @@ :global DownloadPackage; :global Grep; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global ScriptFromTerminal; :global ScriptLock; @@ -29,7 +29,7 @@ :local ScriptName [ :tostr $1 ]; :global GetRandomNumber; - :global LogPrintExit2; + :global LogPrint; :global RebootForUpdate do={ /system/reboot; @@ -39,8 +39,8 @@ /system/scheduler/add name="_RebootForUpdate" start-time=$StartTime interval=1d \ on-event=("/system/scheduler/remove \"_RebootForUpdate\"; " . \ ":global RebootForUpdate; \$RebootForUpdate;"); - $LogPrintExit2 info $ScriptName ("Scheduled reboot for update at " . $StartTime . \ - " local time (" . [ /system/clock/get time-zone-name ] . ").") false; + $LogPrint info $ScriptName ("Scheduled reboot for update at " . $StartTime . \ + " local time (" . [ /system/clock/get time-zone-name ] . ")."); :return true; } @@ -51,11 +51,12 @@ :local Update [ /system/package/update/get ]; :if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ - $LogPrintExit2 warning $ScriptName ("Latest version is not known.") true; + $LogPrint warning $ScriptName ("Latest version is not known."); + :error false; } :if ($Update->"installed-version" = $Update->"latest-version") do={ - $LogPrintExit2 info $ScriptName ("Version " . $Update->"latest-version" . " is already installed.") false; + $LogPrint info $ScriptName ("Version " . $Update->"latest-version" . " is already installed."); :error true; } @@ -63,8 +64,9 @@ :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; :if ($NumInstalled < 0x070d0000 && $NumLatest > 0x070d0000) do={ - $LogPrintExit2 error $ScriptName ("Migration to wireless/wifi package in RouterOS " . \ - ($Update->"latest-version") . " is pending. Please update manually!") true; + $LogPrint error $ScriptName ("Migration to wireless/wifi package in RouterOS " . \ + ($Update->"latest-version") . " is pending. Please update manually!"); + :error false; } :local DoDowngrade false; @@ -77,14 +79,16 @@ :put "Canceled..."; } } else={ - $LogPrintExit2 warning $ScriptName ("Not installing downgrade automatically.") true; + $LogPrint warning $ScriptName ("Not installing downgrade automatically."); + :error false; } } :foreach Package in=[ /system/package/find where !bundle ] do={ :local PkgName [ /system/package/get $Package name ]; :if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ - $LogPrintExit2 error $ScriptName ("Download for package " . $PkgName . " failed, update aborted.") true; + $LogPrint error $ScriptName ("Download for package " . $PkgName . " failed, update aborted."); + :error false; } } @@ -99,29 +103,31 @@ :foreach Order,Script in=$RunOrder do={ :set PackagesUpdateBackupFailure false; :do { - $LogPrintExit2 info $ScriptName ("Running backup script " . $Script . " before update.") false; + $LogPrint info $ScriptName ("Running backup script " . $Script . " before update."); /system/script/run $Script; } on-error={ :set PackagesUpdateBackupFailure true; } :if ($PackagesUpdateBackupFailure = true) do={ - $LogPrintExit2 warning $ScriptName ("Running backup script " . $Script . " before update failed!") false; + $LogPrint warning $ScriptName ("Running backup script " . $Script . " before update failed!"); :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ :put "Do you want to continue anyway? [y/N]"; :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - $LogPrintExit2 info $ScriptName ("User requested to continue anyway.") false; + $LogPrint info $ScriptName ("User requested to continue anyway."); } else={ - $LogPrintExit2 info $ScriptName ("Canceled update...") true; + $LogPrint info $ScriptName ("Canceled update..."); + :error false; } } else={ - $LogPrintExit2 warning $ScriptName ("Canceled non-interactive update.") true; + $LogPrint warning $ScriptName ("Canceled non-interactive update."); + :error false; } } } :if ($DoDowngrade = true) do={ - $LogPrintExit2 info $ScriptName ("Rebooting for downgrade.") false; + $LogPrint info $ScriptName ("Rebooting for downgrade."); :delay 1s; /system/package/downgrade; } @@ -137,7 +143,7 @@ } } - $LogPrintExit2 info $ScriptName ("Rebooting for update.") false; + $LogPrint info $ScriptName ("Rebooting for update."); :delay 1s; /system/reboot; } on-error={ } From 88d4c0aff83fffad0952a44a6afbe888d1332c14 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2097/2612] ppp-on-up: switch to $LogPrint --- ppp-on-up.rsc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc index 0cc2405..61766c0 100644 --- a/ppp-on-up.rsc +++ b/ppp-on-up.rsc @@ -14,26 +14,27 @@ :do { :local ScriptName [ :jobname ]; - :global LogPrintExit2; + :global LogPrint; :local Interface $interface; :if ([ :typeof $Interface ] = "nothing") do={ - $LogPrintExit2 error $ScriptName ("This script is supposed to run from ppp on-up script hook.") true; + $LogPrint error $ScriptName ("This script is supposed to run from ppp on-up script hook."); + :error false; } :local IntName [ /interface/get $Interface name ]; - $LogPrintExit2 info $ScriptName ("PPP interface " . $IntName . " is up.") false; + $LogPrint info $ScriptName ("PPP interface " . $IntName . " is up."); /ipv6/dhcp-client/release [ find where interface=$IntName !disabled ]; :foreach Script in=[ /system/script/find where source~("\n# provides: ppp-on-up\n") ] do={ :local ScriptName [ /system/script/get $Script name ]; :do { - $LogPrintExit2 debug $ScriptName ("Running script: " . $ScriptName) false; + $LogPrint debug $ScriptName ("Running script: " . $ScriptName); /system/script/run $Script; } on-error={ - $LogPrintExit2 warning $ScriptName ("Running script '" . $ScriptName . "' failed!") false; + $LogPrint warning $ScriptName ("Running script '" . $ScriptName . "' failed!"); } } } on-error={ } From 5a487d15c2ba464df46b82eceffac622d1f21604 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2098/2612] sms-action: switch to $LogPrint --- sms-action.rsc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sms-action.rsc b/sms-action.rsc index 11d3523..4c37565 100644 --- a/sms-action.rsc +++ b/sms-action.rsc @@ -16,13 +16,14 @@ :global SmsAction; - :global LogPrintExit2; + :global LogPrint; :global ValidateSyntax; :local Action $action; :if ([ :typeof $Action ] = "nothing") do={ - $LogPrintExit2 error $ScriptName ("This script is supposed to run from SMS hook with action=...") true; + $LogPrint error $ScriptName ("This script is supposed to run from SMS hook with action=..."); + :error false; } :local Code ($SmsAction->$Action); @@ -31,6 +32,6 @@ :delay 1s; [ :parse $Code ]; } else={ - $LogPrintExit2 warning $ScriptName ("The code for action '" . $Action . "' failed syntax validation!") false; + $LogPrint warning $ScriptName ("The code for action '" . $Action . "' failed syntax validation!"); } } on-error={ } From be1aeccbe520be193906e24de7c2fa82af5970dd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2099/2612] sms-forward: switch to $LogPrint --- sms-forward.rsc | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/sms-forward.rsc b/sms-forward.rsc index c745b81..b0966c3 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -19,7 +19,7 @@ :global SmsForwardHooks; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global LogPrintOnce; :global ScriptLock; :global SendNotification2; @@ -41,7 +41,7 @@ :local Settings [ /tool/sms/get ]; :if ([ /interface/lte/get ($Settings->"port") running ] != true) do={ - $LogPrintExit2 info $ScriptName ("The LTE interface is not in running state, skipping.") false; + $LogPrint info $ScriptName ("The LTE interface is not in running state, skipping."); :error true; } @@ -56,7 +56,7 @@ :if ($Phone = $Settings->"allowed-number" && \ ($SmsVal->"message")~("^:cmd " . $Settings->"secret" . " script ")) do={ - $LogPrintExit2 debug $ScriptName ("Removing SMS, which started a script.") false; + $LogPrint debug $ScriptName ("Removing SMS, which started a script."); /tool/sms/inbox/remove $Sms; } else={ :set Messages ($Messages . "\n\nOn " . $SmsVal->"timestamp" . \ @@ -64,20 +64,16 @@ :foreach Hook in=$SmsForwardHooks do={ :if ($Phone~($Hook->"allowed-number") && ($SmsVal->"message")~($Hook->"match")) do={ :if ([ $ValidateSyntax ($Hook->"command") ] = true) do={ - $LogPrintExit2 info $ScriptName ("Running hook '" . $Hook->"match" . "': " . \ - $Hook->"command") false; + $LogPrint info $ScriptName ("Running hook '" . $Hook->"match" . "': " . $Hook->"command"); :do { :local Command [ :parse ($Hook->"command") ]; $Command Phone=$Phone Message=($SmsVal->"message"); - :set Messages ($Messages . "\n\nRan hook '" . $Hook->"match" . "':\n" . \ - $Hook->"command"); + :set Messages ($Messages . "\n\nRan hook '" . $Hook->"match" . "':\n" . $Hook->"command"); } on-error={ - $LogPrintExit2 warning $ScriptName ("The code for hook '" . $Hook->"match" . \ - "' failed to run!") false; + $LogPrint warning $ScriptName ("The code for hook '" . $Hook->"match" . "' failed to run!"); } } else={ - $LogPrintExit2 warning $ScriptName ("The code for hook '" . $Hook->"match" . \ - "' failed syntax validation!") false; + $LogPrint warning $ScriptName ("The code for hook '" . $Hook->"match" . "' failed syntax validation!"); } } } From 19fb5c5801a0769e3b94123b8b28aca14f0e73d9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2100/2612] telegram-chat: switch to $LogPrint --- telegram-chat.rsc | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 799569f..c81b714 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -30,7 +30,7 @@ :global EscapeForRegEx; :global GetRandom20CharAlNum; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global MAX; :global MIN; :global MkDir; @@ -57,7 +57,8 @@ } :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ - $LogPrintExit2 warning $ScriptName ("Downloading required certificate failed.") true; + $LogPrint warning $ScriptName ("Downloading required certificate failed."); + :error false; } $RandomDelay $TelegramRandomDelay; @@ -72,7 +73,7 @@ :set TelegramRandomDelay [ $MAX 0 ($TelegramRandomDelay - 1) ]; } on-error={ :if ($I < 4) do={ - $LogPrintExit2 debug $ScriptName ("Fetch failed, " . $I . ". try.") false; + $LogPrint debug $ScriptName ("Fetch failed, " . $I . ". try."); :set TelegramRandomDelay [ $MIN 15 ($TelegramRandomDelay + 5) ]; :delay (($I * $I) . "s"); } @@ -81,7 +82,8 @@ } :if ($Data = false) do={ - $LogPrintExit2 warning $ScriptName ("Failed getting updates from Telegram.") true; + $LogPrint warning $ScriptName ("Failed getting updates from Telegram."); + :error false; } :local UpdateID 0; @@ -106,7 +108,7 @@ :if ($Trusted = true) do={ :local Done false; :if ($Message->"text" = "?") do={ - $LogPrintExit2 info $ScriptName ("Sending notice for update " . $UpdateID . ".") false; + $LogPrint info $ScriptName ("Sending notice for update " . $UpdateID . "."); $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Online, awaiting your commands!") }); @@ -118,8 +120,8 @@ } else={ :set TelegramChatActive false; } - $LogPrintExit2 info $ScriptName ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . \ - " from update " . $UpdateID . "!") false; + $LogPrint info $ScriptName ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . \ + " from update " . $UpdateID . "!"); :set Done true; } :if ($Done = false && ($IsMyReply = 1 || ($IsReply = 0 && $TelegramChatActive = true)) && [ :len ($Message->"text") ] > 0) do={ @@ -127,9 +129,10 @@ :local State ""; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); :if ([ $MkDir "tmpfs/telegram-chat" ] = false) do={ - $LogPrintExit2 error $ScriptName ("Failed creating directory!") true; + $LogPrint error $ScriptName ("Failed creating directory!"); + :error false; } - $LogPrintExit2 info $ScriptName ("Running command from update " . $UpdateID . ": " . $Message->"text") false; + $LogPrint info $ScriptName ("Running command from update " . $UpdateID . ": " . $Message->"text"); :execute script=(":do {\n" . $Message->"text" . "\n} on-error={ /file/add name=\"" . $File . ".failed\" };" . \ "/file/add name=\"" . $File . ".done\"") file=($File . "\00"); :if ([ $WaitForFile ($File . ".done") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ @@ -146,7 +149,7 @@ ("Output exceeds file read size.") ("No output.") ] ]) }); /file/remove "tmpfs/telegram-chat"; } else={ - $LogPrintExit2 info $ScriptName ("The command from update " . $UpdateID . " failed syntax validation!") false; + $LogPrint info $ScriptName ("The command from update " . $UpdateID . " failed syntax validation!"); $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Command:\n" . $Message->"text" . "\n\nThe command failed syntax validation!") }); @@ -157,16 +160,16 @@ [ $IfThenElse ([ :len ($From->"username") ] = 0) "without username" ("'" . $From->"username" . "'") ] . \ " (ID " . $From->"id" . ") in update " . $UpdateID . "!"); :if ($Message->"text" ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ - $LogPrintExit2 warning $ScriptName $MessageText false; + $LogPrint warning $ScriptName $MessageText; $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("You are not trusted.") }); } else={ - $LogPrintExit2 info $ScriptName $MessageText false; + $LogPrint info $ScriptName $MessageText; } } } else={ - $LogPrintExit2 debug $ScriptName ("Already handled update " . $UpdateID . ".") false; + $LogPrint debug $ScriptName ("Already handled update " . $UpdateID . "."); } } :set TelegramChatOffset ([ :pick $TelegramChatOffset 1 3 ], \ From 1c6154728411e206d651ad05fce093a80168f64f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 12 Mar 2024 10:34:26 +0100 Subject: [PATCH 2101/2612] global-config: merge loading overlay and snippets --- global-config.rsc | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/global-config.rsc b/global-config.rsc index 85731c3..2b688bc 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -243,20 +243,14 @@ "cert2-cn"="4n0th3r-s3cr3t"; }; -# load custom settings from overlay +# load custom settings from overlay and snippets # Warning: Do *NOT* copy this code to overlay! -:do { - /system/script/run global-config-overlay; -} on-error={ - :log error ("Loading configuration from overlay failed!"); -} - -# configuration overlay snippets -:foreach Script in=[ /system/script/find where name ~ "^global-config-overlay.d/" ] do={ +:foreach Script in=([ /system/script/find where name="global-config-overlay" ], \ + [ /system/script/find where name~"^global-config-overlay.d/" ]) do={ :do { /system/script/run $Script; } on-error={ - :log error ("Loading configuration from overlay snippet " . \ + :log error ("Loading configuration from overlay or snippet " . \ [ /system/script/get $Script name ] . " failed!"); } } From 9a21f4d3e3bf1ba0abe565058f7f8688024b68a2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2102/2612] update-gre-address: switch to $LogPrint --- update-gre-address.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/update-gre-address.rsc b/update-gre-address.rsc index 78705c5..74967cd 100644 --- a/update-gre-address.rsc +++ b/update-gre-address.rsc @@ -16,7 +16,7 @@ :local ScriptName [ :jobname ]; :global CharacterReplace; - :global LogPrintExit2; + :global LogPrint; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -33,7 +33,7 @@ :if ([ :typeof ($PeerVal->"dynamic-address") ] = "str" && \ ($PeerVal->"dynamic-address" != $GreIntVal->"remote-address" || \ $GreIntVal->"disabled" = true)) do={ - $LogPrintExit2 info $ScriptName ("Updating remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address") false; + $LogPrint info $ScriptName ("Updating remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address"); /interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$PeerVal->"dynamic-address" name!=$GreIntVal->"name" ]; /interface/gre/set $GreInt remote-address=($PeerVal->"dynamic-address") disabled=no; } From 76f65c13d77759321f128035bd1ce4aa9b2cec46 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 12 Mar 2024 15:59:41 +0100 Subject: [PATCH 2103/2612] global-functions: add architecture in user-agent string --- global-functions.rsc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index d2386f4..1c2523a 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -16,7 +16,12 @@ # global variables not to be changed by user :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 functions From 242ecef012f5208b6fa088a1222d0d5477e5b2ed Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 12:45:38 +0100 Subject: [PATCH 2104/2612] update-tunnelbroker: switch to $LogPrint --- update-tunnelbroker.rsc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index 9f316e3..c76b7ec 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -17,7 +17,7 @@ :local ScriptName [ :jobname ]; :global CertificateAvailable; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :global ScriptLock; @@ -26,7 +26,8 @@ } :if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ - $LogPrintExit2 error $ScriptName ("Downloading required certificate failed.") true; + $LogPrint error $ScriptName ("Downloading required certificate failed."); + :error false; } :foreach Interface in=[ /interface/6to4/find where comment~"^tunnelbroker" !disabled ] do={ @@ -41,24 +42,25 @@ ("https://ipv4.tunnelbroker.net/nic/update?hostname=" . $Comment->"id") \ user=($Comment->"user") password=($Comment->"pass") output=user as-value ]->"data"); } on-error={ - $LogPrintExit2 debug $ScriptName ("Failed downloading, " . $I . " retries pending.") false; + $LogPrint debug $ScriptName ("Failed downloading, " . $I . " retries pending."); :delay 2s; } } } :if (!($Data ~ "^(good|nochg) ")) do={ - $LogPrintExit2 error $ScriptName ("Failed sending the local address to tunnelbroker or unexpected response!") true; + $LogPrint error $ScriptName ("Failed sending the local address to tunnelbroker or unexpected response!"); + :error false; } :local PublicAddress [ :pick $Data ([ :find $Data " " ] + 1) [ :find $Data "\n" ] ]; :if ($PublicAddress != $InterfaceVal->"local-address") do={ :if ([ :len [ /ip/address find where address~("^" . $PublicAddress . "/") ] ] < 1) do={ - $LogPrintExit2 warning $ScriptName ("The address " . $PublicAddress . " is not configured on your device. NAT by ISP?") false; + $LogPrint warning $ScriptName ("The address " . $PublicAddress . " is not configured on your device. NAT by ISP?"); } - $LogPrintExit2 info $ScriptName ("Local address changed, updating tunnel configuration with address: " . $PublicAddress) false; + $LogPrint info $ScriptName ("Local address changed, updating tunnel configuration with address: " . $PublicAddress); /interface/6to4/set $Interface local-address=$PublicAddress; } } From 19802c0b6977f9467fada4ace3cab017dd98964b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 11:09:22 +0100 Subject: [PATCH 2105/2612] global-functions: $LogPrintOnce: drop support for exit This is not widely adopted or used, so let's just drop it - no compatibility. --- dhcp-to-dns.rsc | 4 ++-- fw-addr-lists.rsc | 2 +- global-functions.rsc | 9 ++++----- sms-forward.rsc | 3 ++- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 84a1e84..d0638c7 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -61,7 +61,7 @@ :do { :set LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; :if ([ :len [ /ip/dhcp-server/lease/find where active-mac-address=($LeaseVal->"active-mac-address") status=bound ] ] > 1) do={ - $LogPrintOnce info $ScriptName ("Multiple bound leases found for mac-address " . ($LeaseVal->"active-mac-address") . "!") false; + $LogPrintOnce info $ScriptName ("Multiple bound leases found for mac-address " . ($LeaseVal->"active-mac-address") . "!"); } } on-error={ $LogPrintExit2 debug $ScriptName ("A lease just vanished, ignoring.") false; @@ -117,7 +117,7 @@ } :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!") false; + $LogPrintOnce warning $ScriptName ("The name '" . $FullA . "' appeared in more than one A record!"); } } else={ $LogPrintExit2 debug $ScriptName ("No address available... Ignoring.") false; diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 6071f7b..4ec4105 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -82,7 +82,7 @@ } :if ([ :len $Data ] > 63000) do={ - $LogPrintOnce warning $ScriptName ("The list is huge and may be truncated: " . $List->"url") false; + $LogPrintOnce warning $ScriptName ("The list is huge and may be truncated: " . $List->"url"); } :while ([ :len $Data ] != 0) do={ diff --git a/global-functions.rsc b/global-functions.rsc index 1c2523a..aca4cd8 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -703,7 +703,6 @@ :local Severity [ :tostr $1 ]; :local Name [ :tostr $2 ]; :local Message [ :tostr $3 ]; - :local Exit [ :tostr $4 ]; :global LogPrintExit2; @@ -718,7 +717,7 @@ } :set ($LogPrintOnceMessages->$Message) 1; - $LogPrintExit2 $Severity $Name $Message $Exit; + $LogPrintExit2 $Severity $Name $Message false; } # get max value @@ -1048,7 +1047,7 @@ } } else={ $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={ $LogPrintExit2 warning $0 ("Looks like new script '" . $ScriptVal->"name" . \ @@ -1359,7 +1358,7 @@ } :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 ""; } @@ -1540,7 +1539,7 @@ # Log success :local Resource [ /system/resource/get ]; $LogPrintOnce info $ScriptName ("Loaded on " . $Resource->"board-name" . \ - " with RouterOS " . $Resource->"version" . ".") false; + " with RouterOS " . $Resource->"version" . "."); # signal we are ready :set GlobalFunctionsReady true; diff --git a/sms-forward.rsc b/sms-forward.rsc index 2f549b1..c745b81 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -32,7 +32,8 @@ } :if ([ /tool/sms/get receive-enabled ] = false) do={ - $LogPrintOnce warning $ScriptName ("Receiving of SMS is not enabled.") true; + $LogPrintOnce warning $ScriptName ("Receiving of SMS is not enabled."); + :error false; } $WaitFullyConnected; From 39dd1f2a63bc8477bf444111189a7ecead77a667 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 17:50:28 +0100 Subject: [PATCH 2106/2612] mod/bridge-port-to: do not exit with error --- mod/bridge-port-to.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/bridge-port-to.rsc b/mod/bridge-port-to.rsc index 441094f..567a762 100644 --- a/mod/bridge-port-to.rsc +++ b/mod/bridge-port-to.rsc @@ -26,7 +26,7 @@ :if ([ :len $DHCPClient ] != 1) do={ $LogPrint warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!"); - :error false; + :return false; } :local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ]; From 525e4325daadb94757c8632c1c07391d986c9e0e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 17:51:22 +0100 Subject: [PATCH 2107/2612] mod/bridge-port-vlan: do not exit with error --- mod/bridge-port-vlan.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/bridge-port-vlan.rsc b/mod/bridge-port-vlan.rsc index 522e9a6..aee5ef9 100644 --- a/mod/bridge-port-vlan.rsc +++ b/mod/bridge-port-vlan.rsc @@ -26,7 +26,7 @@ :if ([ :len $DHCPClient ] != 1) do={ $LogPrint warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!"); - :error false; + :return false; } :local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ]; @@ -43,7 +43,7 @@ :set $Vlan ([ /interface/bridge/vlan/get [ find where comment=$Vlan ] vlan-ids ]->0); } on-error={ $LogPrint warning $0 ("Could not find VLAN '" . $Vlan . "' for interface " . $BridgePortVal->"interface" . "!"); - :error false; + :return false; } } :if ($BridgePortVal->"disabled" = true || $Vlan != $BridgePortVal->"pvid") do={ From c2dc8a0837cd848512a8587f406f9dadd31b957c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 17:53:48 +0100 Subject: [PATCH 2108/2612] mod/notification-matrix: do not exit with error --- mod/notification-matrix.rsc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index c4fe100..aa95841 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -198,7 +198,7 @@ $LogPrint debug $0 ("Home server is: " . $MatrixHomeServer); } on-error={ $LogPrint error $0 ("Failed getting home server!"); - :error false; + :return false; } :if ([ :pick $MatrixHomeServer 0 8 ] = "https://") do={ @@ -213,7 +213,7 @@ $LogPrint debug $0 ("Access token is: " . $MatrixAccessToken); } on-error={ $LogPrint error $0 ("Failed logging in (and getting access token)!"); - :error false; + :return false; } :do { @@ -223,7 +223,7 @@ $LogPrint info $0 ("Appended configuration to global-config-overlay. Now create and join a room, please!"); } on-error={ $LogPrint error $0 ("Failed appending configuration to global-config-overlay!"); - :error false; + :return false; } } @@ -246,7 +246,7 @@ $LogPrint debug $0 ("Joined the room."); } on-error={ $LogPrint error $0 ("Failed joining the room!"); - :error false; + :return false; } :do { @@ -255,6 +255,6 @@ $LogPrint info $0 ("Appended configuration to global-config-overlay. Please review and cleanup!"); } on-error={ $LogPrint error $0 ("Failed appending configuration to global-config-overlay!"); - :error false; + :return false; } } From 0e2e7efdb223baa10d06b9f0d917fbe507264307 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 17:52:07 +0100 Subject: [PATCH 2109/2612] mod/scriptrunonce: do not exit with error --- mod/scriptrunonce.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index ffb1aff..85d465a 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -22,7 +22,7 @@ :if (!($Script ~ "^(ftp|https?|sftp)://")) do={ :if ([ :len $ScriptRunOnceBaseUrl ] = 0) do={ $LogPrint warning $0 ("Script '" . $Script . "' is not an url and base url is not available."); - :error false; + :return false; } :set Script ($ScriptRunOnceBaseUrl . $Script . ".rsc" . $ScriptRunOnceUrlSuffix); } From b829ec1fc9091fe8add28d56c81da64c7aa9be3a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Mar 2024 17:47:56 +0100 Subject: [PATCH 2110/2612] mod/ssh-keys-import: do not exit with error --- mod/ssh-keys-import.rsc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index fbc667e..6716958 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -24,23 +24,23 @@ :if ([ :len $Key ] = 0 || [ :len $User ] = 0) do={ $LogPrint warning $0 ("Missing argument(s), please pass key and user!"); - :error false; + :return false; } :if ([ :len [ /user/find where name=$User ] ] = 0) do={ $LogPrint warning $0 ("User '" . $User . "' does not exist."); - :error false; + :return false; } :local KeyVal [ :toarray [ $CharacterReplace $Key " " "," ] ]; :if (!($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa")) do={ $LogPrint warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported."); - :error false; + :return false; } :if ([ $MkDir "tmpfs/ssh-keys-import" ] = false) do={ $LogPrint warning $0 ("Creating directory 'tmpfs/ssh-keys-import' failed!"); - :error false; + :return false; } :local FingerPrintMD5 [ :convert from=base64 transform=md5 to=hex ($KeyVal->1) ]; @@ -61,7 +61,7 @@ "MD5:" . $FingerPrintMD5 . ") for user '" . $User . "'."); } on-error={ $LogPrint warning $0 ("Failed importing key."); - :error false; + :return false; } } @@ -78,13 +78,13 @@ :if ([ :len $FileName ] = 0 || [ :len $User ] = 0) do={ $LogPrint warning $0 ("Missing argument(s), please pass file name and user!"); - :error false; + :return false; } :local File [ /file/find where name=$FileName ]; :if ([ :len $File ] = 0) do={ $LogPrint warning $0 ("File '" . $FileName . "' does not exist."); - :error false; + :return false; } :local Keys ([ /file/get $FileName contents ] . "\n"); From 44fc69e82d1a612ad276998377b1c3f34310422e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Dec 2023 23:43:23 +0100 Subject: [PATCH 2111/2612] packages-update: drop RouterOS version check... ... and allow all updates again. This requires RouterOS 7.13. --- doc/packages-update.md | 2 +- packages-update.rsc | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/doc/packages-update.md b/doc/packages-update.md index 86eae0d..fae3896 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -4,7 +4,7 @@ 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.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/packages-update.rsc b/packages-update.rsc index 22ea501..2723b3b 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # download packages and reboot for installation # https://git.eworm.de/cgit/routeros-scripts/about/doc/packages-update.md @@ -63,12 +63,6 @@ :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; - :if ($NumInstalled < 0x070d0000 && $NumLatest > 0x070d0000) do={ - $LogPrint error $ScriptName ("Migration to wireless/wifi package in RouterOS " . \ - ($Update->"latest-version") . " is pending. Please update manually!"); - :error false; - } - :local DoDowngrade false; :if ($NumInstalled > $NumLatest) do={ :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ From c016a6ef47eb08ad0f1f72968348af7bfa0acad0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 12 Mar 2024 21:52:18 +0100 Subject: [PATCH 2112/2612] mod/notification-email: add display name with identity (if not given) --- mod/notification-email.rsc | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 78192f3..d801d78 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -8,6 +8,7 @@ # send notifications via e-mail # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-email.md +:global EMailGenerateFrom; :global FlushEmailQueue; :global LogForwardFilterLogForwarding; :global NotificationEMailSubject; @@ -17,11 +18,25 @@ :global SendEMail; :global SendEMail2; +# generate from-property with display name +:set EMailGenerateFrom do={ + :global Identity; + + :local From [ /tool/e-mail/get from ]; + + :if ($From ~ "<.*>\$") do={ + :return $From; + } + + :return ("\"" . $Identity . " via routeros-scripts\" <" . $From . ">"); +} + # flush e-mail queue :set FlushEmailQueue do={ :global EmailQueue; :global EitherOr; + :global EMailGenerateFrom; :global IsDNSResolving; :global IsTimeSync; :global LogPrint; @@ -67,8 +82,8 @@ $LogPrint warning $0 ("File '" . $File . "' does not exist, can not attach."); } } - /tool/e-mail/send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \ - body=($Message->"body") file=$Attach; + /tool/e-mail/send from=[ $EMailGenerateFrom ] to=($Message->"to") cc=($Message->"cc") \ + subject=($Message->"subject") body=($Message->"body") file=$Attach; :local Wait true; :do { :delay 1s; From ccfbabde5eed08a021b2d47f34bc4498940fda1d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 12 Mar 2024 22:03:04 +0100 Subject: [PATCH 2113/2612] mod/notification-email: clean name for display name --- mod/notification-email.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index d801d78..0d83d69 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -22,13 +22,15 @@ :set EMailGenerateFrom do={ :global Identity; + :global CleanName; + :local From [ /tool/e-mail/get from ]; :if ($From ~ "<.*>\$") do={ :return $From; } - :return ("\"" . $Identity . " via routeros-scripts\" <" . $From . ">"); + :return ([ $CleanName $Identity ] . " via routeros-scripts <" . $From . ">"); } # flush e-mail queue From 3d4a14d44935fff6777a97afb4b598238c57b47e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Mar 2024 08:37:11 +0100 Subject: [PATCH 2114/2612] netwatch-notify: pass link to notification This is pass verbatim below the notification text. --- doc/netwatch-notify.md | 7 +++++++ global-functions.rsc | 2 +- netwatch-notify.rsc | 4 ++-- news-and-changes.rsc | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 6f3e1ce..806bb3a 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -111,6 +111,13 @@ included verbatim into the notification. /tool/netwatch/add comment="notify, name=example, note=Do not touch!" host=10.0.0.31; +### Add a link in notification + +It is possible to add a link in notification, that is added below the +formatted notification text. + + /tool/netwatch/add comment="notify, name=example.com, resolve=example.com, link=https://example.com/"; + Tips & Tricks ------------- diff --git a/global-functions.rsc b/global-functions.rsc index d33e3e2..e4d0fd2 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 123; +:global ExpectedConfigVersion 124; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 9536dd7..adcfc37 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -144,7 +144,7 @@ } $SendNotification2 ({ origin=[ $EitherOr ($HostInfo->"origin") $ScriptName ]; silent=($HostInfo->"silent"); \ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $Name . " up"); \ - message=$Message }); + message=$Message; link=($HostInfo->"link") }); } :set ($Metric->"notified") false; :set ($Metric->"parent") ($HostInfo->"parent"); @@ -199,7 +199,7 @@ :if ($HostInfo->"no-down-notification" != true) do={ $SendNotification2 ({ origin=[ $EitherOr ($HostInfo->"origin") $ScriptName ]; silent=($HostInfo->"silent"); \ subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $Name . " down"); \ - message=$Message }); + message=$Message; link=($HostInfo->"link") }); } :set ($Metric->"notified") true; } diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 6b0a538..1f1094d 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -48,6 +48,7 @@ 121="The 'wifiwave2' scripts are finally gone. Development continues with 'wifi' in RouterOS 7.13 and later."; 122="The global configuration was enhanced to support loading snippets. Configuration can be split off to scripts where name starts with 'global-config-overlay.d/'."; 123="Introduced new function '\$LogPrint', and deprecated '\$LogPrintExit2'. Please update custom scripts if you use it."; + 124="Added support for links in 'netwatch-notify', these are added below the formatted notification text."; }; # Migration steps to be applied on script updates From 9b4e5ce369b4061f0d4b02f7cbcf9898cf86d0f0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 14 Mar 2024 22:12:03 +0100 Subject: [PATCH 2115/2612] global-functions: $SymbolByUnicodeName: add these for later use --- global-functions.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index e4d0fd2..2a3c0dd 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1365,6 +1365,9 @@ "mobile-phone"="\F0\9F\93\B1"; "pushpin"="\F0\9F\93\8C"; "scissors"="\E2\9C\82"; + "smiley-partying-face"="\F0\9F\A5\B3"; + "smiley-smiling-face"="\E2\98\BA"; + "smiley-winking-face-with-tongue"="\F0\9F\98\9C"; "sparkles"="\E2\9C\A8"; "speech-balloon"="\F0\9F\92\AC"; "star"="\E2\AD\90"; From eb03a4608bdff08dcbb8ef5776931485625e26f4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 Mar 2024 10:05:32 +0100 Subject: [PATCH 2116/2612] global-functions: $ScriptInstallUpdate: use shorter url --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 2a3c0dd..206c345 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1171,7 +1171,7 @@ "This project is developed in private spare time and usage is " . \ "free of charge for you. If you like the scripts and think this is " . \ "of value for you or your business please consider a donation."); - :set Link "https://git.eworm.de/cgit/routeros-scripts/about/#donate"; + :set Link "https://rsc.eworm.de/#donate"; } $SendNotification2 ({ origin=$0; \ From 2cf4f333d4ab3a0db2742965a430a5d5836c588b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 Mar 2024 11:26:44 +0100 Subject: [PATCH 2117/2612] README: add QR code with (shortened) upstream url --- README.d/upstream.png | Bin 0 -> 207 bytes README.md | 2 ++ 2 files changed, 2 insertions(+) create mode 100644 README.d/upstream.png diff --git a/README.d/upstream.png b/README.d/upstream.png new file mode 100644 index 0000000000000000000000000000000000000000..fd5e877c7ba42c3475e2ccb0bcacb0d71748b968 GIT binary patch literal 207 zcmeAS@N?(olHy`uVBq!ia0vp^F(Ayy3?y$VI!FU4&H|6fVg?3oArNM~bhqvgP>?Oa zC&cyt|NlT{=%LGXKq}wU#WAGf*4!(Gj4X}kj|hKN)Y?_<3AZsk#ibn!(f6&t;ucLK6VSvPZ)J literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 61b1725..614095a 100644 --- a/README.md +++ b/README.md @@ -366,6 +366,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Upstream -------- +![upstream](README.d/upstream.png) + URL: [GitHub.com](https://github.com/eworm-de/routeros-scripts#routeros-scripts) From 576a2c97cf88b7d1b36907469fb6fd34618523b3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 Mar 2024 14:42:50 +0100 Subject: [PATCH 2118/2612] global-functions: $LogPrintExit2: add deprecation warning --- global-functions.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 206c345..c616724 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -703,6 +703,10 @@ :local Exit [ :tostr $4 ]; :global LogPrint; + :global LogPrintOnce; + + $LogPrintOnce warning $0 \ + ("This function is deprecated and will be removed. Please make your adjustments!"); $LogPrint $1 $2 $3; From eb7919c1d8b4ad5c77e0d120136c4f54e1e157e6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 16 Mar 2024 23:10:47 +0100 Subject: [PATCH 2119/2612] global-functions: generate user agent string in function... ... and add the caller and my shortened url. --- check-certificates.rsc | 2 +- fw-addr-lists.rsc | 4 ++-- global-functions.rsc | 27 ++++++++++++++++----------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 7504955..9aa24fd 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -48,7 +48,7 @@ :foreach Type in={ ".pem"; ".p12" } do={ :local CertFileName ([ $UrlEncode $Name ] . $Type); :do { - /tool/fetch check-certificate=yes-without-crl http-header-field=({ $FetchUserAgent }) \ + /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgent $0 ] }) \ ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; $WaitForFile $CertFileName; diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 64233ac..3a422e8 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -14,12 +14,12 @@ :do { :local ScriptName [ :jobname ]; - :global FetchUserAgent; :global FwAddrLists; :global FwAddrListTimeOut; :global CertificateAvailable; :global EitherOr; + :global FetchUserAgent; :global LogPrint; :global LogPrintOnce; :global ScriptLock; @@ -65,7 +65,7 @@ :if ($Data = false) do={ :do { :set Data ([ /tool/fetch check-certificate=$CheckCertificate output=user \ - http-header-field=({ $FetchUserAgent }) ($List->"url") as-value ]->"data"); + http-header-field=({ [ $FetchUserAgent $ScriptName ] }) ($List->"url") as-value ]->"data"); } on-error={ :if ($I < 4) do={ $LogPrint debug $ScriptName ("Failed downloading, " . $I . ". try: " . $List->"url"); diff --git a/global-functions.rsc b/global-functions.rsc index c616724..8df70f1 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -16,12 +16,6 @@ # global variables not to be changed by user :global GlobalFunctionsReady false; -: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 functions @@ -38,6 +32,7 @@ :global DownloadPackage; :global EitherOr; :global EscapeForRegEx; +:global FetchUserAgent; :global FormatLine; :global FormatMultiLines; :global GetMacVendor; @@ -137,11 +132,11 @@ :set CertificateDownload do={ :local CommonName [ :tostr $1 ]; - :global FetchUserAgent; :global ScriptUpdatesBaseUrl; :global ScriptUpdatesUrlSuffix; :global CertificateNameByCN; + :global FetchUserAgent; :global LogPrint; :global UrlEncode; :global WaitForFile; @@ -151,7 +146,7 @@ :do { :local LocalFileName ($CommonName . ".pem"); :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); - /tool/fetch check-certificate=yes-without-crl http-header-field=({ $FetchUserAgent }) \ + /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgent $0 ] }) \ ($ScriptUpdatesBaseUrl . "certs/" . $UrlFileName . $ScriptUpdatesUrlSuffix) \ dst-path=$LocalFileName as-value; $WaitForFile $LocalFileName; @@ -396,6 +391,16 @@ :return $Return; } +# generate user agent string for fetch +:global FetchUserAgent do={ + :local Caller [ :tostr $1 ]; + + :local Resource [ /system/resource/get ]; + + :return ("User-Agent: Mikrotik/" . $Resource->"version" . " " . \ + $Resource->"architecture-name" . " " . $Caller . "/Fetch (https://rsc.eworm.de/)"); +} + # format a line for output :set FormatLine do={ :local Key [ :tostr $1 ]; @@ -975,7 +980,6 @@ :local NewComment [ :tostr $2 ]; :global ExpectedConfigVersion; - :global FetchUserAgent; :global Identity; :global IDonate; :global NoNewsAndChangesNotification; @@ -984,6 +988,7 @@ :global CertificateAvailable; :global EitherOr; + :global FetchUserAgent; :global Grep; :global IfThenElse; :global LogPrint; @@ -1029,7 +1034,7 @@ :local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix); $LogPrint debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url); :local Result [ /tool/fetch check-certificate=yes-without-crl \ - http-header-field=({ $FetchUserAgent }) $Url output=user as-value ]; + http-header-field=({ [ $FetchUserAgent $0 ] }) $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set SourceNew ($Result->"data"); } @@ -1112,7 +1117,7 @@ :local Url ($ScriptUpdatesBaseUrl . "news-and-changes.rsc" . $ScriptUpdatesUrlSuffix); $LogPrint debug $0 ("Fetching news, changes and migration: " . $Url); :local Result [ /tool/fetch check-certificate=yes-without-crl \ - http-header-field=({ $FetchUserAgent }) $Url output=user as-value ]; + http-header-field=({ [ $FetchUserAgent $0 ] }) $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set ChangeLogCode ($Result->"data"); } From cd371b69a642d9e3a0bc32795e959c7feef42522 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 16 Mar 2024 23:27:45 +0100 Subject: [PATCH 2120/2612] global-functions: $CertificateDownload: download via clean name... ... and rename certificates in repository. --- ...ECC CA-3.pem => Cloudflare-Inc-ECC-CA-3.pem} | 0 ...iCert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem} | 0 ...DigiCert-TLS-Hybrid-ECC-SHA384-2020-CA1.pem} | 0 certs/{GTS CA 1C3.pem => GTS-CA-1C3.pem} | 0 certs/{GTS CA 1P5.pem => GTS-CA-1P5.pem} | 0 ...> GlobalSign-Atlas-R3-DV-TLS-CA-2022-Q3.pem} | 0 ...o-Daddy-Secure-Certificate-Authority-G2.pem} | 0 ...arfield-Secure-Certificate-Authority-G2.pem} | 0 global-functions.rsc | 17 ++++++++--------- 9 files changed, 8 insertions(+), 9 deletions(-) rename certs/{Cloudflare Inc ECC CA-3.pem => Cloudflare-Inc-ECC-CA-3.pem} (100%) rename certs/{DigiCert Global G2 TLS RSA SHA256 2020 CA1.pem => DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem} (100%) rename certs/{DigiCert TLS Hybrid ECC SHA384 2020 CA1.pem => DigiCert-TLS-Hybrid-ECC-SHA384-2020-CA1.pem} (100%) rename certs/{GTS CA 1C3.pem => GTS-CA-1C3.pem} (100%) rename certs/{GTS CA 1P5.pem => GTS-CA-1P5.pem} (100%) rename certs/{GlobalSign Atlas R3 DV TLS CA 2022 Q3.pem => GlobalSign-Atlas-R3-DV-TLS-CA-2022-Q3.pem} (100%) rename certs/{Go Daddy Secure Certificate Authority - G2.pem => Go-Daddy-Secure-Certificate-Authority-G2.pem} (100%) rename certs/{Starfield Secure Certificate Authority - G2.pem => Starfield-Secure-Certificate-Authority-G2.pem} (100%) diff --git a/certs/Cloudflare Inc ECC CA-3.pem b/certs/Cloudflare-Inc-ECC-CA-3.pem similarity index 100% rename from certs/Cloudflare Inc ECC CA-3.pem rename to certs/Cloudflare-Inc-ECC-CA-3.pem diff --git a/certs/DigiCert Global G2 TLS RSA SHA256 2020 CA1.pem b/certs/DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem similarity index 100% rename from certs/DigiCert Global G2 TLS RSA SHA256 2020 CA1.pem rename to certs/DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem diff --git a/certs/DigiCert TLS Hybrid ECC SHA384 2020 CA1.pem b/certs/DigiCert-TLS-Hybrid-ECC-SHA384-2020-CA1.pem similarity index 100% rename from certs/DigiCert TLS Hybrid ECC SHA384 2020 CA1.pem rename to certs/DigiCert-TLS-Hybrid-ECC-SHA384-2020-CA1.pem diff --git a/certs/GTS CA 1C3.pem b/certs/GTS-CA-1C3.pem similarity index 100% rename from certs/GTS CA 1C3.pem rename to certs/GTS-CA-1C3.pem diff --git a/certs/GTS CA 1P5.pem b/certs/GTS-CA-1P5.pem similarity index 100% rename from certs/GTS CA 1P5.pem rename to certs/GTS-CA-1P5.pem diff --git a/certs/GlobalSign Atlas R3 DV TLS CA 2022 Q3.pem b/certs/GlobalSign-Atlas-R3-DV-TLS-CA-2022-Q3.pem similarity index 100% rename from certs/GlobalSign Atlas R3 DV TLS CA 2022 Q3.pem rename to certs/GlobalSign-Atlas-R3-DV-TLS-CA-2022-Q3.pem diff --git a/certs/Go Daddy Secure Certificate Authority - G2.pem b/certs/Go-Daddy-Secure-Certificate-Authority-G2.pem similarity index 100% rename from certs/Go Daddy Secure Certificate Authority - G2.pem rename to certs/Go-Daddy-Secure-Certificate-Authority-G2.pem diff --git a/certs/Starfield Secure Certificate Authority - G2.pem b/certs/Starfield-Secure-Certificate-Authority-G2.pem similarity index 100% rename from certs/Starfield Secure Certificate Authority - G2.pem rename to certs/Starfield-Secure-Certificate-Authority-G2.pem diff --git a/global-functions.rsc b/global-functions.rsc index 8df70f1..ca238ba 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -136,25 +136,24 @@ :global ScriptUpdatesUrlSuffix; :global CertificateNameByCN; + :global CleanName; :global FetchUserAgent; :global LogPrint; - :global UrlEncode; :global WaitForFile; $LogPrint info $0 ("Downloading and importing certificate with " . \ "CommonName \"" . $CommonName . "\"."); :do { - :local LocalFileName ($CommonName . ".pem"); - :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); + :local FileName ([ $CleanName $CommonName ] . ".pem"); /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgent $0 ] }) \ - ($ScriptUpdatesBaseUrl . "certs/" . $UrlFileName . $ScriptUpdatesUrlSuffix) \ - dst-path=$LocalFileName as-value; - $WaitForFile $LocalFileName; - /certificate/import file-name=$LocalFileName passphrase="" as-value; + ($ScriptUpdatesBaseUrl . "certs/" . $FileName . $ScriptUpdatesUrlSuffix) \ + dst-path=$FileName as-value; + $WaitForFile $FileName; + /certificate/import file-name=$FileName passphrase="" as-value; :delay 1s; - /file/remove $LocalFileName; + /file/remove $FileName; - :foreach Cert in=[ /certificate/find where name~("^" . $LocalFileName . "_[0-9]+\$") ] do={ + :foreach Cert in=[ /certificate/find where name~("^" . $FileName . "_[0-9]+\$") ] do={ $CertificateNameByCN [ /certificate/get $Cert common-name ]; } } on-error={ From 079249f3d7a1c4c11aa2b4d93b3cf239b0f5da0d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 18 Mar 2024 09:31:40 +0100 Subject: [PATCH 2121/2612] check-routeros-update: use custom user agent string --- check-routeros-update.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index e209610..fde7cb5 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -24,6 +24,7 @@ :global DeviceInfo; :global EscapeForRegEx; + :global FetchUserAgent; :global LogPrint; :global ScriptFromTerminal; :global ScriptLock; @@ -108,7 +109,8 @@ :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 ]; + "&latest=" . $Update->"latest-version") http-header-field=({ [ $FetchUserAgent $ScriptName ] }) \ + output=user as-value ]; } on-error={ $LogPrint warning $ScriptName ("Failed receiving safe version for " . $Update->"channel" . "."); } From be231ce4f3a3d829e7892b6f17751d04991ccd42 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 18 Mar 2024 13:46:46 +0100 Subject: [PATCH 2122/2612] global-config: prepare a (commented) address-list for Mikrotik This is AS51894: https://bgp.he.net/AS51894 --- global-config.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/global-config.rsc b/global-config.rsc index 2b688bc..63a4a3f 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -104,6 +104,10 @@ # { url="https://www.spamhaus.org/drop/edrop.txt"; # cert="Cloudflare Inc ECC CA-3" }; }; +# "mikrotik"={ +# { url="https://eworm.de/ros/fw-addr-lists/mikrotik"; +# cert="E1"; timeout=1w }; +# }; }; :global FwAddrListTimeOut 1d; From 6845eb69b3fb47038bb3d69ba239fd8678447409 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 20 Mar 2024 13:34:37 +0100 Subject: [PATCH 2123/2612] global-config: put example fw-addr-lists into repository --- fw-addr-lists.d/allow | 3 +++ fw-addr-lists.d/block | 5 +++++ fw-addr-lists.d/mikrotik | 5 +++++ global-config.rsc | 6 +++--- 4 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 fw-addr-lists.d/allow create mode 100644 fw-addr-lists.d/block create mode 100644 fw-addr-lists.d/mikrotik diff --git a/fw-addr-lists.d/allow b/fw-addr-lists.d/allow new file mode 100644 index 0000000..8b59ed7 --- /dev/null +++ b/fw-addr-lists.d/allow @@ -0,0 +1,3 @@ +# an ip address list for use with fw-addr-lists script +# https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md +git.eworm.de diff --git a/fw-addr-lists.d/block b/fw-addr-lists.d/block new file mode 100644 index 0000000..5e9fef2 --- /dev/null +++ b/fw-addr-lists.d/block @@ -0,0 +1,5 @@ +# an ip address list for use with fw-addr-lists script +# https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md + +# example.net +93.184.216.34 diff --git a/fw-addr-lists.d/mikrotik b/fw-addr-lists.d/mikrotik new file mode 100644 index 0000000..3b31a94 --- /dev/null +++ b/fw-addr-lists.d/mikrotik @@ -0,0 +1,5 @@ +# AS51894 Mikrotikls SIA +# https://bgp.he.net/AS51894 +159.148.147.0/24 +159.148.172.0/24 +2a02:610:7501::/48 diff --git a/global-config.rsc b/global-config.rsc index 63a4a3f..f393abb 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -87,11 +87,11 @@ # This defines the settings for firewall address-lists (fw-addr-lists). :global FwAddrLists { # "allow"={ -# { url="https://eworm.de/ros/fw-addr-lists/allow"; +# { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/allow"; # cert="E1"; timeout=1w }; # }; "block"={ -# { url="https://eworm.de/ros/fw-addr-lists/block"; +# { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/block"; # cert="E1" }; { url="https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt"; cert="GlobalSign Atlas R3 DV TLS CA 2022 Q3" }; @@ -105,7 +105,7 @@ # cert="Cloudflare Inc ECC CA-3" }; }; # "mikrotik"={ -# { url="https://eworm.de/ros/fw-addr-lists/mikrotik"; +# { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/mikrotik"; # cert="E1"; timeout=1w }; # }; }; From 81f1d9aa99b928fea43612a9e2e58e4c17eee7d6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 20 Mar 2024 13:55:55 +0100 Subject: [PATCH 2124/2612] check-certificates: pass script name into local function --- check-certificates.rsc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 9aa24fd..ab78e22 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -31,7 +31,8 @@ :global WaitFullyConnected; :local CheckCertificatesDownloadImport do={ - :local Name [ :tostr $1 ]; + :local ScriptName [ :tostr $1 ]; + :local Name [ :tostr $2 ]; :global CertRenewUrl; :global CertRenewPass; @@ -48,7 +49,7 @@ :foreach Type in={ ".pem"; ".p12" } do={ :local CertFileName ([ $UrlEncode $Name ] . $Type); :do { - /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgent $0 ] }) \ + /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgent $ScriptName ] }) \ ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; $WaitForFile $CertFileName; @@ -62,7 +63,7 @@ /file/remove [ find where name=$CertFileName ]; :if ($DecryptionFailed = true) do={ - $LogPrint warning $0 ("Decryption failed for certificate file '" . $CertFileName . "'."); + $LogPrint warning $ScriptName ("Decryption failed for certificate file '" . $CertFileName . "'."); } :foreach CertInChain in=[ /certificate/find where name~("^" . [ $EscapeForRegEx $CertFileName ] . "_[0-9]+\$") \ @@ -72,7 +73,7 @@ :set Return true; } on-error={ - $LogPrint debug $0 ("Could not download certificate file '" . $CertFileName . "'."); + $LogPrint debug $ScriptName ("Could not download certificate file '" . $CertFileName . "'."); } } @@ -150,11 +151,11 @@ :local ImportSuccess false; :set LastName ($CertVal->"common-name"); - :set ImportSuccess [ $CheckCertificatesDownloadImport $LastName ]; + :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName ]; :foreach SAN in=($CertVal->"subject-alt-name") do={ :if ($ImportSuccess = false) do={ :set LastName [ :pick $SAN ([ :find $SAN ":" ] + 1) [ :len $SAN ] ]; - :set ImportSuccess [ $CheckCertificatesDownloadImport $LastName ]; + :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName ]; } } :if ($ImportSuccess = false) do={ :error false; } From 6628d9f9665cc224423c904ef65d84a25c8de817 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 20 Mar 2024 13:59:44 +0100 Subject: [PATCH 2125/2612] netwatch-notify: pass script name into local functions --- netwatch-notify.rsc | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index adcfc37..bdabe2e 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -27,10 +27,11 @@ :global SymbolForNotification; :local NetwatchNotifyHook do={ - :local Name [ :tostr $1 ]; - :local Type [ :tostr $2 ]; - :local State [ :tostr $3 ]; - :local Hook [ :tostr $4 ]; + :local ScriptName [ :tostr $1 ]; + :local Name [ :tostr $2 ]; + :local Type [ :tostr $3 ]; + :local State [ :tostr $4 ]; + :local Hook [ :tostr $5 ]; :global LogPrint; :global ValidateSyntax; @@ -39,25 +40,26 @@ :do { [ :parse $Hook ]; } on-error={ - $LogPrint warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . "' failed to run."); + $LogPrint warning $ScriptName ("The " . $State . "-hook for " . $Type . " '" . $Name . "' failed to run."); :return ("The hook failed to run."); } } else={ - $LogPrint warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . "' failed syntax validation."); + $LogPrint warning $ScriptName ("The " . $State . "-hook for " . $Type . " '" . $Name . "' failed syntax validation."); :return ("The hook failed syntax validation."); } - $LogPrint info $0 ("Ran hook on " . $Type . " '" . $Name . "' " . $State . ": " . $Hook); + $LogPrint info $ScriptName ("Ran hook on " . $Type . " '" . $Name . "' " . $State . ": " . $Hook); :return ("Ran hook:\n" . $Hook); } :local ResolveExpected do={ - :local Name [ :tostr $1 ]; - :local Expected [ :tostr $2 ]; + :local ScriptName [ :tostr $1 ]; + :local Name [ :tostr $2 ]; + :local Expected [ :tostr $3 ]; :global GetRandom20CharAlNum; - :local FwAddrList ($0 . "-" . [ $GetRandom20CharAlNum ]); + :local FwAddrList ($ScriptName . "-" . [ $GetRandom20CharAlNum ]); /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s; :delay 20ms; :if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ @@ -102,7 +104,7 @@ :do { :local Resolve [ :resolve ($HostInfo->"resolve") ]; :if ($Resolve != $HostVal->"host") do={ - :if ([ $ResolveExpected ($HostInfo->"resolve") ($HostVal->"host") ] = false) do={ + :if ([ $ResolveExpected $ScriptName ($HostInfo->"resolve") ($HostVal->"host") ] = false) do={ $LogPrint info $ScriptName ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ @@ -139,7 +141,7 @@ :set Message ($Message . "\n\nNote:\n" . ($HostInfo->"note")); } :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "up" \ + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $ScriptName $Name $Type "up" \ ($HostInfo->"up-hook") ]); } $SendNotification2 ({ origin=[ $EitherOr ($HostInfo->"origin") $ScriptName ]; silent=($HostInfo->"silent"); \ @@ -183,7 +185,7 @@ } :if ((($CountDown * 2) - ($Metric->"count-down" * 3)) / 2 = 0 && \ [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ - $NetwatchNotifyHook $Name $Type "pre-down" ($HostInfo->"pre-down-hook"); + $NetwatchNotifyHook $ScriptName $Name $Type "pre-down" ($HostInfo->"pre-down-hook"); } :if ($ParentNotified = false && $Metric->"count-down" >= $CountDown && \ ($ParentUp = false || $ParentUp > 2) && $Metric->"notified" != true) do={ @@ -193,7 +195,7 @@ :set Message ($Message . "\n\nNote:\n" . ($HostInfo->"note")); } :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "down" \ + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $ScriptName $Name $Type "down" \ ($HostInfo->"down-hook") ]); } :if ($HostInfo->"no-down-notification" != true) do={ From cc81e556491c40d9b2a0d164eda16e196ac72aa6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 21 Mar 2024 13:39:56 +0100 Subject: [PATCH 2126/2612] telegram-chat: improve readability with symbols --- global-functions.rsc | 1 + telegram-chat.rsc | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index ca238ba..1b1a8c8 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1361,6 +1361,7 @@ "earth"="\F0\9F\8C\8D"; "fire"="\F0\9F\94\A5"; "floppy-disk"="\F0\9F\92\BE"; + "gear"="\E2\9A\99"; "heart"="\E2\99\A5"; "high-voltage-sign"="\E2\9A\A1"; "incoming-envelope"="\F0\9F\93\A8"; diff --git a/telegram-chat.rsc b/telegram-chat.rsc index c81b714..4245cfd 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -136,23 +136,26 @@ :execute script=(":do {\n" . $Message->"text" . "\n} on-error={ /file/add name=\"" . $File . ".failed\" };" . \ "/file/add name=\"" . $File . ".done\"") file=($File . "\00"); :if ([ $WaitForFile ($File . ".done") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ - :set State "The command did not finish, still running in background.\n\n"; + :set State ([ $SymbolForNotification "warning-sign" ] . "The command did not finish, still running in background.\n\n"); } :if ([ :len [ /file/find where name=($File . ".failed") ] ] > 0) do={ - :set State "The command failed with an error!\n\n"; + :set State ([ $SymbolForNotification "cross-mark" ] . "The command failed with an error!\n\n"); } :local Content [ /file/get $File contents ]; $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Command:\n" . $Message->"text" . "\n\n" . $State . [ $IfThenElse ([ :len $Content ] > 0) \ - ("Output:\n" . $Content) [ $IfThenElse ([ /file/get $File size ] > 0) \ - ("Output exceeds file read size.") ("No output.") ] ]) }); + message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Message->"text" . "\n\n" . \ + $State . [ $IfThenElse ([ :len $Content ] > 0) \ + ([ $SymbolForNotification "memo" ] . "Output:\n" . $Content) [ $IfThenElse ([ /file/get $File size ] > 0) \ + ([ $SymbolForNotification "warning-sign" ] . "Output exceeds file read size.") \ + ([ $SymbolForNotification "memo" ] . "No output.") ] ]) }); /file/remove "tmpfs/telegram-chat"; } else={ $LogPrint info $ScriptName ("The command from update " . $UpdateID . " failed syntax validation!"); $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Command:\n" . $Message->"text" . "\n\nThe command failed syntax validation!") }); + message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Message->"text" . "\n\n" . \ + [ $SymbolForNotification "cross-mark" ] . "The command failed syntax validation!") }); } } } else={ From f72aadfc591ece4c79522256e5b6a4d71fb18467 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 21 Mar 2024 21:10:51 +0100 Subject: [PATCH 2127/2612] telegram-chat: note active state when answering broadcast --- telegram-chat.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 4245cfd..9ae5967 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -111,7 +111,7 @@ $LogPrint info $ScriptName ("Sending notice for update " . $UpdateID . "."); $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Online, awaiting your commands!") }); + message=("Online" . [ $IfThenElse $TelegramChatActive " (and active!)" ] . ", awaiting your commands!") }); :set Done true; } :if ($Done = false && [ :pick ($Message->"text") 0 1 ] = "!") do={ From 9ec8b9c03fbd5529eee0d62417d5de8ffc72abd4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 Mar 2024 08:37:07 +0100 Subject: [PATCH 2128/2612] fw-addr-lists: one more interation on download failure... ... with even more delay. This script is called with long interval from scheduler, so should not be an issue. --- fw-addr-lists.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 3a422e8..887263e 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -61,13 +61,13 @@ } } - :for I from=1 to=4 do={ + :for I from=1 to=5 do={ :if ($Data = false) do={ :do { :set Data ([ /tool/fetch check-certificate=$CheckCertificate output=user \ http-header-field=({ [ $FetchUserAgent $ScriptName ] }) ($List->"url") as-value ]->"data"); } on-error={ - :if ($I < 4) do={ + :if ($I < 5) do={ $LogPrint debug $ScriptName ("Failed downloading, " . $I . ". try: " . $List->"url"); :delay (($I * $I) . "s"); } From bd2301a28cf34bb0302487719a82a40cd64fa4ef Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 Mar 2024 13:51:44 +0100 Subject: [PATCH 2129/2612] global-functions: $LogPrintOnce: indicate action via return --- global-functions.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 1b1a8c8..59ba039 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -734,11 +734,12 @@ } :if ($LogPrintOnceMessages->$Message = 1) do={ - :return true; + :return false; } :set ($LogPrintOnceMessages->$Message) 1; $LogPrint $Severity $Name $Message; + :return true; } # get max value From 43ecec854fccb27bdf4424d684f72519f75e0484 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 27 Mar 2024 07:43:32 +0100 Subject: [PATCH 2130/2612] global-functions: $LogPrintOnce: detect and warn on possible crash --- global-functions.rsc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 59ba039..b3d8719 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -737,6 +737,11 @@ :return false; } + :if ([ :len [ /log/find where message=($Name . ": " . $Message) ] ] > 0) do={ + $LogPrint warning $0 \ + ("The message is already in log, scripting subsystem may have crashed before!"); + } + :set ($LogPrintOnceMessages->$Message) 1; $LogPrint $Severity $Name $Message; :return true; From 7212d8bd23c555970e22fa43edb56dabfe14b820 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 27 Mar 2024 22:17:06 +0100 Subject: [PATCH 2131/2612] packages-update: do not reboot when scheduled --- packages-update.rsc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages-update.rsc b/packages-update.rsc index 2723b3b..0208b1e 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -130,10 +130,12 @@ :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; :if (([ /terminal/inkey timeout=60 ] % 32) = 19) do={ $Schedule $ScriptName; + :error true; } } else={ :if ($PackagesUpdateDeferReboot = true) do={ $Schedule $ScriptName; + :error true; } } From 1d816d94f60ed953e67760bf2f567442002c0a6f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 27 Mar 2024 22:58:33 +0100 Subject: [PATCH 2132/2612] global-functions: $FetchUserAgent: set declared function only --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index b3d8719..35eeca9 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -391,7 +391,7 @@ } # generate user agent string for fetch -:global FetchUserAgent do={ +:set FetchUserAgent do={ :local Caller [ :tostr $1 ]; :local Resource [ /system/resource/get ]; From acf8e88db2c3a96b1d196d29e19f3f65be9c21eb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 27 Mar 2024 23:00:27 +0100 Subject: [PATCH 2133/2612] global-functions: $AlignRight: set declared function only --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 35eeca9..919ffbe 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -79,7 +79,7 @@ :global WaitTimeSync; # align string to the right -:global AlignRight do={ +:set AlignRight do={ :local Input [ :tostr $1 ]; :local Len [ :tonum $2 ]; From bbdc9c65f50d2d290e4cd15a8c49ec0cb36a347d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 27 Mar 2024 23:01:07 +0100 Subject: [PATCH 2134/2612] global-functions: $HumanReadableNum: set declared function only --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 919ffbe..17ccda8 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -528,7 +528,7 @@ } # return human readable number -:global HumanReadableNum do={ +:set HumanReadableNum do={ :local Input [ :tonum $1 ]; :local Base [ :tonum $2 ]; From 4df1468e2569dfc1603876e24a9be933dc8cf8f2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 29 Mar 2024 11:09:22 +0100 Subject: [PATCH 2135/2612] global-functions: rename $FetchUserAgent -> $FetchUserAgentStr ... to make sure the function does not clash with the variable we had before, as this causes issue with news and changes notification. --- check-certificates.rsc | 4 ++-- check-routeros-update.rsc | 4 ++-- fw-addr-lists.rsc | 4 ++-- global-functions.rsc | 14 +++++++------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index ab78e22..20e2902 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -39,7 +39,7 @@ :global CertificateNameByCN; :global EscapeForRegEx; - :global FetchUserAgent; + :global FetchUserAgentStr; :global LogPrint; :global UrlEncode; :global WaitForFile; @@ -49,7 +49,7 @@ :foreach Type in={ ".pem"; ".p12" } do={ :local CertFileName ([ $UrlEncode $Name ] . $Type); :do { - /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgent $ScriptName ] }) \ + /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) \ ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; $WaitForFile $CertFileName; diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index fde7cb5..c9ab93b 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -24,7 +24,7 @@ :global DeviceInfo; :global EscapeForRegEx; - :global FetchUserAgent; + :global FetchUserAgentStr; :global LogPrint; :global ScriptFromTerminal; :global ScriptLock; @@ -109,7 +109,7 @@ :do { :set Result [ /tool/fetch check-certificate=yes-without-crl \ ($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \ - "&latest=" . $Update->"latest-version") http-header-field=({ [ $FetchUserAgent $ScriptName ] }) \ + "&latest=" . $Update->"latest-version") http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) \ output=user as-value ]; } on-error={ $LogPrint warning $ScriptName ("Failed receiving safe version for " . $Update->"channel" . "."); diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 887263e..68775b4 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -19,7 +19,7 @@ :global CertificateAvailable; :global EitherOr; - :global FetchUserAgent; + :global FetchUserAgentStr; :global LogPrint; :global LogPrintOnce; :global ScriptLock; @@ -65,7 +65,7 @@ :if ($Data = false) do={ :do { :set Data ([ /tool/fetch check-certificate=$CheckCertificate output=user \ - http-header-field=({ [ $FetchUserAgent $ScriptName ] }) ($List->"url") as-value ]->"data"); + http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) ($List->"url") as-value ]->"data"); } on-error={ :if ($I < 5) do={ $LogPrint debug $ScriptName ("Failed downloading, " . $I . ". try: " . $List->"url"); diff --git a/global-functions.rsc b/global-functions.rsc index 17ccda8..1e98019 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -32,7 +32,7 @@ :global DownloadPackage; :global EitherOr; :global EscapeForRegEx; -:global FetchUserAgent; +:global FetchUserAgentStr; :global FormatLine; :global FormatMultiLines; :global GetMacVendor; @@ -137,7 +137,7 @@ :global CertificateNameByCN; :global CleanName; - :global FetchUserAgent; + :global FetchUserAgentStr; :global LogPrint; :global WaitForFile; @@ -145,7 +145,7 @@ "CommonName \"" . $CommonName . "\"."); :do { :local FileName ([ $CleanName $CommonName ] . ".pem"); - /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgent $0 ] }) \ + /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $0 ] }) \ ($ScriptUpdatesBaseUrl . "certs/" . $FileName . $ScriptUpdatesUrlSuffix) \ dst-path=$FileName as-value; $WaitForFile $FileName; @@ -391,7 +391,7 @@ } # generate user agent string for fetch -:set FetchUserAgent do={ +:set FetchUserAgentStr do={ :local Caller [ :tostr $1 ]; :local Resource [ /system/resource/get ]; @@ -993,7 +993,7 @@ :global CertificateAvailable; :global EitherOr; - :global FetchUserAgent; + :global FetchUserAgentStr; :global Grep; :global IfThenElse; :global LogPrint; @@ -1039,7 +1039,7 @@ :local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix); $LogPrint debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url); :local Result [ /tool/fetch check-certificate=yes-without-crl \ - http-header-field=({ [ $FetchUserAgent $0 ] }) $Url output=user as-value ]; + http-header-field=({ [ $FetchUserAgentStr $0 ] }) $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set SourceNew ($Result->"data"); } @@ -1122,7 +1122,7 @@ :local Url ($ScriptUpdatesBaseUrl . "news-and-changes.rsc" . $ScriptUpdatesUrlSuffix); $LogPrint debug $0 ("Fetching news, changes and migration: " . $Url); :local Result [ /tool/fetch check-certificate=yes-without-crl \ - http-header-field=({ [ $FetchUserAgent $0 ] }) $Url output=user as-value ]; + http-header-field=({ [ $FetchUserAgentStr $0 ] }) $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set ChangeLogCode ($Result->"data"); } From bdcf5b327518e5c8806bdb9a1896f86523ec2925 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 14 Mar 2024 22:32:15 +0100 Subject: [PATCH 2136/2612] news on charge and fees --- global-functions.rsc | 2 +- news-and-changes.rsc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 1e98019..bd72313 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 124; +:global ExpectedConfigVersion 125; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 1f1094d..e66ad2e 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -49,6 +49,7 @@ 122="The global configuration was enhanced to support loading snippets. Configuration can be split off to scripts where name starts with 'global-config-overlay.d/'."; 123="Introduced new function '\$LogPrint', and deprecated '\$LogPrintExit2'. Please update custom scripts if you use it."; 124="Added support for links in 'netwatch-notify', these are added below the formatted notification text."; + 125=("Donations do not pay off, thus I will start charging fees soon: 5\C2\A2 each notification, 20\C2\A2 each backup, 50\C2\A2 for script updates. Please add credit card information and mail address for invoice."); }; # Migration steps to be applied on script updates @@ -57,4 +58,5 @@ 100=":global ScriptInstallUpdate; :if ([ :len [ /system/script/find where name=\"ssh-keys-import\" source~\"^#!rsc by RouterOS\\n\" ] ] > 0) do={ /system/script/set name=\"mod/ssh-keys-import\" ssh-keys-import; \$ScriptInstallUpdate; }"; 104=":global CharacterReplace; :global ScriptInstallUpdate; :foreach Script in={ \"capsman-download-packages\"; \"capsman-rolling-upgrade\"; \"hotspot-to-wpa\"; \"hotspot-to-wpa-cleanup\" } do={ /system/script/set name=(\$Script . \".capsman\") [ find where name=\$Script ]; :foreach Scheduler in=[ /system/scheduler/find where on-event~(\$Script . \"([^-.]|\\\$)\") ] do={ /system/scheduler/set \$Scheduler on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Script (\$Script . \".capsman\") ]; }; }; /ip/hotspot/user/profile/set on-login=\"hotspot-to-wpa.capsman\" [ find where on-login=\"hotspot-to-wpa\" ]; \$ScriptInstallUpdate;"; 111=":local Rec [ /ip/dns/static/find where comment~\"^managed by dhcp-to-dns for \" ]; :if ([ :len \$Rec ] > 0) do={ /ip/dns/static/remove \$Rec; /system/script/run dhcp-to-dns; }"; + 125="/system/scheduler/add interval=20h name=_AprilsFool on-event=\"/system/scheduler/remove _AprilsFool; :global SendNotification; :global SymbolForNotification; \\\$SendNotification ([ \\\$SymbolForNotification \\\"smiley-partying-face\\\" ] . \\\"April's Fool!\\\") (\\\"Just played an April's Fool... Of course this project is and remains open source, free of charge and fees.\\\\n\\\\n(Anyway... Donations are much appreciated, \\\" . [ \\\$SymbolForNotification \\\"smiley-smiling-face\\\" ] . \\\"thanks!)\\\") \\\"https://rsc.eworm.de/#donate\\\";\";"; }; From 1e47c909f08a71d850f252bf5ccec7330e436d05 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 14 Mar 2024 22:36:27 +0100 Subject: [PATCH 2137/2612] =?UTF-8?q?news=20on=20April's=20Fool!=20?= =?UTF-8?q?=F0=9F=A5=B3=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- news-and-changes.rsc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/news-and-changes.rsc b/news-and-changes.rsc index e66ad2e..5523c73 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -49,7 +49,7 @@ 122="The global configuration was enhanced to support loading snippets. Configuration can be split off to scripts where name starts with 'global-config-overlay.d/'."; 123="Introduced new function '\$LogPrint', and deprecated '\$LogPrintExit2'. Please update custom scripts if you use it."; 124="Added support for links in 'netwatch-notify', these are added below the formatted notification text."; - 125=("Donations do not pay off, thus I will start charging fees soon: 5\C2\A2 each notification, 20\C2\A2 each backup, 50\C2\A2 for script updates. Please add credit card information and mail address for invoice."); + 125=("April's Fool! " . [ $SymbolForNotification "smiley-partying-face" ] . "Well, you missed it... - no charge nor fees. (Anyway... Donations are much appreciated, " . [ $SymbolForNotification "smiley-smiling-face" ] . "thanks!)"); }; # Migration steps to be applied on script updates @@ -58,5 +58,4 @@ 100=":global ScriptInstallUpdate; :if ([ :len [ /system/script/find where name=\"ssh-keys-import\" source~\"^#!rsc by RouterOS\\n\" ] ] > 0) do={ /system/script/set name=\"mod/ssh-keys-import\" ssh-keys-import; \$ScriptInstallUpdate; }"; 104=":global CharacterReplace; :global ScriptInstallUpdate; :foreach Script in={ \"capsman-download-packages\"; \"capsman-rolling-upgrade\"; \"hotspot-to-wpa\"; \"hotspot-to-wpa-cleanup\" } do={ /system/script/set name=(\$Script . \".capsman\") [ find where name=\$Script ]; :foreach Scheduler in=[ /system/scheduler/find where on-event~(\$Script . \"([^-.]|\\\$)\") ] do={ /system/scheduler/set \$Scheduler on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Script (\$Script . \".capsman\") ]; }; }; /ip/hotspot/user/profile/set on-login=\"hotspot-to-wpa.capsman\" [ find where on-login=\"hotspot-to-wpa\" ]; \$ScriptInstallUpdate;"; 111=":local Rec [ /ip/dns/static/find where comment~\"^managed by dhcp-to-dns for \" ]; :if ([ :len \$Rec ] > 0) do={ /ip/dns/static/remove \$Rec; /system/script/run dhcp-to-dns; }"; - 125="/system/scheduler/add interval=20h name=_AprilsFool on-event=\"/system/scheduler/remove _AprilsFool; :global SendNotification; :global SymbolForNotification; \\\$SendNotification ([ \\\$SymbolForNotification \\\"smiley-partying-face\\\" ] . \\\"April's Fool!\\\") (\\\"Just played an April's Fool... Of course this project is and remains open source, free of charge and fees.\\\\n\\\\n(Anyway... Donations are much appreciated, \\\" . [ \\\$SymbolForNotification \\\"smiley-smiling-face\\\" ] . \\\"thanks!)\\\") \\\"https://rsc.eworm.de/#donate\\\";\";"; }; From 7e5010a60853c946e6e73406031fe0e937bee8df Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 28 Mar 2024 22:33:49 +0100 Subject: [PATCH 2138/2612] telegram-chat: use :deserialize ... ... instead of $ParseJson. This requires RouterOS 7.13. --- telegram-chat.rsc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 3d0f397..c1a1cbc 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -34,7 +34,6 @@ :global MAX; :global MIN; :global MkDir; - :global ParseJson; :global RandomDelay; :global ScriptLock; :global SendTelegram2; @@ -86,18 +85,18 @@ :error false; } + :local JSON [ :deserialize from=json value=$Data ]; :local UpdateID 0; :local Uptime [ /system/resource/get uptime ]; - :foreach UpdateArray in=([ $ParseJson $Data ]->"result") do={ - :local Update [ $ParseJson $UpdateArray ]; + :foreach Update in=($JSON->"result") do={ :set UpdateID ($Update->"update_id"); - :local Message [ $ParseJson ($Update->"message") ]; + :local Message ($Update->"message"); :local IsReply [ :len ($Message->"reply_to_message") ]; - :local IsMyReply ($TelegramMessageIDs->([ $ParseJson ($Message->"reply_to_message") ]->"message_id")); + :local IsMyReply ($TelegramMessageIDs->[ :tostr ($Message->"reply_to_message"->"message_id") ]); :if (($IsMyReply = 1 || $TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={ :local Trusted false; - :local Chat [ $ParseJson ($Message->"chat") ]; - :local From [ $ParseJson ($Message->"from") ]; + :local Chat ($Message->"chat"); + :local From ($Message->"from"); :foreach IdsTrusted in=($TelegramChatId, $TelegramChatIdsTrusted) do={ :if ($From->"id" = $IdsTrusted || $From->"username" = $IdsTrusted) do={ From 29bcbc4db9d39573e8c8017e75eea4df7f603c2c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 28 Mar 2024 22:43:18 +0100 Subject: [PATCH 2139/2612] mod/notification-telegram: use :deserialize ... ... instead of $ParseJson. This requires RouterOS 7.13. --- doc/mod/notification-telegram.md | 2 +- mod/notification-telegram.rsc | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index cb326f0..159fda9 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 506ec80..a43ff10 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.13 +# # send notifications via Telegram # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-telegram.md @@ -19,7 +21,6 @@ :global IsFullyConnected; :global LogPrint; - :global ParseJson; :global UrlEncode; :if ([ $IsFullyConnected ] = false) do={ @@ -43,7 +44,7 @@ "&reply_to_message_id=" . ($Message->"replyto") . "&disable_web_page_preview=true" . \ "&parse_mode=MarkdownV2&text=" . [ $UrlEncode ($Message->"text") ]) as-value ]->"data"); :set ($TelegramQueue->$Id); - :set ($TelegramMessageIDs->([ $ParseJson ([ $ParseJson $Data ]->"result") ]->"message_id")) 1; + :set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1; } on-error={ $LogPrint debug $0 ("Sending queued Telegram message failed."); :set AllDone false; @@ -75,7 +76,6 @@ :global EitherOr; :global IfThenElse; :global LogPrint; - :global ParseJson; :global SymbolForNotification; :global UrlEncode; @@ -144,7 +144,7 @@ http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ "&reply_to_message_id=" . ($Notification->"replyto") . "&disable_web_page_preview=true" . \ "&parse_mode=MarkdownV2&text=" . [ $UrlEncode $Text ]) as-value ]->"data"); - :set ($TelegramMessageIDs->([ $ParseJson ([ $ParseJson $Data ]->"result") ]->"message_id")) 1; + :set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1; } on-error={ $LogPrint info $0 ("Failed sending telegram notification! Queuing..."); From bb237dcef3fea8c5a6988cc52b2a0360078faad8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 28 Mar 2024 22:54:23 +0100 Subject: [PATCH 2140/2612] mod/notification-matrix: use :deserialize ... ... instead of $ParseJson. This requires RouterOS 7.13. --- doc/mod/notification-matrix.md | 2 +- mod/notification-matrix.rsc | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index c68b0aa..88628e4 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index aa95841..8234779 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -4,6 +4,8 @@ # Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.13 +# # send notifications via Matrix # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-matrix.md @@ -183,9 +185,7 @@ :local User [ :tostr $1 ]; :local Pass [ :tostr $2 ]; - :global CharacterReplace; :global LogPrint; - :global ParseJson; :global MatrixAccessToken; :global MatrixHomeServer; @@ -194,7 +194,7 @@ :do { :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ ("https://" . $Domain . "/.well-known/matrix/client") as-value ]->"data"); - :set MatrixHomeServer ([ $ParseJson ([ $ParseJson [ $CharacterReplace $Data " " "" ] ]->"m.homeserver") ]->"base_url"); + :set MatrixHomeServer ([ :deserialize from=json value=$Data ]->"m.homeserver"->"base_url"); $LogPrint debug $0 ("Home server is: " . $MatrixHomeServer); } on-error={ $LogPrint error $0 ("Failed getting home server!"); @@ -209,7 +209,7 @@ :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ http-method=post http-data=("{\"type\":\"m.login.password\", \"user\":\"" . $User . "\", \"password\":\"" . $Pass . "\"}") \ ("https://" . $MatrixHomeServer . "/_matrix/client/r0/login") as-value ]->"data"); - :set MatrixAccessToken ([ $ParseJson $Data ]->"access_token"); + :set MatrixAccessToken ([ :deserialize from=json value=$Data ]->"access_token"); $LogPrint debug $0 ("Access token is: " . $MatrixAccessToken); } on-error={ $LogPrint error $0 ("Failed logging in (and getting access token)!"); From c01a424f4f41997d1b8b4a45c2bb033f37470393 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 28 Mar 2024 21:29:27 +0100 Subject: [PATCH 2141/2612] telegram-chat: read file content... ... instead of getting it. This lifts the size limit, though we are still limited by Telegram message size. This requires RouterOS 7.13. --- doc/telegram-chat.md | 7 +++---- global-functions.rsc | 2 +- news-and-changes.rsc | 1 + telegram-chat.rsc | 9 ++++----- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index 2a4af99..eb4acf5 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -4,7 +4,7 @@ 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/) +[![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) @@ -130,9 +130,8 @@ send information on its own. Something like this should do the job: ### Output size -RouterOS is limited in reading file content to a size of about four -kilobytes. Reading larger files does just fail, and that is also the limit -for command output. +Telegram messages have a limit of 4096 characters. If output is too large it +is truncated, and a warning is added to the message. ### Sending commands to a group diff --git a/global-functions.rsc b/global-functions.rsc index bd72313..b2ef3a2 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 125; +:global ExpectedConfigVersion 126; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 5523c73..2b04c29 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -50,6 +50,7 @@ 123="Introduced new function '\$LogPrint', and deprecated '\$LogPrintExit2'. Please update custom scripts if you use it."; 124="Added support for links in 'netwatch-notify', these are added below the formatted notification text."; 125=("April's Fool! " . [ $SymbolForNotification "smiley-partying-face" ] . "Well, you missed it... - no charge nor fees. (Anyway... Donations are much appreciated, " . [ $SymbolForNotification "smiley-smiling-face" ] . "thanks!)"); + 126="Made 'telegram-chat' capable of handling large command output. Telegram messages still limit the size, so it is truncated now."; }; # Migration steps to be applied on script updates diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 9ae5967..3d0f397 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2023-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # use Telegram to chat with your Router and send commands # https://git.eworm.de/cgit/routeros-scripts/about/doc/telegram-chat.md @@ -141,14 +141,13 @@ :if ([ :len [ /file/find where name=($File . ".failed") ] ] > 0) do={ :set State ([ $SymbolForNotification "cross-mark" ] . "The command failed with an error!\n\n"); } - :local Content [ /file/get $File contents ]; + :local Content ([ /file/read chunk-size=32768 file=$File as-value ]->"data"); $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Message->"text" . "\n\n" . \ $State . [ $IfThenElse ([ :len $Content ] > 0) \ - ([ $SymbolForNotification "memo" ] . "Output:\n" . $Content) [ $IfThenElse ([ /file/get $File size ] > 0) \ - ([ $SymbolForNotification "warning-sign" ] . "Output exceeds file read size.") \ - ([ $SymbolForNotification "memo" ] . "No output.") ] ]) }); + ([ $SymbolForNotification "memo" ] . "Output:\n" . $Content) \ + ([ $SymbolForNotification "memo" ] . "No output.") ]) }); /file/remove "tmpfs/telegram-chat"; } else={ $LogPrint info $ScriptName ("The command from update " . $UpdateID . " failed syntax validation!"); From 4db91ec16eb482d0989435f40373f455f1665f97 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 28 Mar 2024 23:27:57 +0100 Subject: [PATCH 2142/2612] global-functions: drop $ParseJson --- global-functions.rsc | 61 -------------------------------------------- 1 file changed, 61 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index b2ef3a2..e19ed65 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -56,7 +56,6 @@ :global MkDir; :global NotificationFunctions; :global ParseDate; -:global ParseJson; :global ParseKeyValueStore; :global PrettyPrint; :global RandomDelay; @@ -830,66 +829,6 @@ "day"=[ :tonum [ :pick $Date 8 10 ] ] }); } -# parse JSON into array -# Warning: This is not a complete parser! -:set ParseJson do={ - :local Input [ :tostr $1 ]; - - :local InLen; - :local Return ({}); - :local Skip 0; - - :if ([ :pick $Input 0 ] = "{") do={ - :set Input [ :pick $Input 1 ([ :len $Input ] - 1) ]; - } - :set Input [ :toarray $Input ]; - :set InLen [ :len $Input ]; - - :for I from=0 to=$InLen do={ - :if ($Skip > 0 || $Input->$I = "\n" || $Input->$I = "\r\n") do={ - :if ($Skip > 0) do={ - :set $Skip ($Skip - 1); - } - } else={ - :local Done false; - :local Key ($Input->$I); - :local Val1 ($Input->($I + 1)); - :local Val2 ($Input->($I + 2)); - :if ($Val1 = ":") do={ - :set Skip 2; - :set ($Return->$Key) $Val2; - :set Done true; - } - :if ($Done = false && $Val1 = ":[") do={ - :local Last false; - :set Skip 1; - :set ($Return->$Key) ({}); - :do { - :set Skip ($Skip + 1); - :local ValX ($Input->($I + $Skip)); - :if ([ :pick $ValX ([ :len $ValX ] - 1) ] = "]") do={ - :set Last true; - :set ValX [ :pick $ValX 0 ([ :len $ValX ] - 1) ]; - } - :set ($Return->$Key) (($Return->$Key), $ValX); - } while=($Last = false && $I + $Skip < $InLen); - :set Done true; - } - :if ($Done = false && $Val1 = ":[]") do={ - :set Skip 1; - :set ($Return->$Key) ({}); - :set Done true; - } - :if ($Done = false) do={ - :set Skip 1; - :set ($Return->$Key) [ :pick $Val1 1 [ :len $Val1 ] ]; - } - } - } - - :return $Return; -} - # parse key value store :set ParseKeyValueStore do={ :local Source $1; From 6f6840680359757838664b1ae5f38cc47e90e37a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 1 Apr 2024 23:40:09 +0200 Subject: [PATCH 2143/2612] mod/notification-matrix: add new configuration snippet... ... instead of appending to global-config-overlay. --- .../01-authenticate.avif | Bin 4209 -> 3870 bytes .../notification-matrix.d/02-join-room.avif | Bin 3955 -> 3745 bytes doc/mod/notification-matrix.md | 7 +++++-- mod/notification-matrix.rsc | 15 +++++++++------ 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/doc/mod/notification-matrix.d/01-authenticate.avif b/doc/mod/notification-matrix.d/01-authenticate.avif index 1db516b784b2779b1ab1054fcb149753b2c53dbf..b897943b1fc7d8c7c0ac6a9f225733d24dff9e37 100644 GIT binary patch delta 2829 zcmV+o3-a{wAf6tOdK3wf000Gz00IC2009610b2k72sV+9#{vz@lUD(N0;~tK*#Ub3 zf8bxk*LQNobem?QSjNg1WC-uim`wLe;=Ao zm+$o&BR}Z+GDP#I`p(N0lLR%2$wB9JUIv;PxZdxT$rGQgkUcrFkN@avpXd z;;c&ATAreA&nxo;q_^7s{-NsYW#)Gi^U6(b5B@ z=H64_hEz+4k^<6z9FnVs$;0HKe;nj<&r(hz!D(e`Zf|@uIn&(2R!!^)!Z2cACmWfR z;9ztfm4Ldoq_M{u>K9=nAfkzz3yfm}JYxeNN=bEHMtf0fHT~3<;9x}aF+e!u1mm#$ zg;SekM-2$8CjRz!^GRWGti8;B2WZdTFku2HQpA9~4a5LCXXQTiUe3o(e_yb&_!{x% z^Ajxdv5rH}7$+Df9eBV!tCO+UHE-=ZX%3}!%p^gUnT|j_1Cz+)@$P+T_d5QtZEWNI z)x8L@a0Ki*5;h6vlkfEOquMbnBoeZ3?|tgAH3&4{_(!F>xlteyr2biLrbp!D zbQm0xNL&uo?-JYEE}tZke|TEr!c}yS?FK?oLL#9U91>U(PjcS1%g29t70TR4cREg> zg_UF>fH}?&UUGjkQe0~KmD~mkoks3xOKvgAGcuFwf^nK$&ekbVikCIt-pYH@gRi082 z(zyYw>VoI(BT~E<8+Li3cHOr-v7F}_=N`06tm>1(@Xe`SNfUq>9(F3gX8?kE>VGII`)h|#)yCVy5<6`l^=YhcE*j3AIPWIEovzu$FA$jh{n$hf5&NM9i@zjrJz{TK4PF;h5!+g zpqw9GxjDn4iU260iU260iU260iU85kf8+800PC6lVz+AxMgIVg$NvDXXZecVpb!7q z5&#MbI3;p8*g!);q%!>qOvnV>gUn8L^U<9O&$%+0w`#KYA*%KrmdO!#yl1n5_^(n` zSEOf?f0Aid#mxDd`A%ziOmGlDunhQ<7iOxZMf|Cb4HIC4jK4`($}N%cPg< zZhYSED&D6~&M1|ihy(Ot9QH&{c2pfwc-{QsJ4lK@VuY7fA6|4-9xB))=XWxz&M8aQ5980Zz&1pa}*3t z6D@4vBG#V14{;mdJHW-kUWO0jdoc<890=;S40s?KDT2z2pt2vtT}7WE73~TlJDubG zomL4QbZOI8v)QIQtHXiqSF@Lp06DkO1z+b47dc~$+JV$G7zcWst`0M4+k124%Eqy; ze@<3ku?49z_!U{@c9+>&k|ssSAu$|uq$#3OB`rpi60N(~M*u&t!3O7w+)8ETdvWLYMwHV?$^UI z*x``4BN`!bC1G(e=sq-m(n852c{F-2j%>u(_s!V+pX*T7)W5DpYtE!(J60v;BFPY zCx4sA)yU!6@vT#9pE=;9;~dxF&6G+#3k0#OLM;sZKGhXwRyfhS7|Cx3v;9UGbIe-7 z>8B~!va$@2R@hlY|B~#G4MQ*j%0P0nG}q-FWT(+SH~rq9>)>-BPl&IX60o5 z-!)s9F@PHePbhw`e-}UrM}h8!$kAwQ*?r3z$Y}dS7lwo3W%Vns7INCse_xhT4edCA zZrpS;ASQ*71WC0tfFr>h;`2q$$NHIRX@yXU`Dvg?$Q~hbyIbZPI5d#0Dfy@r?i*U0 z+f&wz;gNZH`JG(?8sT=!GuCF!Fe)>lS<||BZj%hb&c}mf+H(cDj*g5Xhw%_7I(6l8 z9TAo;D3)@8e2weAo^LWURSN=$Mh`%gYyituUa zUkbPd`qX4JG9}NZ^&kt)k2|xCEMm%ZCe(pE0bOPx_52j4)AOk_qM^NBBl1uAX?hx% z5{Uh4-=sTLyKr%Ff8}Z<689gUBs;f=8PHACwlFz4%@)$IQC3!Y}@%}FicU)=qXk6)>_!W$GQdis6cJvK9d5MmwV`%jYyeBB!p00-|^mxFKM=-0hTYKimu2cpim3O!E;(j fO9X$sZ0tKx(FVvoX?{SiPU$5pd@nWyn2X;Cj2d3n delta 3171 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 L(XQ(=Q&YQu{cNRZ diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index 88628e4..92383be 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -70,6 +70,9 @@ and write first part of the configuration: ![authenticate](notification-matrix.d/01-authenticate.avif) +The configuration is written to a new configuration snippet +`global-config-overlay.d/mod/notification-matrix`. + #### Join Room Every Matix chat is a room, so we have to create one. Do that with your @@ -87,8 +90,8 @@ the invite. ![join room](notification-matrix.d/02-join-room.avif) -The settings have been appended to `global-config-overlay`. You may want to -edit to move it to an appropriate place. +The configuration is appended to the configuration snippet +`global-config-overlay.d/mod/notification-matrix`. Usage and invocation -------------------- diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 8234779..5a08146 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -217,12 +217,14 @@ } :do { - /system/script/set global-config-overlay source=([ get global-config-overlay source ] . "\n" . \ + /system/script/remove [ find where name="global-config-overlay.d/mod/notification-matrix" ]; + /system/script/add name="global-config-overlay.d/mod/notification-matrix" source=( \ + "# configuration snippet: mod/notification-matrix\n\n" . \ ":global MatrixHomeServer \"" . $MatrixHomeServer . "\";\n" . \ ":global MatrixAccessToken \"" . $MatrixAccessToken . "\";\n"); - $LogPrint info $0 ("Appended configuration to global-config-overlay. Now create and join a room, please!"); + $LogPrint info $0 ("Added configuration snippet. Now create and join a room, please!"); } on-error={ - $LogPrint error $0 ("Failed appending configuration to global-config-overlay!"); + $LogPrint error $0 ("Failed adding configuration snippet!"); :return false; } } @@ -250,11 +252,12 @@ } :do { - /system/script/set global-config-overlay source=([ get global-config-overlay source ] . "\n" . \ + :local Snippet [ /system/script/find where name="global-config-overlay.d/mod/notification-matrix" ]; + /system/script/set $Snippet source=([ get $Snippet source ] . \ ":global MatrixRoom \"" . $MatrixRoom . "\";\n"); - $LogPrint info $0 ("Appended configuration to global-config-overlay. Please review and cleanup!"); + $LogPrint info $0 ("Appended configuration to configuration snippet. Please review!"); } on-error={ - $LogPrint error $0 ("Failed appending configuration to global-config-overlay!"); + $LogPrint error $0 ("Failed appending configuration to snippet!"); :return false; } } From 444f56f9b44baf8a2553e2e475f796626c5da3ae Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 4 Apr 2024 19:09:00 +0200 Subject: [PATCH 2144/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index dff933b..20a1140 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -33,6 +33,7 @@ Add yourself to the list, * Andrea Ruffini Perico * Andrew Cox * Christoph Boss (@Kampfwurst) +* Daniel Ziegenberg (@ziegenberg) * Devin Dean (@dd2594gh) * Evaldo Gardenal * Giorgio Bikos From 1d8347d8ea0b4c16d4a3763e2f73c186da360a01 Mon Sep 17 00:00:00 2001 From: netravnen <1938389+netravnen@users.noreply.github.com> Date: Wed, 3 Apr 2024 18:11:36 +0000 Subject: [PATCH 2145/2612] README: add start-time & change interval in scheduler example Set the interval to once a day, Instead of every 1 hour. Add start-time to start-up. Thereby introducing randomization based on when the user last rebooted there device. As the interval is counted based on last boot time. --- README.d/11-schedule-script.avif | Bin 1847 -> 4113 bytes README.md | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.d/11-schedule-script.avif b/README.d/11-schedule-script.avif index 27541b75d69575591c432fe49b06da2b47a5ebf3..d6eb0f895d413232e27710b9a0ba2fae9e3d26c5 100644 GIT binary patch literal 4113 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 V659%C*l99!+jD6bz1FIc{x6~x&wc;^ delta 1600 zcmV-G2EX}{Ah!;XA_4&Nkt9JW9%*cEV*mgE07L))0RRC200031009~R00tcZ001ay zX>Mi!000000g;>?k?d&}1|@A|VRRAz3JEwRay-~TLqVi6jSQ2I2{3;oi|ja&nr%tA z3fh;(7tV^=51B3Lxt>LFq(F|Z|W_gRgBzG%sX4$_T zmXyO(Z5Q_XakN?V;!U#e$m_kW(F6nMDGL}MbJ*qz!U-`BV0Pk3alIj}&{O`$Vs^v^ z-=NRKLY4{W`msc2{3CyF2IY3I!+!^v!AUvI<9No1Rq$_*5u&SzoLUK$PUVKyMyfTj z_?F%=W9Kvq56Nxz^?GWKUq7KcG~X z181@h-vNbL&X4+Z>JJMQIkctNgAv4C9F$zUxcs}LU}pM8VXukYJg`u|5{FC9vt!Zs>L`DTAvo_qypKkWw=aUWVjamt z{PnM>TU9WHBK6QULfsO@#>Mm#${6BVY$>%Pr?V_aEt~mqZS}>rwfx@8Y(WMto?2n72M7yPt=8$tm7DC;eF3h=Wraz-;w zUA>dEcrHX-4cifjWTE@;5j39g&U`a!S@U})&FO!?K*ZxtJ?Cax8Q7NxUG0WYzF5PS zm_SFPMdR3$jUcfJnurYK8bXnS5v9k29@G{dD@65K5uPwzJ)`p;L#8Jmz1f?~-9*?wm7Y62tM=skFs3+r_o|;4BK03ed19tPwgxO#JH- z_bA9L%wJ#4%ye&ySykYg#l}5GC`1ORTC<9zcBnMB+&+~}@jFX=rvCa;diPy*KewbO z7%uGN9OU%jZniVPBs$^V6E~sd)>7cK0V2BFgsLvsEQ?pi17=tmn#N;Y!YW>!NqNPsIgf~*A#4zKE ziZkQ7@X!v?-en!zZYbp7bf{EV&4GmD{Er4?iFh)|q0^jEC6%4-e3#-5-AMSp2cLhn zK6zNRKX7?0RR;Dq`g#B-A&u%6`w0`4ny9m5-NL{IBIn3H(#HR^>e_*CTzcp=YMlDapgMPV)jWPhGBnk-~$Xw#WbK}?jT|h;{o;f(iz#`CLVB14RR_P9^ Date: Thu, 4 Apr 2024 19:10:55 +0200 Subject: [PATCH 2146/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 20a1140..f4056e5 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -21,6 +21,7 @@ for details! * [Ben Harris](mailto:mail@bharr.is) (@bharrisau) * [Daniel Ziegenberg](mailto:daniel@ziegenberg.at) (@ziegenberg) * [Michael Gisbers](mailto:michael@gisbers.de) (@mgisbers) +* @netravnen * [netztrip](mailto:dave-tvg@netztrip.de) (@netztrip) * [Stefan MÃŧller](mailto:stefan.mueller.83@gmail.com) (@PackElend) From 86d0f71acb760793c8ccd5320351320f684ce052 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 4 Apr 2024 21:14:17 +0200 Subject: [PATCH 2147/2612] README: update screenshot on lease script setup --- README.d/12-setup-lease-script.avif | Bin 1686 -> 7642 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/README.d/12-setup-lease-script.avif b/README.d/12-setup-lease-script.avif index 365e0e8d05470af99aef604d1ec24c292113d926..fb4024e2a730947774c6f165c7c5e3b191a4804c 100644 GIT binary patch literal 7642 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 Date: Wed, 27 Mar 2024 23:01:38 +0100 Subject: [PATCH 2148/2612] global-functions: introduce $FetchHuge --- README.md | 2 +- global-functions.rsc | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5109173..4516736 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ RouterOS Scripts [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/global-functions.rsc b/global-functions.rsc index e19ed65..bd35cdf 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # global functions # https://git.eworm.de/cgit/routeros-scripts/about/ @@ -32,6 +32,7 @@ :global DownloadPackage; :global EitherOr; :global EscapeForRegEx; +:global FetchHuge; :global FetchUserAgentStr; :global FormatLine; :global FormatMultiLines; @@ -389,6 +390,42 @@ :return $Return; } +# fetch huge data to file, read in chunks +:set FetchHuge do={ + :local ScriptName [ :tostr $1 ]; + :local Url [ :tostr $2 ]; + + :global GetRandom20CharAlNum; + :global LogPrint; + :global MkDir; + :global WaitForFile; + + :if ([ $MkDir "tmpfs/" . $ScriptName ] = false) do={ + $LogPrint error $0 ("Failed creating directory!"); + :return false; + } + + :local FileName ("tmpfs/" . $ScriptName . "/" . $0 . "-" . [ $GetRandom20CharAlNum ]); + + :do { + /tool/fetch check-certificate=yes-without-crl $Url dst-path=$FileName as-value; + } on-error={ + $LogPrint debug $0 ("Failed downloading from: " . $Url); + :return false; + } + $WaitForFile $FileName; + + :local FileSize [ /file/get $FileName size ]; + :local Return ""; + :local VarSize 0; + :while ($VarSize < $FileSize) do={ + :set Return ($Return . ([ /file/read offset=$VarSize chunk-size=32768 file=$FileName as-value ]->"data")); + :set VarSize [ :len $Return ]; + } + /file/remove $FileName; + :return $Return; +} + # generate user agent string for fetch :set FetchUserAgentStr do={ :local Caller [ :tostr $1 ]; From ab6fd8855881681d7c69af3e5ce18b3a6e2e69fb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 27 Mar 2024 23:37:31 +0100 Subject: [PATCH 2149/2612] global-functions: $FetchHuge: use custom user agent string --- global-functions.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index bd35cdf..0ea7120 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -395,6 +395,7 @@ :local ScriptName [ :tostr $1 ]; :local Url [ :tostr $2 ]; + :global FetchUserAgentStr; :global GetRandom20CharAlNum; :global LogPrint; :global MkDir; @@ -408,7 +409,8 @@ :local FileName ("tmpfs/" . $ScriptName . "/" . $0 . "-" . [ $GetRandom20CharAlNum ]); :do { - /tool/fetch check-certificate=yes-without-crl $Url dst-path=$FileName as-value; + /tool/fetch check-certificate=yes-without-crl $Url dst-path=$FileName \ + http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) as-value; } on-error={ $LogPrint debug $0 ("Failed downloading from: " . $Url); :return false; From 2edf983698a18d45de1c9e7823dad0959bff2504 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 27 Mar 2024 23:35:01 +0100 Subject: [PATCH 2150/2612] global-functions: $FetchHuge: control check-certificate with parameter --- global-functions.rsc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 0ea7120..65dd06e 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -392,15 +392,19 @@ # fetch huge data to file, read in chunks :set FetchHuge do={ - :local ScriptName [ :tostr $1 ]; - :local Url [ :tostr $2 ]; + :local ScriptName [ :tostr $1 ]; + :local Url [ :tostr $2 ]; + :local CheckCert [ :tobool $3 ]; :global FetchUserAgentStr; :global GetRandom20CharAlNum; + :global IfThenElse; :global LogPrint; :global MkDir; :global WaitForFile; + :set CheckCert [ $IfThenElse ($CheckCert = false) "no" "yes-without-crl" ]; + :if ([ $MkDir "tmpfs/" . $ScriptName ] = false) do={ $LogPrint error $0 ("Failed creating directory!"); :return false; @@ -409,7 +413,7 @@ :local FileName ("tmpfs/" . $ScriptName . "/" . $0 . "-" . [ $GetRandom20CharAlNum ]); :do { - /tool/fetch check-certificate=yes-without-crl $Url dst-path=$FileName \ + /tool/fetch check-certificate=$CheckCert $Url dst-path=$FileName \ http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) as-value; } on-error={ $LogPrint debug $0 ("Failed downloading from: " . $Url); From 61ee5cbd6cbce28385857f9cca184387234fe326 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 3 Apr 2024 17:03:27 +0200 Subject: [PATCH 2151/2612] global-functions: $FetchHuge: make sure to work with clean file names --- global-functions.rsc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 65dd06e..3c14f22 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -396,6 +396,7 @@ :local Url [ :tostr $2 ]; :local CheckCert [ :tobool $3 ]; + :global CleanName; :global FetchUserAgentStr; :global GetRandom20CharAlNum; :global IfThenElse; @@ -405,13 +406,13 @@ :set CheckCert [ $IfThenElse ($CheckCert = false) "no" "yes-without-crl" ]; - :if ([ $MkDir "tmpfs/" . $ScriptName ] = false) do={ + :local FileName ("tmpfs/" . [ $CleanName $ScriptName ]); + :if ([ $MkDir $FileName ] = false) do={ $LogPrint error $0 ("Failed creating directory!"); :return false; } - :local FileName ("tmpfs/" . $ScriptName . "/" . $0 . "-" . [ $GetRandom20CharAlNum ]); - + :set FileName ($FileName . "/" . [ $CleanName $0 ] . "-" . [ $GetRandom20CharAlNum ]); :do { /tool/fetch check-certificate=$CheckCert $Url dst-path=$FileName \ http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) as-value; From 402f847db2b7446a67634d3720d824a7e6b87e71 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 3 Apr 2024 17:36:47 +0200 Subject: [PATCH 2152/2612] global-functions: $FetchHuge: remove file on failed download --- global-functions.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 3c14f22..ab8860f 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -417,6 +417,9 @@ /tool/fetch check-certificate=$CheckCert $Url dst-path=$FileName \ http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) as-value; } on-error={ + :if ([ $WaitForFile $FileName 500ms ] = true) do={ + /file/remove $FileName; + } $LogPrint debug $0 ("Failed downloading from: " . $Url); :return false; } From c3809f240d292e80c936e104e8aa9414b3dd3367 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 27 Mar 2024 23:39:55 +0100 Subject: [PATCH 2153/2612] fw-addr-lists: use $FetchHuge --- doc/fw-addr-lists.md | 6 +++++- fw-addr-lists.rsc | 18 ++++++------------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md index 70ca6e9..ac34c88 100644 --- a/doc/fw-addr-lists.md +++ b/doc/fw-addr-lists.md @@ -4,7 +4,7 @@ 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/) +[![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) @@ -29,6 +29,10 @@ see situation when the lists are not populated. To mitigate man-in-the-middle attacks with altered lists the server's certificate is checked. +> âš ī¸ **Warning**: The script does not limit the size of a list, but keep in +> mind that huge lists can exhaust your device's resources (RAM and CPU), +> and may take a long time to process. + Requirements and installation ----------------------------- diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 68775b4..66f8581 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2023-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # download, import and update firewall address-lists # https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md @@ -19,7 +19,7 @@ :global CertificateAvailable; :global EitherOr; - :global FetchUserAgentStr; + :global FetchHuge; :global LogPrint; :global LogPrintOnce; :global ScriptLock; @@ -50,12 +50,12 @@ :local Failure false; :foreach List in=$FwList do={ - :local CheckCertificate "no"; + :local CheckCertificate false; :local Data false; :local TimeOut [ $EitherOr [ :totime ($List->"timeout") ] $FwAddrListTimeOut ]; :if ([ :len ($List->"cert") ] > 0) do={ - :set CheckCertificate "yes-without-crl"; + :set CheckCertificate true; :if ([ $CertificateAvailable ($List->"cert") ] = false) do={ $LogPrint warning $ScriptName ("Downloading required certificate failed, trying anyway."); } @@ -63,10 +63,8 @@ :for I from=1 to=5 do={ :if ($Data = false) do={ - :do { - :set Data ([ /tool/fetch check-certificate=$CheckCertificate output=user \ - http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) ($List->"url") as-value ]->"data"); - } on-error={ + :set Data [ $FetchHuge $ScriptName ($List->"url") $CheckCertificate ]; + :if ($Data = false) do={ :if ($I < 5) do={ $LogPrint debug $ScriptName ("Failed downloading, " . $I . ". try: " . $List->"url"); :delay (($I * $I) . "s"); @@ -81,10 +79,6 @@ $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")); From 4b6d0c02f134f4c6535d4df44016dc9ae2ae5db2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 5 Apr 2024 00:20:33 +0200 Subject: [PATCH 2154/2612] fw-addr-lists: try with less regexp matches --- fw-addr-lists.rsc | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 66f8581..7e7ee38 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -82,14 +82,21 @@ :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; - } + :do { + :if ($Address ~ "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(/[0-9]{1,2})?\$") do={ + :set ($IPv4Addresses->$Address) $TimeOut; + :error true; + } + :if ($Address ~ "^[0-9a-zA-Z]*:[0-9a-zA-Z:\\.]+(/[0-9]{1,3})?\$") do={ + :set ($IPv6Addresses->$Address) $TimeOut; + :error true; + } + :if ($Address ~ "^[\\.a-zA-Z0-9-]+\\.[a-zA-Z]{2,}\$") do={ + :set ($IPv4Addresses->$Address) $TimeOut; + :set ($IPv6Addresses->$Address) $TimeOut; + :error true; + } + } on-error={ } :set Data [ :pick $Data ([ :len $Line ] + 1) [ :len $Data ] ]; } } From af6556bdba9d68174b45561215ea3be2e098e349 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 4 Apr 2024 19:37:38 +0200 Subject: [PATCH 2155/2612] fw-addr-lists: add debug message on successful download --- fw-addr-lists.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 7e7ee38..5cdd379 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -20,6 +20,7 @@ :global CertificateAvailable; :global EitherOr; :global FetchHuge; + :global HumanReadableNum; :global LogPrint; :global LogPrintOnce; :global ScriptLock; @@ -77,6 +78,8 @@ :set Data ""; :set Failure true; $LogPrint warning $ScriptName ("Failed downloading list from: " . $List->"url"); + } else={ + $LogPrint debug $ScriptName ("Downloaded " . [ $HumanReadableNum [ :len $Data ] 1024 ] . "B from: " . $List->"url"); } :while ([ :len $Data ] != 0) do={ From 70cc1ff53b7d113f8aff24034e5f5a25efb8b261 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 5 Apr 2024 23:41:17 +0200 Subject: [PATCH 2156/2612] fw-addr-lists: rework log messages, always include list name --- fw-addr-lists.rsc | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 5cdd379..c9f894b 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -58,7 +58,8 @@ :if ([ :len ($List->"cert") ] > 0) do={ :set CheckCertificate true; :if ([ $CertificateAvailable ($List->"cert") ] = false) do={ - $LogPrint warning $ScriptName ("Downloading required certificate failed, trying anyway."); + $LogPrint warning $ScriptName ("Downloading required certificate (" . $FwListName . \ + " / " . $List->"url" . ") failed, trying anyway."); } } @@ -67,7 +68,8 @@ :set Data [ $FetchHuge $ScriptName ($List->"url") $CheckCertificate ]; :if ($Data = false) do={ :if ($I < 5) do={ - $LogPrint debug $ScriptName ("Failed downloading, " . $I . ". try: " . $List->"url"); + $LogPrint debug $ScriptName ("Failed downloading for list '" . $FwListName . \ + "', " . $I . ". try from: " . $List->"url"); :delay (($I * $I) . "s"); } } @@ -77,9 +79,11 @@ :if ($Data = false) do={ :set Data ""; :set Failure true; - $LogPrint warning $ScriptName ("Failed downloading list from: " . $List->"url"); + $LogPrint warning $ScriptName ("Failed downloading for list '" . $FwListName . \ + "' from: " . $List->"url"); } else={ - $LogPrint debug $ScriptName ("Downloaded " . [ $HumanReadableNum [ :len $Data ] 1024 ] . "B from: " . $List->"url"); + $LogPrint debug $ScriptName ("Downloaded " . [ $HumanReadableNum [ :len $Data ] 1024 ] . \ + "B for list '" . $FwListName . "' from: " . $List->"url"); } :while ([ :len $Data ] != 0) do={ @@ -107,13 +111,15 @@ :foreach Entry in=[ /ip/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={ :local Address [ /ip/firewall/address-list/get $Entry address ]; :if ([ :typeof ($IPv4Addresses->$Address) ] = "time") do={ - $LogPrint debug $ScriptName ("Renewing IPv4 address for " . ($IPv4Addresses->$Address) . ": " . $Address); + $LogPrint debug $ScriptName ("Renewing IPv4 address in list '" . $FwListName . \ + "' with " . ($IPv4Addresses->$Address) . ": " . $Address); /ip/firewall/address-list/set $Entry timeout=($IPv4Addresses->$Address); :set ($IPv4Addresses->$Address); :set CntRenew ($CntRenew + 1); } else={ :if ($Failure = false) do={ - $LogPrint debug $ScriptName ("Removing IPv4 address: " . $Address); + $LogPrint debug $ScriptName ("Removing IPv4 address from list '" . $FwListName . \ + "': " . $Address); /ip/firewall/address-list/remove $Entry; :set CntRemove ($CntRemove + 1); } @@ -123,13 +129,15 @@ :foreach Entry in=[ /ipv6/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={ :local Address [ /ipv6/firewall/address-list/get $Entry address ]; :if ([ :typeof ($IPv6Addresses->$Address) ] = "time") do={ - $LogPrint debug $ScriptName ("Renewing IPv6 address for " . ($IPv6Addresses->$Address) . ": " . $Address); + $LogPrint debug $ScriptName ("Renewing IPv6 address in list '" . $FwListName . \ + "' with " . ($IPv6Addresses->$Address) . ": " . $Address); /ipv6/firewall/address-list/set $Entry timeout=($IPv6Addresses->$Address); :set ($IPv6Addresses->$Address); :set CntRenew ($CntRenew + 1); } else={ :if ($Failure = false) do={ - $LogPrint debug $ScriptName ("Removing: " . $Address); + $LogPrint debug $ScriptName ("Removing IPv6 address from list '" . $FwListName . \ + "': " . $Address); /ipv6/firewall/address-list/remove $Entry; :set CntRemove ($CntRemove + 1); } @@ -137,27 +145,32 @@ } :foreach Address,Timeout in=$IPv4Addresses do={ - $LogPrint debug $ScriptName ("Adding IPv4 address for " . $Timeout . ": " . $Address); + $LogPrint debug $ScriptName ("Adding IPv4 address to list '" . $FwListName . \ + "' with " . $Timeout . ": " . $Address); :do { /ip/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout; :set ($IPv4Addresses->$Address); :set CntAdd ($CntAdd + 1); } on-error={ - $LogPrint warning $ScriptName ("Failed to add IPv4 address " . $Address . " to list '" . $FwListName . "'."); + $LogPrint warning $ScriptName ("Failed to add IPv4 address to list '" . $FwListName . \ + "': " . $Address); } } :foreach Address,Timeout in=$IPv6Addresses do={ - $LogPrint debug $ScriptName ("Adding IPv6 address for " . $Timeout . ": " . $Address); + $LogPrint debug $ScriptName ("Adding IPv6 address to list '" . $FwListName . \ + "' with " . $Timeout . ": " . $Address); :do { /ipv6/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout; :set ($IPv6Addresses->$Address); :set CntAdd ($CntAdd + 1); } on-error={ - $LogPrint warning $ScriptName ("Failed to add IPv6 address " . $Address . " to list '" . $FwListName . "'."); + $LogPrint warning $ScriptName ("Failed to add IPv6 address to list '" . $FwListName . \ + "': " . $Address); } } - $LogPrint info $ScriptName ("list: " . $FwListName . " -- added: " . $CntAdd . " - renewed: " . $CntRenew . " - removed: " . $CntRemove); + $LogPrint info $ScriptName ("list: " . $FwListName . " -- added: " . $CntAdd . \ + " - renewed: " . $CntRenew . " - removed: " . $CntRemove); } } on-error={ } From 491d85000d607db09b7abd67d6002c9ca1a870f2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 7 Apr 2024 20:54:41 +0200 Subject: [PATCH 2157/2612] fw-addr-lists: human readable numbers for counts --- fw-addr-lists.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index c9f894b..15d292e 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -170,7 +170,9 @@ } } - $LogPrint info $ScriptName ("list: " . $FwListName . " -- added: " . $CntAdd . \ - " - renewed: " . $CntRenew . " - removed: " . $CntRemove); + $LogPrint info $ScriptName ("list: " . $FwListName . \ + " -- added: " . [ $HumanReadableNum $CntAdd 1000 ] . \ + " - renewed: " . [ $HumanReadableNum $CntRenew 1000 ] . \ + " - removed: " . [ $HumanReadableNum $CntRemove 1000 ]); } } on-error={ } From 19c52ed2a7a59c7ecfb472a9f0bbf4843fc5d713 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 7 Apr 2024 22:50:04 +0200 Subject: [PATCH 2158/2612] fw-addr-lists: show count of active addresses --- fw-addr-lists.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 15d292e..ab417cd 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -171,6 +171,7 @@ } $LogPrint info $ScriptName ("list: " . $FwListName . \ + " (" . [ $HumanReadableNum ($CntAdd + $CntRenew) 1000 ] . ")" . \ " -- added: " . [ $HumanReadableNum $CntAdd 1000 ] . \ " - renewed: " . [ $HumanReadableNum $CntRenew 1000 ] . \ " - removed: " . [ $HumanReadableNum $CntRemove 1000 ]); From c4d2ea19dda3434c92f604605c1d3f06ec8148c2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 5 Apr 2024 23:53:05 +0200 Subject: [PATCH 2159/2612] fw-addr-lists: break long lines --- fw-addr-lists.rsc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index ab417cd..007282c 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -108,7 +108,8 @@ } } - :foreach Entry in=[ /ip/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={ + :foreach Entry in=[ /ip/firewall/address-list/find where \ + list=$FwListName comment=$ListComment ] do={ :local Address [ /ip/firewall/address-list/get $Entry address ]; :if ([ :typeof ($IPv4Addresses->$Address) ] = "time") do={ $LogPrint debug $ScriptName ("Renewing IPv4 address in list '" . $FwListName . \ @@ -126,7 +127,8 @@ } } - :foreach Entry in=[ /ipv6/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={ + :foreach Entry in=[ /ipv6/firewall/address-list/find where \ + list=$FwListName comment=$ListComment ] do={ :local Address [ /ipv6/firewall/address-list/get $Entry address ]; :if ([ :typeof ($IPv6Addresses->$Address) ] = "time") do={ $LogPrint debug $ScriptName ("Renewing IPv6 address in list '" . $FwListName . \ @@ -148,7 +150,8 @@ $LogPrint debug $ScriptName ("Adding IPv4 address to list '" . $FwListName . \ "' with " . $Timeout . ": " . $Address); :do { - /ip/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout; + /ip/firewall/address-list/add list=$FwListName comment=$ListComment \ + address=$Address timeout=$Timeout; :set ($IPv4Addresses->$Address); :set CntAdd ($CntAdd + 1); } on-error={ @@ -161,7 +164,8 @@ $LogPrint debug $ScriptName ("Adding IPv6 address to list '" . $FwListName . \ "' with " . $Timeout . ": " . $Address); :do { - /ipv6/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout; + /ipv6/firewall/address-list/add list=$FwListName comment=$ListComment \ + address=$Address timeout=$Timeout; :set ($IPv6Addresses->$Address); :set CntAdd ($CntAdd + 1); } on-error={ From 009674b5bcf27589cd3469bc418dea72c9b4e979 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 4 Apr 2024 21:45:02 +0200 Subject: [PATCH 2160/2612] bump RouterOS requirement for all scripts and modules... ... now that global-functions requires RouterOS 7.13 anyway. --- BRANCHES.md | 2 +- CONTRIBUTIONS.md | 2 +- INITIAL-COMMANDS.md | 2 +- accesslist-duplicates.capsman.rsc | 2 +- accesslist-duplicates.local.rsc | 2 +- accesslist-duplicates.template.rsc | 2 +- accesslist-duplicates.wifi.rsc | 2 +- backup-cloud.rsc | 2 +- backup-email.rsc | 2 +- backup-partition.rsc | 2 +- backup-upload.rsc | 2 +- capsman-download-packages.capsman.rsc | 2 +- capsman-download-packages.template.rsc | 2 +- capsman-download-packages.wifi.rsc | 2 +- capsman-rolling-upgrade.capsman.rsc | 2 +- capsman-rolling-upgrade.template.rsc | 2 +- capsman-rolling-upgrade.wifi.rsc | 2 +- certificate-renew-issued.rsc | 2 +- check-certificates.rsc | 2 +- check-health.rsc | 2 +- check-lte-firmware-upgrade.rsc | 2 +- check-routeros-update.rsc | 2 +- collect-wireless-mac.capsman.rsc | 2 +- collect-wireless-mac.local.rsc | 2 +- collect-wireless-mac.template.rsc | 2 +- collect-wireless-mac.wifi.rsc | 2 +- daily-psk.capsman.rsc | 2 +- daily-psk.local.rsc | 2 +- daily-psk.template.rsc | 2 +- daily-psk.wifi.rsc | 2 +- dhcp-lease-comment.capsman.rsc | 2 +- dhcp-lease-comment.local.rsc | 2 +- dhcp-lease-comment.template.rsc | 2 +- dhcp-lease-comment.wifi.rsc | 2 +- dhcp-to-dns.rsc | 2 +- doc/accesslist-duplicates.md | 2 +- doc/backup-cloud.md | 2 +- doc/backup-email.md | 2 +- doc/backup-partition.md | 2 +- doc/backup-upload.md | 2 +- doc/capsman-download-packages.md | 2 +- doc/capsman-rolling-upgrade.md | 2 +- doc/certificate-renew-issued.md | 2 +- doc/check-certificates.md | 2 +- doc/check-health.md | 2 +- doc/check-lte-firmware-upgrade.md | 2 +- doc/check-routeros-update.md | 2 +- doc/collect-wireless-mac.md | 2 +- doc/daily-psk.md | 2 +- doc/dhcp-lease-comment.md | 2 +- doc/dhcp-to-dns.md | 2 +- doc/firmware-upgrade-reboot.md | 2 +- doc/global-wait.md | 2 +- doc/gps-track.md | 2 +- doc/hotspot-to-wpa.md | 2 +- doc/ip-addr-bridge.md | 2 +- doc/ipsec-to-dns.md | 2 +- doc/ipv6-update.md | 2 +- doc/lease-script.md | 2 +- doc/leds-mode.md | 2 +- doc/log-forward.md | 2 +- doc/mod/bridge-port-to.md | 2 +- doc/mod/bridge-port-vlan.md | 2 +- doc/mod/inspectvar.md | 2 +- doc/mod/ipcalc.md | 2 +- doc/mod/notification-email.md | 2 +- doc/mod/notification-ntfy.md | 2 +- doc/mod/scriptrunonce.md | 2 +- doc/mod/ssh-keys-import.md | 2 +- doc/mode-button.md | 2 +- doc/netwatch-dns.md | 2 +- doc/netwatch-notify.md | 2 +- doc/ospf-to-leds.md | 2 +- doc/ppp-on-up.md | 2 +- doc/sms-action.md | 2 +- doc/sms-forward.md | 2 +- doc/super-mario-theme.md | 2 +- doc/unattended-lte-firmware-upgrade.md | 2 +- doc/update-gre-address.md | 2 +- doc/update-tunnelbroker.md | 2 +- firmware-upgrade-reboot.rsc | 2 +- global-wait.rsc | 2 +- gps-track.rsc | 2 +- hotspot-to-wpa-cleanup.capsman.rsc | 2 +- hotspot-to-wpa-cleanup.template.rsc | 2 +- hotspot-to-wpa-cleanup.wifi.rsc | 2 +- hotspot-to-wpa.capsman.rsc | 2 +- hotspot-to-wpa.template.rsc | 2 +- hotspot-to-wpa.wifi.rsc | 2 +- ipsec-to-dns.rsc | 2 +- ipv6-update.rsc | 2 +- lease-script.rsc | 2 +- log-forward.rsc | 2 +- mod/bridge-port-to.rsc | 2 ++ mod/bridge-port-vlan.rsc | 2 ++ mod/inspectvar.rsc | 2 ++ mod/ipcalc.rsc | 2 ++ mod/notification-email.rsc | 2 +- mod/notification-ntfy.rsc | 2 ++ mod/scriptrunonce.rsc | 2 ++ mod/ssh-keys-import.rsc | 2 +- mode-button.rsc | 2 +- netwatch-dns.rsc | 2 +- netwatch-notify.rsc | 2 +- ospf-to-leds.rsc | 2 +- ppp-on-up.rsc | 2 +- sms-action.rsc | 2 +- sms-forward.rsc | 2 +- update-gre-address.rsc | 2 +- update-tunnelbroker.rsc | 2 +- 110 files changed, 116 insertions(+), 104 deletions(-) diff --git a/BRANCHES.md b/BRANCHES.md index 0fdbdb4..f1062bb 100644 --- a/BRANCHES.md +++ b/BRANCHES.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index f4056e5..13d0508 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 0de50ae..0320fe8 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index 2ce8302..781ae78 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index 51ef6f3..b79a724 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index 770fb30..b8067c8 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc index 65f8aaa..c05e02c 100644 --- a/accesslist-duplicates.wifi.rsc +++ b/accesslist-duplicates.wifi.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/backup-cloud.rsc b/backup-cloud.rsc index cccb41b..9a062f2 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=40 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # upload backup to MikroTik cloud # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md diff --git a/backup-email.rsc b/backup-email.rsc index 64ca69c..c32eb27 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=20 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # create and email backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md diff --git a/backup-partition.rsc b/backup-partition.rsc index 503d382..fc186c0 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=70 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # save configuration to fallback partition # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md diff --git a/backup-upload.rsc b/backup-upload.rsc index ef5b7c7..18223bb 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=50 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # create and upload backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index a3bd4a5..f5695f4 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # download and cleanup packages for CAP installation from CAPsMAN # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index cad3bcb..762dbb6 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # download and cleanup packages for CAP installation from CAPsMAN # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 909688f..79aa9a7 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # download and cleanup packages for CAP installation from CAPsMAN # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc index 11bfd69..2c9ae3d 100644 --- a/capsman-rolling-upgrade.capsman.rsc +++ b/capsman-rolling-upgrade.capsman.rsc @@ -5,7 +5,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: capsman-rolling-upgrade -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # upgrade CAPs one after another # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index e0effd4..2098bc0 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -5,7 +5,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: capsman-rolling-upgrade -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # upgrade CAPs one after another # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc index 8ec6f26..36b8c0f 100644 --- a/capsman-rolling-upgrade.wifi.rsc +++ b/capsman-rolling-upgrade.wifi.rsc @@ -5,7 +5,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: capsman-rolling-upgrade -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # upgrade CAPs one after another # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc index 45805c5..77ed3d0 100644 --- a/certificate-renew-issued.rsc +++ b/certificate-renew-issued.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # renew locally issued certificates # https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md diff --git a/check-certificates.rsc b/check-certificates.rsc index 20e2902..e9235f1 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # check for certificate validity # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md diff --git a/check-health.rsc b/check-health.rsc index 2a97ad6..1e8fcc0 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # check for RouterOS health state # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index e7f06f3..3a25f83 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # check for LTE firmware upgrade, send notification # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index c9ab93b..6dca99a 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # check for RouterOS update, send notification and/or install # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index dcb303c..74c0754 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index 7c1122c..8a60fea 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index b8c5ff8..c5cf74a 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc index b8ad939..12c3361 100644 --- a/collect-wireless-mac.wifi.rsc +++ b/collect-wireless-mac.wifi.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index 43651d0..64e8ce7 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 2dbc61b..48e2b8d 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index e190ffb..5097b00 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index ee3e1b0..9d7f285 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc index 4ac228b..b7f3589 100644 --- a/dhcp-lease-comment.capsman.rsc +++ b/dhcp-lease-comment.capsman.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc index a49f74f..e35bbe7 100644 --- a/dhcp-lease-comment.local.rsc +++ b/dhcp-lease-comment.local.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index 0f0975b..d4323ad 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc index c9c091b..f67ce6e 100644 --- a/dhcp-lease-comment.wifi.rsc +++ b/dhcp-lease-comment.wifi.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 5b6e64a..a3d41c9 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=20 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # check DHCP leases and add/remove/update DNS entries # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index 109bebf..a1f9198 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -4,7 +4,7 @@ Find and remove access list duplicates [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index 03d5953..be6e06d 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/backup-email.md b/doc/backup-email.md index 56b0540..a506543 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/backup-partition.md b/doc/backup-partition.md index e2ca8e0..ba20657 100644 --- a/doc/backup-partition.md +++ b/doc/backup-partition.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/backup-upload.md b/doc/backup-upload.md index 953ac93..f524adb 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index 20fb007..c68900e 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -4,7 +4,7 @@ Download packages for CAP upgrade from CAPsMAN [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index 8362794..27d855f 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -4,7 +4,7 @@ Run rolling CAP upgrades from CAPsMAN [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/certificate-renew-issued.md b/doc/certificate-renew-issued.md index 2df8be3..91a1914 100644 --- a/doc/certificate-renew-issued.md +++ b/doc/certificate-renew-issued.md @@ -4,7 +4,7 @@ Renew locally issued certificates [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 62b9ceb..636f719 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -4,7 +4,7 @@ Renew certificates and notify on expiration [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/check-health.md b/doc/check-health.md index ee52b61..f94a0bf 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index bec3177..59a62c7 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -4,7 +4,7 @@ Notify on LTE firmware upgrade [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index dbb2b89..f9d485c 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -4,7 +4,7 @@ Notify on RouterOS update [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index b0a2298..57032d8 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -4,7 +4,7 @@ Collect MAC addresses in wireless access list [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/daily-psk.md b/doc/daily-psk.md index f723617..3894d52 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -4,7 +4,7 @@ Use wireless network with daily psk [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/dhcp-lease-comment.md b/doc/dhcp-lease-comment.md index 4831b8c..f95b124 100644 --- a/doc/dhcp-lease-comment.md +++ b/doc/dhcp-lease-comment.md @@ -4,7 +4,7 @@ Comment DHCP leases with info from access list [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index e7f3b88..13d5ef3 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/firmware-upgrade-reboot.md b/doc/firmware-upgrade-reboot.md index 420dfe1..bac17a7 100644 --- a/doc/firmware-upgrade-reboot.md +++ b/doc/firmware-upgrade-reboot.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/global-wait.md b/doc/global-wait.md index a3fe6d6..4b42717 100644 --- a/doc/global-wait.md +++ b/doc/global-wait.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/gps-track.md b/doc/gps-track.md index 03f79a7..7006fb3 100644 --- a/doc/gps-track.md +++ b/doc/gps-track.md @@ -4,7 +4,7 @@ Send GPS position to server [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index 6ce4421..275fe4d 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/ip-addr-bridge.md b/doc/ip-addr-bridge.md index 8bb9811..941a8ae 100644 --- a/doc/ip-addr-bridge.md +++ b/doc/ip-addr-bridge.md @@ -4,7 +4,7 @@ Manage IP addresses with bridge status [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/ipsec-to-dns.md b/doc/ipsec-to-dns.md index ca5b86c..0a91960 100644 --- a/doc/ipsec-to-dns.md +++ b/doc/ipsec-to-dns.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md index a5661fc..20265fe 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/lease-script.md b/doc/lease-script.md index f346621..4d2f3bc 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/leds-mode.md b/doc/leds-mode.md index 5dd5f63..90ea418 100644 --- a/doc/leds-mode.md +++ b/doc/leds-mode.md @@ -4,7 +4,7 @@ Manage LEDs dark mode [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/log-forward.md b/doc/log-forward.md index 4183d7b..44409dc 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/mod/bridge-port-to.md b/doc/mod/bridge-port-to.md index 838d1e0..5c8bebc 100644 --- a/doc/mod/bridge-port-to.md +++ b/doc/mod/bridge-port-to.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/mod/bridge-port-vlan.md b/doc/mod/bridge-port-vlan.md index 5660b9d..d23d5b5 100644 --- a/doc/mod/bridge-port-vlan.md +++ b/doc/mod/bridge-port-vlan.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/mod/inspectvar.md b/doc/mod/inspectvar.md index 7ec74f2..d4e59b3 100644 --- a/doc/mod/inspectvar.md +++ b/doc/mod/inspectvar.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/mod/ipcalc.md b/doc/mod/ipcalc.md index 5b24952..cb655bc 100644 --- a/doc/mod/ipcalc.md +++ b/doc/mod/ipcalc.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/mod/notification-email.md b/doc/mod/notification-email.md index 76816c1..2138e31 100644 --- a/doc/mod/notification-email.md +++ b/doc/mod/notification-email.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/mod/notification-ntfy.md b/doc/mod/notification-ntfy.md index a3fdf88..afa3109 100644 --- a/doc/mod/notification-ntfy.md +++ b/doc/mod/notification-ntfy.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/mod/scriptrunonce.md b/doc/mod/scriptrunonce.md index 6619efb..c5fa891 100644 --- a/doc/mod/scriptrunonce.md +++ b/doc/mod/scriptrunonce.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md index 3d81566..db8e322 100644 --- a/doc/mod/ssh-keys-import.md +++ b/doc/mod/ssh-keys-import.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/mode-button.md b/doc/mode-button.md index 22ec215..8734352 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -4,7 +4,7 @@ Mode button with multiple presses [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index e00ccd0..443106f 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 806bb3a..90cd830 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -4,7 +4,7 @@ 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/) +[![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) diff --git a/doc/ospf-to-leds.md b/doc/ospf-to-leds.md index a7d4e9a..121f77b 100644 --- a/doc/ospf-to-leds.md +++ b/doc/ospf-to-leds.md @@ -4,7 +4,7 @@ Visualize OSPF state via LEDs [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/ppp-on-up.md b/doc/ppp-on-up.md index 418f05e..21847c7 100644 --- a/doc/ppp-on-up.md +++ b/doc/ppp-on-up.md @@ -4,7 +4,7 @@ Run scripts on ppp connection [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/sms-action.md b/doc/sms-action.md index 18ca574..b4678af 100644 --- a/doc/sms-action.md +++ b/doc/sms-action.md @@ -4,7 +4,7 @@ Act on received SMS [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 2fe9486..597410b 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -4,7 +4,7 @@ Forward received SMS [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/super-mario-theme.md b/doc/super-mario-theme.md index ec59b39..e4bae2e 100644 --- a/doc/super-mario-theme.md +++ b/doc/super-mario-theme.md @@ -4,7 +4,7 @@ Play Super Mario theme [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/unattended-lte-firmware-upgrade.md b/doc/unattended-lte-firmware-upgrade.md index a6bf994..6680447 100644 --- a/doc/unattended-lte-firmware-upgrade.md +++ b/doc/unattended-lte-firmware-upgrade.md @@ -4,7 +4,7 @@ Install LTE firmware upgrade [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/update-gre-address.md b/doc/update-gre-address.md index fba2a65..80902b9 100644 --- a/doc/update-gre-address.md +++ b/doc/update-gre-address.md @@ -4,7 +4,7 @@ Update GRE configuration with dynamic addresses [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/doc/update-tunnelbroker.md b/doc/update-tunnelbroker.md index 5aca581..2539e2f 100644 --- a/doc/update-tunnelbroker.md +++ b/doc/update-tunnelbroker.md @@ -4,7 +4,7 @@ Update tunnelbroker configuration [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.12-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![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) diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc index 038f74e..169a2e0 100644 --- a/firmware-upgrade-reboot.rsc +++ b/firmware-upgrade-reboot.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2022-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # install firmware upgrade, and reboot # https://git.eworm.de/cgit/routeros-scripts/about/doc/firmware-upgrade-reboot.md diff --git a/global-wait.rsc b/global-wait.rsc index f8c767b..239f575 100644 --- a/global-wait.rsc +++ b/global-wait.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # wait for global-functions to finish # https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md diff --git a/gps-track.rsc b/gps-track.rsc index 1aeab84..dbca38a 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # track gps data by sending json data to http server # https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index 0540ad5..8f55d71 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 6f3b3e1..7ac996c 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index 9c79628..39c9f25 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index 37c8464..113c95d 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # add private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index cbce42a..10f0c7e 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # add private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index 86aeed7..dbf50e0 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # add private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index dd40ca2..8894eee 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2021-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # and add/remove/update DNS entries from IPSec mode-config # https://git.eworm.de/cgit/routeros-scripts/about/doc/ipsec-to-dns.md diff --git a/ipv6-update.rsc b/ipv6-update.rsc index 65bb959..ec9a03a 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # update firewall and dns settings on IPv6 prefix change # https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md diff --git a/lease-script.rsc b/lease-script.rsc index 8e1e8f6..a9d4b68 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # run scripts on DHCP lease # https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md diff --git a/log-forward.rsc b/log-forward.rsc index a919d8f..7abcb4d 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # forward log messages via notification # https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md diff --git a/mod/bridge-port-to.rsc b/mod/bridge-port-to.rsc index 567a762..000532a 100644 --- a/mod/bridge-port-to.rsc +++ b/mod/bridge-port-to.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.13 +# # reset bridge ports to default bridge # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-to.md diff --git a/mod/bridge-port-vlan.rsc b/mod/bridge-port-vlan.rsc index aee5ef9..760e8a6 100644 --- a/mod/bridge-port-vlan.rsc +++ b/mod/bridge-port-vlan.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.13 +# # manage VLANs on bridge ports # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-vlan.md diff --git a/mod/inspectvar.rsc b/mod/inspectvar.rsc index 577abf3..5adca0a 100644 --- a/mod/inspectvar.rsc +++ b/mod/inspectvar.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.13 +# # inspect variables # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/inspectvar.md diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc index b098b44..128ca54 100644 --- a/mod/ipcalc.rsc +++ b/mod/ipcalc.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.13 +# # ip address calculation # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ipcalc.md diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 0d83d69..dbd648b 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # send notifications via e-mail # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-email.md diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index 6d48a59..5da575a 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.13 +# # send notifications via Ntfy (ntfy.sh) # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-ntfy.md diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index 85d465a..c3972a0 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.13 +# # download script and run it once # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/scriptrunonce.md diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 6716958..f37c28b 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # import ssh keys for public key authentication # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ssh-keys-import.md diff --git a/mode-button.rsc b/mode-button.rsc index f453f11..4994f6b 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # act on multiple mode and reset button presses # https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 50c2b4c..09365ba 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2022-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # monitor and manage dns/doh with netwatch # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-dns.md diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index bdabe2e..0b6c366 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # monitor netwatch and send notifications # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc index a22e5a5..0932815 100644 --- a/ospf-to-leds.rsc +++ b/ospf-to-leds.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # visualize ospf instance state via leds # https://git.eworm.de/cgit/routeros-scripts/about/doc/ospf-to-leds.md diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc index 61766c0..4ed92c5 100644 --- a/ppp-on-up.rsc +++ b/ppp-on-up.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # run scripts on ppp up # https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md diff --git a/sms-action.rsc b/sms-action.rsc index 4c37565..70bfb28 100644 --- a/sms-action.rsc +++ b/sms-action.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # run action on received SMS # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-action.md diff --git a/sms-forward.rsc b/sms-forward.rsc index b0966c3..477d11e 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -4,7 +4,7 @@ # Anatoly Bubenkov # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # forward SMS to e-mail # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md diff --git a/update-gre-address.rsc b/update-gre-address.rsc index 74967cd..76d0c81 100644 --- a/update-gre-address.rsc +++ b/update-gre-address.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # update gre interface remote address with dynamic address from # ipsec remote peer diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index c76b7ec..364dc08 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -5,7 +5,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: ppp-on-up -# requires RouterOS, version=7.12 +# requires RouterOS, version=7.13 # # update local address of tunnelbroker interface # https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md From 36cf4d028bcf9597143249aed238dc5e131fda50 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 18 Mar 2024 10:30:32 +0100 Subject: [PATCH 2161/2612] global-functions: drop $LogPrintExit2 --- global-functions.rsc | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index ab8860f..c8fec8d 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -50,7 +50,6 @@ :global IsMacLocallyAdministered; :global IsTimeSync; :global LogPrint; -:global LogPrintExit2; :global LogPrintOnce; :global MAX; :global MIN; @@ -744,27 +743,6 @@ } } -# log and print with same text, optionally exit -# Deprectated! - TODO: remove later -:set LogPrintExit2 do={ - :local Severity [ :tostr $1 ]; - :local Name [ :tostr $2 ]; - :local Message [ :tostr $3 ]; - :local Exit [ :tostr $4 ]; - - :global LogPrint; - :global LogPrintOnce; - - $LogPrintOnce warning $0 \ - ("This function is deprecated and will be removed. Please make your adjustments!"); - - $LogPrint $1 $2 $3; - - :if ($Exit = "true") do={ - :error ("Hard error to exit."); - } -} - # log and print, once until reboot :set LogPrintOnce do={ :local Severity [ :tostr $1 ]; From 3015743b19883d2e19605b819fd2bbcbc6597d8f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 7 Apr 2024 21:11:03 +0200 Subject: [PATCH 2162/2612] global-functions: $HumanReadableNum: indicate binary base... ... and update scripts to match the change. --- backup-cloud.rsc | 2 +- backup-upload.rsc | 2 +- check-health.rsc | 6 +++--- global-functions.rsc | 8 ++++++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 9a062f2..8e29c67 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -71,7 +71,7 @@ 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 "Size" ([ $HumanReadableNum ($Cloud->"size") 1024 ] . "B") ] . "\n" . \ [ $FormatLine "Download key" ($Cloud->"secret-download-key") ]); silent=true }); } else={ $SendNotification2 ({ origin=$ScriptName; \ diff --git a/backup-upload.rsc b/backup-upload.rsc index 18223bb..63e5b7f 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -140,7 +140,7 @@ :return \ [ $IfThenElse ([ :typeof $File ] = "array") \ ($Name . ":\n" . [ $FormatLine " name" ($File->"name") ] . "\n" . \ - [ $FormatLine " size" ([ $HumanReadableNum ($File->"size") 1024 ] . "iB") ]) \ + [ $FormatLine " size" ([ $HumanReadableNum ($File->"size") 1024 ] . "B") ]) \ [ $FormatLine $Name $File ] ]; } diff --git a/check-health.rsc b/check-health.rsc index 1e8fcc0..a769fa8 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -64,9 +64,9 @@ $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 ]) }); + [ $FormatLine "total" ([ $HumanReadableNum ($Resource->"total-memory") 1024 ] . "B") 8 ] . "\n" . \ + [ $FormatLine "used" ([ $HumanReadableNum ($Resource->"total-memory" - $Resource->"free-memory") 1024 ] . "B") 8 ] . "\n" . \ + [ $FormatLine "free" ([ $HumanReadableNum ($Resource->"free-memory") 1024 ] . "B") 8 ]) }); :set CheckHealthRAMUtilizationNotified true; } :if ($CheckHealthRAMUtilization < 70 && $CheckHealthRAMUtilizationNotified = true) do={ diff --git a/global-functions.rsc b/global-functions.rsc index c8fec8d..aa39118 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -578,11 +578,13 @@ :local Base [ :tonum $2 ]; :global EitherOr; + :global IfThenElse; :local Prefix "kMGTPE"; :local Pow 1; :set Base [ $EitherOr $Base 1024 ]; + :local Bin [ $IfThenElse ($Base = 1024) "i" "" ]; :if ($Input < $Base) do={ :return $Input; @@ -595,9 +597,11 @@ :local Tmp1 ($Input * 100 / $Pow); :local Tmp2 ($Tmp1 / 100); :if ($Tmp2 >= 100) do={ - :return ($Tmp2 . $Prefix); + :return ($Tmp2 . $Prefix . $Bin); } - :return ($Tmp2 . "." . [ :pick $Tmp1 [ :len $Tmp2 ] ([ :len $Tmp1 ] - [ :len $Tmp2 ] + 1) ] . $Prefix); + :return ($Tmp2 . "." . \ + [ :pick $Tmp1 [ :len $Tmp2 ] ([ :len $Tmp1 ] - [ :len $Tmp2 ] + 1) ] . \ + $Prefix . $Bin); } } } From c5a5fb58363805efb824fb3336e95a1f6bf3dbb8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 Apr 2024 08:27:55 +0200 Subject: [PATCH 2163/2612] global-functions: $SendNotification: set origin --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index aa39118..c98a012 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1299,7 +1299,7 @@ :set SendNotification do={ :global SendNotification2; - $SendNotification2 ({ subject=$1; message=$2; link=$3; silent=$4 }); + $SendNotification2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 }); } # send notification via NotificationFunctions - expects one array argument From 012d259ca1421e31390358cb6749fda80ef4e3ab Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 9 Apr 2024 23:59:00 +0200 Subject: [PATCH 2164/2612] mod/notification-email: $SendEMail: set origin --- mod/notification-email.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index dbd648b..df2e81a 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -227,7 +227,7 @@ :set SendEMail do={ :global SendEMail2; - $SendEMail2 ({ subject=$1; message=$2; link=$3 }); + $SendEMail2 ({ origin=$0; subject=$1; message=$2; link=$3 }); } # send notification via e-mail - expects one array argument From a9b9f853ffb6b6a9b331f055d47463654bd2a5e2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 9 Apr 2024 23:58:29 +0200 Subject: [PATCH 2165/2612] mod/notification-matrix: $SendMatrix: set origin --- mod/notification-matrix.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 5a08146..477bb09 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -168,7 +168,7 @@ :set SendMatrix do={ :global SendMatrix2; - $SendMatrix2 ({ subject=$1; message=$2; link=$3 }); + $SendMatrix2 ({ origin=$0; subject=$1; message=$2; link=$3 }); } # send notification via Matrix - expects one array argument From 9e2b72ccdc59bc6abc936bf271d9bfaf2a986107 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 9 Apr 2024 23:56:36 +0200 Subject: [PATCH 2166/2612] mod/notification-ntfy: $SendNtfy: set origin --- mod/notification-ntfy.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index 5da575a..dc03903 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -125,7 +125,7 @@ :set SendNtfy do={ :global SendNtfy2; - $SendNtfy2 ({ subject=$1; message=$2; link=$3; silent=$4 }); + $SendNtfy2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 }); } # send notification via ntfy - expects one array argument From 9e4749a5b71e97c7732639019cff6ba7f6e84d57 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 9 Apr 2024 23:57:40 +0200 Subject: [PATCH 2167/2612] mod/notification-telegram: $SendTelegram: set origin --- mod/notification-telegram.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index a43ff10..c78a8ad 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -175,7 +175,7 @@ :set SendTelegram do={ :global SendTelegram2; - $SendTelegram2 ({ subject=$1; message=$2; link=$3; silent=$4 }); + $SendTelegram2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 }); } # send notification via telegram - expects one array argument From e53c31e9e669738fa50e45387d88d97a934f7e4d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Apr 2024 13:39:40 +0200 Subject: [PATCH 2168/2612] global-functions: $ScriptLock: degrade message to debug --- global-functions.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index c98a012..ded34c3 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1290,8 +1290,8 @@ } $RemoveTicket $Script $MyTicket; - $LogPrint info $0 ("Script '" . $Script . "' started more than once" . [ $IfThenElse ($WaitCount > 0) \ - " and timed out waiting for lock" "" ] . "..."); + $LogPrint debug $0 ("Script '" . $Script . "' started more than once" . \ + [ $IfThenElse ($WaitCount > 0) " and timed out waiting for lock" "" ] . "..."); :return false; } From 6db3355858157aceb92af47faa7937008d9cbf28 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Apr 2024 13:40:55 +0200 Subject: [PATCH 2169/2612] global-functions: $ScriptLock: break long lines --- global-functions.rsc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index ded34c3..25c248d 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1278,12 +1278,15 @@ $AddTicket $Script $MyTicket; :local WaitCount 0; - :while ($WaitMax > $WaitCount && ([ $IsFirstTicket $Script $MyTicket ] = false || [ $TicketCount $Script ] < [ $JobCount $Script ])) do={ + :while ($WaitMax > $WaitCount && \ + ([ $IsFirstTicket $Script $MyTicket ] = false || \ + [ $TicketCount $Script ] < [ $JobCount $Script ])) do={ :set WaitCount ($WaitCount + 1); :delay 100ms; } - :if ([ $IsFirstTicket $Script $MyTicket ] = true && [ $TicketCount $Script ] = [ $JobCount $Script ]) do={ + :if ([ $IsFirstTicket $Script $MyTicket ] = true && \ + [ $TicketCount $Script ] = [ $JobCount $Script ]) do={ $RemoveTicket $Script $MyTicket; $CleanupTickets $Script; :return true; From 5f76c245b016125f9e56d45bef381bae38731491 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Apr 2024 13:57:11 +0200 Subject: [PATCH 2170/2612] global-functions: $ScriptFromTerminal: check multiple invocations... ... and return false. We can not tell which job is us... So better safe than sorry. --- global-functions.rsc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 25c248d..abb9e22 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -931,6 +931,11 @@ :local Script [ :tostr $1 ]; :global LogPrint; + :global ScriptLock; + + :if ([ $ScriptLock $Script ] = false) do={ + :return false; + } :foreach Job in=[ /system/script/job/find where script=$Script ] do={ :set Job [ /system/script/job/get $Job ]; @@ -942,8 +947,8 @@ :return true; } } - $LogPrint debug $0 ("Script " . $Script . " NOT started from terminal."); + $LogPrint debug $0 ("Script " . $Script . " NOT started from terminal."); :return false; } From ca2e5f2a017c20f272419c5539b7c234a02f45a4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 9 Apr 2024 23:46:32 +0200 Subject: [PATCH 2171/2612] mod/notification-ntfy: support basic auth Closes #59 --- doc/mod/notification-ntfy.md | 5 +++++ global-config.rsc | 2 ++ global-functions.rsc | 2 +- mod/notification-ntfy.rsc | 14 +++++++++++--- news-and-changes.rsc | 1 + 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/doc/mod/notification-ntfy.md b/doc/mod/notification-ntfy.md index afa3109..b2330a5 100644 --- a/doc/mod/notification-ntfy.md +++ b/doc/mod/notification-ntfy.md @@ -47,6 +47,11 @@ Then reload the configuration. > [`global-config`](../../global-config.rsc) (the one without `-overlay`) to > your local `global-config-overlay` and modify it to your specific needs. +Using a paid account or running a server on-premises allows to add additional +basic authentication. Configure `NtfyServerUser` and `NtfyServerPass` for this. +Even authentication via access token is possible, adding it as password with +a blank username. + Usage and invocation -------------------- diff --git a/global-config.rsc b/global-config.rsc index f393abb..6a37c0c 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -56,6 +56,8 @@ # install the module: # $ScriptInstallUpdate mod/notification-ntfy :global NtfyServer "ntfy.sh"; +:global NtfyServerUser []; +:global NtfyServerPass []; :global NtfyTopic ""; # It is possible to override e-mail, Telegram, Matrix and Ntfy setting diff --git a/global-functions.rsc b/global-functions.rsc index abb9e22..8f2f179 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 126; +:global ExpectedConfigVersion 127; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index dc03903..ffe0c50 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -38,7 +38,8 @@ :if ([ :typeof $Message ] = "array" ) do={ :do { /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ - ($Message->"url") http-header-field=($Message->"headers") http-data=($Message->"text") as-value; + http-header-field=($Message->"headers") http-data=($Message->"text") \ + ($Message->"url") user=($Message->"user") password=($Message->"pass") as-value; :set ($NtfyQueue->$Id); } on-error={ $LogPrint debug $0 ("Sending queued Ntfy message failed."); @@ -62,6 +63,10 @@ :global NtfyQueue; :global NtfyServer; :global NtfyServerOverride; + :global NtfyServerPass; + :global NtfyServerPassOverride; + :global NtfyServerUser; + :global NtfyServerUserOverride; :global NtfyTopic; :global NtfyTopicOverride; @@ -73,6 +78,8 @@ :global UrlEncode; :local Server [ $EitherOr ($NtfyServerOverride->($Notification->"origin")) $NtfyServer ]; + :local User [ $EitherOr ($NtfyServerUserOverride->($Notification->"origin")) $NtfyServerUser ]; + :local Pass [ $EitherOr ($NtfyServerPassOverride->($Notification->"origin")) $NtfyServerPass ]; :local Topic [ $EitherOr ($NtfyTopicOverride->($Notification->"origin")) $NtfyTopic ]; :if ([ :len $Topic ] = 0) do={ @@ -95,7 +102,7 @@ } } /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ - $Url http-header-field=$Headers http-data=$Text as-value; + http-header-field=$Headers http-data=$Text $Url user=$User password=$Pass as-value; } on-error={ $LogPrint info $0 ("Failed sending ntfy notification! Queuing..."); @@ -105,7 +112,8 @@ :set Text ($Text . "\n" . [ $SymbolForNotification "alarm-clock" ] . \ "This message was queued since " . [ /system/clock/get date ] . " " . \ [ /system/clock/get time ] . " and may be obsolete."); - :set ($NtfyQueue->[ :len $NtfyQueue ]) { url=$Url; headers=$Headers; text=$Text }; + :set ($NtfyQueue->[ :len $NtfyQueue ]) \ + { url=$Url; user=$User; pass=$Pass; headers=$Headers; text=$Text }; :if ([ :len [ /system/scheduler/find where name="_FlushNtfyQueue" ] ] = 0) do={ /system/scheduler/add name="_FlushNtfyQueue" interval=1m start-time=startup \ on-event=(":global FlushNtfyQueue; \$FlushNtfyQueue;"); diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 2b04c29..8ddeb91 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -51,6 +51,7 @@ 124="Added support for links in 'netwatch-notify', these are added below the formatted notification text."; 125=("April's Fool! " . [ $SymbolForNotification "smiley-partying-face" ] . "Well, you missed it... - no charge nor fees. (Anyway... Donations are much appreciated, " . [ $SymbolForNotification "smiley-smiling-face" ] . "thanks!)"); 126="Made 'telegram-chat' capable of handling large command output. Telegram messages still limit the size, so it is truncated now."; + 127="Added support for authentication to Ntfy notification module."; }; # Migration steps to be applied on script updates From fb865ba114e610bcb272d8de7c1c882705e6e06e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 9 Apr 2024 23:50:00 +0200 Subject: [PATCH 2172/2612] mod/notification-ntfy: use custom user agent string --- mod/notification-ntfy.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index ffe0c50..4413f07 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -72,6 +72,7 @@ :global CertificateAvailable; :global EitherOr; + :global FetchUserAgentStr; :global IfThenElse; :global LogPrint; :global SymbolForNotification; @@ -87,7 +88,8 @@ } :local Url ("https://" . $NtfyServer . "/" . [ $UrlEncode $NtfyTopic ]); - :local Headers ({ ("Priority: " . [ $IfThenElse ($Notification->"silent") "low" "default" ]); \ + :local Headers ({ [ $FetchUserAgentStr ($Notification->"origin") ]; \ + ("Priority: " . [ $IfThenElse ($Notification->"silent") "low" "default" ]); \ ("Title: " . "[" . $IdentityExtra . $Identity . "] " . ($Notification->"subject")) }); :local Text (($Notification->"message") . "\n"); :if ([ :len ($Notification->"link") ] > 0) do={ From 9dfa11eac534019d08a5cfa289d7cde0f22c2a92 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 Apr 2024 11:51:47 +0200 Subject: [PATCH 2173/2612] mod/notification-matrix: use custom user agent string --- mod/notification-matrix.rsc | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 477bb09..12a0e33 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -39,7 +39,8 @@ :foreach Id,Message in=$MatrixQueue do={ :if ([ :typeof $Message ] = "array" ) do={ :do { - /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + /tool/fetch check-certificate=yes-without-crl output=none \ + http-header-field=($Message->"headers") http-method=post \ ("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \ "/send/m.room.message?access_token=" . $Message->"accesstoken") \ http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Message->"plain" . "\"," . \ @@ -74,6 +75,7 @@ :global MatrixRoomOverride; :global EitherOr; + :global FetchUserAgentStr; :global LogPrint; :global SymbolForNotification; @@ -115,6 +117,7 @@ :return false; } + :local Headers ({ [ $FetchUserAgentStr ($Notification->"origin") ] }); :local Plain [ $PrepareText ("## [" . $IdentityExtra . $Identity . "] " . \ ($Notification->"subject") . "\n```\n" . ($Notification->"message") . "\n```") "plain" ]; :local Formatted ("

    " . [ $PrepareText ("[" . $IdentityExtra . $Identity . "] " . \ @@ -129,7 +132,8 @@ } :do { - /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + /tool/fetch check-certificate=yes-without-crl output=none \ + http-header-field=$Headers http-method=post \ ("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \ "/send/m.room.message?access_token=" . $AccessToken) \ http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Plain . "\"," . \ @@ -146,9 +150,9 @@ " " . [ /system/clock/get time ] . " and may be obsolete."); :set Plain ($Plain . "\\n" . $Text); :set Formatted ($Formatted . "
    " . $Text); - :set ($MatrixQueue->[ :len $MatrixQueue ]) { room=$Room; \ - accesstoken=$AccessToken; homeserver=$HomeServer; \ - plain=$Plain; formatted=$Formatted }; + :set ($MatrixQueue->[ :len $MatrixQueue ]) { headers=$Headers; \ + accesstoken=$AccessToken; homeserver=$HomeServer; room=$Room; \ + plain=$Plain; formatted=$Formatted }; :if ([ :len [ /system/scheduler/find where name="_FlushMatrixQueue" ] ] = 0) do={ /system/scheduler/add name="_FlushMatrixQueue" interval=1m start-time=startup \ on-event=(":global FlushMatrixQueue; \$FlushMatrixQueue;"); @@ -185,6 +189,7 @@ :local User [ :tostr $1 ]; :local Pass [ :tostr $2 ]; + :global FetchUserAgentStr; :global LogPrint; :global MatrixAccessToken; @@ -193,6 +198,7 @@ :local Domain [ :pick $User ([ :find $User ":" ] + 1) [ :len $User] ]; :do { :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ + http-header-field=({ [ $FetchUserAgentStr $0 ] }) \ ("https://" . $Domain . "/.well-known/matrix/client") as-value ]->"data"); :set MatrixHomeServer ([ :deserialize from=json value=$Data ]->"m.homeserver"->"base_url"); $LogPrint debug $0 ("Home server is: " . $MatrixHomeServer); @@ -207,7 +213,8 @@ :do { :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ - http-method=post http-data=("{\"type\":\"m.login.password\", \"user\":\"" . $User . "\", \"password\":\"" . $Pass . "\"}") \ + http-header-field=({ [ $FetchUserAgentStr $0 ] }) http-method=post \ + http-data=("{\"type\":\"m.login.password\", \"user\":\"" . $User . "\", \"password\":\"" . $Pass . "\"}") \ ("https://" . $MatrixHomeServer . "/_matrix/client/r0/login") as-value ]->"data"); :set MatrixAccessToken ([ :deserialize from=json value=$Data ]->"access_token"); $LogPrint debug $0 ("Access token is: " . $MatrixAccessToken); @@ -233,6 +240,7 @@ :set SetupMatrixJoinRoom do={ :global MatrixRoom [ :tostr $1 ]; + :global FetchUserAgentStr; :global LogPrint; :global UrlEncode; @@ -242,7 +250,7 @@ :do { /tool/fetch check-certificate=yes-without-crl output=none \ - http-method=post http-data="" \ + http-header-field=({ [ $FetchUserAgentStr $0 ] }) http-method=post http-data="" \ ("https://" . $MatrixHomeServer . "/_matrix/client/r0/rooms/" . [ $UrlEncode $MatrixRoom ] . \ "/join?access_token=" . [ $UrlEncode $MatrixAccessToken ]) as-value; $LogPrint debug $0 ("Joined the room."); From 2a232ad2f5eef4b60c97306ef731bc5883bf5cfb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 12 Apr 2024 11:03:14 +0200 Subject: [PATCH 2174/2612] mod/notification-matrix: generate JSON with :serialize --- mod/notification-matrix.rsc | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 12a0e33..3e3a33e 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -40,12 +40,11 @@ :if ([ :typeof $Message ] = "array" ) do={ :do { /tool/fetch check-certificate=yes-without-crl output=none \ - http-header-field=($Message->"headers") http-method=post \ - ("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \ - "/send/m.room.message?access_token=" . $Message->"accesstoken") \ - http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Message->"plain" . "\"," . \ - "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ - $Message->"formatted" . "\" }") as-value; + http-header-field=($Message->"headers") http-method=post \ + http-data=[ :serialize to=json { "msgtype"="m.text"; "body"=($Message->"plain"); + "format"="org.matrix.custom.html"; "formatted_body"=($Message->"formatted") } ] \ + ("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \ + "/send/m.room.message?access_token=" . $Message->"accesstoken") as-value; :set ($MatrixQueue->$Id); } on-error={ $LogPrint debug $0 ("Sending queued Matrix message failed."); @@ -133,12 +132,11 @@ :do { /tool/fetch check-certificate=yes-without-crl output=none \ - http-header-field=$Headers http-method=post \ - ("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \ - "/send/m.room.message?access_token=" . $AccessToken) \ - http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Plain . "\"," . \ - "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ - $Formatted . "\" }") as-value; + http-header-field=$Headers http-method=post \ + http-data=[ :serialize to=json { "msgtype"="m.text"; "body"=$Plain; + "format"="org.matrix.custom.html"; "formatted_body"=$Formatted } ] \ + ("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \ + "/send/m.room.message?access_token=" . $AccessToken) as-value; } on-error={ $LogPrint info $0 ("Failed sending Matrix notification! Queuing..."); @@ -214,7 +212,7 @@ :do { :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ http-header-field=({ [ $FetchUserAgentStr $0 ] }) http-method=post \ - http-data=("{\"type\":\"m.login.password\", \"user\":\"" . $User . "\", \"password\":\"" . $Pass . "\"}") \ + http-data=[ :serialize to=json { "type"="m.login.password"; "user"=$User; "password"=$Pass } ] \ ("https://" . $MatrixHomeServer . "/_matrix/client/r0/login") as-value ]->"data"); :set MatrixAccessToken ([ :deserialize from=json value=$Data ]->"access_token"); $LogPrint debug $0 ("Access token is: " . $MatrixAccessToken); From d31afc9ec330634a2b66b346ee2d830ea5e5d436 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 12 Apr 2024 11:10:34 +0200 Subject: [PATCH 2175/2612] gps-track: generate JSON with :serialize --- gps-track.rsc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gps-track.rsc b/gps-track.rsc index dbca38a..f78dfe7 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -33,11 +33,8 @@ :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; + http-data=[ :serialize to=json { "identity"=$Identity; \ + "lat"=($Gps->"latitude"); "lon"=($Gps->"longitude") } ] as-value; $LogPrint debug $ScriptName ("Sending GPS data in " . $CoordinateFormat . " format: " . \ "lat: " . ($Gps->"latitude") . " " . \ "lon: " . ($Gps->"longitude")); From 5736ecebc53a8e97e986eb50e4a1611b410dcc14 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 12 Apr 2024 11:14:01 +0200 Subject: [PATCH 2176/2612] gps-track: use custom user agent string --- gps-track.rsc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gps-track.rsc b/gps-track.rsc index f78dfe7..e2a4e16 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -17,6 +17,7 @@ :global GpsTrackUrl; :global Identity; + :global FetchUserAgentStr; :global LogPrint; :global ScriptLock; :global WaitFullyConnected; @@ -31,10 +32,10 @@ :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" }) \ + /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + http-header-field=({ [ $FetchUserAgentStr $ScriptName ]; "Content-Type: application/json" }) \ http-data=[ :serialize to=json { "identity"=$Identity; \ - "lat"=($Gps->"latitude"); "lon"=($Gps->"longitude") } ] as-value; + "lat"=($Gps->"latitude"); "lon"=($Gps->"longitude") } ] $GpsTrackUrl as-value; $LogPrint debug $ScriptName ("Sending GPS data in " . $CoordinateFormat . " format: " . \ "lat: " . ($Gps->"latitude") . " " . \ "lon: " . ($Gps->"longitude")); From 7aa5059f6d478fb8984caae7c906154a1d598488 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 12 Apr 2024 11:18:42 +0200 Subject: [PATCH 2177/2612] global-functions: $CertificateAvailable: use single quotes --- global-functions.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 8f2f179..17aa38f 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -107,7 +107,7 @@ } :if ([ :len [ /certificate/find where common-name=$CommonName ] ] = 0) do={ - $LogPrint info $0 ("Certificate with CommonName \"" . $CommonName . "\" not available."); + $LogPrint info $0 ("Certificate with CommonName '" . $CommonName . "' not available."); :if ([ $CertificateDownload $CommonName ] = false) do={ :return false; } @@ -116,8 +116,8 @@ :local CertVal [ /certificate/get [ find where common-name=$CommonName ] ]; :while (($CertVal->"akid") != "" && ($CertVal->"akid") != ($CertVal->"skid")) do={ :if ([ :len [ /certificate/find where skid=($CertVal->"akid") ] ] = 0) do={ - $LogPrint info $0 ("Certificate chain for \"" . $CommonName . \ - "\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\"."); + $LogPrint info $0 ("Certificate chain for '" . $CommonName . \ + "' is incomplete, missing '" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "'."); :if ([ $CertificateDownload $CommonName ] = false) do={ :return false; } From e1781fb8053db5cdb3b26d04009c216f7d2204ac Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 12 Apr 2024 11:19:37 +0200 Subject: [PATCH 2178/2612] global-functions: $CertificateDownload: use single quotes --- global-functions.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 17aa38f..918ea9a 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -141,7 +141,7 @@ :global WaitForFile; $LogPrint info $0 ("Downloading and importing certificate with " . \ - "CommonName \"" . $CommonName . "\"."); + "CommonName '" . $CommonName . "'."); :do { :local FileName ([ $CleanName $CommonName ] . ".pem"); /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $0 ] }) \ @@ -156,7 +156,7 @@ $CertificateNameByCN [ /certificate/get $Cert common-name ]; } } on-error={ - $LogPrint warning $0 ("Failed importing certificate with CommonName \"" . $CommonName . "\"!"); + $LogPrint warning $0 ("Failed importing certificate with CommonName '" . $CommonName . "'!"); :return false; } :return true; From 8c1543a402570278a8dfdcf8d052ab8bb6f282e5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 12 Apr 2024 11:21:54 +0200 Subject: [PATCH 2179/2612] certificate-renew-issued: use single quotes --- certificate-renew-issued.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc index 77ed3d0..7815443 100644 --- a/certificate-renew-issued.rsc +++ b/certificate-renew-issued.rsc @@ -36,13 +36,13 @@ /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\"."); + $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" . "\"."); + $LogPrint info $ScriptName ("Issued a new certificate for '" . $CertVal->"common-name" . "'."); } } } on-error={ } From 3a36db6de8a69cba493bdd0baf86c60401fe971c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Apr 2024 08:43:41 +0200 Subject: [PATCH 2180/2612] mod/notification-matrix: fix double escaping That was introduced with 2a232ad2f5eef4b60c97306ef731bc5883bf5cfb when switching to :serialize... --- mod/notification-matrix.rsc | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 3e3a33e..86e6b5f 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -86,21 +86,15 @@ } :local Return ""; - :local Chars { - "plain"={ "\\"; "\""; "\n" }; - "format"={ "\\"; "\""; "\n"; "&"; "<"; ">" }; - } - :local Subs { - "plain"={ "\\\\"; "\\\""; "\\n" }; - "format"={ "\\\\"; """; "
    "; "&"; "<"; ">" }; - } + :local Chars { "\""; "\n"; "&"; "<"; ">" }; + :local Subs { """; "
    "; "&"; "<"; ">" }; :for I from=0 to=([ :len $Input ] - 1) do={ :local Char [ :pick $Input $I ]; - :local Replace [ :find ($Chars->$2) $Char ]; + :local Replace [ :find $Chars $Char ]; :if ([ :typeof $Replace ] = "num") do={ - :set Char ($Subs->$2->$Replace); + :set Char ($Subs->$Replace); } :set Return ($Return . $Char); } @@ -117,17 +111,17 @@ } :local Headers ({ [ $FetchUserAgentStr ($Notification->"origin") ] }); - :local Plain [ $PrepareText ("## [" . $IdentityExtra . $Identity . "] " . \ - ($Notification->"subject") . "\n```\n" . ($Notification->"message") . "\n```") "plain" ]; + :local Plain ("## [" . $IdentityExtra . $Identity . "] " . \ + ($Notification->"subject") . "\n```\n" . ($Notification->"message") . "\n```"); :local Formatted ("

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

    " . "
    " . \
    -    [ $PrepareText ($Notification->"message") "format" ] . "
    "); + ($Notification->"subject")) ] . "

    " . "
    " . \
    +    [ $PrepareText ($Notification->"message") ] . "
    "); :if ([ :len ($Notification->"link") ] > 0) do={ :set Plain ($Plain . "\\n" . [ $SymbolForNotification "link" ] . \ - [ $PrepareText ("[" . $Notification->"link" . "](" . $Notification->"link" . ")") "plain" ]); + "[" . $Notification->"link" . "](" . $Notification->"link" . ")"); :set Formatted ($Formatted . "
    " . [ $SymbolForNotification "link" ] . \ - "
    "link") "format" ] . "\\\">" . \ - [ $PrepareText ($Notification->"link") "format" ] . ""); + ""link") ] . "\">" . \ + [ $PrepareText ($Notification->"link") ] . ""); } :do { From b50a5b294a50729e70d96c65ed1a12657bd1adf3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 18 Apr 2024 21:47:50 +0200 Subject: [PATCH 2181/2612] mod/notification-matrix: ... and more double escaping --- mod/notification-matrix.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 86e6b5f..7eae1b0 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -117,7 +117,7 @@ ($Notification->"subject")) ] . "

  • rb2y&J9R0rU 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 literal 0 HcmV?d00001 diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md new file mode 100644 index 0000000..511d9a2 --- /dev/null +++ b/doc/mod/notification-telegram.md @@ -0,0 +1,58 @@ +Send notifications via Telegram +=============================== + +[◀ Go back to main README](../../README.md) + +> â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base +> installation. See [main README](../../README.md) for details. + +Description +----------- + +This module adds support for sending notifications via +[Telegram](https://telegram.org/) via bot api. A queue is used to make sure +notifications are not lost on failure but sent later. + +Requirements and installation +----------------------------- + +Just install the module: + + $ScriptInstallUpdate mod/notification-telegram; + +Also install Telegram on at least one of your mobile and/or desktop devices +and create an account. + +Configuration +------------- + +Open Telegram, then start a chat with [BotFather](https://t.me/BotFather) and +create your own bot: + +![create new bot](notification-telegram.d/newbot.avif) + +Now open a chat with your bot and start it by clicking the `START` button. + +Open just another chat with [GetIDs Bot](https://t.me/getidsbot), again start +with the `START` button. It will send you some information, including the +`id`, just below `You`. + +Finally edit `global-config-overlay`, add `TelegramTokenId` with the token +from *BotFather* and `TelegramChatId` with your id from *GetIDs Bot*. Then +reload the configuration. + +### Notifications to a group + +Sending notifications to a group is possible as well. Add your bot and the +*GetIDs Bot* to a group, then use the group's id (which starts with a dash) +for `TelegramChatId`. Then remove *GetIDs Bot* from group. + +Usage and invocation +-------------------- + +There's nothing special to do. Every script or function sending a notification +will now send it to your Telegram account. + +--- +[◀ Go back to main README](../../README.md) +[▲ Go back to top](#top) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index c9917cb..47fa5f3 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -88,7 +88,8 @@ powered off, but accessibility is of interest. Go and get your coffee â˜•ī¸ before sending the print job. -Also notification settings are required for e-mail, matrix and/or telegram. +Also notification settings are required for e-mail, matrix and/or +[telegram](mod/notification-telegram.md). Tips & Tricks ------------- diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 417f462..9028045 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -31,8 +31,9 @@ Just install the script: Configuration ------------- -Notification settings are required for e-mail, matrix and/or telegram. Also -you have to enable receiving of SMS: +Notification settings are required for e-mail, matrix and/or +[telegram](mod/notification-telegram.md). Also you have to enable receiving +of SMS: / tool sms set receive-enabled=yes; From 07fc5c898ad36debad96d06e3a65fa06ccdadde8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Nov 2021 16:03:25 +0100 Subject: [PATCH 0948/2612] add doc/mod/notification-matrix --- README.md | 1 + doc/backup-cloud.md | 3 ++- doc/backup-upload.md | 3 ++- doc/check-certificates.md | 3 ++- doc/check-health.md | 3 ++- doc/check-lte-firmware-upgrade.md | 3 ++- doc/check-routeros-update.md | 3 ++- doc/collect-wireless-mac.md | 3 ++- doc/daily-psk.md | 3 ++- doc/log-forward.md | 3 ++- doc/mod/notification-matrix.md | 45 +++++++++++++++++++++++++++++++ doc/mod/notification-telegram.md | 5 ++++ doc/netwatch-notify.md | 3 ++- doc/sms-forward.md | 3 ++- 14 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 doc/mod/notification-matrix.md diff --git a/README.md b/README.md index 69461a9..78925bb 100644 --- a/README.md +++ b/README.md @@ -224,6 +224,7 @@ Available modules * [Manage ports in bridge](doc/mod/bridge-port-to.md) * [Manage VLANs on bridge ports](doc/mod/bridge-port-vlan.md) +* [Send notifications via Matrix](doc/mod/notification-matrix.md) * [Send notifications via Telegram](doc/mod/notification-telegram.md) Contact diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index c768be1..0761982 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -30,7 +30,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupPassword`: password to encrypt the backup with * `BackupRandomDelay`: delay up to amount of seconds when run from scheduler -Also notification settings are required for e-mail, matrix and/or +Also notification settings are required for e-mail, +[matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). Usage and invocation diff --git a/doc/backup-upload.md b/doc/backup-upload.md index cbda74e..72781ba 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -36,7 +36,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupUploadUser`: username for server authentication * `BackupUploadPass`: password for server authentication -Also notification settings are required for e-mail, matrix and/or +Also notification settings are required for e-mail, +[matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). ### Issues with SFTP client diff --git a/doc/check-certificates.md b/doc/check-certificates.md index bddcd5a..a553e6a 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -27,7 +27,8 @@ Configuration ------------- The expiry notifications just require notification settings for e-mail, -matrix and/or [telegram](mod/notification-telegram.md). +[matrix](mod/notification-matrix.md) and/or +[telegram](mod/notification-telegram.md). For automatic download and renewal of certificates you need configuration in `global-config-overlay`, these are the parameters: diff --git a/doc/check-health.md b/doc/check-health.md index 81a9f75..f6900ce 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -56,7 +56,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `CheckHealthVoltageLow`: value (in volt*10) giving a hard lower limit * `CheckHealthVoltagePercent`: percentage value to trigger voltage jumps -Also notification settings are required for e-mail, matrix and/or +Also notification settings are required for e-mail, +[matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). --- diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index e5027a8..704a86b 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -35,7 +35,8 @@ Just install the script: Configuration ------------- -Notification setting are required for e-mail, matrix and/or +Notification setting are required for e-mail, +[matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). See also diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index b8f6183..cac1850 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -47,7 +47,8 @@ safe versions from a web server. The configuration goes to * `SafeUpdateUrl`: url to check for safe update, the channel (`long-term`, `stable` or `testing`) is appended -Also notification settings are required for e-mail, matrix and/or +Also notification settings are required for e-mail, +[matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). Usage and invocation diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 4e629a5..5425f76 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -40,7 +40,8 @@ On first run a disabled access list entry acting as marker (with comment "`--- collected above ---`") is added. Move this entry to define where new entries are to be added. -Also notification settings are required for e-mail, matrix and/or +Also notification settings are required for e-mail, +[matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). Usage and invocation diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 0d6ddef..d204691 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -51,7 +51,8 @@ Then add an access list entry: / interface wireless access-list add comment="Daily PSK" interface=wl-daily private-pre-shared-key="ToBeChangedDaily"; -Also notification settings are required for e-mail, matrix and/or +Also notification settings are required for e-mail, +[matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). --- diff --git a/doc/log-forward.md b/doc/log-forward.md index 6ff652f..1ac6a04 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -46,7 +46,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `LogForwardIncludeMessage`: define message text to be forwarded (even if filter matches) -Also notification settings are required for e-mail, matrix and/or +Also notification settings are required for e-mail, +[matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md)m. --- diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md new file mode 100644 index 0000000..e357b5b --- /dev/null +++ b/doc/mod/notification-matrix.md @@ -0,0 +1,45 @@ +Send notifications via Matrix +============================= + +[◀ Go back to main README](../../README.md) + +> â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base +> installation. See [main README](../../README.md) for details. + +Description +----------- + +This module adds support for sending notifications via +[Matrix](https://matrix.org/) via client server api. A queue is used to +make sure notifications are not lost on failure but sent later. + +Requirements and installation +----------------------------- + +Just install the module: + + $ScriptInstallUpdate mod/notification-matrix; + +Also install a Matrix client on at least one of your mobile and/or desktop +devices and create an account. + +Configuration +------------- + +Edit `global-config-overlay`, add `MatrixHomeServer`, `MatrixAccessToken` and +`MatrixRoom`. Then reload the configuration. + +Usage and invocation +-------------------- + +There's nothing special to do. Every script or function sending a notification +will now send it to your Matrix account. + +See also +-------- + +* [Send notifications via Telegram](notification-telegram.md) + +--- +[◀ Go back to main README](../../README.md) +[▲ Go back to top](#top) diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index 511d9a2..435694e 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -53,6 +53,11 @@ Usage and invocation There's nothing special to do. Every script or function sending a notification will now send it to your Telegram account. +See also +-------- + +* [Send notifications via Matrix](notification-matrix.md) + --- [◀ Go back to main README](../../README.md) [▲ Go back to top](#top) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 47fa5f3..b2f6dd0 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -88,7 +88,8 @@ powered off, but accessibility is of interest. Go and get your coffee â˜•ī¸ before sending the print job. -Also notification settings are required for e-mail, matrix and/or +Also notification settings are required for e-mail, +[matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). Tips & Tricks diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 9028045..9ebae69 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -31,7 +31,8 @@ Just install the script: Configuration ------------- -Notification settings are required for e-mail, matrix and/or +Notification settings are required for e-mail, +[matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). Also you have to enable receiving of SMS: From 002315035c25b8569d2b6f232a6f8dfba37cf07b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Nov 2021 16:02:55 +0100 Subject: [PATCH 0949/2612] add doc/mod/inspectvar --- README.md | 1 + doc/mod/inspectvar.d/inspectvar.avif | Bin 0 -> 2891 bytes doc/mod/inspectvar.md | 33 +++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 doc/mod/inspectvar.d/inspectvar.avif create mode 100644 doc/mod/inspectvar.md diff --git a/README.md b/README.md index 78925bb..fa0663c 100644 --- a/README.md +++ b/README.md @@ -224,6 +224,7 @@ Available modules * [Manage ports in bridge](doc/mod/bridge-port-to.md) * [Manage VLANs on bridge ports](doc/mod/bridge-port-vlan.md) +* [Inspect variables](doc/mod/inspectvar.md) * [Send notifications via Matrix](doc/mod/notification-matrix.md) * [Send notifications via Telegram](doc/mod/notification-telegram.md) diff --git a/doc/mod/inspectvar.d/inspectvar.avif b/doc/mod/inspectvar.d/inspectvar.avif new file mode 100644 index 0000000000000000000000000000000000000000..d4a745f2c26446eb02c053a96294bfe35219a984 GIT binary patch literal 2891 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 literal 0 HcmV?d00001 diff --git a/doc/mod/inspectvar.md b/doc/mod/inspectvar.md new file mode 100644 index 0000000..d3fb3b2 --- /dev/null +++ b/doc/mod/inspectvar.md @@ -0,0 +1,33 @@ +Inspect variables +================= + +[◀ Go back to main README](../../README.md) + +> â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base +> installation. See [main README](../../README.md) for details. + +Description +----------- + +RouterOS handles not just scalar variables, but also arrays - even nested. +This module adds a function to inspect variables. + +Requirements and installation +----------------------------- + +Just install the module: + + $ScriptInstallUpdate mod/inspectvar; + +Usage and invocation +-------------------- + +Call the function `$InspectVar` with a variable as parameter: + + $InspectVar $ModeButton + +![InspectVar](inspectvar.d/inspectvar.avif) + +--- +[◀ Go back to main README](../../README.md) +[▲ Go back to top](#top) From e9953c361267f10fd15d3280ccd985062c1dde28 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Nov 2021 16:03:10 +0100 Subject: [PATCH 0950/2612] add doc/mod/ipcalc --- README.md | 1 + doc/mod/ipcalc.d/ipcalc.avif | Bin 0 -> 1791 bytes doc/mod/ipcalc.d/ipcalcreturn.avif | Bin 0 -> 1283 bytes doc/mod/ipcalc.md | 53 +++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+) create mode 100644 doc/mod/ipcalc.d/ipcalc.avif create mode 100644 doc/mod/ipcalc.d/ipcalcreturn.avif create mode 100644 doc/mod/ipcalc.md diff --git a/README.md b/README.md index fa0663c..752f5e8 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,7 @@ Available modules * [Manage ports in bridge](doc/mod/bridge-port-to.md) * [Manage VLANs on bridge ports](doc/mod/bridge-port-vlan.md) * [Inspect variables](doc/mod/inspectvar.md) +* [IP address calculation](doc/mod/ipcalc.md) * [Send notifications via Matrix](doc/mod/notification-matrix.md) * [Send notifications via Telegram](doc/mod/notification-telegram.md) diff --git a/doc/mod/ipcalc.d/ipcalc.avif b/doc/mod/ipcalc.d/ipcalc.avif new file mode 100644 index 0000000000000000000000000000000000000000..022f325bc4637fbb9e4cee8a8d9ad66eab3ba49e GIT binary patch literal 1791 zcmXv|3p~>c8~&RSjTz}+iOmv~bJ|KLa&M?;Tg+XqL$)?sEaEE;$#MHIq@&1mIbY2E zk{q{`+i|}XK5RlR=V;TAYxp+b@4WBt_df6YJkRfaUjP6Q0nBiQPbfJ65QP|N=S^qz*vZ=WtuSKL*yv7%!Y|UxGXNf*x z45sGa1W9*6w8LBLRCefI@A%0vuLcxBSLgON+KC5=le}DCpgRBs?=qY?8gOr%EK82<+EcD0E-GkjOm|k<|dp56PhQ7PJHXpq3wB8^o2leDnK2k5d=6f4Y(KPN{ zXikb}as9KN`Jizw!BGEC)nCcy^RUxXWT>!skOXQ6(&(BuS zZB^j^$}!d2rJ&r^Fs{hwr;XG~+FNEex4c*OG?Cs5ijn=fZ^9dLIJQOHxy0lVa89P> zI=gNZl+fc?o!HTo6-G!2PGX!<^IlRkN1o@Uv)MhFN(G@`93td2V0u@vr2Na>IMif{ zj2RHKcEsW2>$gjWfjG7ua%t<>vQ%2n;Xih|z9QvTAJ z90*6xc;%s%qpJ2pS^hgHCP8~bYQsoPEdzZAXaD(l%uCNR!3%6MR%*Cfnv&h_N7+tx zzz{EUIS+;l_;73Qz9w_7hE_akLK@-JD%kXhtJ_=t{o(-+e|b46XtCT(2LxAhZF$ zBa-^H^KND%XSFUV$&lh!XQpUXrlJV-yO;R*EHsdRgxJ#&vW#LB{C2{sb-L`O9qc6K z=V}&}cs)6rbFi`1RVUYFgln$$vG0Q3YH;}ivc|ft^Mf^XCK~3?VW_ZP8yq4ow7A+XW3;3JbmIuqm`Xkond@VS*K(2K)Oz8@;_wILqxi%O{~ zzrOP*?YW*jTu=%bL6p(4y7`z#Beae}rz2*|LTT|PdWfx_SCKYc(gKNI8Sz@X6ku5Q_J(& zro0pU+9?+0)u+0|c+qwK1O!)C`p9tp5z-vESQbP>D?;59yg~af+Z(UvG z5x^Ym)s4PzJHk?pGYy(O>aFO4Wt_GO;Qj$FP!eUDxr#agRs$aDEoD`sJ)K!MuLx(%}dRt0uKApN5kshW3dQq4wZ z3|{JjY8lT_t@=*$y)COT7da^D;UC+;G*xU`T)^u2l7)KX)l&9*oAf!kt=7t+1#rKD4FAgS Oj1?32im|Lp#Qy*bWgj&F literal 0 HcmV?d00001 diff --git a/doc/mod/ipcalc.d/ipcalcreturn.avif b/doc/mod/ipcalc.d/ipcalcreturn.avif new file mode 100644 index 0000000000000000000000000000000000000000..d858bb12cd8b487f6d1dc8106f978304eae4f524 GIT binary patch literal 1283 zcmZQzU{FXasVqn=%S>Yc0uY^>nP!-qnV9D5Xy^zO`jnemk_eIm0*#E6oFWL5fuSHX zxdg@r(K(q(Fk|=%GD~v7a*RMyE;A=T8N_p8U|EXYj+$pHb-VJwVH%`8CEKIWz* zmIyI$aayPrS=?}Nc3fg~lilY8%bn(BD&gO!-N<|KGGNgpL6aqstR0KLlreOP^Kyjy zDa*f^=woKey#4LpoY{Fi+FCUV;ZH)B&x}?K;+`Amb$-#`laJWBX3Bo|o!KCNq~Kie z>F1LEt9J9J>e>Ezlb_r7-RkS3{rnbR5{(x&hqn8cFIWHmRxN1NqfS}9XV-;w7W~Qz z(B8^f*SspX*}6pX)|||rNtG{`N7(BNRJq(_u-Rs>`0{nwiLf(83#5*|>Nz88KmFOP z*`c1Vt=5%$-Pt;+=b7N_S94N$cS?zg?y5fZ_-|%*cHpggw_i!g?Dx}jx27Kd>n>wD zeO=pO$L4}RPhb2BT<|w%&5@LpGc)V+t=Xm>{g4~_!bFkvl6(5zzI`Suc^ccimRA|b z?l~{_tF2(p-zCSd+x+LXxlq{<{8s4fypTUo|ZC>&(|#oIU;NG@YbZXU{M3y7J^u_0Nc# zM>*=*jx()XBwwd5*}L?1nf;E8pXzMO|4p|4naZ{PqTv(kOm(dguH4+0Rev}H)idWu zAAWi1DAw%aX7-z9;VPNbK>y}Epj~iDu4ff zOK5pv8p+5r#X}`np#Jmk{g>}_RsZyPxch)KhgSmEHW?P>Yf{TEo{N2}$66zFRwrL; zWpMo|(Y2TEzghI`#9y~phpzn#$|^dywCJ_cIfuh~0UYZW@Hm`(@@#AOw`R>x{iRRz zublh&%I=u$Eil`*#5P9C&~5!( z=GD`FPiWc1Sr~cw-}?B>Fv@KiRH33D@k&9~^# z+PiC(*xIFfC*1`XEz`0nR+zBAq?9e~XJtjE?FXM8zU3t>!v4~n*BoOm%yfwhHtKJS zWdB;Q_+y>@C%ropF53AUu&PX3x?R9(ZWotlrkvx;Tw`D1thZd#d3 â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base +> installation. See [main README](../../README.md) for details. + +Description +----------- + +This module adds functions for IP address calculation. + +Requirements and installation +----------------------------- + +Just install the module: + + $ScriptInstallUpdate mod/ipcalc; + +Usage and invocation +-------------------- + +### IPCalc + +The function `$IPCalc` prints information to terminal, including: + +* address +* netmask +* network in CIDR notation +* minimum host address +* maximum host address +* broadcast address + +It expects an IP address in CIDR notation as argument. + + $IPCalc 192.168.88.1/24; + +![IPCalc](ipcalc.d/ipcalc.avif) + +### IPCalcReturn + +The function `$IPCalcReturn` expects an IP address in CIDR notation as +argument as well. But it does not print to terminal, instead it returns +the information in a named array. + + :put ([ $IPCalcReturn 192.168.88.1/24 ]->"broadcast"); + +![IPCalcReturn](ipcalc.d/ipcalcreturn.avif) + +--- +[◀ Go back to main README](../../README.md) +[▲ Go back to top](#top) From 26e471122f029b8e585e1e88e5f2fdaa1f21abd7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Nov 2021 16:03:56 +0100 Subject: [PATCH 0951/2612] add doc/mod/scriptrunonce --- README.md | 1 + doc/mod/scriptrunonce.d/hello-world.rsc | 3 ++ doc/mod/scriptrunonce.d/scriptrunonce.avif | Bin 0 -> 2466 bytes doc/mod/scriptrunonce.md | 35 +++++++++++++++++++++ 4 files changed, 39 insertions(+) create mode 100644 doc/mod/scriptrunonce.d/hello-world.rsc create mode 100644 doc/mod/scriptrunonce.d/scriptrunonce.avif create mode 100644 doc/mod/scriptrunonce.md diff --git a/README.md b/README.md index 752f5e8..a3da7e7 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,7 @@ Available modules * [IP address calculation](doc/mod/ipcalc.md) * [Send notifications via Matrix](doc/mod/notification-matrix.md) * [Send notifications via Telegram](doc/mod/notification-telegram.md) +* [Download script and run it once](doc/mod/scriptrunonce.md) Contact ------- diff --git a/doc/mod/scriptrunonce.d/hello-world.rsc b/doc/mod/scriptrunonce.d/hello-world.rsc new file mode 100644 index 0000000..17ec575 --- /dev/null +++ b/doc/mod/scriptrunonce.d/hello-world.rsc @@ -0,0 +1,3 @@ +#!rsc by RouterOS + +:put ("Hello World from " . [ / system identity get name ] . "!"); diff --git a/doc/mod/scriptrunonce.d/scriptrunonce.avif b/doc/mod/scriptrunonce.d/scriptrunonce.avif new file mode 100644 index 0000000000000000000000000000000000000000..614c72c670ff87f31bbd59d11c73927d62630129 GIT binary patch literal 2466 zcmXw4c{mh$7oH(Y_9aPnV_&MtSYnv0V;PsR6(h{G%`lU(j}V5)I>{1|ExshXB(6qw zC1b0|mXPJMRTyLK8-33`=lPxYocBG?Ip@D0005Bk4h|=vL$TffhMgiF>kYG72xI(`H5wI`j(I$RFqbXQeNe5J+I~mRN#^KLgKU zg9u)yjQ{|%EF;)69v=Zq#QtH}+1VM$g$@N9#Y&wr06`CbT;OdF9FZ}Z8^9XFpoFmm zJo;2)7~`-rK&H4ejH@2tJ<-7e0FJZTat%5-De2JvBn$~hmr8p&q6!>t5;U-AJf6@G4cq~G$_cvz#i)P#X1pM+$1ViJ-T1MiW0 zc6ZIdtAc)PTxW8BO!8Pg*o!at#}AA#0Ot;Ib~r?C4+B?WO8G>aIuKJ^Muq z5?Nb0`UOHlV77b;?9(C=ILrv{6&IT0BnRgU$Dwq%DuTaHd8CJZOt!nHJ!%(PrP(On zxHMu(fuz)|EprfgEcsw%0cnLgevg&7YNA53#F93kC%`7#{z7JyY#3_l^PY0=0?0;V< z&X^_YAgH4;uDomDj}4?(KAS5}z1_Jts{=oE<(5JQeq#cLS}lTt?%0Y|7>f*}UTnwv z;%72Z(#eqCK$m|mH^VA!z_O#{ZYprp4~ct?r(EgHAEb-O>Lzf1>R#Fd#vGSu! z?s>%w#W)O-`%&Z`!xVG2BnE!+Lv(hAqOV~>{1 z4&^OnSMI=w+O6Z!&pVUyz-8Fd;ST%wnvG8zzlotLB55EC;$SS*xXnx|c6y zI4`6WsKBV_u8*3J|fHgn?@n-CzDsVeqHyr3J$rhY|6 zI+JQ=<=d(_559ztWFy^LrLQJABwuy8iqNt?7JIEV6&F`^BZ0j2o$WmO`-Sg4RmA>M zqRhm%t?n5|-pVUzgu?G7b{qY+jD6R{06-k%t~xF7=3q&49ud zC;t9U5!Fr_i{jgzkHdAxrsrB!jIS29>xRhC_lVWds6`vN4C`P4@3c<0=wIf zk#PTq<=XUxNT4cbNt=E1uF2lk{u_$p+_5Y3EvRYimn65Gp2)e761X);58DT-B!iP3 z+Q||U#MB|zeYW&~MoTAh&u&NdVpGOd{ByxMdvBh5PRce#nKsK&Bz=XcsMmHvXn1~Y zEfrz$?m9S-_PW%zu~;i9zl9&Y$oL%e%d5+~oG|-VNa<@a1NGuuSz+xZwYg6Amv8O2 z62$6wxhB?!b|oGnpJLJ`@x3P(4dFAnArUQy>7KA_X1HA{l;)F%k^6e`Xn}6LBjZwE zS`?$;Dcv^0W|FzpAZ*Tj#o#1inLecVZ66bkk}Z-AE@`2Ku(?^?{R>>ibnAib`&x?^ zUNL&nVX<64{q(v#Cb}NqeL=}YZ!o`7DYgB4&l#aM;A7NaE1TA_l6(#x`Gg5p`6<4% z#7*L+kysUiKsn;JW% z^_1hI>_v3s!>A^g^CBP0Mu|f5O-P)^YhzvTu~0i`@`c~&ZNDM; z&MMmmPz!yWn`WUs#Ho;bBzPZ=w} zSPNhF1O;U^oAxe>)aBM_SpoEmx;YD>IgZ;x&>*(j@a1<-A-eG**R=Jg6NGOoJ`Lvc zGk%jLyhkw`@Ij;(YzVIMG>gR3vf$I-A5F}<-kYM!e$bW?(g-_g{C3X3#246+H*TkA TP0`4OjfKTV!F_r)V0HfktQ2I! literal 0 HcmV?d00001 diff --git a/doc/mod/scriptrunonce.md b/doc/mod/scriptrunonce.md new file mode 100644 index 0000000..190ed03 --- /dev/null +++ b/doc/mod/scriptrunonce.md @@ -0,0 +1,35 @@ +Download script and run it once +=============================== + +[◀ Go back to main README](../../README.md) + +> â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base +> installation. See [main README](../../README.md) for details. + +Description +----------- + +This module adds a function that downloads a script, checks for syntax +validity and runs it once. + +Requirements and installation +----------------------------- + +Just install the module: + + $ScriptInstallUpdate mod/scriptrunonce; + +Usage and invocation +-------------------- + +The function `$ScriptRunOnce` expects an url pointing to a script as parameter. + + $ScriptRunOnce https://git.eworm.de/cgit/routeros-scripts/plain/doc/mod/scriptrunonce.d/hello-world.rsc + +![ScriptRunOnce](scriptrunonce.d/scriptrunonce.avif) + +Giving multiple scripts is possible, separated by comma. + +--- +[◀ Go back to main README](../../README.md) +[▲ Go back to top](#top) From d74aac8f6ad3edfdf65d4a3ee6714aae1d3ade0f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 20 Feb 2022 23:17:16 +0100 Subject: [PATCH 0952/2612] doc/mod: notify about new documentation --- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/global-config b/global-config index 50e7f54..3ae4557 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 77; +:global GlobalConfigVersion 78; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index d8c2e0a..7d0c83d 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 77; +:global GlobalConfigVersion 78; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 727b259..7e029be 100644 --- a/global-config.changes +++ b/global-config.changes @@ -86,6 +86,7 @@ ("Still running RouterOS v6, so last reminder to see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v6") ]); 76="Added an option to suppress notifications on host down with 'netwatch-notify'."; 77="Introduced new script 'firmware-upgrade-reboot'. Handle with care!"; + 78="New documentation is online for notifications via Telegram & Matrix, variable inspection, ip address calculation and running scripts once."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 3323f36..2b37bea 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 77; +:global ExpectedConfigVersion 78; # global variables not to be changed by user :global GlobalFunctionsReady false; From 8e401bf498065814442c4c39e2fcc949f73bfc3b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Feb 2022 22:15:08 +0100 Subject: [PATCH 0953/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index ba4dfed..2210ea7 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -23,6 +23,7 @@ Add yourself to the list, * Andrew Cox * Christoph Boss (@Kampfwurst) * Devin Dean (@dd2594gh) +* Evaldo Gardenal * Klaus Michael RÃŧbsam * Linux-Schmie.de Michael Gisbers * Manuel Kuhn From d50f6ffb79c448b8ffef246a0e7ef90d51c8dadb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Feb 2022 22:31:49 +0100 Subject: [PATCH 0954/2612] doc/mod/scriptrunonce: document optional configuration --- doc/mod/scriptrunonce.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/doc/mod/scriptrunonce.md b/doc/mod/scriptrunonce.md index 190ed03..aaa64a9 100644 --- a/doc/mod/scriptrunonce.md +++ b/doc/mod/scriptrunonce.md @@ -19,10 +19,23 @@ Just install the module: $ScriptInstallUpdate mod/scriptrunonce; +Configuration +------------- + +The optional configuration goes to `global-config-overlay`. + +* `ScriptRunOnceBaseUrl`: base url, prepended to parameter +* `ScriptRunOnceUrlSuffix`: url suffix, appended to parameter + +If the parameter passed to the function is not a complete URL (starting +with protocol `ftp://`, `http://`, `https://` or `sftp://`) the values are +prepended and appended. + Usage and invocation -------------------- -The function `$ScriptRunOnce` expects an url pointing to a script as parameter. +The function `$ScriptRunOnce` expects an URL (or name if +`ScriptRunOnceBaseUrl` is given) pointing to a script as parameter. $ScriptRunOnce https://git.eworm.de/cgit/routeros-scripts/plain/doc/mod/scriptrunonce.d/hello-world.rsc From c872c18d76553647ebeab613df4edc8cabef84f2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Feb 2022 22:41:59 +0100 Subject: [PATCH 0955/2612] doc/log-forward: remove extra character Looks like copy'n'paste error... --- doc/log-forward.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/log-forward.md b/doc/log-forward.md index 1ac6a04..1f3eae5 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -48,7 +48,7 @@ The configuration goes to `global-config-overlay`, these are the parameters: Also notification settings are required for e-mail, [matrix](mod/notification-matrix.md) and/or -[telegram](mod/notification-telegram.md)m. +[telegram](mod/notification-telegram.md). --- [◀ Go back to main README](../README.md) From 0ab99fcdbb9b9210b3ebdfeb59b8185b4d760567 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Feb 2022 09:24:10 +0100 Subject: [PATCH 0956/2612] INITIAL-COMMANDS: give another delay before fetch --- INITIAL-COMMANDS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 2cea9a9..66db40c 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -22,6 +22,7 @@ Then run the complete base installation: :error "Something is wrong with your certificates!"; }; / file remove "letsencrypt-R3.pem"; + :delay 1s; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . $ScriptUpdatesUrlSuffix) output=user as-value]->"data"); }; From 6e7f6ff8b48ca101c08a4d878fa83b634245f0b3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Feb 2022 10:19:04 +0100 Subject: [PATCH 0957/2612] doc/backup-email: mention used option `show-sensitive` --- doc/backup-email.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/backup-email.md b/doc/backup-email.md index e6bed51..19bbeee 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -10,7 +10,7 @@ Description ----------- This script sends binary backup (`/ system backup save`) and complete -configuration export (`/ export terse`) via e-mail. +configuration export (`/ export terse show-sensitive`) via e-mail. Requirements and installation ----------------------------- From ef6f9efb10a2cb7e06a4ef03fe75249ffa3c689c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Feb 2022 10:19:45 +0100 Subject: [PATCH 0958/2612] doc/backup-upload: mention used option `show-sensitive` --- doc/backup-upload.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/backup-upload.md b/doc/backup-upload.md index 72781ba..b5aa232 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -10,7 +10,7 @@ Description ----------- This script uploads binary backup (`/ system backup save`) and complete -configuration export (`/ export terse`) to external server. +configuration export (`/ export terse show-sensitive`) to external server. ### Sample notification From a78b2bfcdef7e7cc84fd777e7fe0f7aa4cb5fe0c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Feb 2022 12:36:57 +0100 Subject: [PATCH 0959/2612] doc/backup-cloud: warn about possible issue --- doc/backup-cloud.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index 0761982..2573a65 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -11,6 +11,11 @@ Description This script uploads [binary backup to Mikrotik cloud](https://wiki.mikrotik.com/wiki/Manual:IP/Cloud#Backup). +> âš ī¸ **Warning**: The used command can hit errors that a script can not handle. +> This may result in script termination (where no notification is sent) or +> malfunction of fetch command (where all up- and downloads break) for some +> time. Failed notifications are queued then. + ### Sample notification ![backup-cloud notification](backup-cloud.d/notification.svg) From a754932211d3cc87563a483302350e65a03ceba1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Feb 2022 12:40:54 +0100 Subject: [PATCH 0960/2612] doc/backup-upload: warn about possible issue --- doc/backup-upload.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/backup-upload.md b/doc/backup-upload.md index b5aa232..a4d2bc7 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -12,6 +12,11 @@ Description This script uploads binary backup (`/ system backup save`) and complete configuration export (`/ export terse show-sensitive`) to external server. +> âš ī¸ **Warning**: The used command can hit errors that a script can not handle. +> This may result in script termination (where no notification is sent) or +> malfunction of fetch command (where all up- and downloads break) for some +> time. Failed notifications are queued then. + ### Sample notification ![backup-upload notification](backup-upload.d/notification.svg) From c72702cc51a732242d96904d04dad41573439378 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Feb 2022 23:31:29 +0100 Subject: [PATCH 0961/2612] doc/backup-cloud: break long line --- doc/backup-cloud.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index 2573a65..f3631ad 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -9,7 +9,8 @@ Upload backup to Mikrotik cloud Description ----------- -This script uploads [binary backup to Mikrotik cloud](https://wiki.mikrotik.com/wiki/Manual:IP/Cloud#Backup). +This script uploads +[binary backup to Mikrotik cloud](https://wiki.mikrotik.com/wiki/Manual:IP/Cloud#Backup). > âš ī¸ **Warning**: The used command can hit errors that a script can not handle. > This may result in script termination (where no notification is sent) or From 544647fc345338ce97cb39bc67fb3d3c711d4841 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 24 Feb 2022 11:49:15 +0100 Subject: [PATCH 0962/2612] doc/backup-cloud: update versions in screenshot --- doc/backup-cloud.d/notification.svg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/backup-cloud.d/notification.svg b/doc/backup-cloud.d/notification.svg index b023e50..6e48cd4 100644 --- a/doc/backup-cloud.d/notification.svg +++ b/doc/backup-cloud.d/notification.svg @@ -187,7 +187,7 @@ Installed: 6.48.3 + id="tspan13487"> Installed: 7.1.3 Current: 55 + id="tspan13491"> Current: 78 Name: cloud-20210614-092419 + id="tspan13495">Name: cloud-20220224-092419 Date: Thu, 24 Feb 2022 11:49:47 +0100 Subject: [PATCH 0963/2612] doc/backup-upload: update versions in screenshot --- doc/backup-upload.d/notification.svg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/backup-upload.d/notification.svg b/doc/backup-upload.d/notification.svg index 90573ab..a157840 100644 --- a/doc/backup-upload.d/notification.svg +++ b/doc/backup-upload.d/notification.svg @@ -187,7 +187,7 @@ Installed: 6.48.3 + id="tspan10789"> Installed: 7.1.3 Current: 55 + id="tspan10793"> Current: 78 Date: Thu, 24 Feb 2022 11:50:06 +0100 Subject: [PATCH 0964/2612] doc/check-routeros-update: update versions in screenshot --- doc/check-routeros-update.d/notification.svg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/check-routeros-update.d/notification.svg b/doc/check-routeros-update.d/notification.svg index 1eabdbb..8a5cc67 100644 --- a/doc/check-routeros-update.d/notification.svg +++ b/doc/check-routeros-update.d/notification.svg @@ -171,7 +171,7 @@ A new RouterOS version 6.48.3 is available for MikroTik. + id="tspan13545">A new RouterOS version 7.1.3 is available for MikroTik. Installed: 6.48.2 + id="tspan13559"> Installed: 7.1.2 Available: 6.48.3 + id="tspan13561"> Available: 7.1.3 Current: 55 + id="tspan13565"> Current: 78 Date: Thu, 24 Feb 2022 11:58:22 +0100 Subject: [PATCH 0965/2612] global-functions: $DeviceInfo: firmware only if upgrade pending --- global-functions | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 2b37bea..11c3bd7 100644 --- a/global-functions +++ b/global-functions @@ -221,7 +221,8 @@ [ $IfThenElse ([ :typeof ($Update->"latest-version") ] != "nothing" && \ $Update->"installed-version" != $Update->"latest-version") \ ("\n Available: " . $Update->"latest-version") ] . \ - [ $IfThenElse ($RouterBoard->"routerboard" = true) \ + [ $IfThenElse ($RouterBoard->"routerboard" = true && \ + $RouterBoard->"current-firmware" != $RouterBoard->"upgrade-firmware") \ ("\n Firmware: " . $RouterBoard->"current-firmware") ] . \ "\nRouterOS-Scripts:" . \ "\n Current: " . $GlobalConfigVersion . \ From c35485454c60ae489fd5b9fb7d0afde566cae645 Mon Sep 17 00:00:00 2001 From: Michael Gisbers Date: Mon, 21 Feb 2022 18:21:26 +0100 Subject: [PATCH 0966/2612] doc/mod/notification-matrix: add verbose steps for setup Modified-by: Christian Hesse --- .../notification-matrix.d/01-home-server.avif | Bin 0 -> 2402 bytes .../02-access-token.avif | Bin 0 -> 4278 bytes .../notification-matrix.d/03-join-room.avif | Bin 0 -> 3143 bytes doc/mod/notification-matrix.md | 59 +++++++++++++++++- 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 doc/mod/notification-matrix.d/01-home-server.avif create mode 100644 doc/mod/notification-matrix.d/02-access-token.avif create mode 100644 doc/mod/notification-matrix.d/03-join-room.avif diff --git a/doc/mod/notification-matrix.d/01-home-server.avif b/doc/mod/notification-matrix.d/01-home-server.avif new file mode 100644 index 0000000000000000000000000000000000000000..8a79ae6a1d304cc01e0f4c12021f9da3d0ee737f GIT binary patch literal 2402 zcmXw4c{~&T8{g1HIdf$*cTwafIh(VlIU_mR;aF|Vm?LttN~0;layCRH$@N8)J0vp1 zcOyhuF|iKCe$(&ueV*6nc|Xtl{k)#%`R@Y&02Bhkqw$CcOaOpqyNJUC=-@Dj07okw zD<1U?=O2#P)p&L+2#qEDKLr5r7*zOw`7UBH$p6L&<1yj5zZ#GiH^Lh{w+B(n>Y{=i0S1@=2p2wfV;87twJd6p$ z`|maa0Q@Sv;KqBRcuW-LFSCFDejXk~MCd>h6?Peb1S$ke2u5L}c#{tS_9pNsX$&5R z*wuK(J4^t`mn^`$$_a-?go^_N4;ZUHGr=k-7LVyRi^9-+41Fk)$$UYZDu&FjE&@l^ zlXRNMaQ;iHiEcwVjLAj%LH3TOb*yfKD&Y%G<#=a`QE<+%Iv+!H$Iybs9d+wvje>ry{hfyfFoPkM8Lwxj2cLZ| z$?+UtgT9aiTPjdz%r6PwYh|6OUv3>LWBTPMw&$^lTBTc1w<9=n*@SY}R^x~MmM7Zz zI9>*VSjt7Gr0bK1VneiarUo6F096|0qrp?n7K! z%BYx#&!VZHMEM zcCzBv6gsi36aVl*i{6PcnwTw$4>UI?R<5Hg;F7d%;w44BLGl$(#-wXk!5U(=;+?n_{;0d3)IdpWy^BJr>7q$BJ;e?-$E>%;J(}| zbL;(Uz4NWA)AML)yX(%qGvA^OU>F8jq~{CGL8?4eN~Y0DLdo3A^45~#&PlLJ8C3E~ z=4<8d_m-?`I5+H_!j|t^_C5!KrvisQ*KhEX(|I0_wfwo0ZGzN3I~!x)zepjPCKx>Q z>8T$7oSoZ2ZT;@xMzH?q5(wr$*`F?{DrG@rUpAAca#nVx*laBj6{>M9Lt zQ#~Y;*mTxg;B0Hi+r1^%=Z;;k<_zdtK!oeSsUDlfY|x&$bN-UMx&@BKHJ{b09JoAMlj+s9J=Q%5?Jj7r-4vL4 z*y$qDWt`Q17l>Fh3Z%q4+l+C)A;vWnmzN{ETjIFk@a2EwPG9Q}FSeMztV_Y%9c>*J z|JYB0mddMVsT`?mo{|W7+Podu2hgrMX!uBUq#HRC`8?XssOfQji;UQZaciX=gb8hgrVpU< zRJVxxE=kpAXlE?8T5~%-d5qO&T72q@db$1R62$Sqv(AJ(p^~ECJ;PGTJCwu` zu%0~yCArz=Xzm~4Qd7cNP|%{qOI%?-cO<9V?-S?CX}l<}cT{ z|LL2UaEdV`=w?l>kgeoR;2KU{7df1QWhK8@Sf~sUxy6A(E#8QiUV*>ju2H4MQ zs$}su^z;Q~HqslIrZIx&@SVc~`{lfA?HoTmkn2|byne+n%!BqICEpqzO#ZXOcjIXT zw+QGYzISo6B8jEv3|)3fSYJOexpt*g{;1GGPL!D~cFfC|eC{yj(?+4KR~J#$|M&)8^4d@s$x}w8j6YUi+0ZaKT4lpIQ1>(EW67x4FOMM; zsri|Ze*M*ZF9=g+qqAu{K`j~Eo251F$Q0OI#i`02#oR=;I;G>OzN^KGN1u>@=o$hu zPz&oV6kQT2sdY8!@Hh%SHDp>=eIbDOBOR1Mt^#SKNP*ffN9LMb zzUK^7>7M4uaIJQAwn#3}cYG#;N?J-Eos20nVQ~;HvZ~q9FgnA|SFBt-u!^g^42u8p zaOBOE3LE}X?v#DIwLfz~Q$lHh%#MW?M0%szHF8{%WhhA@em>6)IWL5VQ@(4)HnIp_ zh3e=+I{%jFQkYx%aV;?A-wS(`zK3Q;RUY{hOH}lE8KOllWX#tXT@(X_T`jaCNs9gt D0((xn literal 0 HcmV?d00001 diff --git a/doc/mod/notification-matrix.d/02-access-token.avif b/doc/mod/notification-matrix.d/02-access-token.avif new file mode 100644 index 0000000000000000000000000000000000000000..8a0b6473f5f241648545246ee7f3c6dbd6f8edbd GIT binary patch literal 4278 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 Date: Tue, 1 Mar 2022 12:47:23 +0100 Subject: [PATCH 0967/2612] global-functions: $FlushEmailQueue: delay if "in-progress"... Something else is sending a mail... Let's wait and hope the status is not confused. --- global-functions | 1 + 1 file changed, 1 insertion(+) diff --git a/global-functions b/global-functions index 11c3bd7..f207ac8 100644 --- a/global-functions +++ b/global-functions @@ -354,6 +354,7 @@ :foreach Id,Message in=$EmailQueue do={ :if ([ :typeof $Message ] = "array" ) do={ :local Attach [ $EitherOr ($Message->"attach") "" ]; + :while ([ / tool e-mail get last-status ] = "in-progress") do={ :delay 1s; } / tool e-mail send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \ body=($Message->"body") file=$Attach; :local Wait true; From df0d826999f198c650d50585c72d92ef7eb6a4c3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Mar 2022 22:25:38 +0100 Subject: [PATCH 0968/2612] hotspot-to-wpa: initialize variables earlier --- hotspot-to-wpa | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hotspot-to-wpa b/hotspot-to-wpa index c40e08a..b307a10 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -17,8 +17,11 @@ :local MacAddress $"mac-address"; :local UserName $username; :local Date [ / system clock get date ]; -:local Hotspot [ / ip hotspot host get [ find where mac-address=$MacAddress authorized ] server ]; :local UserVal [ / ip hotspot user get [ find where name=$UserName ] ]; +:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; +:local Hotspot [ / ip hotspot host get [ find where mac-address=$MacAddress authorized ] server ]; +:local Template [ / caps-man access-list get ([ find where disabled \ + comment=("hotspot-to-wpa template " . $Hotspot) ]->0) ]; :if ([ :len [ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ / caps-man access-list add comment="--- hotspot-to-wpa above ---" disabled=yes; @@ -28,16 +31,12 @@ $LogPrintExit2 info $0 ("Adding/updating accesslist entry for mac address " . $MacAddress . \ " (user " . $UserName . ").") false; - / caps-man access-list remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; / caps-man access-list add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ mac-address=$MacAddress private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" place-before=$PlaceBefore; -:local Template [ / caps-man access-list get ([ find where comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; -:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; :local Entry [ / caps-man access-list find where mac-address=$MacAddress \ comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; - :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; :if ([ :len $PrivatePassphrase ] > 0) do={ :if ($PrivatePassphrase = "ignore") do={ From c1fa0f3579573b75cadba585c1aeb7e68313645c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Mar 2022 22:26:41 +0100 Subject: [PATCH 0969/2612] hotspot-to-wpa: support ignoring specific hotspot --- doc/hotspot-to-wpa.md | 1 + hotspot-to-wpa | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index b410979..8733a7c 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -56,6 +56,7 @@ Create hotspot login credentials: Additionally templates can be created to give more options for access list: +* `action`: set to `reject` to ignore logins on that hotspot * `private-passphrase`: do **not** use passphrase from hotspot's user credentials, but given one - or unset (use default passphrase) with special word `ignore` diff --git a/hotspot-to-wpa b/hotspot-to-wpa index b307a10..6290eda 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -23,6 +23,10 @@ :local Template [ / caps-man access-list get ([ find where disabled \ comment=("hotspot-to-wpa template " . $Hotspot) ]->0) ]; +:if ($Template->"action" = "reject") do={ + $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; +} + :if ([ :len [ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ / caps-man access-list add comment="--- hotspot-to-wpa above ---" disabled=yes; $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; From 07cc38e973a6037649083494332fbae1946b48b4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 8 Mar 2022 22:28:48 +0100 Subject: [PATCH 0970/2612] global-functions: (re-)introduce global $Read ... to interactively read input from user on terminal. --- global-functions | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/global-functions b/global-functions index f207ac8..af617b3 100644 --- a/global-functions +++ b/global-functions @@ -38,6 +38,7 @@ :global ParseKeyValueStore; :global QuotedPrintable; :global RandomDelay; +:global Read; :global RequiredRouterOS; :global ScriptFromTerminal; :global ScriptInstallUpdate; @@ -636,6 +637,11 @@ :delay ([ $GetRandomNumber $1 ] . [ $EitherOr $2 "s" ]); } +# read input from user +:set Read do={ + :return; +} + # check for required RouterOS version :set RequiredRouterOS do={ :local Caller [ :tostr $1 ]; From cbb2f067e64d09d3d1443d9c2b17266fa56b2e99 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 8 Mar 2022 22:30:01 +0100 Subject: [PATCH 0971/2612] accesslist-duplicates: use global $Read --- accesslist-duplicates.capsman | 2 +- accesslist-duplicates.local | 2 +- accesslist-duplicates.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman index 6d2c896..74cf3b3 100644 --- a/accesslist-duplicates.capsman +++ b/accesslist-duplicates.capsman @@ -12,7 +12,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Read do={ :return; } +:global Read; :local Seen [ :toarray "" ]; :local Shown [ :toarray "" ]; diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local index 24c8e29..0aa946c 100644 --- a/accesslist-duplicates.local +++ b/accesslist-duplicates.local @@ -12,7 +12,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Read do={ :return; } +:global Read; :local Seen [ :toarray "" ]; :local Shown [ :toarray "" ]; diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template index f9f4494..f1862bb 100644 --- a/accesslist-duplicates.template +++ b/accesslist-duplicates.template @@ -13,7 +13,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:local Read do={ :return; } +:global Read; :local Seen [ :toarray "" ]; :local Shown [ :toarray "" ]; From 122f90b6930ba499f917887b6e25adae3109a513 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 8 Mar 2022 22:47:26 +0100 Subject: [PATCH 0972/2612] firmware-upgrade-reboot: ignore firmware downgrade --- firmware-upgrade-reboot | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/firmware-upgrade-reboot b/firmware-upgrade-reboot index a3a25db..ac2cb55 100644 --- a/firmware-upgrade-reboot +++ b/firmware-upgrade-reboot @@ -11,11 +11,15 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global LogPrintExit2; +:global VersionToNum; :local RouterBoard [ / system routerboard get ]; :if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ $LogPrintExit2 info $0 ("Firmware is already up to date.") true; } +:if ([ $VersionToNum ($RouterBoard->"current-firmware") ] > [ $VersionToNum ($RouterBoard->"upgrade-firmware") ]) do={ + $LogPrintExit2 info $0 ("Different firmware version is available, but it is a downgrade. Ignoring.") true; +} :if ([ / system routerboard settings get auto-upgrade ] = false) do={ $LogPrintExit2 info $0 ("Firmware version " . $RouterBoard->"upgrade-firmware" . \ From c4a5f8787a57836bb3e8463cdda6cab6043b0169 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Mar 2022 22:33:46 +0100 Subject: [PATCH 0973/2612] capsman-download-packages: get info from log Relying on older packages in local storage may be problematic due to size constraints. Let's check the log for required packages. --- capsman-download-packages | 19 +++++++++++++++++++ doc/capsman-download-packages.md | 13 +++---------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/capsman-download-packages b/capsman-download-packages index 6f4642c..ac5ec0e 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -50,6 +50,25 @@ $WaitFullyConnected; } } +:if ($Updated = false && [ / system resource get uptime ] < 2m) do={ + $LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false; + :delay 2m; +} + +:foreach Log in=[ / log find where topics=({"caps", "error"}) \ + message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . "-.*\\.npk', no such file") ] do={ + :local Message [ / log get $Log message ]; + :local Package [ :pick $Message \ + ([ :find $Message "'" ] + 1) \ + [ :find $Message ("-" . $InstalledVersion . "-") ] ]; + :local Arch [ :pick $Message \ + ([ :find $Message ("-" . $InstalledVersion . "-") ] + 2 + [ :len $InstalledVersion ]) \ + [ :find $Message ".npk" ] ]; + :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ + :set Updated true; + } +} + :if ($Updated = true) do={ :if ([ :len [ / system script find where name="capsman-rolling-upgrade" ] ] > 0) do={ / system script run capsman-rolling-upgrade; diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index d3e08ad..bac8a3c 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -26,16 +26,9 @@ Optionally add a scheduler to run after startup: / system scheduler add name=capsman-download-packages on-event="/ system script run capsman-download-packages;" start-time=startup; -Only packages available in older version are downloaded. For initial setup -place the required packages to CAPsMAN package path (see -`/ caps-man manager`). The packages can be downloaded from device with -function `$DownloadPackage`, use something like this to download latest -packages to directory `routeros`: - - $DownloadPackage routeros "" arm routeros; - $DownloadPackage routeros "" arm64 routeros; - $DownloadPackage routeros "" mipsbe routeros; - [...] +Packages available in local storage in older version are downloaded +unconditionally. The script tries to download missing packages by guessing +from system log. Usage and invocation -------------------- From 7bd40b34f147cc18207436c7351beeff5ae70935 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Mar 2022 11:42:16 +0200 Subject: [PATCH 0974/2612] check-lte-firmware-upgrade: fix command for ROS 7.x --- check-lte-firmware-upgrade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index aef27fe..cc64304 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -28,7 +28,7 @@ ($Firmware->"latest") . ".") false; } else={ :if (($Firmware->"installed") != ($Firmware->"latest")) do={ - :local Info [ / interface lte info $Interface once as-value ]; + :local Info [ / interface lte monitor $Interface once as-value ]; $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \ message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \ From 5aecc9f1a316874f9c2935b6065347223927a299 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Mar 2022 12:31:38 +0200 Subject: [PATCH 0975/2612] check-lte-firmware-upgrade: be more verbose --- check-lte-firmware-upgrade | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index cc64304..90de3fe 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -15,6 +15,7 @@ :global CharacterReplace; :global LogPrintExit2; +:global ScriptFromTerminal; :global SendNotification2; :global SymbolForNotification; @@ -22,13 +23,15 @@ :local IntName [ / interface lte get $Interface name ]; :do { :local Firmware [ / interface lte firmware-upgrade $Interface once as-value ]; + :local Info [ / interface lte monitor $Interface once as-value ]; :if ($SentLteFirmwareUpgradeNotification = ($Firmware->"latest")) do={ $LogPrintExit2 debug $0 ("Already sent the LTE firmware upgrade notification for version " . \ ($Firmware->"latest") . ".") false; } else={ :if (($Firmware->"installed") != ($Firmware->"latest")) do={ - :local Info [ / interface lte monitor $Interface once as-value ]; + $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 " . \ @@ -37,6 +40,10 @@ "Installed: " . ($Firmware->"installed") . "\n" . \ "Available: " . ($Firmware->"latest")); silent=true }); :set SentLteFirmwareUpgradeNotification ($Firmware->"latest"); + } else={ + :if ([ $ScriptFromTerminal $0 ] = true) do={ + $LogPrintExit2 info $0 ("No firmware upgrade available for LTE interface " . $IntName . ".") false; + } } } } on-error={ From d952e7e6c703dcc949478de351e9bf622be9d319 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Mar 2022 12:37:58 +0200 Subject: [PATCH 0976/2612] check-lte-firmware-upgrade: support starting unattended firmware upgrade... ... from terminal if script is installed. --- check-lte-firmware-upgrade | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 90de3fe..0ae239c 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -32,6 +32,18 @@ :if (($Firmware->"installed") != ($Firmware->"latest")) do={ $LogPrintExit2 info $0 ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ "LTE interface " . $IntName . ".") false; + + :if ([ $ScriptFromTerminal $0 ] = true && \ + [ :len [ / system script find where name="unattended-lte-firmware-upgrade" ] ] > 0) do={ + :put ("Do you want to start unattended lte firmware upgrade for interface " . $IntName . "? [y/N]"); + :if (([ / terminal inkey timeout=60 ] % 32) = 25) do={ + / system script run unattended-lte-firmware-upgrade; + $LogPrintExit2 info $0 ("Scheduled lte firmware upgrade for interface " . $IntName . "...") true; + } else={ + :put "Canceled..."; + } + } + $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \ message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \ From 2aa93a06716350d5e29fff4cfd1e7deb338ab80c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Mar 2022 13:36:11 +0200 Subject: [PATCH 0977/2612] check-lte-firmware-upgrade: rework code and its logic --- check-lte-firmware-upgrade | 103 +++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 43 deletions(-) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 0ae239c..6918c7b 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -10,56 +10,73 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } -:global Identity; :global SentLteFirmwareUpgradeNotification; -:global CharacterReplace; -:global LogPrintExit2; -:global ScriptFromTerminal; -:global SendNotification2; -:global SymbolForNotification; +:if ([ :typeof $SentLteFirmwareUpgradeNotification ] != "array") do={ + :global SentLteFirmwareUpgradeNotification [ :toarray "" ]; +} + +:local CheckInterface do={ + :local Interface $1; + + :global Identity; + :global SentLteFirmwareUpgradeNotification; + + :global CharacterReplace; + :global LogPrintExit2; + :global ScriptFromTerminal; + :global SendNotification2; + :global SymbolForNotification; -:foreach Interface in=[ / interface lte find ] do={ :local IntName [ / interface lte get $Interface name ]; + :local Firmware; + :local Info; :do { - :local Firmware [ / interface lte firmware-upgrade $Interface once as-value ]; - :local Info [ / interface lte monitor $Interface once as-value ]; - - :if ($SentLteFirmwareUpgradeNotification = ($Firmware->"latest")) do={ - $LogPrintExit2 debug $0 ("Already sent the LTE firmware upgrade notification for version " . \ - ($Firmware->"latest") . ".") false; - } else={ - :if (($Firmware->"installed") != ($Firmware->"latest")) do={ - $LogPrintExit2 info $0 ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ - "LTE interface " . $IntName . ".") false; - - :if ([ $ScriptFromTerminal $0 ] = true && \ - [ :len [ / system script find where name="unattended-lte-firmware-upgrade" ] ] > 0) do={ - :put ("Do you want to start unattended lte firmware upgrade for interface " . $IntName . "? [y/N]"); - :if (([ / terminal inkey timeout=60 ] % 32) = 25) do={ - / system script run unattended-lte-firmware-upgrade; - $LogPrintExit2 info $0 ("Scheduled lte firmware upgrade for interface " . $IntName . "...") true; - } else={ - :put "Canceled..."; - } - } - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \ - message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \ - "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ - "Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \ - "Installed: " . ($Firmware->"installed") . "\n" . \ - "Available: " . ($Firmware->"latest")); silent=true }); - :set SentLteFirmwareUpgradeNotification ($Firmware->"latest"); - } else={ - :if ([ $ScriptFromTerminal $0 ] = true) do={ - $LogPrintExit2 info $0 ("No firmware upgrade available for LTE interface " . $IntName . ".") false; - } - } - } + :set Firmware [ / interface lte firmware-upgrade $Interface once as-value ]; + :set Info [ / interface lte monitor $Interface once as-value ]; } on-error={ $LogPrintExit2 debug $0 ("Could not get latest LTE firmware version for interface " . \ $IntName . ".") false; + :return false; } + + :if (($Firmware->"installed") = ($Firmware->"latest")) do={ + :if ([ $ScriptFromTerminal "check-lte-firmware-upgrade" ] = true) do={ + $LogPrintExit2 info $0 ("No firmware upgrade available for LTE interface " . $IntName . ".") false; + } + :return true; + } + + :if ([ $ScriptFromTerminal "check-lte-firmware-upgrade" ] = true && \ + [ :len [ / system script find where name="unattended-lte-firmware-upgrade" ] ] > 0) do={ + :put ("Do you want to start unattended lte firmware upgrade for interface " . $IntName . "? [y/N]"); + :if (([ / terminal inkey timeout=60 ] % 32) = 25) do={ + / system script run unattended-lte-firmware-upgrade; + $LogPrintExit2 info $0 ("Scheduled lte firmware upgrade for interface " . $IntName . "...") false; + :return true; + } else={ + :put "Canceled..."; + } + } + + :if (($SentLteFirmwareUpgradeNotification->$IntName) = ($Firmware->"latest")) do={ + $LogPrintExit2 debug $0 ("Already sent the LTE firmware upgrade notification for version " . \ + ($Firmware->"latest") . ".") false; + :return false; + } + + $LogPrintExit2 info $0 ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ + "LTE interface " . $IntName . ".") false; + $SendNotification2 ({ origin=$0; \ + subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \ + message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \ + "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ + "Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \ + "Installed: " . ($Firmware->"installed") . "\n" . \ + "Available: " . ($Firmware->"latest")); silent=true }); + :set ($SentLteFirmwareUpgradeNotification->$IntName) ($Firmware->"latest"); +} + +:foreach Interface in=[ / interface lte find ] do={ + $CheckInterface $Interface; } From 71b69fc1898babf490b7dc8e7b0769022d5a2f79 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 30 Mar 2022 18:03:50 +0200 Subject: [PATCH 0978/2612] introduce backup-partition --- README.md | 1 + backup-partition | 36 +++++++++++++++++++++++++++++++++ doc/backup-cloud.md | 1 + doc/backup-email.md | 1 + doc/backup-partition.md | 45 +++++++++++++++++++++++++++++++++++++++++ doc/backup-upload.md | 3 ++- doc/packages-update.md | 1 + global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 1 + global-functions | 2 +- 11 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 backup-partition create mode 100644 doc/backup-partition.md diff --git a/README.md b/README.md index a3da7e7..361dbd5 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,7 @@ Available scripts * [Find and remove access list duplicates](doc/accesslist-duplicates.md) * [Upload backup to Mikrotik cloud](doc/backup-cloud.md) * [Send backup via e-mail](doc/backup-email.md) +* [Save configuration to fallback partition](doc/backup-partition.md) * [Upload backup to server](doc/backup-upload.md) * [Download packages for CAP upgrade from CAPsMAN](doc/capsman-download-packages.md) * [Run rolling CAP upgrades from CAPsMAN](doc/capsman-rolling-upgrade.md) diff --git a/backup-partition b/backup-partition new file mode 100644 index 0000000..c72c7f9 --- /dev/null +++ b/backup-partition @@ -0,0 +1,36 @@ +#!rsc by RouterOS +# RouterOS script: backup-partition +# Copyright (c) 2022 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: backup-script +# +# save configuration to fallback partition +# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md + +:local 0 "backup-partition"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global LogPrintExit2; + +:if ([ :len [ / partitions find ] ] < 2) do={ + $LogPrintExit2 error $0 ("Device does not have a fallback partition.") true; +} + +:local ActiveRunning [ / partitions find where active running ]; + +:if ([ :len $ActiveRunning ] < 1) do={ + $LogPrintExit2 error $0 ("Device is not running from active partition.") true; +} + +:local ActiveRunningVar [ / partitions get $ActiveRunning ]; + +:do { + / partitions save-config-to ($ActiveRunningVar->"fallback-to"); + $LogPrintExit2 info $0 ("Saved configuration to partition '" . \ + ($ActiveRunningVar->"fallback-to") . "'.") false; +} on-error={ + $LogPrintExit2 error $0 ("Failed saving configuration to partition '" . \ + ($ActiveRunningVar->"fallback-to") . "'!") true; +} diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index f3631ad..6a15688 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -55,6 +55,7 @@ See also -------- * [Send backup via e-mail](backup-email.md) +* [Save configuration to fallback partition](doc/backup-partition.md) * [Upload backup to server](backup-upload.md) --- diff --git a/doc/backup-email.md b/doc/backup-email.md index 19bbeee..701f10a 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -46,6 +46,7 @@ See also -------- * [Upload backup to Mikrotik cloud](backup-cloud.md) +* [Save configuration to fallback partition](doc/backup-partition.md) * [Upload backup to server](backup-upload.md) --- diff --git a/doc/backup-partition.md b/doc/backup-partition.md new file mode 100644 index 0000000..c31c780 --- /dev/null +++ b/doc/backup-partition.md @@ -0,0 +1,45 @@ +Save configuration to fallback partition +======================================== + +[◀ Go back to main README](../README.md) + +> â„šī¸ **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. + +Description +----------- + +This script saves the current configuration to fallback +[partition](https://wiki.mikrotik.com/wiki/Manual:Partitions). + +For this to work you need a device with sufficient flash storage that is +properly partitioned. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate backup-partition; + +Usage and invocation +-------------------- + +Just run the script: + + / system script run backup-partition; + +Creating a scheduler may be an option: + + / system scheduler add interval=1w name=backup-partition on-event="/ system script run backup-partition;" start-time=09:30:00; + +See also +-------- + +* [Upload backup to Mikrotik cloud](backup-cloud.md) +* [Send backup via e-mail](backup-email.md) +* [Upload backup to server](backup-upload.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/backup-upload.md b/doc/backup-upload.md index a4d2bc7..a3620c4 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -69,8 +69,9 @@ Creating a scheduler may be an option: See also -------- -* [Send backup via e-mail](backup-email.md) * [Upload backup to Mikrotik cloud](backup-cloud.md) +* [Send backup via e-mail](backup-email.md) +* [Save configuration to fallback partition](doc/backup-partition.md) --- [◀ Go back to main README](../README.md) diff --git a/doc/packages-update.md b/doc/packages-update.md index 0007acc..243e72b 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -43,6 +43,7 @@ See also * [Notify on RouterOS update](check-routeros-update.md) * [Upload backup to Mikrotik cloud](backup-cloud.md) * [Send backup via e-mail](backup-email.md) +* [Save configuration to fallback partition](doc/backup-partition.md) * [Upload backup to server](backup-upload.md) * [Automatically upgrade firmware and reboot](firmware-upgrade-reboot.md) diff --git a/global-config b/global-config index 3ae4557..ea5176e 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 78; +:global GlobalConfigVersion 79; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index 7d0c83d..d5df364 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 78; +:global GlobalConfigVersion 79; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 7e029be..7183619 100644 --- a/global-config.changes +++ b/global-config.changes @@ -87,6 +87,7 @@ 76="Added an option to suppress notifications on host down with 'netwatch-notify'."; 77="Introduced new script 'firmware-upgrade-reboot'. Handle with care!"; 78="New documentation is online for notifications via Telegram & Matrix, variable inspection, ip address calculation and running scripts once."; + 79="Introduced new script 'backup-partition' to save configuration to fallback partition."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index af617b3..96a5ce8 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 78; +:global ExpectedConfigVersion 79; # global variables not to be changed by user :global GlobalFunctionsReady false; From 0786111c5c5bd3085a52fec749fc68a1584c1a4c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 31 Mar 2022 10:27:07 +0200 Subject: [PATCH 0979/2612] hotspot-to-wpa: allow login page to load Depending on configuration the VLAN is changed on the SSID currently serving the hotspot. So give the login page (with success status) a moment to load before kicking the device. --- hotspot-to-wpa | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hotspot-to-wpa b/hotspot-to-wpa index 6290eda..a08e3bc 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -33,6 +33,9 @@ } :local PlaceBefore ([ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ]->0); +# allow login page to load +:delay 1s; + $LogPrintExit2 info $0 ("Adding/updating accesslist entry for mac address " . $MacAddress . \ " (user " . $UserName . ").") false; / caps-man access-list remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; From 9dbc56457b1fb25099f7d487b8284a03b47ffbe4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Apr 2022 17:40:21 +0200 Subject: [PATCH 0980/2612] capsman-download-packages: try to warn about missing logs --- capsman-download-packages | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/capsman-download-packages b/capsman-download-packages index ac5ec0e..da43454 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -50,9 +50,15 @@ $WaitFullyConnected; } } -:if ($Updated = false && [ / system resource get uptime ] < 2m) do={ - $LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false; - :delay 2m; +:if ([ :len [ / system logging find where topics~"error" !(topics~"!error") \ + !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ + $LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \ + "Probably can not download packages automatically.") false; +} else={ + :if ($Updated = false && [ / system resource get uptime ] < 2m) do={ + $LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false; + :delay 2m; + } } :foreach Log in=[ / log find where topics=({"caps", "error"}) \ From 57fab952908c9ad52e73a0103d0d5e422f8cdeda Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 7 Apr 2022 09:23:16 +0200 Subject: [PATCH 0981/2612] capsman-download-packages: break long lines --- capsman-download-packages | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/capsman-download-packages b/capsman-download-packages index da43454..10585ec 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -44,7 +44,8 @@ $WaitFullyConnected; :if ($File->"package-architecture" = "mips") do={ :set ($File->"package-architecture") "mipsbe"; } - :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion ($File->"package-architecture") $PackagePath ] = true) do={ + :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ + ($File->"package-architecture") $PackagePath ] = true) do={ :set Updated true; / file remove $Package; } @@ -62,7 +63,8 @@ $WaitFullyConnected; } :foreach Log in=[ / log find where topics=({"caps", "error"}) \ - message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . "-.*\\.npk', no such file") ] do={ + message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \ + "-.*\\.npk', no such file") ] do={ :local Message [ / log get $Log message ]; :local Package [ :pick $Message \ ([ :find $Message "'" ] + 1) \ From c132d2840843a5da40f30e5b66cb1495f5c02357 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 Apr 2022 14:19:50 +0200 Subject: [PATCH 0982/2612] hotspot-to-wpa: move code for marker up --- hotspot-to-wpa | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hotspot-to-wpa b/hotspot-to-wpa index a08e3bc..9ffee91 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -20,12 +20,6 @@ :local UserVal [ / ip hotspot user get [ find where name=$UserName ] ]; :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; :local Hotspot [ / ip hotspot host get [ find where mac-address=$MacAddress authorized ] server ]; -:local Template [ / caps-man access-list get ([ find where disabled \ - comment=("hotspot-to-wpa template " . $Hotspot) ]->0) ]; - -:if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; -} :if ([ :len [ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ / caps-man access-list add comment="--- hotspot-to-wpa above ---" disabled=yes; @@ -33,6 +27,13 @@ } :local PlaceBefore ([ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ]->0); +:local Template [ / caps-man access-list get ([ find where disabled \ + comment=("hotspot-to-wpa template " . $Hotspot) ]->0) ]; + +:if ($Template->"action" = "reject") do={ + $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; +} + # allow login page to load :delay 1s; From 3f8d3acd60dab580c590a5a5e87f65cdcceb3433 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 Apr 2022 14:21:28 +0200 Subject: [PATCH 0983/2612] hotspot-to-wpa: create template if missing --- hotspot-to-wpa | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hotspot-to-wpa b/hotspot-to-wpa index 9ffee91..628d748 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -27,8 +27,13 @@ } :local PlaceBefore ([ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ]->0); -:local Template [ / caps-man access-list get ([ find where disabled \ - comment=("hotspot-to-wpa template " . $Hotspot) ]->0) ]; +:if ([ :len [ / caps-man access-list find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ + / caps-man access-list add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; +} +:local Template [ / caps-man access-list get ([ find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; :if ($Template->"action" = "reject") do={ $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; From a058c9e1edd8dc4895a64881ee1b495e86fe7510 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 Apr 2022 14:29:46 +0200 Subject: [PATCH 0984/2612] global-functions: $ScriptInstallUpdate: support giving comment... ... for new scripts. This allows to have extra settings from the beginning, for example: $ScriptInstallUpdate script1,script2 "base-url=https://example.com/your/custom/repository/" --- global-functions | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 96a5ce8..dc64824 100644 --- a/global-functions +++ b/global-functions @@ -684,7 +684,8 @@ # install new scripts, update existing scripts :set ScriptInstallUpdate do={ - :local Scripts [ :toarray $1 ]; + :local Scripts [ :toarray $1 ]; + :local NewComment [ :tostr $2 ]; :global ExpectedConfigVersion; :global GlobalConfigVersion; @@ -711,7 +712,7 @@ :foreach Script in=$Scripts do={ :if ([ :len [ / system script find where name=$Script ] ] = 0) do={ $LogPrintExit2 info $0 ("Adding new script: " . $Script) false; - / system script add name=$Script source="#!rsc by RouterOS\n"; + / system script add name=$Script owner=$Script source="#!rsc by RouterOS\n" comment=$NewComment; } } From a36aa441edc73bc1f4e45ffebcf9773f5f4dd154 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 Apr 2022 16:25:47 +0200 Subject: [PATCH 0985/2612] global-functions: $DefaultRouteIsReachable: update properties for ROS 7.x --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index dc64824..fcf2d46 100644 --- a/global-functions +++ b/global-functions @@ -183,7 +183,7 @@ # default route is reachable :set DefaultRouteIsReachable do={ - :if ([ :len [ / ip route find where dst-address=0.0.0.0/0 active !blackhole !routing-mark !unreachable ] ] > 0) do={ + :if ([ :len [ / ip route find where dst-address=0.0.0.0/0 active routing-table=main ] ] > 0) do={ :return true; } :return false; From 9bc2123ee5bd7af4a8e1ca47696a3f3379d5a028 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 28 Apr 2022 10:11:00 +0200 Subject: [PATCH 0986/2612] global-functions: set $0 with script name Now that we have some active code at the bottom... --- global-functions | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index fcf2d46..7e359cf 100644 --- a/global-functions +++ b/global-functions @@ -7,6 +7,8 @@ # global functions # https://git.eworm.de/cgit/routeros-scripts/about/ +:local 0 "global-functions"; + # expected configuration version :global ExpectedConfigVersion 79; @@ -1269,8 +1271,8 @@ } # check for required RouterOS version -:if ([ $RequiredRouterOS "global-functions" "7.0" false ] = true) do={ - $RequiredRouterOS "global-functions" "7.1" true; +:if ([ $RequiredRouterOS $0 "7.0" false ] = true) do={ + $RequiredRouterOS $0 "7.1" true; } else={ $LogPrintExit2 warning $0 ("Still running RouterOS v6, please switch to branch " . \ "'routeros-v6', see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v6") false; From 7c8e230521f1a936da034dfc05197fe9434926ed Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 28 Apr 2022 09:34:12 +0200 Subject: [PATCH 0987/2612] global-functions: validate syntax of modules --- global-functions | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 7e359cf..397a10d 100644 --- a/global-functions +++ b/global-functions @@ -1267,7 +1267,12 @@ # load modules :foreach Script in=[ / system script find where name ~ "^mod/." ] do={ - / system script run $Script; + :local ScriptVal [ / system script get $Script ]; + :if ([ $ValidateSyntax ($ScriptVal->"source") ] = true) do={ + / system script run $Script; + } else={ + $LogPrintExit2 error $0 ("Module '" . $ScriptVal->"name" . "' failed syntax validation, skipping.") false; + } } # check for required RouterOS version From e74bec7e5b62e54d10b1f3ba058868536b35fdc6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 28 Apr 2022 09:55:28 +0200 Subject: [PATCH 0988/2612] global-functions: catch runtime error when loading modules --- global-functions | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 397a10d..6cd6b85 100644 --- a/global-functions +++ b/global-functions @@ -1269,7 +1269,11 @@ :foreach Script in=[ / system script find where name ~ "^mod/." ] do={ :local ScriptVal [ / system script get $Script ]; :if ([ $ValidateSyntax ($ScriptVal->"source") ] = true) do={ - / system script run $Script; + :do { + / system script run $Script; + } on-error={ + $LogPrintExit2 error $0 ("Module '" . $ScriptVal->"name" . "' failed to run.") false; + } } else={ $LogPrintExit2 error $0 ("Module '" . $ScriptVal->"name" . "' failed syntax validation, skipping.") false; } From f417bcbcd4ab7458f1d0b4265ccda2854ba96b4f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 28 Apr 2022 11:01:57 +0200 Subject: [PATCH 0989/2612] global-functions: $LogPrintExit2: handle empty name --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 6cd6b85..0feeb1d 100644 --- a/global-functions +++ b/global-functions @@ -481,7 +481,7 @@ :return ("\1B[" . $Color->$1 . "m" . $1 . "\1B[0m"); } - :local Log ($Name . ": " . $Message); + :local Log ([ $EitherOr $Name "" ] . ": " . $Message); :if ($Severity ~ ("^(debug|error|info)\$")) do={ :if ($Severity = "debug") do={ :log debug $Log; } :if ($Severity = "error") do={ :log error $Log; } From 56c5da8ed4097018300c1cf284ce7308acd7ece4 Mon Sep 17 00:00:00 2001 From: PackElend Date: Sat, 30 Apr 2022 00:20:19 +0200 Subject: [PATCH 0990/2612] doc/lease-script: reflect actual action of the script --- doc/lease-script.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/doc/lease-script.md b/doc/lease-script.md index 0ad67fb..16fc73e 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -9,13 +9,19 @@ Run other scripts on DHCP lease Description ----------- -This script is supposed to run from dhcp server as lease script. Currently -it does: +This script is supposed to run from dhcp server as lease script. On a dhcp +lease it runs each script containing the following line, where `##` is a +decimal number for ordering: -* run [collect-wireless-mac](collect-wireless-mac.md) -* run [dhcp-lease-comment](dhcp-lease-comment.md) -* run [dhcp-to-dns](dhcp-to-dns.md) -* run [hotspot-to-wpa](hotspot-to-wpa.md) + # provides: lease-script, order=## + +Currently it runs if available, in order: + +* [dhcp-to-dns](dhcp-to-dns.md) +* [collect-wireless-mac](collect-wireless-mac.md) +* [dhcp-lease-comment](dhcp-lease-comment.md) +* `hotspot-to-wpa-cleanup`, which is an optional cleanup script + of [hotspot-to-wpa](hotspot-to-wpa.md) Requirements and installation ----------------------------- From e9575ead7ab16b1af0ce1407db7706b6e3f805b2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 May 2022 12:05:11 +0200 Subject: [PATCH 0991/2612] update list of contributors --- CONTRIBUTIONS.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 2210ea7..a427aed 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -7,12 +7,14 @@ Thanks a lot for your contributions! ## Patches -These persons contributed code. See the git history for details! +These persons contributed code or documentation. See the git history +for details! * [Ben Harris](mailto:mail@bharr.is) (@bharrisau) * [Daniel Ziegenberg](mailto:daniel@ziegenberg.at) (@ziegenberg) * [Michael Gisbers](mailto:michael@gisbers.de) (@mgisbers) * [netztrip](mailto:dave-tvg@netztrip.de) (@netztrip) +* [Stefan MÃŧller](mailto:stefan.mueller.83@gmail.com) (@PackElend) ## Donations From 7189a3bbe5320a80d1cfbcbf940c1a2d57c45b73 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 4 May 2022 21:11:26 +0200 Subject: [PATCH 0992/2612] global-wait: do not claim to be a backup script... Probalby a copy and paste issue? --- global-wait | 2 -- 1 file changed, 2 deletions(-) diff --git a/global-wait b/global-wait index 9f3d438..43cc5cc 100644 --- a/global-wait +++ b/global-wait @@ -3,8 +3,6 @@ # Copyright (c) 2020-2022 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: backup-script -# # wait for global-functions to finish # https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md From ecde864263f8572503eeaba2ad7c806847adb594 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 4 May 2022 22:23:17 +0200 Subject: [PATCH 0993/2612] README: installing custom scripts & modules --- README.d/12-install-custom-script.avif | Bin 0 -> 2349 bytes README.d/hello-world.rsc | 3 +++ README.md | 23 +++++++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 README.d/12-install-custom-script.avif create mode 100644 README.d/hello-world.rsc diff --git a/README.d/12-install-custom-script.avif b/README.d/12-install-custom-script.avif new file mode 100644 index 0000000000000000000000000000000000000000..fb536061f7d59c1f3c52ebd75b418962e929f9d3 GIT binary patch literal 2349 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 Date: Fri, 6 May 2022 08:20:34 +0200 Subject: [PATCH 0994/2612] doc/check-routeros-update: mention neighbor discovery --- doc/check-routeros-update.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index cac1850..f045352 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -14,7 +14,8 @@ The primary use of this script is to notify about RouterOS updates. Run from a terminal you can start the update process or schedule it. Centrally managing update process of several devices is possibly by -specifying versions safe to be updated on a web server. +specifying versions safe to be updated on a web server. Versions seen +in neighbor discovery can be specified to be safe as well. Also installing patch updates (where just last digit is increased) automatically is supported. From c4008b91cd1eaea7789b2c4b40b590e5eb2f8ed6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 May 2022 08:20:53 +0200 Subject: [PATCH 0995/2612] doc/check-routeros-update: give warning about possible breakage --- doc/check-routeros-update.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index f045352..d53ae18 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -20,6 +20,11 @@ in neighbor discovery can be specified to be safe as well. Also installing patch updates (where just last digit is increased) automatically is supported. +> âš ī¸ **Warning**: Installing updates is important from a security point +> of view. At the same time it can be source of serve breakage. So test +> versions in lab and read forum before deploying to your production +> environment! Automatic updates should be handled with care! + ### Sample notification ![check-routeros-update notification](check-routeros-update.d/notification.svg) From 6784f82593c1af6b9db7cef39ba0326292fe654e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 May 2022 08:26:00 +0200 Subject: [PATCH 0996/2612] doc/check-routeros-update: link changelog and forum --- doc/check-routeros-update.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index d53ae18..0710b76 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -22,8 +22,11 @@ automatically is supported. > âš ī¸ **Warning**: Installing updates is important from a security point > of view. At the same time it can be source of serve breakage. So test -> versions in lab and read forum before deploying to your production -> environment! Automatic updates should be handled with care! +> versions in lab and read +> [changelog](https://mikrotik.com/download/changelogs/) and +> [forum](https://forum.mikrotik.com/viewforum.php?f=21) before deploying +> to your production environment! Automatic updates should be handled +> with care! ### Sample notification From 93ec9afe558ef6eba5d513fab359bb5f6618666d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Jan 2022 10:44:55 +0100 Subject: [PATCH 0997/2612] cleanup dummy scripts from backup scripts renames --- cloud-backup | 2 -- email-backup | 2 -- upload-backup | 2 -- 3 files changed, 6 deletions(-) delete mode 100644 cloud-backup delete mode 100644 email-backup delete mode 100644 upload-backup diff --git a/cloud-backup b/cloud-backup deleted file mode 100644 index 2c48f07..0000000 --- a/cloud-backup +++ /dev/null @@ -1,2 +0,0 @@ -#!rsc by RouterOS -# dummy for migration diff --git a/email-backup b/email-backup deleted file mode 100644 index 2c48f07..0000000 --- a/email-backup +++ /dev/null @@ -1,2 +0,0 @@ -#!rsc by RouterOS -# dummy for migration diff --git a/upload-backup b/upload-backup deleted file mode 100644 index 2c48f07..0000000 --- a/upload-backup +++ /dev/null @@ -1,2 +0,0 @@ -#!rsc by RouterOS -# dummy for migration From 1cac1c1b059a2a1fc6e4f6d37d7b6c499baf1e69 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:54:25 +0200 Subject: [PATCH 0998/2612] global-config: RouterOS v7 path syntax --- global-config | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/global-config b/global-config index ea5176e..933ec2e 100644 --- a/global-config +++ b/global-config @@ -128,10 +128,10 @@ # Run different commands with multiple mode-button presses. :global ModeButton { - 1="/ system script run leds-toggle-mode;"; + 1="/system/script/run leds-toggle-mode;"; 2=":global SendNotification; :global Identity; \$SendNotification (\"Hello...\") (\"Hello world, \" . \$Identity . \" calling!\");"; - 3="/ system shutdown;"; - 4="/ system reboot;"; + 3="/system/shutdown;"; + 4="/system/reboot;"; 5=":global BridgePortVlan; \$BridgePortVlan alt;"; # add more here... }; @@ -141,8 +141,8 @@ # Run commands on SMS action. :global SmsAction { bridge-port-vlan-alt=":global BridgePortVlan; \$BridgePortVlan alt;"; - reboot="/ system reboot;"; - shutdown="/ system shutdown;"; + reboot="/system/reboot;"; + shutdown="/system/shutdown;"; # add more here... }; @@ -194,7 +194,7 @@ # load custom settings from overlay # Warning: Do *NOT* copy this code to overlay! :do { - / system script run global-config-overlay; + /system/script/run global-config-overlay; } on-error={ :log error ("Loading configuration from overlay failed!"); } From b996f00dd5f92493b211b59ae2a0db32a918c8b6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:58:02 +0200 Subject: [PATCH 0999/2612] global-config.changes: RouterOS v7 path syntax --- global-config.changes | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/global-config.changes b/global-config.changes index 7183619..0ee4eba 100644 --- a/global-config.changes +++ b/global-config.changes @@ -24,7 +24,7 @@ 15="New documentation is online! https://git.eworm.de/cgit/routeros-scripts/about/#available-scripts"; 16="Happy with RouterOS Scripts and have a GitHub and/or GitLab account? Please star!"; 17="Introduced script 'early-errors'"; - 18=("Added a simple IP calculation function, try: \$IPCalc " . [ / ip address get ([ find ]->0) address ]); + 18=("Added a simple IP calculation function, try: \$IPCalc " . [ /ip/address/get ([ find ]->0) address ]); 19="Commenting scripts with 'ignore', 'base-url=...' and 'url-suffix=...' is honored on update"; 20="Added support for hooks to 'netwatch-notify'"; 21="Added support for installing patch updates automatically by 'check-routeros-update'"; @@ -93,11 +93,11 @@ # Migration steps to be applied on script updates :global GlobalConfigMigration { 41=":global SendNotification; \$SendNotification (\"Migration mechanism\") (\"Congratulations!\nSuccessfully tested the new migration mechanism.\");"; - 47="/ certificate remove [ find where fingerprint=\"731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568\" or fingerprint=\"25847d668eb4f04fdd40b12b6b0740c567da7d024308eb6c2c96fe41d9de218d\" ];"; - 52=":global CertificateDownload; :if ([ :len [ / certificate find where fingerprint=\"67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd\" or fingerprint=\"96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6\" ] ] < 2) do={ \$CertificateDownload \"R3\"; }; / certificate remove [ find where fingerprint=\"0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739\" ];"; + 47="/certificate/remove [ find where fingerprint=\"731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568\" or fingerprint=\"25847d668eb4f04fdd40b12b6b0740c567da7d024308eb6c2c96fe41d9de218d\" ];"; + 52=":global CertificateDownload; :if ([ :len [ /certificate/find where fingerprint=\"67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd\" or fingerprint=\"96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6\" ] ] < 2) do={ \$CertificateDownload \"R3\"; }; /certificate/remove [ find where fingerprint=\"0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739\" ];"; 54=":global ScriptInstallUpdate; :global TelegramTokenId; :global TelegramChatId; :if ([ :len \$TelegramTokenId ] > 0 && [ :len \$TelegramChatId ] > 0) do={ \$ScriptInstallUpdate mod/notification-telegram; }"; - 61="/ system script remove [ find where name~\"^(early-errors|mode-button-(event|scheduler)|script-updates)\\\$\" source~\"^#!rsc by RouterOS\\n\" ];"; - 66=":global ScriptInstallUpdate; :if ([ :len [ / system script find where name=\"bridge-port-to-default\" ] ] > 0) do={ / system script remove [ find where name~\"^bridge-port-to(-default|ggle)\\\$\" ]; \$ScriptInstallUpdate mod/bridge-port-to; }"; - 67=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Script in=[ / system script find where name~\"^global-functions.d/\" ] do={ / system script set name=[ \$CharacterReplace [ / system script get \$Script name ] \"global-functions.d/\" \"mod/\" ] \$Script; }; \$ScriptInstallUpdate;"; - 73=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Old,New in={ \"cloud-backup\"=\"backup-cloud\"; \"email-backup\"=\"backup-email\"; \"upload-backup\"=\"backup-upload\" } do={ / system script set name=\$New [ find where name=\$Old ]; :foreach Scheduler in=[ / system scheduler find where on-event~\$Old ] do={ / system scheduler set \$Scheduler name=[ \$CharacterReplace [ get \$Scheduler name ] \$Old \$New ] on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Old \$New ]; }; }; \$ScriptInstallUpdate;"; + 61="/system/script/remove [ find where name~\"^(early-errors|mode-button-(event|scheduler)|script-updates)\\\$\" source~\"^#!rsc by RouterOS\\n\" ];"; + 66=":global ScriptInstallUpdate; :if ([ :len [ /system/script/find where name=\"bridge-port-to-default\" ] ] > 0) do={ /system/script/remove [ find where name~\"^bridge-port-to(-default|ggle)\\\$\" ]; \$ScriptInstallUpdate mod/bridge-port-to; }"; + 67=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Script in=[ /system/script/find where name~\"^global-functions.d/\" ] do={ /system/script/set name=[ \$CharacterReplace [ /system/script/get \$Script name ] \"global-functions.d/\" \"mod/\" ] \$Script; }; \$ScriptInstallUpdate;"; + 73=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Old,New in={ \"cloud-backup\"=\"backup-cloud\"; \"email-backup\"=\"backup-email\"; \"upload-backup\"=\"backup-upload\" } do={ /system/script/set name=\$New [ find where name=\$Old ]; :foreach Scheduler in=[ /system/scheduler/find where on-event~\$Old ] do={ /system/scheduler/set \$Scheduler name=[ \$CharacterReplace [ get \$Scheduler name ] \$Old \$New ] on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Old \$New ]; }; }; \$ScriptInstallUpdate;"; }; From 0ccebc39c75672117b3f9e59fa1db97f6468b012 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:07:11 +0200 Subject: [PATCH 1000/2612] global-functions: RouterOS v7 path syntax --- global-functions | 161 +++++++++++++++++++++++------------------------ 1 file changed, 78 insertions(+), 83 deletions(-) diff --git a/global-functions b/global-functions index 0feeb1d..a12eb5d 100644 --- a/global-functions +++ b/global-functions @@ -14,7 +14,7 @@ # global variables not to be changed by user :global GlobalFunctionsReady false; -:global Identity [ / system identity get name ]; +:global Identity [ /system/identity/get name ]; # global functions :global CertificateAvailable; @@ -69,30 +69,30 @@ :global LogPrintExit2; :global ParseKeyValueStore; - :if ([ / system resource get free-hdd-space ] < 8388608 && \ - [ / certificate settings get crl-download ] = true && \ - [ / certificate settings get crl-store ] = "system") do={ + :if ([ /system/resource/get free-hdd-space ] < 8388608 && \ + [ /certificate/settings/get crl-download ] = true && \ + [ /certificate/settings/get crl-store ] = "system") do={ $LogPrintExit2 warning $0 ("This system has low free flash space but " . \ "is configured to download certificate CRLs to system!") false; } - :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; :if ([ $CertificateDownload $CommonName ] = false) do={ :return false; } } - :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={ - :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 . \ "\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\".") false; :if ([ $CertificateDownload $CommonName ] = false) do={ :return false; } } - :set CertVal [ / certificate get [ find where skid=($CertVal->"akid") ] ]; + :set CertVal [ /certificate/get [ find where skid=($CertVal->"akid") ] ]; } :return true; } @@ -114,16 +114,16 @@ :do { :local LocalFileName ($CommonName . ".pem"); :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); - / tool fetch check-certificate=yes-without-crl \ + /tool/fetch check-certificate=yes-without-crl \ ($ScriptUpdatesBaseUrl . "certs/" . \ $UrlFileName . $ScriptUpdatesUrlSuffix) \ dst-path=$LocalFileName as-value; $WaitForFile $LocalFileName; - / certificate import file-name=$LocalFileName passphrase="" as-value; - / file remove $LocalFileName; + /certificate/import file-name=$LocalFileName passphrase="" as-value; + /file/remove $LocalFileName; - :foreach Cert in=[ / certificate find where name~("^" . $LocalFileName . "_[0-9]+\$") ] do={ - $CertificateNameByCN [ / certificate get $Cert common-name ]; + :foreach Cert in=[ /certificate/find where name~("^" . $LocalFileName . "_[0-9]+\$") ] do={ + $CertificateNameByCN [ /certificate/get $Cert common-name ]; } } on-error={ $LogPrintExit2 warning $0 ("Failed importing certificate with " . \ @@ -139,8 +139,8 @@ :global CharacterReplace; - :local Cert [ / certificate find where common-name=$CommonName ]; - / certificate set $Cert \ + :local Cert [ /certificate/find where common-name=$CommonName ]; + /certificate/set $Cert \ name=[ $CharacterReplace [ $CharacterReplace [ $CharacterReplace $CommonName "'" "-" ] " " "-" ] "---" "-" ]; } @@ -185,7 +185,7 @@ # default route is reachable :set DefaultRouteIsReachable do={ - :if ([ :len [ / ip route find where dst-address=0.0.0.0/0 active routing-table=main ] ] > 0) do={ + :if ([ :len [ /ip/route/find where dst-address=0.0.0.0/0 active routing-table=main ] ] > 0) do={ :return true; } :return false; @@ -199,13 +199,13 @@ :global IfThenElse; - :local Resource [ / system resource get ]; + :local Resource [ /system/resource/get ]; :local RouterBoard; :do { - :set RouterBoard [ / system routerboard get ]; + :set RouterBoard [[ :parse "/system/routerboard/get" ]]; } on-error={ } - :local License [ / system license get ]; - :local Update [ / system package update get ]; + :local License [ /system/license/get ]; + :local Update [ /system/package/update/get ]; :return ( \ "Hostname: " . $Identity . \ @@ -259,8 +259,8 @@ :global WaitForFile; :if ([ :len $PkgName ] = 0) do={ :return false; } - :if ([ :len $PkgVer ] = 0) do={ :set PkgVer [ / system package update get installed-version ]; } - :if ([ :len $PkgArch ] = 0) do={ :set PkgArch [ / system resource get architecture-name ]; } + :if ([ :len $PkgVer ] = 0) do={ :set PkgVer [ /system/package/update/get installed-version ]; } + :if ([ :len $PkgArch ] = 0) do={ :set PkgArch [ /system/resource/get architecture-name ]; } :if ($PkgName = "system") do={ :set PkgName "routeros"; } @@ -273,7 +273,7 @@ :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; :return true; } @@ -288,17 +288,17 @@ :local Retry 3; :while ($Retry > 0) do={ :do { - / tool fetch check-certificate=yes-without-crl $Url dst-path=$PkgDest; + /tool/fetch check-certificate=yes-without-crl $Url dst-path=$PkgDest; $WaitForFile $PkgDest; - :if ([ / file get [ find where name=$PkgDest ] type ] = "package") do={ + :if ([ /file/get [ find where name=$PkgDest ] type ] = "package") do={ :return true; } } on-error={ $LogPrintExit2 debug $0 ("Downloading package file failed.") false; } - / file remove [ find where name=$PkgDest ]; + /file/remove [ find where name=$PkgDest ]; :set Retry ($Retry - 1); } @@ -348,28 +348,28 @@ :local AllDone true; :local QueueLen [ :len $EmailQueue ]; - :if ([ :len [ / system scheduler find where name="FlushEmailQueue" ] ] > 0 && $QueueLen = 0) do={ + :if ([ :len [ /system/scheduler/find where name="FlushEmailQueue" ] ] > 0 && $QueueLen = 0) do={ $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; } - / system scheduler set interval=($QueueLen . "m") [ find where name="FlushEmailQueue" ]; + /system/scheduler/set interval=($QueueLen . "m") [ find where name="FlushEmailQueue" ]; :foreach Id,Message in=$EmailQueue do={ :if ([ :typeof $Message ] = "array" ) do={ :local Attach [ $EitherOr ($Message->"attach") "" ]; - :while ([ / tool e-mail get last-status ] = "in-progress") do={ :delay 1s; } - / tool e-mail send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \ + :while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; } + /tool/e-mail/send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \ body=($Message->"body") file=$Attach; :local Wait true; :do { :delay 1s; - :local Status [ / tool e-mail get last-status ]; + :local Status [ /tool/e-mail/get last-status ]; :if ($Status = "succeeded") do={ :set ($EmailQueue->$Id); :set Wait false; :if (($Message->"remove-attach") = true) do={ :foreach File in=[ :toarray $Attach ] do={ - / file remove $File; + /file/remove $File; } } } @@ -382,10 +382,10 @@ } :if ($AllDone = true && $QueueLen = [ :len $EmailQueue ]) do={ - / system scheduler remove [ find where name="FlushEmailQueue" ]; + /system/scheduler/remove [ find where name="FlushEmailQueue" ]; :set EmailQueue; } else={ - / system scheduler set interval=1m [ find where name="FlushEmailQueue" ]; + /system/scheduler/set interval=1m [ find where name="FlushEmailQueue" ]; } } @@ -400,12 +400,12 @@ :if ([ $CertificateAvailable "Cloudflare Inc ECC CA-3" ] = false) do={ $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; } - :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"); :return $Vendor; } on-error={ :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; $LogPrintExit2 debug $0 ("The mac vendor is not known in database.") false; } on-error={ @@ -417,7 +417,7 @@ # generate random 20 chars hex (0-9 and a-f) :set GetRandom20CharHex do={ - :return ([ / certificate scep-server otp generate minutes-valid=0 as-value ]->"password"); + :return ([ /certificate/scep-server/otp/generate minutes-valid=0 as-value ]->"password"); } # generate random number @@ -515,20 +515,20 @@ :return true; } - :if ([ :len [ / file find where name=$Dir type="directory" ] ] = 1) do={ + :if ([ :len [ /file/find where name=$Dir type="directory" ] ] = 1) do={ :return true; } :local Return true; :local Name ($Dir . "-" . [ $GetRandom20CharHex ]); :do { - / ip smb share add disabled=yes directory=$Dir name=$Name; + /ip/smb/share/add disabled=yes directory=$Dir name=$Name; $WaitForFile $Dir; } on-error={ $LogPrintExit2 warning $0 ("Making directory '" . $Dir . "' failed!") false; :set Return false; } - / ip smb share remove [ find where name=$Name ]; + /ip/smb/share/remove [ find where name=$Name ]; :return $Return; } @@ -555,7 +555,7 @@ :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; - :local EMailSettings [ / tool e-mail get ]; + :local EMailSettings [ /tool/e-mail/get ]; :if ([ :len $To ] = 0 || ($EMailSettings->"address") = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={ :return false; } @@ -563,7 +563,7 @@ :if ([ :typeof $EmailQueue ] = "nothing") do={ :set EmailQueue [ :toarray "" ]; } - :local Signature [ / system note get note ]; + :local Signature [ /system/note/get note ]; :set ($EmailQueue->[ :len $EmailQueue ]) { to=$To; cc=$Cc; subject=[ $QuotedPrintable ("[" . $Identity . "] " . ($Notification->"subject")) ]; @@ -571,8 +571,8 @@ [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \ attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") }; - :if ([ :len [ / system scheduler find where name="FlushEmailQueue" ] ] = 0) do={ - / system scheduler add name=FlushEmailQueue interval=1s start-time=startup \ + :if ([ :len [ /system/scheduler/find where name="FlushEmailQueue" ] ] = 0) do={ + /system/scheduler/add name=FlushEmailQueue interval=1s start-time=startup \ on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); } } @@ -653,7 +653,7 @@ :global IfThenElse; :global LogPrintExit2; :global VersionToNum; - :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={ $LogPrintExit2 warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = ("\$")) "function" "script" ] . \ " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!") false; @@ -669,10 +669,10 @@ :global LogPrintExit2; - :foreach Job in=[ / system script job find where script=$Script ] do={ - :set Job [ / system script job get $Job ]; + :foreach Job in=[ /system/script/job/find where script=$Script ] do={ + :set Job [ /system/script/job/get $Job ]; :while ([ :typeof ($Job->"parent") ] = "id") do={ - :set Job [ / system script job get [ find where .id=($Job->"parent") ] ]; + :set Job [ /system/script/job/get [ find where .id=($Job->"parent") ] ]; } :if (($Job->"type") = "login") do={ $LogPrintExit2 debug $0 ("Script " . $Script . " started from terminal.") false; @@ -712,9 +712,9 @@ } :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; - / 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; } } @@ -722,17 +722,17 @@ :local ReloadGlobalFunctions false; :local ReloadGlobalConfig false; - :foreach Script in=[ / system script find where source~"^#!rsc by RouterOS\n" ] do={ - :local ScriptVal [ / system script get $Script ]; - :local ScriptFile [ / file find where name=("script-updates/" . $ScriptVal->"name") ]; + :foreach Script in=[ /system/script/find where source~"^#!rsc by RouterOS\n" ] do={ + :local ScriptVal [ /system/script/get $Script ]; + :local ScriptFile [ /file/find where name=("script-updates/" . $ScriptVal->"name") ]; :local SourceNew; :if ([ :len $ScriptFile ] > 0) do={ - :set SourceNew [ / file get $ScriptFile content ]; - / file remove $ScriptFile; + :set SourceNew [ /file/get $ScriptFile content ]; + /file/remove $ScriptFile; } - :foreach Scheduler in=[ / system scheduler find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ - :local SchedulerVal [ / system scheduler get $Scheduler ]; + :foreach Scheduler in=[ /system/scheduler/find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ + :local SchedulerVal [ /system/scheduler/get $Scheduler ]; :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ $LogPrintExit2 warning $0 ("Policies differ for script '" . $ScriptVal->"name" . \ "' and its scheduler '" . $SchedulerVal->"name" . "'!") false; @@ -750,7 +750,7 @@ :local Url ($BaseUrl . $ScriptVal->"name" . $UrlSuffix); $LogPrintExit2 debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url) false; - :local Result [ / tool fetch check-certificate=yes-without-crl $Url output=user as-value ]; + :local Result [ /tool/fetch check-certificate=yes-without-crl $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set SourceNew ($Result->"data"); } @@ -767,7 +767,7 @@ :local DontRequirePermissions \ ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); $LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; - / system script set owner=($ScriptVal->"name") source=$SourceNew \ + /system/script/set owner=($ScriptVal->"name") source=$SourceNew \ dont-require-permissions=$DontRequirePermissions $Script; :if ($ScriptVal->"name" = "global-config") do={ :set ReloadGlobalConfig true; @@ -794,7 +794,7 @@ :if ($ReloadGlobalFunctions = true) do={ $LogPrintExit2 info $0 ("Reloading global functions.") false; :do { - / system script run global-functions; + /system/script/run global-functions; } on-error={ $LogPrintExit2 error $0 ("Reloading global functions failed!") false; } @@ -803,7 +803,7 @@ :if ($ReloadGlobalConfig = true) do={ $LogPrintExit2 info $0 ("Reloading global configuration.") false; :do { - / system script run global-config; + /system/script/run global-config; } on-error={ $LogPrintExit2 error $0 ("Reloading global configuration failed!" . \ " Syntax error or missing overlay\?") false; @@ -818,7 +818,7 @@ :do { :local Url ($ScriptUpdatesBaseUrl . "global-config.changes" . $ScriptUpdatesUrlSuffix); $LogPrintExit2 debug $0 ("Fetching news, changes and migration: " . $Url) false; - :local Result [ / tool fetch check-certificate=yes-without-crl $Url output=user as-value ]; + :local Result [ /tool/fetch check-certificate=yes-without-crl $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ :set ChangeLogCode ($Result->"data"); } @@ -918,7 +918,7 @@ :local JobCount do={ :local Script [ :tostr $1 ]; - :return [ :len [ / system script job find where script=$Script ] ]; + :return [ :len [ /system/script/job/find where script=$Script ] ]; } :local TicketCount do={ @@ -990,7 +990,7 @@ :set ($ScriptLockOrder->$Script) [ :toarray "" ]; } - :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; } @@ -1001,7 +1001,7 @@ :if ([ $TicketCount $Script ] >= [ $JobCount $Script ]) do={ $LogPrintExit2 error $0 ("More tickets than running scripts '" . $Script . "', resetting!") false; :set ($ScriptLockOrder->$Script) [ :toarray "" ]; - / system script job remove [ find where script=$Script ]; + /system/script/job/remove [ find where script=$Script ]; } :local MyTicket [ $GetRandom20CharHex ]; @@ -1107,21 +1107,21 @@ :set TimeIsSync do={ :global LogPrintExit2; - :if ([ / system ntp client get enabled ] = true) do={ + :if ([ /system/ntp/client/get enabled ] = true) do={ :do { - :if ([ / system ntp client get status ] = "synchronized") do={ + :if ([ /system/ntp/client/get status ] = "synchronized") do={ :return true; } } on-error={ - :if ([ :typeof [ / system ntp client get last-adjustment ] ] = "time") do={ + :if ([ :typeof [ /system/ntp/client/get last-adjustment ] ] = "time") do={ :return true; } } :return false; } - :if ([ / ip cloud get ddns-enabled ] = true && [ / ip cloud get update-time ] = true) do={ - :if ([ :typeof [ / ip cloud get public-address ] ] = "ip") do={ + :if ([ /ip/cloud/get ddns-enabled ] = true && [ /ip/cloud/get update-time ] = true) do={ + :if ([ :typeof [ /ip/cloud/get public-address ] ] = "ip") do={ :return true; } :return false; @@ -1226,7 +1226,7 @@ :set FileName [ $CleanFilePath $FileName ]; :local I 0; - :while ([ :len [ / file find where name=$FileName ] ] = 0) do={ + :while ([ :len [ /file/find where name=$FileName ] ] = 0) do={ :if ($I > 20) do={ :return false; } @@ -1253,10 +1253,10 @@ :global TimeIsSync; :while ([ $TimeIsSync ] = false) do={ - :if ([ :len [ / system script find where name="rotate-ntp" ] ] > 0 && \ - ([ / system resource get uptime ] % (180 * 1000000000)) = 0s) do={ + :if ([ :len [ /system/script/find where name="rotate-ntp" ] ] > 0 && \ + ([ /system/resource/get uptime ] % (180 * 1000000000)) = 0s) do={ :do { - / system script run rotate-ntp; + /system/script/run rotate-ntp; } on-error={ $LogPrintExit2 debug $0 ("Running rotate-ntp failed.") false; } @@ -1266,11 +1266,11 @@ } # load modules -:foreach Script in=[ / system script find where name ~ "^mod/." ] do={ - :local ScriptVal [ / system script get $Script ]; +:foreach Script in=[ /system/script/find where name ~ "^mod/." ] do={ + :local ScriptVal [ /system/script/get $Script ]; :if ([ $ValidateSyntax ($ScriptVal->"source") ] = true) do={ :do { - / system script run $Script; + /system/script/run $Script; } on-error={ $LogPrintExit2 error $0 ("Module '" . $ScriptVal->"name" . "' failed to run.") false; } @@ -1280,12 +1280,7 @@ } # check for required RouterOS version -:if ([ $RequiredRouterOS $0 "7.0" false ] = true) do={ - $RequiredRouterOS $0 "7.1" true; -} else={ - $LogPrintExit2 warning $0 ("Still running RouterOS v6, please switch to branch " . \ - "'routeros-v6', see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v6") false; -} +$RequiredRouterOS $0 "7.1" true; # signal we are ready :set GlobalFunctionsReady true; From d98d69a8c932c0c0bbc56efb27063d47c290761b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:27:53 +0200 Subject: [PATCH 1001/2612] Makefile: RouterOS v7 path syntax --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9f21255..930c1ae 100644 --- a/Makefile +++ b/Makefile @@ -15,11 +15,11 @@ all: $(CAPSMAN) $(LOCAL) $(HTML) markdown $< | sed 's/href="\([-_\./[:alnum:]]*\)\.md"/href="\1.html"/g' > $@ %.local: %.template Makefile - sed -e '/\/ caps-man/d' -e 's|%PATH%|interface wireless|' -e 's|%TEMPL%|$(suffix $@)|' \ + sed -e '/\/caps-man/d' -e 's|%PATH%|interface\/wireless|' -e 's|%TEMPL%|$(suffix $@)|' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ %.capsman: %.template Makefile - sed -e '/\/ interface wireless/d' -e 's/%PATH%/caps-man/' -e 's/%TEMPL%/$(suffix $@)/' \ + sed -e '/\/interface\/wireless/d' -e 's/%PATH%/caps-man/' -e 's/%TEMPL%/$(suffix $@)/' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ From ab410466dcb9198455978146cbcdf0a3eb85c7ce Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:28:18 +0200 Subject: [PATCH 1002/2612] accesslist-duplicates: RouterOS v7 path syntax --- accesslist-duplicates.capsman | 8 ++++---- accesslist-duplicates.local | 8 ++++---- accesslist-duplicates.template | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman index 74cf3b3..e1f83a3 100644 --- a/accesslist-duplicates.capsman +++ b/accesslist-duplicates.capsman @@ -17,8 +17,8 @@ :local Seen [ :toarray "" ]; :local Shown [ :toarray "" ]; -:foreach AccList in=[ / caps-man access-list find where mac-address!="00:00:00:00:00:00" ] do={ - :local Mac [ / caps-man access-list get $AccList mac-address ]; +:foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ + :local Mac [ /caps-man/access-list/get $AccList mac-address ]; :foreach SeenMac in=$Seen do={ :if ($SeenMac = $Mac) do={ :local Skip 0; @@ -26,14 +26,14 @@ :if ($ShownMac = $Mac) do={ :set Skip 1; } } :if ($Skip = 0) do={ - / caps-man access-list print where mac-address=$Mac; + /caps-man/access-list/print where mac-address=$Mac; :set Shown ($Shown, $Mac); :put "\nNumeric id to remove, any key to skip!"; :local Remove [ :tonum [ $Read ] ]; :if ([ :typeof $Remove ] = "num") do={ :put ("Removing numeric id " . $Remove . "...\n"); - / caps-man access-list remove $Remove; + /caps-man/access-list/remove $Remove; } } } diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local index 0aa946c..c1bf2a2 100644 --- a/accesslist-duplicates.local +++ b/accesslist-duplicates.local @@ -17,8 +17,8 @@ :local Seen [ :toarray "" ]; :local Shown [ :toarray "" ]; -:foreach AccList in=[ / interface wireless access-list find where mac-address!="00:00:00:00:00:00" ] do={ - :local Mac [ / interface wireless access-list get $AccList mac-address ]; +:foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ + :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; :foreach SeenMac in=$Seen do={ :if ($SeenMac = $Mac) do={ :local Skip 0; @@ -26,14 +26,14 @@ :if ($ShownMac = $Mac) do={ :set Skip 1; } } :if ($Skip = 0) do={ - / interface wireless access-list print where mac-address=$Mac; + /interface/wireless/access-list/print where mac-address=$Mac; :set Shown ($Shown, $Mac); :put "\nNumeric id to remove, any key to skip!"; :local Remove [ :tonum [ $Read ] ]; :if ([ :typeof $Remove ] = "num") do={ :put ("Removing numeric id " . $Remove . "...\n"); - / interface wireless access-list remove $Remove; + /interface/wireless/access-list/remove $Remove; } } } diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template index f1862bb..8ad8e8f 100644 --- a/accesslist-duplicates.template +++ b/accesslist-duplicates.template @@ -18,8 +18,8 @@ :local Seen [ :toarray "" ]; :local Shown [ :toarray "" ]; -:foreach AccList in=[ / %PATH% access-list find where mac-address!="00:00:00:00:00:00" ] do={ - :local Mac [ / %PATH% access-list get $AccList mac-address ]; +:foreach AccList in=[ /%PATH%/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ + :local Mac [ /%PATH%/access-list/get $AccList mac-address ]; :foreach SeenMac in=$Seen do={ :if ($SeenMac = $Mac) do={ :local Skip 0; @@ -27,14 +27,14 @@ :if ($ShownMac = $Mac) do={ :set Skip 1; } } :if ($Skip = 0) do={ - / %PATH% access-list print where mac-address=$Mac; + /%PATH%/access-list/print where mac-address=$Mac; :set Shown ($Shown, $Mac); :put "\nNumeric id to remove, any key to skip!"; :local Remove [ :tonum [ $Read ] ]; :if ([ :typeof $Remove ] = "num") do={ :put ("Removing numeric id " . $Remove . "...\n"); - / %PATH% access-list remove $Remove; + /%PATH%/access-list/remove $Remove; } } } From 18a0bee80f191037afec4f3579ee8ef2ee0ee1bb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:36:41 +0200 Subject: [PATCH 1003/2612] backup-cloud: RouterOS v7 path syntax --- backup-cloud | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backup-cloud b/backup-cloud index d1d9f14..38aed1f 100644 --- a/backup-cloud +++ b/backup-cloud @@ -33,15 +33,15 @@ $WaitFullyConnected; :do { # we are not interested in output, but print is # required to fetch information from cloud - / system backup cloud print as-value; - :if ([ :len [ / system backup cloud find ] ] > 0) do={ - / system backup cloud upload-file action=create-and-upload \ + /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 \ + /system/backup/cloud/upload-file action=create-and-upload \ password=$BackupPassword; } - :local Cloud [ / system backup cloud get ([ find ]->0) ]; + :local Cloud [ /system/backup/cloud/get ([ find ]->0) ]; $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "floppy-disk,cloud" ] . "Cloud backup"); \ From dffd634885a640ca060d1658820f4999cae5b408 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:36:53 +0200 Subject: [PATCH 1004/2612] backup-email: RouterOS v7 path syntax --- backup-email | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backup-email b/backup-email index ccbd4de..55f2309 100644 --- a/backup-email +++ b/backup-email @@ -54,7 +54,7 @@ $WaitFullyConnected; # binary backup :if ($BackupSendBinary = true) do={ - / system backup save encryption=aes-sha256 name=$FilePath password=$BackupPassword; + /system/backup/save encryption=aes-sha256 name=$FilePath password=$BackupPassword; $WaitForFile ($FilePath . ".backup"); :set BackupFile ($FileName . ".backup"); :set Attach ($Attach, ($FilePath . ".backup")); @@ -62,7 +62,7 @@ $WaitFullyConnected; # create configuration export :if ($BackupSendExport = true) do={ - / export terse show-sensitive file=$FilePath; + /export terse show-sensitive file=$FilePath; $WaitForFile ($FilePath . ".rsc"); :set ConfigFile ($FileName . ".rsc"); :set Attach ($Attach, ($FilePath . ".rsc")); From 21c4520d1729e4865f81b3e4ae0ea9e389bf6890 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:37:04 +0200 Subject: [PATCH 1005/2612] backup-partition: RouterOS v7 path syntax --- backup-partition | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backup-partition b/backup-partition index c72c7f9..a8aecac 100644 --- a/backup-partition +++ b/backup-partition @@ -14,20 +14,20 @@ :global LogPrintExit2; -:if ([ :len [ / partitions find ] ] < 2) do={ +:if ([ :len [ /partitions/find ] ] < 2) do={ $LogPrintExit2 error $0 ("Device does not have a fallback partition.") true; } -:local ActiveRunning [ / partitions find where active running ]; +:local ActiveRunning [ /partitions/find where active running ]; :if ([ :len $ActiveRunning ] < 1) do={ $LogPrintExit2 error $0 ("Device is not running from active partition.") true; } -:local ActiveRunningVar [ / partitions get $ActiveRunning ]; +:local ActiveRunningVar [ /partitions/get $ActiveRunning ]; :do { - / partitions save-config-to ($ActiveRunningVar->"fallback-to"); + /partitions/save-config-to ($ActiveRunningVar->"fallback-to"); $LogPrintExit2 info $0 ("Saved configuration to partition '" . \ ($ActiveRunningVar->"fallback-to") . "'.") false; } on-error={ From 219fd994d7f0efddc6533e0de306368d5b32088a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:37:13 +0200 Subject: [PATCH 1006/2612] backup-upload: RouterOS v7 path syntax --- backup-upload | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backup-upload b/backup-upload index c482b42..8ed4149 100644 --- a/backup-upload +++ b/backup-upload @@ -58,11 +58,11 @@ $WaitFullyConnected; # binary backup :if ($BackupSendBinary = true) do={ - / system backup save encryption=aes-sha256 name=$FilePath password=$BackupPassword; + /system/backup/save encryption=aes-sha256 name=$FilePath password=$BackupPassword; $WaitForFile ($FilePath . ".backup"); :do { - / tool fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \ + /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \ user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".backup"); :set BackupFile ($FileName . ".backup"); } on-error={ @@ -71,16 +71,16 @@ $WaitFullyConnected; :set Failed 1; } - / file remove ($FilePath . ".backup"); + /file/remove ($FilePath . ".backup"); } # create configuration export :if ($BackupSendExport = true) do={ - / export terse show-sensitive file=$FilePath; + /export terse show-sensitive file=$FilePath; $WaitForFile ($FilePath . ".rsc"); :do { - / tool fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \ + /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \ user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".rsc"); :set ConfigFile ($FileName . ".rsc"); } on-error={ @@ -89,7 +89,7 @@ $WaitFullyConnected; :set Failed 1; } - / file remove ($FilePath . ".rsc"); + /file/remove ($FilePath . ".rsc"); } $SendNotification2 ({ origin=$0; \ From ac4eb87be68dd40de63f59950a1b474f76283506 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:39:09 +0200 Subject: [PATCH 1007/2612] capsman-download-packages: RouterOS v7 path syntax --- capsman-download-packages | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/capsman-download-packages b/capsman-download-packages index 10585ec..1e901d8 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -21,15 +21,15 @@ $ScriptLock $0; $WaitFullyConnected; -:local PackagePath [ $CleanFilePath [ / caps-man manager get package-path ] ]; -:local InstalledVersion [ / system package update get installed-version ]; +:local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; +:local InstalledVersion [ /system/package/update/get installed-version ]; :local Updated false; :if ([ :len $PackagePath ] = 0) do={ $LogPrintExit2 warning $0 ("The CAPsMAN package path is not defined, can not download packages.") true; } -:if ([ :len [ / file find where name=$PackagePath type="directory" ] ] = 0) do={ +:if ([ :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; @@ -38,34 +38,34 @@ $WaitFullyConnected; "). Please place your packages!") false; } -:foreach Package in=[ / file find where type=package \ +:foreach Package in=[ /file/find where type=package \ package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ - :local File [ / file get $Package ]; + :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; + /file/remove $Package; } } -:if ([ :len [ / system logging find where topics~"error" !(topics~"!error") \ +:if ([ :len [ /system/logging/find where topics~"error" !(topics~"!error") \ !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ $LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \ "Probably can not download packages automatically.") false; } else={ - :if ($Updated = false && [ / system resource get uptime ] < 2m) do={ + :if ($Updated = false && [ /system/resource/get uptime ] < 2m) do={ $LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false; :delay 2m; } } -:foreach Log in=[ / log find where topics=({"caps", "error"}) \ +:foreach Log in=[ /log/find where topics=({"caps", "error"}) \ message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \ "-.*\\.npk', no such file") ] do={ - :local Message [ / log get $Log message ]; + :local Message [ /log/get $Log message ]; :local Package [ :pick $Message \ ([ :find $Message "'" ] + 1) \ [ :find $Message ("-" . $InstalledVersion . "-") ] ]; @@ -78,9 +78,9 @@ $WaitFullyConnected; } :if ($Updated = true) do={ - :if ([ :len [ / system script find where name="capsman-rolling-upgrade" ] ] > 0) do={ - / system script run capsman-rolling-upgrade; + :if ([ :len [ /system/script/find where name="capsman-rolling-upgrade" ] ] > 0) do={ + /system/script/run capsman-rolling-upgrade; } else={ - / caps-man remote-cap upgrade [ find where version!=$InstalledVersion ]; + /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; } } From f17342ed6ec05d15cefcc00cfd6b1677175f1fd4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:40:08 +0200 Subject: [PATCH 1008/2612] capsman-rolling-upgrade: RouterOS v7 path syntax --- capsman-rolling-upgrade | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade index 2893915..e6b1c51 100644 --- a/capsman-rolling-upgrade +++ b/capsman-rolling-upgrade @@ -16,18 +16,18 @@ $ScriptLock $0; -:local InstalledVersion [ / system package update get installed-version ]; +:local InstalledVersion [ /system/package/update/get installed-version ]; -:local RemoteCapCount [ :len [ / caps-man remote-cap find ] ]; +: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 ]; + :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; + /caps-man/remote-cap/upgrade $RemoteCap; } else={ $LogPrintExit2 warning $0 ("Remote CAP vanished, skipping upgrade.") false; } From 0f3166d4275d9cb2ae3a2fe3337ee042394921ec Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:41:16 +0200 Subject: [PATCH 1009/2612] certificate-renew-issued: RouterOS v7 path syntax --- certificate-renew-issued | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/certificate-renew-issued b/certificate-renew-issued index 72b723f..29aaa93 100644 --- a/certificate-renew-issued +++ b/certificate-renew-issued @@ -15,16 +15,16 @@ :global LogPrintExit2; :global MkDir; -:foreach Cert in=[ / certificate find where issued expires-after<3w ] do={ - :local CertVal [ / certificate get $Cert ]; - / certificate issued-revoke $Cert; - / certificate set name=($CertVal->"name" . "-revoked-" . [ / system clock get date ]) $Cert; - / certificate add name=($CertVal->"name") common-name=($CertVal->"common-name") \ +: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"); + /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 \ + /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" . \ From 3ed153520ef510bf556ef9c53d01d1aeaf4e2a15 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:42:19 +0200 Subject: [PATCH 1010/2612] check-certificates: RouterOS v7 path syntax --- check-certificates | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/check-certificates b/check-certificates index 1f40496..99da7d5 100644 --- a/check-certificates +++ b/check-certificates @@ -33,8 +33,8 @@ $WaitFullyConnected; -:foreach Cert in=[ / certificate find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ - :local CertVal [ / certificate get $Cert ]; +:foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ + :local CertVal [ /certificate/get $Cert ]; :do { :if ([ :len $CertRenewUrl ] = 0) do={ @@ -45,24 +45,24 @@ $WaitFullyConnected; :foreach Type in={ ".pem"; ".p12" } do={ :local CertFileName ([ $UrlEncode ($CertVal->"common-name") ] . $Type); :do { - / tool fetch check-certificate=yes-without-crl \ + /tool/fetch check-certificate=yes-without-crl \ ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; $WaitForFile $CertFileName; :foreach PassPhrase in=$CertRenewPass do={ - / certificate import file-name=$CertFileName passphrase=$PassPhrase as-value; + /certificate/import file-name=$CertFileName passphrase=$PassPhrase as-value; } - / file remove [ find where name=$CertFileName ]; + /file/remove [ find where name=$CertFileName ]; - :foreach CertInChain in=[ / certificate find where name~("^" . $CertFileName . "_[0-9]+\$") common-name!=($CertVal->"common-name") ] do={ - $CertificateNameByCN [ / certificate get $CertInChain common-name ]; + :foreach CertInChain in=[ /certificate/find where name~("^" . $CertFileName . "_[0-9]+\$") common-name!=($CertVal->"common-name") ] do={ + $CertificateNameByCN [ /certificate/get $CertInChain common-name ]; } } on-error={ $LogPrintExit2 debug $0 ("Could not download certificate file " . $CertFileName) false; } } - :local CertNew [ / certificate find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ]; - :local CertNewVal [ / certificate get $CertNew ]; + :local CertNew [ /certificate/find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ]; + :local CertNewVal [ /certificate/get $CertNew ]; :if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") ] = false) do={ $LogPrintExit2 warning $0 ("The certificate chain is not available!") false; @@ -72,27 +72,19 @@ $WaitFullyConnected; $LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; :if (($CertVal->"private-key") = true && ($CertVal->"private-key") != ($CertNewVal->"private-key")) do={ - / certificate remove $CertNew; + /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/service/set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; - :do { - / ip ipsec identity set certificate=($CertNewVal->"name") [ / ip ipsec identity find where certificate=($CertVal->"name") ]; - / ip ipsec identity set remote-certificate=($CertNewVal->"name") [ / ip ipsec identity find where remote-certificate=($CertVal->"name") ]; - } on-error={ - $LogPrintExit2 debug $0 ("Setting IPSEC certificates failed. Package 'security' not installed?") false; - } + /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") ]; - :do { - / ip hotspot profile set ssl-certificate=($CertNewVal->"name") [ / ip hotspot profile find where ssl-certificate=($CertVal->"name") ]; - } on-error={ - $LogPrintExit2 debug $0 ("Setting hotspot certificates failed. Package 'hotspot' not installed?") false; - } + /ip/hotspot/profile/set ssl-certificate=($CertNewVal->"name") [ find where ssl-certificate=($CertVal->"name") ]; - / certificate remove $Cert; - / certificate set $CertNew name=($CertVal->"name"); + /certificate/remove $Cert; + /certificate/set $CertNew name=($CertVal->"name"); } $SendNotification2 ({ origin=$0; \ @@ -111,10 +103,10 @@ $WaitFullyConnected; } } -:foreach Cert in=[ / certificate find where !revoked !scep-url !(expires-after=[]) expires-after<2w !(fingerprint=[]) ] do={ - :local CertVal [ / certificate get $Cert ]; +:foreach Cert in=[ /certificate/find where !revoked !scep-url !(expires-after=[]) expires-after<2w !(fingerprint=[]) ] do={ + :local CertVal [ /certificate/get $Cert ]; - :if ([ :len [ / certificate scep-server find where ca-cert=($CertVal->"ca") ] ] > 0) do={ + :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" ]; From af8a24b959a3e731fb925304170e99576936a296 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:43:04 +0200 Subject: [PATCH 1011/2612] check-health: RouterOS v7 path syntax --- check-health | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/check-health b/check-health index ca379c4..903c496 100644 --- a/check-health +++ b/check-health @@ -30,7 +30,7 @@ :return ($T->0 * 10 + $T->1); } -:if ([ :len [ / system health find ] ] = 0) do={ +:if ([ :len [ /system/health/find ] ] = 0) do={ $LogPrintExit2 error $0 ("Your device does not provide any health values.") true; } @@ -43,9 +43,9 @@ $ScriptLock $0; -:foreach Voltage in=[ / system health find where type="V" ] do={ - :local Name [ / system health get $Voltage name ]; - :local Value [ / system health get $Voltage value ]; +:foreach Voltage in=[ /system/health/find where type="V" ] do={ + :local Name [ /system/health/get $Voltage name ]; + :local Value [ /system/health/get $Voltage value ]; :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ :local NumCurr [ $TempToNum $Value ]; @@ -75,9 +75,9 @@ $ScriptLock $0; :set ($CheckHealthLast->$Name) $Value; } -:foreach PSU in=[ / system health find where name~"^psu.*-state\$" ] do={ - :local Name [ / system health get $PSU name ]; - :local Value [ / system health get $PSU value ]; +:foreach PSU in=[ /system/health/find where name~"^psu.*-state\$" ] do={ + :local Name [ /system/health/get $PSU name ]; + :local Value [ /system/health/get $PSU value ]; :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ :if ($CheckHealthLast->$Name = "ok" && \ @@ -96,19 +96,19 @@ $ScriptLock $0; :set ($CheckHealthLast->$Name) $Value; } -:foreach Temperature in=[ / system health find where type="C" ] do={ - :local Name [ / system health get $Temperature name ]; - :local Value [ / system health get $Temperature value ]; +:foreach Temperature in=[ /system/health/find where type="C" ] do={ + :local Name [ /system/health/get $Temperature name ]; + :local Value [ /system/health/get $Temperature value ]; :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ $LogPrintExit2 info $0 ("No threshold given for " . $Name . ", assuming 50C.") false; :set ($CheckHealthTemperature->$Name) 50; } - :local Validate [ / system health get [ find where name=$Name ] value ]; + :local Validate [ /system/health/get [ find where name=$Name ] value ]; :while ($Value != $Validate) do={ :set Value $Validate; - :set Validate [ / system health get [ find where name=$Name ] value ]; + :set Validate [ /system/health/get [ find where name=$Name ] value ]; } :if ($Value > $CheckHealthTemperature->$Name && \ $CheckHealthTemperatureNotified->$Name != true) do={ From 602933baec637cd89ccb15d0bd2471e5e9398ef2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:44:15 +0200 Subject: [PATCH 1012/2612] check-lte-firmware-upgrade: RouterOS v7 path syntax --- check-lte-firmware-upgrade | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 6918c7b..759b138 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -28,12 +28,12 @@ :global SendNotification2; :global SymbolForNotification; - :local IntName [ / interface lte get $Interface name ]; + :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 ]; + :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; @@ -48,10 +48,10 @@ } :if ([ $ScriptFromTerminal "check-lte-firmware-upgrade" ] = true && \ - [ :len [ / system script find where name="unattended-lte-firmware-upgrade" ] ] > 0) do={ + [ :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; + :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ + /system/script/run unattended-lte-firmware-upgrade; $LogPrintExit2 info $0 ("Scheduled lte firmware upgrade for interface " . $IntName . "...") false; :return true; } else={ @@ -77,6 +77,6 @@ :set ($SentLteFirmwareUpgradeNotification->$IntName) ($Firmware->"latest"); } -:foreach Interface in=[ / interface lte find ] do={ +:foreach Interface in=[ /interface/lte/find ] do={ $CheckInterface $Interface; } From 4837b4747ebb26e9abef80c5ecc01697cb1b2f90 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:45:58 +0200 Subject: [PATCH 1013/2612] check-routeros-update: RouterOS v7 path syntax --- check-routeros-update | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index 8cad07a..3d4f14a 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -27,10 +27,10 @@ :global WaitFullyConnected; :local DoUpdate do={ - :if ([ :len [ / system script find where name="packages-update" ] ] > 0) do={ - / system script run packages-update; + :if ([ :len [ /system/script/find where name="packages-update" ] ] > 0) do={ + /system/script/run packages-update; } else={ - / system package update install without-paging; + /system/package/update/install without-paging; } :error "Waiting for system to reboot."; } @@ -39,21 +39,21 @@ $ScriptLock $0; $WaitFullyConnected; -:if ([ :len [ / system package find where name="wireless" disabled=no ] ] > 0) do={ - :if ([ / interface wireless cap get enabled ] = true && \ - [ / caps-man manager get enabled ] = false && \ +:if ([ :len [ /system/package/find where name="wireless" disabled=no ] ] > 0) do={ + :if ([ /interface/wireless/cap/get enabled ] = true && \ + [ /caps-man/manager/get enabled ] = false && \ $SafeUpdateOnCap != true) do={ $LogPrintExit2 error $0 ("System is managed by CAPsMAN, not checking for RouterOS version.") true; } } -:if ([ :len [ / system scheduler find where name="reboot-for-update" ] ] > 0) do={ +:if ([ :len [ /system/scheduler/find where name="reboot-for-update" ] ] > 0) do={ :error "A reboot for update is already scheduled."; } $LogPrintExit2 debug $0 ("Checking for updates...") false; -/ system package update check-for-updates without-paging as-value; -:local Update [ / system package update get ]; +/system/package/update/check-for-updates without-paging as-value; +:local Update [ /system/package/update/get ]; :if ([ :len ($Update->"latest-version") ] = 0) do={ $LogPrintExit2 info $0 ("An empty string is not a valid version.") true; @@ -77,7 +77,7 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; $DoUpdate; } - :if ($SafeUpdateNeighbor = true && [ :len [ / ip neighbor find where \ + :if ($SafeUpdateNeighbor = true && [ :len [ /ip/neighbor/find where \ version=($Update->"latest-version" . " (" . $Update->"channel" . ")") ] ] > 0) do={ $LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; $SendNotification2 ({ origin=$0; \ @@ -90,7 +90,7 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; :if ([ :len $SafeUpdateUrl ] > 0) do={ :local Result; :do { - :set Result [ / tool fetch check-certificate=yes-without-crl \ + :set Result [ /tool/fetch check-certificate=yes-without-crl \ ($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \ "&latest=" . $Update->"latest-version") output=user as-value ]; } on-error={ @@ -108,7 +108,7 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; :if ([ $ScriptFromTerminal $0 ] = true) do={ :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); - :if (([ / terminal inkey timeout=60 ] % 32) = 25) do={ + :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ $DoUpdate; } else={ :put "Canceled..."; From 8af4db9f53622ab4886799e2c2815a28a62e1d87 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:48:32 +0200 Subject: [PATCH 1014/2612] collect-wireless-mac: RouterOS v7 path syntax --- collect-wireless-mac.capsman | 28 ++++++++++++++-------------- collect-wireless-mac.local | 30 +++++++++++++++--------------- collect-wireless-mac.template | 30 +++++++++++++++--------------- 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman index 326aa14..9e502e3 100644 --- a/collect-wireless-mac.capsman +++ b/collect-wireless-mac.capsman @@ -25,47 +25,47 @@ $ScriptLock $0 false 10; -:if ([ :len [ / caps-man access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ - / caps-man access-list add comment="--- collected above ---" disabled=yes; +:if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ + /caps-man/access-list/add comment="--- collected above ---" disabled=yes; $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false; } -:local PlaceBefore ([ / caps-man access-list find where comment="--- collected above ---" disabled ]->0); +:local PlaceBefore ([ /caps-man/access-list/find where comment="--- collected above ---" disabled ]->0); -:foreach Reg in=[ / caps-man registration-table find ] do={ +:foreach Reg in=[ /caps-man/registration-table/find ] do={ :local RegVal; :do { - :set RegVal [ / caps-man registration-table get $Reg ]; + :set RegVal [ /caps-man/registration-table/get $Reg ]; } on-error={ $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; } :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ / caps-man access-list find where mac-address=($RegVal->"mac-address") ]->0); + :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ / caps-man access-list get $AccessList comment ]) false; + [ /caps-man/access-list/get $AccessList comment ]) false; } :if ([ :len $AccessList ] = 0) do={ :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); + :local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); :if ([ :len $Lease ] > 0) do={ - :set Address [ / ip dhcp-server lease get $Lease address ]; - :set HostName [ $EitherOr [ / ip dhcp-server lease get $Lease host-name ] "no hostname" ]; + :set Address [ /ip/dhcp-server/lease/get $Lease address ]; + :set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; :set DnsName "no dns name"; - :local DnsRec ([ / ip dns static find where address=$Address ]->0); + :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ / ip dns static get $DnsRec name ]; + :set DnsName [ /ip/dns/static/get $DnsRec name ]; } } - :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); + :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); $LogPrintExit2 info $0 $Message false; - / caps-man access-list add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; + /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" . \ diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local index 3f9fddb..a6dbd24 100644 --- a/collect-wireless-mac.local +++ b/collect-wireless-mac.local @@ -25,48 +25,48 @@ $ScriptLock $0 false 10; -:if ([ :len [ / interface wireless access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ - / interface wireless access-list add comment="--- collected above ---" disabled=yes; +:if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ + /interface/wireless/access-list/add comment="--- collected above ---" disabled=yes; $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false; } -:local PlaceBefore ([ / interface wireless access-list find where comment="--- collected above ---" disabled ]->0); +:local PlaceBefore ([ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ]->0); -:foreach Reg in=[ / interface wireless registration-table find ] do={ +:foreach Reg in=[ /interface/wireless/registration-table/find ] do={ :local RegVal; :do { - :set RegVal [ / interface wireless 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={ - :local AccessList ([ / interface wireless access-list find where mac-address=($RegVal->"mac-address") ]->0); + :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ / interface wireless access-list get $AccessList comment ]) false; + [ /interface/wireless/access-list/get $AccessList comment ]) false; } :if ([ :len $AccessList ] = 0) do={ :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); + :local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); :if ([ :len $Lease ] > 0) do={ - :set Address [ / ip dhcp-server lease get $Lease address ]; - :set HostName [ $EitherOr [ / ip dhcp-server lease get $Lease host-name ] "no hostname" ]; + :set Address [ /ip/dhcp-server/lease/get $Lease address ]; + :set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; :set DnsName "no dns name"; - :local DnsRec ([ / ip dns static find where address=$Address ]->0); + :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ / ip dns static get $DnsRec name ]; + :set DnsName [ /ip/dns/static/get $DnsRec name ]; } } - :set ($RegVal->"ssid") [ / interface wireless get [ find where name=($RegVal->"interface") ] ssid ]; - :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); + :set ($RegVal->"ssid") [ /interface/wireless/get [ find where name=($RegVal->"interface") ] ssid ]; + :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); $LogPrintExit2 info $0 $Message false; - / interface wireless access-list add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; + /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" . \ diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template index b3c1c04..42a3d0a 100644 --- a/collect-wireless-mac.template +++ b/collect-wireless-mac.template @@ -26,48 +26,48 @@ $ScriptLock $0 false 10; -:if ([ :len [ / %PATH% access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ - / %PATH% access-list add comment="--- collected above ---" disabled=yes; +:if ([ :len [ /%PATH%/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ + /%PATH%/access-list/add comment="--- collected above ---" disabled=yes; $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false; } -:local PlaceBefore ([ / %PATH% access-list find where comment="--- collected above ---" disabled ]->0); +:local PlaceBefore ([ /%PATH%/access-list/find where comment="--- collected above ---" disabled ]->0); -:foreach Reg in=[ / %PATH% registration-table find ] do={ +:foreach Reg in=[ /%PATH%/registration-table/find ] do={ :local RegVal; :do { - :set RegVal [ / %PATH% registration-table get $Reg ]; + :set RegVal [ /%PATH%/registration-table/get $Reg ]; } on-error={ $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; } :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ / %PATH% access-list find where mac-address=($RegVal->"mac-address") ]->0); + :local AccessList ([ /%PATH%/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ / %PATH% access-list get $AccessList comment ]) false; + [ /%PATH%/access-list/get $AccessList comment ]) false; } :if ([ :len $AccessList ] = 0) do={ :local Address "no dhcp lease"; :local DnsName "no dhcp lease"; :local HostName "no dhcp lease"; - :local Lease ([ / ip dhcp-server lease find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); + :local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); :if ([ :len $Lease ] > 0) do={ - :set Address [ / ip dhcp-server lease get $Lease address ]; - :set HostName [ $EitherOr [ / ip dhcp-server lease get $Lease host-name ] "no hostname" ]; + :set Address [ /ip/dhcp-server/lease/get $Lease address ]; + :set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; :set DnsName "no dns name"; - :local DnsRec ([ / ip dns static find where address=$Address ]->0); + :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ / ip dns static get $DnsRec name ]; + :set DnsName [ /ip/dns/static/get $DnsRec name ]; } } - :set ($RegVal->"ssid") [ / interface wireless get [ find where name=($RegVal->"interface") ] ssid ]; - :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); + :set ($RegVal->"ssid") [ /interface/wireless/get [ find where name=($RegVal->"interface") ] ssid ]; + :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); $LogPrintExit2 info $0 $Message false; - / %PATH% access-list add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; + /%PATH%/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ From 71053fec408799e3cba9d6ebbfacf1334fc93c14 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:50:03 +0200 Subject: [PATCH 1015/2612] daily-psk: RouterOS v7 path syntax --- daily-psk.capsman | 14 +++++++------- daily-psk.local | 14 +++++++------- daily-psk.template | 24 ++++++++++++------------ 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/daily-psk.capsman b/daily-psk.capsman index 944d52c..9f81be5 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -56,20 +56,20 @@ $WaitFullyConnected; } :local Seen [ :toarray "" ]; -:local Date [ / system clock get date ]; +:local Date [ /system/clock/get date ]; :local NewPsk [ $GeneratePSK $Date ]; -:foreach AccList in=[ / caps-man access-list find where comment~$DailyPskMatchComment ] do={ - :local Ssid [ / caps-man access-list get $AccList ssid-regexp ]; - :local Configuration [ / caps-man configuration get ([ find where ssid=$Ssid ]->0) name ]; - :local OldPsk [ / caps-man access-list get $AccList private-passphrase ]; +:foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ + :local Ssid [ /caps-man/access-list/get $AccList ssid-regexp ]; + :local Configuration [ /caps-man/configuration/get ([ find where ssid=$Ssid ]->0) name ]; + :local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ]; :local Skip 0; :if ($NewPsk != $OldPsk) do={ $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; - / caps-man access-list set $AccList private-passphrase=$NewPsk; + /caps-man/access-list/set $AccList private-passphrase=$NewPsk; - :if ([ :len [ / caps-man interface find where configuration=$Configuration ] ] > 0) do={ + :if ([ :len [ /caps-man/interface/find where configuration=$Configuration ] ] > 0) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; diff --git a/daily-psk.local b/daily-psk.local index 022b4a3..23df467 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -56,20 +56,20 @@ $WaitFullyConnected; } :local Seen [ :toarray "" ]; -:local Date [ / system clock get date ]; +:local Date [ /system/clock/get date ]; :local NewPsk [ $GeneratePSK $Date ]; -:foreach AccList in=[ / interface wireless access-list find where comment~$DailyPskMatchComment ] do={ - :local IntName [ / interface wireless access-list get $AccList interface ]; - :local Ssid [ / interface wireless get $IntName ssid ]; - :local OldPsk [ / interface wireless access-list get $AccList private-pre-shared-key ]; +:foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ + :local IntName [ /interface/wireless/access-list/get $AccList interface ]; + :local Ssid [ /interface/wireless/get $IntName ssid ]; + :local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ]; :local Skip 0; :if ($NewPsk != $OldPsk) do={ $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; - / interface wireless access-list set $AccList private-pre-shared-key=$NewPsk; + /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; - :if ([ :len [ / interface wireless find where name=$IntName disabled=no ] ] = 1) do={ + :if ([ :len [ /interface/wireless/find where name=$IntName disabled=no ] ] = 1) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; diff --git a/daily-psk.template b/daily-psk.template index 5f7a832..aa05748 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -57,25 +57,25 @@ $WaitFullyConnected; } :local Seen [ :toarray "" ]; -:local Date [ / system clock get date ]; +:local Date [ /system/clock/get date ]; :local NewPsk [ $GeneratePSK $Date ]; -:foreach AccList in=[ / %PATH% access-list find where comment~$DailyPskMatchComment ] do={ - :local IntName [ / interface wireless access-list get $AccList interface ]; - :local Ssid [ / interface wireless get $IntName ssid ]; - :local Ssid [ / caps-man access-list get $AccList ssid-regexp ]; - :local Configuration [ / caps-man configuration get ([ find where ssid=$Ssid ]->0) name ]; - :local OldPsk [ / interface wireless access-list get $AccList private-pre-shared-key ]; - :local OldPsk [ / caps-man access-list get $AccList private-passphrase ]; +:foreach AccList in=[ /%PATH%/access-list/find where comment~$DailyPskMatchComment ] do={ + :local IntName [ /interface/wireless/access-list/get $AccList interface ]; + :local Ssid [ /interface/wireless/get $IntName ssid ]; + :local Ssid [ /caps-man/access-list/get $AccList ssid-regexp ]; + :local Configuration [ /caps-man/configuration/get ([ find where ssid=$Ssid ]->0) name ]; + :local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ]; + :local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ]; :local Skip 0; :if ($NewPsk != $OldPsk) do={ $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; - / interface wireless access-list set $AccList private-pre-shared-key=$NewPsk; - / caps-man access-list set $AccList private-passphrase=$NewPsk; + /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; + /caps-man/access-list/set $AccList private-passphrase=$NewPsk; - :if ([ :len [ / interface wireless find where name=$IntName disabled=no ] ] = 1) do={ - :if ([ :len [ / caps-man interface find where configuration=$Configuration ] ] > 0) do={ + :if ([ :len [ /interface/wireless/find where name=$IntName disabled=no ] ] = 1) do={ + :if ([ :len [ /caps-man/interface/find where configuration=$Configuration ] ] > 0) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; From a01b9b9347f3fa3e8bdf0dc06900030c42b51187 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:51:07 +0200 Subject: [PATCH 1016/2612] dhcp-lease-comment: RouterOS v7 path syntax --- dhcp-lease-comment.capsman | 10 +++++----- dhcp-lease-comment.local | 10 +++++----- dhcp-lease-comment.template | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman index c4844bf..fa34539 100644 --- a/dhcp-lease-comment.capsman +++ b/dhcp-lease-comment.capsman @@ -16,15 +16,15 @@ :global LogPrintExit2; -:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ - :local LeaseVal [ / ip dhcp-server lease get $Lease ]; +:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; :local NewComment; - :local AccessList ([ / caps-man access-list find where mac-address=($LeaseVal->"mac-address") ]->0); + :local AccessList ([ /caps-man/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ - :set NewComment [ / caps-man access-list get $AccessList comment ]; + :set NewComment [ /caps-man/access-list/get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; - / ip dhcp-server lease set comment=$NewComment $Lease; + /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local index 55a2e3c..71e6d5e 100644 --- a/dhcp-lease-comment.local +++ b/dhcp-lease-comment.local @@ -16,15 +16,15 @@ :global LogPrintExit2; -:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ - :local LeaseVal [ / ip dhcp-server lease get $Lease ]; +:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; :local NewComment; - :local AccessList ([ / interface wireless access-list find where mac-address=($LeaseVal->"mac-address") ]->0); + :local AccessList ([ /interface/wireless/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ - :set NewComment [ / interface wireless access-list get $AccessList comment ]; + :set NewComment [ /interface/wireless/access-list/get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; - / ip dhcp-server lease set comment=$NewComment $Lease; + /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template index fea0c14..a31812b 100644 --- a/dhcp-lease-comment.template +++ b/dhcp-lease-comment.template @@ -17,15 +17,15 @@ :global LogPrintExit2; -:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ - :local LeaseVal [ / ip dhcp-server lease get $Lease ]; +:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; :local NewComment; - :local AccessList ([ / %PATH% access-list find where mac-address=($LeaseVal->"mac-address") ]->0); + :local AccessList ([ /%PATH%/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0); :if ([ :len $AccessList ] > 0) do={ - :set NewComment [ / %PATH% access-list get $AccessList comment ]; + :set NewComment [ /%PATH%/access-list/get $AccessList comment ]; } :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; - / ip dhcp-server lease set comment=$NewComment $Lease; + /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } From f5f41a8aa72f840a58b059f1ed7bad5763eab94d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:52:21 +0200 Subject: [PATCH 1017/2612] dhcp-to-dns: RouterOS v7 path syntax --- dhcp-to-dns | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/dhcp-to-dns b/dhcp-to-dns index eb73ca3..368d68f 100644 --- a/dhcp-to-dns +++ b/dhcp-to-dns @@ -32,28 +32,28 @@ $ScriptLock $0 false 10; :local CommentPrefix ("managed by " . $0 . " for "); :local CommentString ("--- " . $0 . " above ---"); -:if ([ :len [ / ip dns static find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ - / ip dns static add comment=$CommentString name=- type=NXDOMAIN disabled=yes; +:if ([ :len [ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ + /ip/dns/static/add comment=$CommentString name=- type=NXDOMAIN disabled=yes; $LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false; } -:local PlaceBefore ([ / ip dns static find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0); +:local PlaceBefore ([ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0); -:foreach DnsRecord in=[ / ip dns static find where comment ~ $CommentPrefix ] do={ - :local DnsRecordVal [ / ip dns static get $DnsRecord ]; +:foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={ + :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; - :if ([ :len [ / ip dhcp-server lease find where mac-address=$MacAddress address=($DnsRecordVal->"address") status=bound ] ] > 0) do={ + :if ([ :len [ /ip/dhcp-server/lease/find where mac-address=$MacAddress address=($DnsRecordVal->"address") status=bound ] ] > 0) do={ $LogPrintExit2 debug $0 ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; } else={ :local Found false; $LogPrintExit2 info $0 ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry.") false; - / ip dns static remove $DnsRecord; + /ip/dns/static/remove $DnsRecord; } } -:foreach Lease in=[ / ip dhcp-server lease find where status=bound ] do={ +:foreach Lease in=[ /ip/dhcp-server/lease/find where status=bound ] do={ :local LeaseVal; :do { - :set LeaseVal [ / ip dhcp-server lease get $Lease ]; + :set LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; } on-error={ $LogPrintExit2 debug $0 ("A lease just vanished, ignoring.") false; } @@ -65,19 +65,19 @@ $ScriptLock $0 false 10; [ $CharacterReplace ($LeaseVal->"host-name") " " "" ] ]; :local Fqdn ($HostName . "." . [ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); - :local DnsRecord [ / ip dns static find where name=$Fqdn ]; + :local DnsRecord [ /ip/dns/static/find where name=$Fqdn ]; :if ([ :len $DnsRecord ] > 0) do={ - :local DnsIp [ / ip dns static get $DnsRecord address ]; + :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; - :local DupMacLeases [ / ip dhcp-server lease find where mac-address=($LeaseVal->"mac-address") status=bound ]; + :local DupMacLeases [ /ip/dhcp-server/lease/find where mac-address=($LeaseVal->"mac-address") status=bound ]; :if ([ :len $DupMacLeases ] > 1) do={ - :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; + :set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; } :if ([ :len ($LeaseVal->"host-name") ] > 0) do={ - :local HostNameLeases [ / ip dhcp-server lease find where host-name=($LeaseVal->"host-name") status=bound ]; + :local HostNameLeases [ /ip/dhcp-server/lease/find where host-name=($LeaseVal->"host-name") status=bound ]; :if ([ :len $HostNameLeases ] > 1) do={ - :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($HostNameLeases->0) address ]; + :set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($HostNameLeases->0) address ]; } } @@ -85,11 +85,11 @@ $ScriptLock $0 false 10; $LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false; } else={ $LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . ".") false; - / ip dns static set name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; + /ip/dns/static/set name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; } } else={ $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false; - / ip dns static add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + /ip/dns/static/add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } else={ $LogPrintExit2 debug $0 ("No address available... Ignoring.") false; From 294aff9c02fd1a40f982654fb4f22b2afa0e4096 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:53:25 +0200 Subject: [PATCH 1018/2612] firmware-upgrade-reboot: RouterOS v7 path syntax --- firmware-upgrade-reboot | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware-upgrade-reboot b/firmware-upgrade-reboot index ac2cb55..27bbe41 100644 --- a/firmware-upgrade-reboot +++ b/firmware-upgrade-reboot @@ -13,7 +13,7 @@ :global LogPrintExit2; :global VersionToNum; -:local RouterBoard [ / system routerboard get ]; +:local RouterBoard [ /system/routerboard/get ]; :if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ $LogPrintExit2 info $0 ("Firmware is already up to date.") true; } @@ -21,21 +21,21 @@ $LogPrintExit2 info $0 ("Different firmware version is available, but it is a downgrade. Ignoring.") true; } -:if ([ / system routerboard settings get auto-upgrade ] = false) do={ +:if ([ /system/routerboard/settings/get auto-upgrade ] = false) do={ $LogPrintExit2 info $0 ("Firmware version " . $RouterBoard->"upgrade-firmware" . \ " is available, upgrading.") false; - / system routerboard upgrade; + /system/routerboard/upgrade; } -:while ([ :len [ / log find where topics=({"system";"info";"critical"}) \ +:while ([ :len [ /log/find where topics=({"system";"info";"critical"}) \ message="Firmware upgraded successfully, please reboot for changes to take effect!" ] ] = 0) do={ :delay 1s; } -:local Uptime [ / system resource get uptime ]; +:local Uptime [ /system/resource/get uptime ]; :if ($Uptime < 1m) do={ :delay $Uptime; } $LogPrintExit2 info $0 ("Firmware upgrade successful, rebooting.") false; -/ system reboot; +/system/reboot; From 270e608d566a6b2807b604a138b1bfcdbddf99ff Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 14:59:00 +0200 Subject: [PATCH 1019/2612] gps-track: RouterOS v7 path syntax --- gps-track | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gps-track b/gps-track index 7c582e2..56a26c5 100644 --- a/gps-track +++ b/gps-track @@ -15,11 +15,11 @@ :global LogPrintExit2; -:local CoordinateFormat [ / system gps get coordinate-format ]; -:local Gps [ / system gps monitor once as-value ]; +:local CoordinateFormat [ /system/gps/get coordinate-format ]; +:local Gps [ /system/gps/monitor once as-value ]; :if ($Gps->"valid" = true) do={ - / tool fetch check-certificate=yes-without-crl $GpsTrackUrl output=none \ + /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") . "\"," . \ From b8f753d8b8bad556a933d53288348d26032e8f13 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:00:33 +0200 Subject: [PATCH 1020/2612] hotspot-to-wpa: RouterOS v7 path syntax --- hotspot-to-wpa | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/hotspot-to-wpa b/hotspot-to-wpa index 628d748..add2893 100644 --- a/hotspot-to-wpa +++ b/hotspot-to-wpa @@ -16,23 +16,23 @@ :local MacAddress $"mac-address"; :local UserName $username; -:local Date [ / system clock get date ]; -:local UserVal [ / ip hotspot user get [ find where name=$UserName ] ]; +:local Date [ /system/clock/get date ]; +:local UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; -:local Hotspot [ / ip hotspot host get [ find where mac-address=$MacAddress authorized ] server ]; +:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; -:if ([ :len [ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - / caps-man access-list add comment="--- hotspot-to-wpa above ---" disabled=yes; +:if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; } -:local PlaceBefore ([ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ]->0); +:local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); -:if ([ :len [ / caps-man access-list find where \ +:if ([ :len [ /caps-man/access-list/find where \ comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - / caps-man access-list add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; } -:local Template [ / caps-man access-list get ([ find where \ +:local Template [ /caps-man/access-list/get ([ find where \ comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; :if ($Template->"action" = "reject") do={ @@ -42,31 +42,31 @@ # allow login page to load :delay 1s; -$LogPrintExit2 info $0 ("Adding/updating accesslist entry for mac address " . $MacAddress . \ +$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \ " (user " . $UserName . ").") false; -/ caps-man access-list remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; -/ caps-man access-list add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ +/caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; +/caps-man/access-list/add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ mac-address=$MacAddress private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" place-before=$PlaceBefore; -:local Entry [ / caps-man access-list find where mac-address=$MacAddress \ +:local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; :if ([ :len $PrivatePassphrase ] > 0) do={ :if ($PrivatePassphrase = "ignore") do={ - / caps-man access-list set $Entry !private-passphrase; + /caps-man/access-list/set $Entry !private-passphrase; } else={ - / caps-man access-list set $Entry private-passphrase=$PrivatePassphrase; + /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; } } :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; :if ([ :len $SsidRegexp ] > 0) do={ - / caps-man access-list set $Entry ssid-regexp=$SsidRegexp; + /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; } :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; :if ([ :len $VlanId ] > 0) do={ - / caps-man access-list set $Entry vlan-id=$VlanId; + /caps-man/access-list/set $Entry vlan-id=$VlanId; } :local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; :if ([ :len $VlanMode] > 0) do={ - / caps-man access-list set $Entry vlan-mode=$VlanMode; + /caps-man/access-list/set $Entry vlan-mode=$VlanMode; } From c1d406fd4a6f54319011b27099429065514e03eb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:00:41 +0200 Subject: [PATCH 1021/2612] hotspot-to-wpa-cleanup: RouterOS v7 path syntax --- hotspot-to-wpa-cleanup | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/hotspot-to-wpa-cleanup b/hotspot-to-wpa-cleanup index f54edc6..26610ae 100644 --- a/hotspot-to-wpa-cleanup +++ b/hotspot-to-wpa-cleanup @@ -17,35 +17,35 @@ $ScriptLock $0 false 10; -:foreach Client in=[ / caps-man registration-table find where comment~"^hotspot-to-wpa:" ] do={ - :local ClientVal [ / caps-man registration-table get $Client ]; - :local Lease [ / ip dhcp-server lease find where server~"wpa" dynamic \ +:foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ + :local ClientVal [ /caps-man/registration-table/get $Client ]; + :local Lease [ /ip/dhcp-server/lease/find where server~"wpa" dynamic \ mac-address=($ClientVal->"mac-address") ]; :if ([ :len $Lease ] > 0) do={ $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ " connected to WPA, making lease static.") false; - / ip dhcp-server lease make-static $Lease; - / ip dhcp-server lease set comment=($ClientVal->"comment") $Lease; + /ip/dhcp-server/lease/make-static $Lease; + /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; } } -:foreach Client in=[ / caps-man access-list find where comment~"^hotspot-to-wpa:" and \ - !(comment~[ / system clock get date ]) ] do={ - :local ClientVal [ / caps-man access-list get $Client ]; - :if ([ :len [ / ip dhcp-server lease find where server~"wpa" !dynamic \ +:foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" and \ + !(comment~[ /system/clock/get date ]) ] do={ + :local ClientVal [ /caps-man/access-list/get $Client ]; + :if ([ :len [ /ip/dhcp-server/lease/find where server~"wpa" !dynamic \ mac-address=($ClientVal->"mac-address") ] ] = 0) do={ $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ " did not connect to WPA, removing from access list.") false; - / caps-man access-list remove $Client; + /caps-man/access-list/remove $Client; } } -:foreach Lease in=[ / ip dhcp-server lease find where !dynamic status=waiting \ +:foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status=waiting \ last-seen>4w comment~"^hotspot-to-wpa:" ] do={ - :local LeaseVal [ / ip dhcp-server lease get $Lease ]; + :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ " was not seen for long time, removing.") false; - / caps-man access-list remove [ find where comment~"^hotspot-to-wpa:" \ + /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ mac-address=($LeaseVal->"mac-address") ]; - / ip dhcp-server lease remove $Lease; + /ip/dhcp-server/lease/remove $Lease; } From 7979fb01085d610ade45387d40d098ffc0a60eaa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:01:19 +0200 Subject: [PATCH 1022/2612] ipsec-to-dns: RouterOS v7 path syntax --- ipsec-to-dns | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/ipsec-to-dns b/ipsec-to-dns index 0131f62..c6cfdc4 100644 --- a/ipsec-to-dns +++ b/ipsec-to-dns @@ -26,43 +26,43 @@ :local CommentPrefix ("managed by " . $0 . " for "); :local CommentString ("--- " . $0 . " above ---"); -:if ([ :len [ / ip dns static find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ - / ip dns static add comment=$CommentString name=- type=NXDOMAIN disabled=yes; +:if ([ :len [ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ + /ip/dns/static/add comment=$CommentString name=- type=NXDOMAIN disabled=yes; $LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false; } -:local PlaceBefore ([ / ip dns static find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0); +:local PlaceBefore ([ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0); -:foreach DnsRecord in=[ / ip dns static find where comment ~ $CommentPrefix ] do={ - :local DnsRecordVal [ / ip dns static get $DnsRecord ]; +:foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={ + :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; :local PeerId [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; - :if ([ :len [ / ip ipsec active-peers find where id=$PeerId dynamic-address=($DnsRecordVal->"address") ] ] > 0) do={ + :if ([ :len [ /ip/ipsec/active-peers/find where id=$PeerId dynamic-address=($DnsRecordVal->"address") ] ] > 0) do={ $LogPrintExit2 debug $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; } else={ :local Found false; $LogPrintExit2 info $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") has gone, deleting DNS entry.") false; - / ip dns static remove $DnsRecord; + /ip/dns/static/remove $DnsRecord; } } -:foreach Peer in=[ / ip ipsec active-peers find where !(dynamic-address=[]) ] do={ - :local PeerVal [ / ip ipsec active-peers get $Peer ]; +:foreach Peer in=[ /ip/ipsec/active-peers/find where !(dynamic-address=[]) ] do={ + :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; :local Comment ($CommentPrefix . $PeerVal->"id"); :put ($PeerVal->"id"); :local HostName [ :pick ($PeerVal->"id") 0 [ :find ($PeerVal->"id" . ".") "." ] ]; :put $HostName; :local Fqdn ($HostName . "." . $Zone); - :local DnsRecord [ / ip dns static find where name=$Fqdn ]; + :local DnsRecord [ /ip/dns/static/find where name=$Fqdn ]; :if ([ :len $DnsRecord ] > 0) do={ - :local DnsIp [ / ip dns static get $DnsRecord address ]; + :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; :if ($DnsIp = $PeerVal->"dynamic-address") do={ $LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false; } else={ $LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $PeerVal->"dynamic-address" . ".") false; - / ip dns static set name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment $DnsRecord; + /ip/dns/static/set name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment $DnsRecord; } } else={ $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $PeerVal->"dynamic-address" . ".") false; - / ip dns static add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + /ip/dns/static/add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } From 3befc38d21f22e08d15ccb7996f49f25a18f557d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:02:43 +0200 Subject: [PATCH 1023/2612] ipv6-update: RouterOS v7 path syntax --- ipv6-update | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/ipv6-update b/ipv6-update index 742a7cf..b81a0ec 100644 --- a/ipv6-update +++ b/ipv6-update @@ -19,44 +19,44 @@ $LogPrintExit2 error $0 ("This script is supposed to run from ipv6 dhcp-client.") true; } -:local Pool [ / ipv6 pool get [ find where prefix=$PdPrefix ] name ]; -:if ([ :len [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={ - / ipv6 firewall address-list add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool); +:local Pool [ /ipv6/pool/get [ find where prefix=$PdPrefix ] name ]; +:if ([ :len [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={ + /ipv6/firewall/address-list/add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool); $LogPrintExit2 warning $0 ("Added ipv6 address list entry for ipv6-pool-" . $Pool) false; } -:local AddrList [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ]; -:local OldPrefix [ / ipv6 firewall address-list get ($AddrList->0) address ]; +:local AddrList [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ]; +:local OldPrefix [ /ipv6/firewall/address-list/get ($AddrList->0) address ]; :if ($OldPrefix != $PdPrefix) do={ $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix) false; - / ipv6 firewall address-list set address=$PdPrefix $AddrList; + /ipv6/firewall/address-list/set address=$PdPrefix $AddrList; # give the interfaces a moment to receive their addresses :delay 2s; - :foreach ListEntry in=[ / ipv6 firewall address-list find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ - :local ListEntryVal [ / ipv6 firewall address-list get $ListEntry ]; + :foreach ListEntry in=[ /ipv6/firewall/address-list/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ + :local ListEntryVal [ /ipv6/firewall/address-list/get $ListEntry ]; :local Comment [ $ParseKeyValueStore ($ListEntryVal->"comment") ]; - :local Address [ / ipv6 address find where from-pool=$Pool interface=($Comment->"interface") ]; + :local Address [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") ]; :if ([ :len $Address ] = 1) do={ - :set Address [ / ipv6 address get $Address address ]; + :set Address [ /ipv6/address/get $Address address ]; $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $Address . \ " from interface " . ($Comment->"interface")) false; - / ipv6 firewall address-list set address=$Address $ListEntry; + /ipv6/firewall/address-list/set address=$Address $ListEntry; } } - :foreach Record in=[ / ip dns static find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ - :local RecordVal [ / ip dns static get $Record ]; + :foreach Record in=[ /ip/dns/static/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ + :local RecordVal [ /ip/dns/static/get $Record ]; :local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ]; - :local Prefix [ / ipv6 address get [ find where interface=($Comment->"interface") from-pool=$Pool global ] address ]; + :local Prefix [ /ipv6/address/get [ find where interface=($Comment->"interface") from-pool=$Pool global ] address ]; :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); $LogPrintExit2 info $0 ("Updating DNS record for " . ($RecordVal->"name") . \ ($RecordVal->"regexp") . " to " . $Address) false; - / ip dns static set address=$Address $Record; + /ip/dns/static/set address=$Address $Record; } } From 0fec08c0cdd17667ea2eb8fbdf64ca73169272ed Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:03:30 +0200 Subject: [PATCH 1024/2612] ip-addr-bridge: RouterOS v7 path syntax --- ip-addr-bridge | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ip-addr-bridge b/ip-addr-bridge index 783ff2f..218eb2e 100644 --- a/ip-addr-bridge +++ b/ip-addr-bridge @@ -6,13 +6,13 @@ # enable or disable ip addresses based on bridge port state # https://git.eworm.de/cgit/routeros-scripts/about/doc/ip-addr-bridge.md -:foreach Bridge in=[ / interface bridge find ] do={ - :local BrName [ / interface bridge get $Bridge name ]; - :if ([ :len [ / interface bridge port find where bridge=$BrName ] ] > 0) do={ - :if ([ :len [ / interface bridge port find where bridge=$BrName and inactive=no ] ] = 0) do={ - / ip address disable [ find where !dynamic interface=$BrName ]; +:foreach Bridge in=[ /interface/bridge/find ] do={ + :local BrName [ /interface/bridge/get $Bridge name ]; + :if ([ :len [ /interface/bridge/port/find where bridge=$BrName ] ] > 0) do={ + :if ([ :len [ /interface/bridge/port/find where bridge=$BrName and inactive=no ] ] = 0) do={ + /ip/address/disable [ find where !dynamic interface=$BrName ]; } else={ - / ip address enable [ find where !dynamic interface=$BrName ]; + /ip/address/enable [ find where !dynamic interface=$BrName ]; } } } From 2ab87f5143191915c27b8d4fe2bb50a032c2d2a6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:05:56 +0200 Subject: [PATCH 1025/2612] learn-mac-based-vlan: RouterOS v7 path syntax --- learn-mac-based-vlan | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/learn-mac-based-vlan b/learn-mac-based-vlan index e05fb7e..ce8957d 100644 --- a/learn-mac-based-vlan +++ b/learn-mac-based-vlan @@ -7,7 +7,7 @@ :local NewVlanId 33; -:if ([ :len [ / interface ethernet switch mac-based-vlan find where src-mac-address=$leaseActMAC ] ] = 0 ) do={ +:if ([ :len [ /interface/ethernet/switch/mac-based-vlan/find where src-mac-address=$leaseActMAC ] ] = 0 ) do={ :log info ("MAC-based-VLAN: learning MAC address " . $leaseActMAC . " for VLAN " . $NewVlanId . "."); - / interface ethernet switch mac-based-vlan add src-mac-address=$leaseActMAC new-customer-vid=$NewVlanId; + /interface/ethernet/switch/mac-based-vlan/add src-mac-address=$leaseActMAC new-customer-vid=$NewVlanId; } From 7d5418718ce02a4ff471ebbb9a4cb1c8fc750be7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:06:01 +0200 Subject: [PATCH 1026/2612] lease-script: RouterOS v7 path syntax --- lease-script | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lease-script b/lease-script index 2b873c8..fa03e11 100644 --- a/lease-script +++ b/lease-script @@ -27,15 +27,15 @@ $LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse $ScriptLock $0 false 10; -:if ([ :len [ / system script job find where script=$0 ] ] > 1) do={ +:if ([ :len [ /system/script/job/find where script=$0 ] ] > 1) do={ $LogPrintExit2 debug $0 ("More invocations are waiting, exiting early.") true; } :local RunOrder [ :toarray "" ]; -:foreach Script in=[ / system script find where source~("\n# provides: lease-script, ") ] do={ - :local Name [ / system script get $Script name ]; - :local Store [ / system script get $Script source ]; +:foreach Script in=[ /system/script/find where source~("\n# provides: lease-script, ") ] do={ + :local Name [ /system/script/get $Script name ]; + :local Store [ /system/script/get $Script source ]; :set Store [ :pick $Store ([ :find $Store "\n# provides: lease-script, " ] + 27) [ :len $Store ] ]; :set Store [ :pick $Store 0 [ :find $Store "\n" ] ]; @@ -47,7 +47,7 @@ $ScriptLock $0 false 10; :foreach Order,Script in=$RunOrder do={ :do { $LogPrintExit2 debug $0 ("Running script with order " . $Order . ": " . $Script) false; - / system script run $Script; + /system/script/run $Script; } on-error={ $LogPrintExit2 warning $0 ("Running script '" . $Script . "' failed!") false; } From efc3e997ef4e4ad22cbfe9213693981e0f6b0694 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:07:47 +0200 Subject: [PATCH 1027/2612] leds-{day,night,toggle}-mode: RouterOS v7 path syntax --- leds-day-mode | 2 +- leds-night-mode | 2 +- leds-toggle-mode | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/leds-day-mode b/leds-day-mode index ed6f68d..78e1fae 100644 --- a/leds-day-mode +++ b/leds-day-mode @@ -6,4 +6,4 @@ # enable LEDs # https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md -/ system leds settings set all-leds-off=never; +/system/leds/settings/set all-leds-off=never; diff --git a/leds-night-mode b/leds-night-mode index af2388c..112f9a1 100644 --- a/leds-night-mode +++ b/leds-night-mode @@ -6,4 +6,4 @@ # disable LEDs # https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md -/ system leds settings set all-leds-off=immediate; +/system/leds/settings/set all-leds-off=immediate; diff --git a/leds-toggle-mode b/leds-toggle-mode index 8ec66e3..225ceb2 100644 --- a/leds-toggle-mode +++ b/leds-toggle-mode @@ -6,8 +6,8 @@ # toggle LEDs mode # https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md -:if ([ / system leds settings get all-leds-off ] = "never") do={ - / system leds settings set all-leds-off=immediate; +:if ([ /system/leds/settings/get all-leds-off ] = "never") do={ + /system/leds/settings/set all-leds-off=immediate; } else={ - / system leds settings set all-leds-off=never; + /system/leds/settings/set all-leds-off=never; } From 1c56809cd4303ab1c38ffddf5d429ec22a57bd1e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:08:30 +0200 Subject: [PATCH 1028/2612] log-forward: RouterOS v7 path syntax --- log-forward | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/log-forward b/log-forward index 3cd83d5..1aa0363 100644 --- a/log-forward +++ b/log-forward @@ -52,10 +52,10 @@ $WaitFullyConnected; :local LogForwardFilterLogForwarding ("^" . [ $EscapeForRegEx ("Error sending e-mail <" . \ [ $QuotedPrintable ("[" . $Identity . "] " . [ $SymbolForNotification "warning-sign" ] . \ "Log Forwarding") ] . ">:") ]); -:foreach Message in=[ / log find where (!(message="") and !(message~$LogForwardFilterLogForwarding) and \ +:foreach Message in=[ /log/find where (!(message="") and !(message~$LogForwardFilterLogForwarding) and \ !(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \ topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={ - :set MessageVal [ / log get $Message ]; + :set MessageVal [ /log/get $Message ]; :if ($Last < [ $HexToNum ($MessageVal->".id") ]) do={ :local DupCount ($MessageDups->($MessageVal->"message")); @@ -75,7 +75,7 @@ $WaitFullyConnected; subject=([ $SymbolForNotification "warning-sign" ] . "Log Forwarding"); \ message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) \ "this message" ("these " . $Count . " messages") ] . " after " . \ - [ / system resource get uptime ] . " uptime." . [ $IfThenElse ($Duplicates = true) \ + [ /system/resource/get uptime ] . " uptime." . [ $IfThenElse ($Duplicates = true) \ (" Multi-repeated messages have been skipped.") ] . "\n" . $Messages) }); :set LogForwardRateLimit ($LogForwardRateLimit + 10); From 8c5348737024038754314d62f1af13eb007c7132 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:09:08 +0200 Subject: [PATCH 1029/2612] manage-umts: RouterOS v7 path syntax --- manage-umts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/manage-umts b/manage-umts index 8f782ec..0cd3e8f 100644 --- a/manage-umts +++ b/manage-umts @@ -9,21 +9,21 @@ :local WlanInt "wl-station"; :local UmtsInt "t-mobile"; -:local EtherStatus [ / interface ethernet get $EtherInt running ]; -:local WlanStatus [ / interface wireless get $WlanInt running ]; +:local EtherStatus [ /interface/ethernet/get $EtherInt running ]; +:local WlanStatus [ /interface/wireless/get $WlanInt running ]; :if ($EtherStatus = true || $WlanStatus = true) do={ - :if ([ / interface get $UmtsInt disabled ] = false) do={ + :if ([ /interface/get $UmtsInt disabled ] = false) do={ :log info ("Ethernet (" . $EtherInt . " / " . $EtherStatus . ") or " . \ "wireless (" . $WlanInt . " / " . $WlanStatus . ") is running, " . \ "UMTS interface " . $UmtsInt . " is enabled. Disabling..."); - / interface set disabled=yes $UmtsInt; + /interface/set disabled=yes $UmtsInt; } } else={ - :if ([ / interface get $UmtsInt disabled ] = true) do={ + :if ([ /interface/get $UmtsInt disabled ] = true) do={ :log info ("Neither ethernet (" . $EtherInt . ") nor wireless (" . \ $WlanInt . ") interface is running, UMTS interface " . $UmtsInt . \ " is disabled. Enabling..."); - / interface set disabled=no $UmtsInt; + /interface/set disabled=no $UmtsInt; } } From 158aea4756edf1d013a910d3fb06fccd8ac2142f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 16:09:42 +0200 Subject: [PATCH 1030/2612] mod/bridge-port-to: RouterOS v7 path syntax --- mod/bridge-port-to | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mod/bridge-port-to b/mod/bridge-port-to index d88b1cd..c2ab55b 100644 --- a/mod/bridge-port-to +++ b/mod/bridge-port-to @@ -15,34 +15,34 @@ :global LogPrintExit2; :global ParseKeyValueStore; - :foreach BridgePort in=[ / interface bridge port find where !(comment=[]) ] do={ - :local BridgePortVal [ / interface bridge port get $BridgePort ]; + :foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={ + :local BridgePortVal [ /interface/bridge/port/get $BridgePort ]; :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ :if ($Config = $BridgePortTo) do={ - :local DHCPClient [ / ip dhcp-client find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; + :local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; :if ($BridgeDefault = "dhcp-client") do={ :if ([ :len $DHCPClient ] != 1) do={ $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; } - :local DHCPClientDisabled [ / ip dhcp-client get $DHCPClient disabled ]; + :local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ]; :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; - / interface bridge port disable $BridgePort; + /interface/bridge/port/disable $BridgePort; :delay 200ms; - / ip dhcp-client enable $DHCPClient; + /ip/dhcp-client/enable $DHCPClient; } } else={ :if ($BridgePortVal->"disabled" = true || $BridgeDefault != $BridgePortVal->"bridge") do={ $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ " bridge " . $BridgeDefault . ", disabling dhcp client.") false; :if ([ :len $DHCPClient ] = 1) do={ - / ip dhcp-client disable $DHCPClient; + /ip/dhcp-client/disable $DHCPClient; :delay 200ms; } - / interface bridge port set disabled=no bridge=$BridgeDefault $BridgePort; + /interface/bridge/port/set disabled=no bridge=$BridgeDefault $BridgePort; } else={ $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ " bridge " . $BridgeDefault . ".") false; From 9bd9f4b4bac56ad1a8278e634d3e64e5fd10102b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 16:09:50 +0200 Subject: [PATCH 1031/2612] mod/bridge-port-vlan: RouterOS v7 path syntax --- mod/bridge-port-vlan | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan index db9cbfd..6255dff 100644 --- a/mod/bridge-port-vlan +++ b/mod/bridge-port-vlan @@ -16,29 +16,29 @@ :global LogPrintExit2; :global ParseKeyValueStore; - :foreach BridgePort in=[ / interface bridge port find where !(comment=[]) ] do={ - :local BridgePortVal [ / interface bridge port get $BridgePort ]; + :foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={ + :local BridgePortVal [ /interface/bridge/port/get $BridgePort ]; :foreach Config,Vlan in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ :if ($Config = $ConfigTo) do={ - :local DHCPClient [ / ip dhcp-client find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; + :local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; :if ($Vlan = "dhcp-client") do={ :if ([ :len $DHCPClient ] != 1) do={ $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; } - :local DHCPClientDisabled [ / ip dhcp-client get $DHCPClient disabled ]; + :local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ]; :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; - / interface bridge port disable $BridgePort; + /interface/bridge/port/disable $BridgePort; :delay 200ms; - / ip dhcp-client enable $DHCPClient; + /ip/dhcp-client/enable $DHCPClient; } } else={ :if ($Vlan != [ :tostr [ :tonum $Vlan ] ]) do={ :do { - :set $Vlan ([ / interface bridge vlan get [ find where comment=$Vlan ] vlan-ids ]->0); + :set $Vlan ([ /interface/bridge/vlan/get [ find where comment=$Vlan ] vlan-ids ]->0); } on-error={ $LogPrintExit2 warning $0 ("Could not find VLAN '" . $Vlan . "' for interface " . $BridgePortVal->"interface" . "!") true; } @@ -47,10 +47,10 @@ $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $ConfigTo . \ " vlan " . $Vlan . ", disabling dhcp client.") false; :if ([ :len $DHCPClient ] = 1) do={ - / ip dhcp-client disable $DHCPClient; + /ip/dhcp-client/disable $DHCPClient; :delay 200ms; } - / interface bridge port set disabled=no pvid=$Vlan $BridgePort; + /interface/bridge/port/set disabled=no pvid=$Vlan $BridgePort; } else={ $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \ " vlan " . $Vlan . ".") false; From 50a139248ff4e9e026d2330c41781f915d39a115 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 16:11:53 +0200 Subject: [PATCH 1032/2612] mod/notification-matrix: RouterOS v7 path syntax --- mod/notification-matrix | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mod/notification-matrix b/mod/notification-matrix index 4ec5f6c..c3cf24f 100644 --- a/mod/notification-matrix +++ b/mod/notification-matrix @@ -18,14 +18,14 @@ :local AllDone true; :local QueueLen [ :len $MatrixQueue ]; - :if ([ :len [ / system scheduler find where name="FlushMatrixQueue" ] ] > 0 && $QueueLen = 0) do={ + :if ([ :len [ /system/scheduler/find where name="FlushMatrixQueue" ] ] > 0 && $QueueLen = 0) do={ $LogPrintExit2 warning $0 ("Flushing Matrix messages from scheduler, but queue is empty.") false; } :foreach Id,Message in=$MatrixQueue do={ :if ([ :typeof $Message ] = "array" ) do={ :do { - / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ ("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \ "/send/m.room.message?access_token=" . $Message->"accesstoken") \ http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Message->"plain" . "\"," . \ @@ -40,7 +40,7 @@ } :if ($AllDone = true && $QueueLen = [ :len $MatrixQueue ]) do={ - / system scheduler remove [ find where name="FlushMatrixQueue" ]; + /system/scheduler/remove [ find where name="FlushMatrixQueue" ]; :set MatrixQueue; } } @@ -113,7 +113,7 @@ } :do { - / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ ("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \ "/send/m.room.message?access_token=" . $AccessToken) \ http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Plain . "\"," . \ @@ -126,15 +126,15 @@ :set MatrixQueue [ :toarray "" ]; } :local Text ([ $SymbolForNotification "alarm-clock" ] . \ - "This message was queued since " . [ / system clock get date ] . \ - " " . [ / system clock get time ] . " and may be obsolete."); + "This message was queued since " . [ /system/clock/get date ] . \ + " " . [ /system/clock/get time ] . " and may be obsolete."); :set Plain ($Plain . "\\n" . $Text); :set Formatted ($Formatted . "
    " . $Text); :set ($MatrixQueue->[ :len $MatrixQueue ]) { room=$Room; \ accesstoken=$AccessToken; homeserver=$HomeServer; \ plain=$Plain; formatted=$Formatted }; - :if ([ :len [ / system scheduler find where name="FlushMatrixQueue" ] ] = 0) do={ - / system scheduler add name=FlushMatrixQueue interval=1m start-time=startup \ + :if ([ :len [ /system/scheduler/find where name="FlushMatrixQueue" ] ] = 0) do={ + /system/scheduler/add name=FlushMatrixQueue interval=1m start-time=startup \ on-event=(":global FlushMatrixQueue; \$FlushMatrixQueue;"); } } From 20b5ca4918b8e087c500f44c5d243feb3674e9ae Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 16:13:34 +0200 Subject: [PATCH 1033/2612] mod/notification-telegram: RouterOS v7 path syntax --- mod/notification-telegram | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mod/notification-telegram b/mod/notification-telegram index d42d459..230dd57 100644 --- a/mod/notification-telegram +++ b/mod/notification-telegram @@ -17,14 +17,14 @@ :local AllDone true; :local QueueLen [ :len $TelegramQueue ]; - :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] > 0 && $QueueLen = 0) do={ + :if ([ :len [ /system/scheduler/find where name="FlushTelegramQueue" ] ] > 0 && $QueueLen = 0) do={ $LogPrintExit2 warning $0 ("Flushing Telegram messages from scheduler, but queue is empty.") false; } :foreach Id,Message in=$TelegramQueue do={ :if ([ :typeof $Message ] = "array" ) do={ :do { - / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ http-data=("chat_id=" . ($Message->"chatid") . \ "&disable_notification=" . ($Message->"silent") . \ @@ -39,7 +39,7 @@ } :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ - / system scheduler remove [ find where name="FlushTelegramQueue" ]; + /system/scheduler/remove [ find where name="FlushTelegramQueue" ]; :set TelegramQueue; } } @@ -125,7 +125,7 @@ :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; } - / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; @@ -136,12 +136,12 @@ :set TelegramQueue [ :toarray "" ]; } :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ - [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ - " " . [ / system clock get time ] . " and may be obsolete.") "plain" ]) ]); + [ $EscapeMD ("This message was queued since " . [ /system/clock/get date ] . \ + " " . [ /system/clock/get time ] . " and may be obsolete.") "plain" ]) ]); :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; parsemode=$ParseMode; text=$Text; silent=($Notification->"silent") }; - :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] = 0) do={ - / system scheduler add name=FlushTelegramQueue interval=1m start-time=startup \ + :if ([ :len [ /system/scheduler/find where name="FlushTelegramQueue" ] ] = 0) do={ + /system/scheduler/add name=FlushTelegramQueue interval=1m start-time=startup \ on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;"); } } From 2f46495be164e3ec8785ed7e25d2e4fe39c33d64 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 16:14:02 +0200 Subject: [PATCH 1034/2612] mod/scriptrunonce: RouterOS v7 path syntax --- mod/scriptrunonce | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/scriptrunonce b/mod/scriptrunonce index 3e02236..6cca175 100644 --- a/mod/scriptrunonce +++ b/mod/scriptrunonce @@ -25,7 +25,7 @@ :local Source; :do { - :set Source ([ / tool fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data"); + :set Source ([ /tool/fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data"); } on-error={ $LogPrintExit2 warning $0 ("Failed fetching script '" . $Script . "'!") false; } From 0e466c3b81017c582c851e2dbf15fe8a7cee46a4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:09:45 +0200 Subject: [PATCH 1035/2612] mode-button: RouterOS v7 path syntax --- mode-button | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mode-button b/mode-button index e1b2a23..e4d33cc 100644 --- a/mode-button +++ b/mode-button @@ -16,7 +16,7 @@ :set ($ModeButton->"count") ($ModeButton->"count" + 1); -:local Scheduler [ / system scheduler find where name="ModeButtonScheduler" ]; +:local Scheduler [ /system/scheduler/find where name="ModeButtonScheduler" ]; :if ([ :len $Scheduler ] = 0) do={ $LogPrintExit2 info $0 ("Creating scheduler ModeButtonScheduler, counting presses...") false; @@ -32,11 +32,11 @@ :global IfThenElse; - :local LED [ / system leds find where leds=$ModeButtonLED type~"^(on|off)\$" interface=[] ]; + :local LED [ /system/leds/find where leds=$ModeButtonLED type~"^(on|off)\$" interface=[] ]; :if ([ :len $LED ] = 0) do={ :return false; } - / system leds set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED; + /system/leds/set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED; } :local Count ($ModeButton->"count"); @@ -44,7 +44,7 @@ :set ($ModeButton->"count") 0; :set ModeButtonScheduler; - / system scheduler remove ModeButtonScheduler; + /system/scheduler/remove ModeButtonScheduler; :if ([ :len $Code ] > 0) do={ :if ([ $ValidateSyntax $Code ] = true) do={ @@ -52,7 +52,7 @@ :for I from=1 to=$Count do={ $LEDInvert; - :if ([ / system routerboard settings get silent-boot ] = false) do={ + :if ([ /system/routerboard/settings/get silent-boot ] = false) do={ :beep length=200ms; } :delay 200ms; @@ -68,9 +68,9 @@ $LogPrintExit2 info $0 ("No action defined for " . $Count . " mode-button presses.") false; } } - / system scheduler add name="ModeButtonScheduler" \ + /system/scheduler/add name="ModeButtonScheduler" \ on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s; } else={ $LogPrintExit2 debug $0 ("Updating scheduler ModeButtonScheduler...") false; - / system scheduler set $Scheduler start-time=[ /system clock get time ]; + /system/scheduler/set $Scheduler start-time=[ /system/clock/get time ]; } From 0696c6ca889dc0b154aaa171f9746e3adebfb1a2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:11:33 +0200 Subject: [PATCH 1036/2612] netwatch-dns: RouterOS v7 path syntax --- netwatch-dns | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/netwatch-dns b/netwatch-dns index e2fcfa3..64c2d8e 100644 --- a/netwatch-dns +++ b/netwatch-dns @@ -17,16 +17,16 @@ $ScriptLock $0; -:if ([ / system resource get uptime ] < 5m) do={ +:if ([ /system/resource/get uptime ] < 5m) do={ $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; } :local DnsServers [ :toarray "" ]; :local DnsFallback [ :toarray "" ]; -:local DnsCurrent [ / ip dns get servers ]; +:local DnsCurrent [ /ip/dns/get servers ]; -:foreach Host in=[ / tool netwatch find where comment~"dns" disabled=no ] do={ - :local HostVal [ / tool netwatch get $Host ]; +:foreach Host in=[ /tool/netwatch/find where comment~"dns" disabled=no ] do={ + :local HostVal [ /tool/netwatch/get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; :if ($HostVal->"status" = "up" && $HostInfo->"disabled" != true) do={ @@ -42,24 +42,24 @@ $ScriptLock $0; :if ([ :len $DnsServers ] > 0) do={ :if ($DnsServers != $DnsCurrent) do={ $LogPrintExit2 info $0 ("Updating DNS servers: " . [ :tostr $DnsServers ]) false; - / ip dns set servers=$DnsServers; - / ip dns cache flush; + /ip/dns/set servers=$DnsServers; + /ip/dns/cache/flush; } } else={ :if ([ :len $DnsFallback ] > 0) do={ :if ($DnsFallback != $DnsCurrent) do={ $LogPrintExit2 info $0 ("Updating DNS servers to fallback: " . [ :tostr $DnsFallback ]) false; - / ip dns set servers=$DnsFallback; - / ip dns cache flush; + /ip/dns/set servers=$DnsFallback; + /ip/dns/cache/flush; } } } :local DohServer ""; -:local DohCurrent [ / ip dns get use-doh-server ]; +:local DohCurrent [ /ip/dns/get use-doh-server ]; -:foreach Host in=[ / tool netwatch find where comment~"doh" disabled=no ] do={ - :local HostVal [ / tool netwatch get $Host ]; +:foreach Host in=[ /tool/netwatch/find where comment~"doh" disabled=no ] do={ + :local HostVal [ /tool/netwatch/get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; :if ($HostVal->"status" = "up" && $HostInfo->"doh" = true && $HostInfo->"disabled" != true && $DohServer = "") do={ @@ -70,13 +70,13 @@ $ScriptLock $0; :if ($DohServer != "") do={ :if ($DohServer != $DohCurrent) do={ $LogPrintExit2 info $0 ("Updating DoH server: " . $DohServer) false; - / ip dns set use-doh-server=$DohServer; - / ip dns cache flush; + /ip/dns/set use-doh-server=$DohServer; + /ip/dns/cache/flush; } } else={ :if ($DohCurrent != "") do={ $LogPrintExit2 info $0 ("DoH server (" . $DohCurrent . ") is down, disabling.") false; - / ip dns set use-doh-server=""; - / ip dns cache flush; + /ip/dns/set use-doh-server=""; + /ip/dns/cache/flush; } } From b368ee9902eea02c9e4ea4222cc02af0561e6441 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:11:44 +0200 Subject: [PATCH 1037/2612] netwatch-notify: RouterOS v7 path syntax --- netwatch-notify | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 34a9e8f..47b7fa1 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -46,7 +46,7 @@ $ScriptLock $0; -:if ([ / system resource get uptime ] < 5m) do={ +:if ([ /system/resource/get uptime ] < 5m) do={ $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; } @@ -54,8 +54,8 @@ $ScriptLock $0; :set NetwatchNotify [ :toarray "" ]; } -:foreach Host in=[ / tool netwatch find where comment~"notify" disabled=no ] do={ - :local HostVal [ / tool netwatch get $Host ]; +:foreach Host in=[ /tool/netwatch/find where comment~"notify" disabled=no ] do={ + :local HostVal [ /tool/netwatch/get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ @@ -74,7 +74,7 @@ $ScriptLock $0; $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . \ "' resolves to different address " . $Resolve . ", updating.") false; - / tool netwatch set host=$Resolve $Host; + /tool/netwatch/set host=$Resolve $Host; :set ($Metric->"resolve-failed") false; } } on-error={ From c18821deb5b1a1128ae6b4bb16a53d11affaa356 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:11:51 +0200 Subject: [PATCH 1038/2612] netwatch-syslog: RouterOS v7 path syntax --- netwatch-syslog | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/netwatch-syslog b/netwatch-syslog index 42e5c52..1d9f37b 100644 --- a/netwatch-syslog +++ b/netwatch-syslog @@ -8,10 +8,10 @@ # manage remote logging facilities # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-syslog.md -:local Remote [ /system logging action get ([ find where target=remote ]->0) remote ]; +:local Remote [ /system/logging/action/get ([ find where target=remote ]->0) remote ]; -if ([ / tool netwatch get [ find where host=$Remote up-script="netwatch-syslog" down-script="netwatch-syslog" ] status ] = "up") do={ - / system logging set disabled=no [ find where action=remote disabled=yes ]; +if ([ /tool/netwatch/get [ find where host=$Remote up-script="netwatch-syslog" down-script="netwatch-syslog" ] status ] = "up") do={ + /system/logging/set disabled=no [ find where action=remote disabled=yes ]; } else={ - / system logging set disabled=yes [ find where action=remote disabled=no ]; + /system/logging/set disabled=yes [ find where action=remote disabled=no ]; } From 008046d569a995d393fc8be1cd8c1fbeb1d76641 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:12:28 +0200 Subject: [PATCH 1039/2612] ospf-to-leds: RouterOS v7 path syntax --- ospf-to-leds | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ospf-to-leds b/ospf-to-leds index 39501c9..c4acb30 100644 --- a/ospf-to-leds +++ b/ospf-to-leds @@ -13,23 +13,23 @@ :global LogPrintExit2; :global ParseKeyValueStore; -:foreach Instance in=[ / routing ospf instance find where comment~"^ospf-to-leds," ] do={ - :local InstanceVal [ / routing ospf instance get $Instance ]; +:foreach Instance in=[ /routing/ospf/instance/find where comment~"^ospf-to-leds," ] do={ + :local InstanceVal [ /routing/ospf/instance/get $Instance ]; :local LED ([ $ParseKeyValueStore ($InstanceVal->"comment") ]->"leds"); - :local LEDType [ / system leds get [ find where leds=$LED ] type ]; + :local LEDType [ /system/leds/get [ find where leds=$LED ] type ]; :local NeighborCount 0; - :foreach Area in=[ / routing ospf area find where instance=($InstanceVal->"name") ] do={ - :local AreaName [ / routing ospf area get $Area name ]; - :set NeighborCount ($NeighborCount + [ :len [ / routing ospf neighbor find where area=$AreaName ] ]); + :foreach Area in=[ /routing/ospf/area/find where instance=($InstanceVal->"name") ] do={ + :local AreaName [ /routing/ospf/area/get $Area name ]; + :set NeighborCount ($NeighborCount + [ :len [ /routing/ospf/neighbor/find where area=$AreaName ] ]); } :if ($NeighborCount > 0 && $LEDType = "off") do={ $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " has " . $NeighborCount . " neighbors, led on!") false; - / system leds set type=on [ find where leds=$LED ]; + /system/leds/set type=on [ find where leds=$LED ]; } :if ($NeighborCount = 0 && $LEDType = "on") do={ $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " has no neighbors, led off!") false; - / system leds set type=off [ find where leds=$LED ]; + /system/leds/set type=off [ find where leds=$LED ]; } } From ba0bb3d2d4fcc1b44681f846630cbabc3c9c96b0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:13:05 +0200 Subject: [PATCH 1040/2612] packages-update: RouterOS v7 path syntax --- packages-update | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages-update b/packages-update index 2e6d8be..2922759 100644 --- a/packages-update +++ b/packages-update @@ -18,7 +18,7 @@ $ScriptLock $0; -:local Update [ / system package update get ]; +:local Update [ /system/package/update/get ]; :if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ $LogPrintExit2 warning $0 ("Latest version is not known.") true; @@ -35,7 +35,7 @@ $ScriptLock $0; :if ($NumInstalled > $NumLatest) do={ :if ([ $ScriptFromTerminal $0 ] = true) do={ :put "Latest version is older than installed one. Want to downgrade? [y/N]"; - :if (([ / terminal inkey timeout=60 ] % 32) = 25) do={ + :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ :set DoDowngrade true; } else={ :put "Canceled..."; @@ -45,23 +45,23 @@ $ScriptLock $0; } } -:foreach Package in=[ / system package find where !bundle ] do={ - :local PkgName [ / system package get $Package name ]; +:foreach Package in=[ /system/package/find where !bundle ] do={ + :local PkgName [ /system/package/get $Package name ]; :if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ $LogPrintExit2 error $0 ("Download for package " . $PkgName . " failed, update aborted.") true; } } -:foreach Script in=[ / system script find where source~"\n# provides: backup-script\n" ] do={ - :local ScriptName [ / system script get $Script name ]; +:foreach Script in=[ /system/script/find where source~"\n# provides: backup-script\n" ] do={ + :local ScriptName [ /system/script/get $Script name ]; :do { $LogPrintExit2 info $0 ("Running backup script " . $ScriptName . " before update.") false; - / system script run $Script; + /system/script/run $Script; } on-error={ $LogPrintExit2 warning $0 ("Running backup script " . $ScriptName . " before update failed!") false; :if ([ $ScriptFromTerminal $0 ] = true) do={ :put "Do you want to continue anyway? [y/N]"; - :if (([ / terminal inkey timeout=60 ] % 32) = 25) do={ + :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ $LogPrintExit2 info $0 ("User requested to continue anyway.") false; } else={ $LogPrintExit2 info $0 ("Canceled update...") true; @@ -75,19 +75,19 @@ $ScriptLock $0; :if ($DoDowngrade = true) do={ $LogPrintExit2 info $0 ("Rebooting for downgrade.") false; :delay 1s; - / system package downgrade; + /system/package/downgrade; } :if ([ $ScriptFromTerminal $0 ] = true) do={ :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; - :if (([ / terminal inkey timeout=60 ] % 32) = 19) do={ - / system scheduler add name="reboot-for-update" start-time=03:00:00 interval=1d \ + :if (([ /terminal/inkey timeout=60 ] % 32) = 19) do={ + /system/scheduler/add name="reboot-for-update" start-time=03:00:00 interval=1d \ on-event=(":global RandomDelay; \$RandomDelay 3600; " . \ - "/ system scheduler remove reboot-for-update; / system reboot;"); + "/system/scheduler/remove reboot-for-update; /system/reboot;"); $LogPrintExit2 info $0 ("Scheduled reboot for update between 03:00 and 04:00.") true; } } $LogPrintExit2 info $0 ("Rebooting for update.") false; :delay 1s; -/ system reboot; +/system/reboot; From b90585f69095e6250dac65a25045fb83bcbd487c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:13:53 +0200 Subject: [PATCH 1041/2612] ppp-on-up: RouterOS v7 path syntax --- ppp-on-up | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ppp-on-up b/ppp-on-up index eebe81c..0529352 100644 --- a/ppp-on-up +++ b/ppp-on-up @@ -18,16 +18,16 @@ $LogPrintExit2 error $0 ("This script is supposed to run from ppp on-up script hook.") true; } -:local IntName [ / interface get $Interface name ]; +:local IntName [ /interface/get $Interface name ]; $LogPrintExit2 info $0 ("PPP interface " . $IntName . " is up.") false; -/ ipv6 dhcp-client release [ find where interface=$IntName !disabled ]; +/ipv6/dhcp-client/release [ find where interface=$IntName !disabled ]; -:foreach Script in=[ / system script find where source~("\n# provides: ppp-on-up\n") ] do={ - :local ScriptName [ / system script get $Script name ]; +:foreach Script in=[ /system/script/find where source~("\n# provides: ppp-on-up\n") ] do={ + :local ScriptName [ /system/script/get $Script name ]; :do { $LogPrintExit2 debug $0 ("Running script: " . $ScriptName) false; - / system script run $Script; + /system/script/run $Script; } on-error={ $LogPrintExit2 warning $0 ("Running script '" . $ScriptName . "' failed!") false; } From 735df85b450be430999384e947d1c7b473e691ab Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:14:34 +0200 Subject: [PATCH 1042/2612] rotate-ntp: RouterOS v7 path syntax --- rotate-ntp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rotate-ntp b/rotate-ntp index dd3483a..2a095f8 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -17,7 +17,7 @@ :local Ntp1; :local Ntp2; -:if ([ / system ntp client get enabled ] != true) do={ +:if ([ /system/ntp/client/get enabled ] != true) do={ $LogPrintExit2 warning $0 ("NTP client is not enabled!") true; } @@ -29,4 +29,4 @@ } $LogPrintExit2 info $0 ("Updating NTP servers to " . $Ntp1 . " and " . $Ntp2) false; -/ system ntp client set servers=($Ntp1, $Ntp2); +/system/ntp/client/set servers=($Ntp1, $Ntp2); From fbc6852687ab964a4303d4fa1b29ab6321ad38b7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:15:47 +0200 Subject: [PATCH 1043/2612] sms-forward: RouterOS v7 path syntax --- sms-forward | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sms-forward b/sms-forward index 436985d..b392805 100644 --- a/sms-forward +++ b/sms-forward @@ -21,27 +21,27 @@ $ScriptLock $0; -:if ([ / tool sms get receive-enabled ] = false) do={ +:if ([ /tool/sms/get receive-enabled ] = false) do={ $LogPrintExit2 warning $0 ("Receiving of SMS is not enabled.") true; } $WaitFullyConnected; -:local Settings [ / tool sms get ]; +:local Settings [ /tool/sms/get ]; # forward SMS in a loop -:while ([ :len [ / tool sms inbox find ] ] > 0) do={ - :local Phone [ / tool sms inbox get ([ find ]->0) phone ]; +:while ([ :len [ /tool/sms/inbox/find ] ] > 0) do={ + :local Phone [ /tool/sms/inbox/get ([ find ]->0) phone ]; :local Messages ""; :local Delete [ :toarray "" ]; - :foreach Sms in=[ / tool sms inbox find where phone=$Phone ] do={ - :local SmsVal [ / tool sms inbox get $Sms ]; + :foreach Sms in=[ /tool/sms/inbox/find where phone=$Phone ] do={ + :local SmsVal [ /tool/sms/inbox/get $Sms ]; :if ($Phone = $Settings->"allowed-number" && \ ($SmsVal->"message")~("^:cmd " . $Settings->"secret" . " script ")) do={ $LogPrintExit2 debug $0 ("Removing SMS, which started a script.") false; - / tool sms inbox remove $Sms; + /tool/sms/inbox/remove $Sms; } else={ :set Messages ($Messages . "\n\nOn " . $SmsVal->"timestamp" . \ " type " . $SmsVal->"type" . ":\n" . $SmsVal->"message"); @@ -56,7 +56,7 @@ $WaitFullyConnected; message=("Received " . [ $IfThenElse ($Count = 1) "this message" ("these " . $Count . " messages") ] . \ " by " . $Identity . " from " . $Phone . ":" . $Messages) }); :foreach Sms in=$Delete do={ - / tool sms inbox remove $Sms; + /tool/sms/inbox/remove $Sms; } } } From c35eec0f22dd5c3ecba21b7fc670a384738c2728 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 16:16:30 +0200 Subject: [PATCH 1044/2612] ssh-keys-import: RouterOS v7 path syntax --- ssh-keys-import | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssh-keys-import b/ssh-keys-import index abf0350..70ddf3d 100644 --- a/ssh-keys-import +++ b/ssh-keys-import @@ -6,6 +6,6 @@ # import ssh keys from file # https://git.eworm.de/cgit/routeros-scripts/about/doc/ssh-keys-import.md -:foreach Key in=[ / file find where type="ssh key" ] do={ - / user ssh-key import user=admin public-key-file=[ / file get $Key name ]; +:foreach Key in=[ /file/find where type="ssh key" ] do={ + /user/ssh-key/import user=admin public-key-file=[ /file/get $Key name ]; } From 2cd0fb88fa79b595f05af18112786f8280058702 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:17:17 +0200 Subject: [PATCH 1045/2612] unattended-lte-firmware-upgrade: RouterOS v7 path syntax --- unattended-lte-firmware-upgrade | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index 14b03e5..d38b917 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -6,11 +6,11 @@ # schedule unattended lte firmware upgrade # https://git.eworm.de/cgit/routeros-scripts/about/doc/unattended-lte-firmware-upgrade.md -:foreach Interface in=[ / interface lte find where running ] do={ +:foreach Interface in=[ /interface/lte/find where running ] do={ :local Firmware; - :local IntName [ / interface lte get $Interface name ]; + :local IntName [ /interface/lte/get $Interface name ]; :do { - :set Firmware [ / interface lte firmware-upgrade $Interface once as-value ]; + :set Firmware [ /interface/lte/firmware-upgrade $Interface once as-value ]; } on-error={ :log debug ("Could not get latest LTE firmware version for interface " . $IntName . "."); } @@ -21,14 +21,14 @@ :global LTEFirmwareUpgrade do={ :global LTEFirmwareUpgrade; :set LTEFirmwareUpgrade; - / system scheduler remove ($1 . "-firmware-upgrade"); - / interface lte firmware-upgrade $1 upgrade=yes; + /system/scheduler/remove ($1 . "-firmware-upgrade"); + /interface/lte/firmware-upgrade $1 upgrade=yes; :log info ("LTE firmware upgrade finished, waiting for installation before reset."); :delay 150s; - / interface lte at-chat $1 input="AT+RESET"; + /interface/lte/at-chat $1 input="AT+RESET"; :log info ("Reset device, waiting to finish and reconnect."); } - / system scheduler add name=($IntName . "-firmware-upgrade") start-time=startup interval=2s \ + /system/scheduler/add name=($IntName . "-firmware-upgrade") start-time=startup interval=2s \ on-event=(":global LTEFirmwareUpgrade; \$LTEFirmwareUpgrade \"" . $IntName . "\";"); } else={ :log info ("The LTE firmware is up to date on interface " . $IntName . "."); From 67bd3a32a8a7dfd372bb804444f6cfbe2b60ad13 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:18:39 +0200 Subject: [PATCH 1046/2612] update-gre-address: RouterOS v7 path syntax --- update-gre-address | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/update-gre-address b/update-gre-address index 475b30c..d1402e3 100644 --- a/update-gre-address +++ b/update-gre-address @@ -13,19 +13,19 @@ :global LogPrintExit2; -/ interface gre set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; +/interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; -:foreach Peer in=[ / ip ipsec active-peers find ] do={ - :local PeerVal [ / ip ipsec active-peers get $Peer ]; - :local GreInt [ / interface gre find where comment=$PeerVal->"id" ]; +:foreach Peer in=[ /ip/ipsec/active-peers/find ] do={ + :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; + :local GreInt [ /interface/gre/find where comment=$PeerVal->"id" ]; :if ([ :len $GreInt ] > 0) do={ - :local GreIntVal [ / interface gre get $GreInt ]; + :local GreIntVal [ /interface/gre/get $GreInt ]; :if ([ :typeof ($PeerVal->"dynamic-address") ] = "str" && \ ($PeerVal->"dynamic-address" != $GreIntVal->"remote-address" || \ $GreIntVal->"disabled" = true)) do={ $LogPrintExit2 info $0 ("Updating remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address") false; - / interface gre set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$PeerVal->"dynamic-address" name!=$GreIntVal->"name" ]; - / interface gre set $GreInt remote-address=($PeerVal->"dynamic-address") disabled=no; + /interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$PeerVal->"dynamic-address" name!=$GreIntVal->"name" ]; + /interface/gre/set $GreInt remote-address=($PeerVal->"dynamic-address") disabled=no; } } } From a71a3d5466548d05d27d31c446c62afdf2412070 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 May 2022 15:18:51 +0200 Subject: [PATCH 1047/2612] update-tunnelbroker: RouterOS v7 path syntax --- update-tunnelbroker | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/update-tunnelbroker b/update-tunnelbroker index d454cd7..0075273 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -17,19 +17,19 @@ :global LogPrintExit2; :global ParseKeyValueStore; -:if ([ / ip cloud get ddns-enabled ] != true) do={ +:if ([ /ip/cloud/get ddns-enabled ] != true) do={ $LogPrintExit2 error $0 ("IP cloud DDNS is not enabled.") true; } # Get the current ip address from cloud -/ ip cloud force-update; -:while ([ / ip cloud get status ] != "updated") do={ +/ip/cloud/force-update; +:while ([ /ip/cloud/get status ] != "updated") do={ :delay 1s; } -:local PublicAddress [ / ip cloud get public-address ]; +:local PublicAddress [ /ip/cloud/get public-address ]; -:foreach Interface in=[ / interface 6to4 find where comment~"^tunnelbroker" !disabled ] do={ - :local InterfaceVal [ / interface 6to4 get $Interface ]; +:foreach Interface in=[ /interface/6to4/find where comment~"^tunnelbroker" !disabled ] do={ + :local InterfaceVal [ /interface/6to4/get $Interface ]; :if ($PublicAddress != $InterfaceVal->"local-address") do={ :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; @@ -38,10 +38,10 @@ $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; } $LogPrintExit2 info $0 ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress) false; - / tool fetch check-certificate=yes-without-crl \ + /tool/fetch check-certificate=yes-without-crl \ ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ user=($Comment->"user") password=($Comment->"pass") output=none as-value; - / interface 6to4 set $Interface local-address=$PublicAddress; + /interface/6to4/set $Interface local-address=$PublicAddress; } else={ $LogPrintExit2 debug $0 ("All tunnelbroker configuration is up to date for interface " . $InterfaceVal->"name" . ".") false; } From b6ddc5968e7a3393bb6e9b0c0ccf96379efc62b4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:42:44 +0200 Subject: [PATCH 1048/2612] README: RouterOS v7 path syntax --- README.d/01-download-certs.avif | Bin 2115 -> 2105 bytes README.d/02-import-certs.avif | Bin 2356 -> 2266 bytes README.d/03-check-certs.avif | Bin 5059 -> 4850 bytes README.d/04-import-scripts.avif | Bin 4599 -> 3782 bytes README.d/05-edit-global-config-overlay.avif | Bin 6600 -> 6602 bytes README.d/06-run-and-schedule-scripts.avif | Bin 2994 -> 1946 bytes README.d/07-schedule-update.avif | Bin 2312 -> 2200 bytes README.d/08-update-scripts.avif | Bin 1917 -> 1733 bytes README.d/09-install-scripts.avif | Bin 2493 -> 2423 bytes README.d/10-schedule-script.avif | Bin 2009 -> 1847 bytes README.d/11-setup-lease-script.avif | Bin 3712 -> 1686 bytes README.d/12-install-custom-script.avif | Bin 2349 -> 2242 bytes README.d/hello-world.rsc | 2 +- README.md | 47 +++++++------------- global-config.changes | 4 +- 15 files changed, 20 insertions(+), 33 deletions(-) diff --git a/README.d/01-download-certs.avif b/README.d/01-download-certs.avif index 41fa5caba52eb91d1144a9d21f2e7a1a00acc096..4da73fabdc93faddeca4f6dba83f23f877ac6edf 100644 GIT binary patch delta 1827 zcmV+;2i*9>5V;VLe*qtnfRz*{ZDe6|5&#MbI3@BpHV_cdX)=$KDFGjU%$D8P}@0~z=St$no-d3wG)1IH&Rq8dj!LKl4fpvp?_RmdSwc#PC_8D@~u zjcTPkY^NjfwHWgt_7{91x>dx@EBa6M#)gg>PkLn6cyo(95f3!&h%W=Ef#SoCx@`G1 z^%}k7r$wJI44O1=sU$aS#zEBEs_BS7ENNbm)d`%qIS=?`Db|;NAhVxF&g0p)83hO} z6~q2~J`#`gg?)&z6rH@psFf=3SKAu(H@!C*z9m*H&>CkqIpw{4%>SG=wGQK9OYu zLP(lSoIHFGw8ZutYjtK~baM4>+rt&bGACSiXJ2;CW@oP+Rk@rEoZl$IdjS({KwZmLQVfFqNZ)lG>?4bB$>SJ)sANv{oT*B zKoY5+tZBY~x-P4M)(dfkZp6yms*jMo!v{0(E@Yi{c-x7Cgd!yTi9|vyGvE*!DvyOU zAX3&cGWR{bfqp^_hn9-QRtD^bVcWntpvdqALIl=WhKI*r(8&-JNipt!By8pqb znJr9<9;>;xrNzlo@ZX|=(e~qST96WJRHX388M*N)!V!8tTR)MC?9Q^~F4ibDq$5y(_Fm7(5>}At^<_Fl} zL?0RYBiMxxS>OE%$@E}cWMuSrHAMSBrV~1GS-#-y84e4gN_=x6dF{dM)V=36htsYS z8d0bB$~p>Nk%`GvJB@fOyyr_lqfh7_Bh+$#Di$OA~cksgi(YDh-cn>tMndx~-sDZXrZ86k&1$ zU`ve$cTs6_<}G#7^~0nZQ-St7P&gYbfGMqgQT949;TpKS|& z5{J9S&=(yJiMs~up^8@e-{l^>GVjk}&X~N>(2l@gR8GG%+dN?ic;z}eKm`XBy#3R2 zQ;dMem*teV<*h9L=cHT3aQXtJUr9qQg0k?pzX6=`3J=yCi@xU7x!7v{loAmo+ zK`fPwUZEZNh%yZn9d-FKZD0YtqnCnz8ygjMuIF5Z5_aIO8AYL$q`ihR#|jgJ)y~vr z^|c5NK7Wq5Rb46Mq5q?5jw6V{!_6J1-JMfeMT+f;?Pvgp7<=MG=VVfJuPWt|Jz zyn1NDMiC9ZXX!FP{uh)*`0<`!DY^_y15wsuffQP+=WBc=SyUyOg7EwQtM@;DN65`| zG-Eit`vm5T=JU`W>Qstb@d{;zG#+G450Gu;>{rgn?1*E1;B&Lk|F?UKBanz$C;a)l ztlad&6lju<3Gm}uEEVXhe6_thS^e8=K0qg7r-cv0I(?k<#gb@p*>TdtIJRV6cjAt_ z(hg0Y#p~WU%RH)bzcqFG&ibll)YYIUB%7tY0?z5(SWcuT;vhggiwMa|CrNjhe9}t zhsCao$Lq||3lR3_$W7`=y%#Muz%#R=^UBlc?c6v#Z_A`6^j}E8LK8=RcrIf5gQu88 zS$~KU`7M}ttsgl(d27@Xa8kvYii R(#l=^4MrI>Ggx84qg1d=kFfv% delta 1838 zcmV+}2hsSs5W^6Ve*r0xfRz+6ZDe6|5&#MbI3@BpHV_cdX)>9UDFGjUz($XtcK^=X zD%xMYBTpzNb^9<@-V23NE z%K8vd>;b+$KR9~dUF27lU-^cH_G!%MjFt)%I6b661*)WV{Ftw{dwN+M#1nT_1&NlR zpr7Q#7{>7?2g9NQAabUEkUo3?NqUzZ1LciAbY@V~^Iq15NcmLv^m(b{m%XZ1|1Tx6 zzqX$ifYt*KY!_pgB{yb0B$?uNy+e*WRx`{@SRW!@F;=&!EC1MIpgvno%Dwx$ck!ln zk)wir_;Yl1BM31S-DLIh(JL?X|GFOn7Ig~9`P6>`oGH?Q&^Bvnr85UAQ*wrY+F^&Oo%^eA*n35D}ucuB;#F4oul4^op#{cH1Na_^cF-u+Yh= z=mp_tPl%j6Y2wm-+$j5$J?P`36Z zzq2tc!jL8#+f*x~$E79$b7AtFq8n2;K<#Lc3n~3(Pt?dY*vGzaM>Xa+)RP|Pn|W#? z8N6OUBBzR;FYG`Vd`Rm(uJ5@OW_GCkmT-GFnUKLw!1iT-ZG>{^*cs}onVN#rZ=wMj z89e<3+niC>;$TH@Thq_Pez8t^l3Hh*S9EC1aO$?7hl`sX_NfO-Wql`m+p|YS}j!QaH8L=C#`5 z<1t3dKGHhLJ)Uh4>pzf6!cvecF*RtO6Nr*6el*UJ=m9taO?^qrJ)Tu_I!O8)?<|A zqGsQIZs3*v4^EBe>>ay*r8bfi!7(S4bh2`PzT;b=@EW&4)BDma?63&d1$SA^CBl^S2^@>r~|8TAW1*t$)G!L1{p#&E+9ESmJ)qU{)IALFFi5C8kOO+a3M z(+n&gEFcuS+nvK*$vEmzN1(IkWYV(mDh~3;9&O8LYc7M4nGoYf6D954qCjtamtDj1 zBBfZ}H-ZYbYl(F3IT(yNldnmF2UJ7jvI&arMnIW}=oo(@$4dRf;8Q|*h#T0sJME3r zI;CCK?2fVWWsQDCkUyHG9qrME&|G7GbWYxEeHj|w;_BPn9zkFNeW6NXPD2DX2j@U< znH47bx$veRAV#7XKHsAPUrkD>zQ=!aNE zSE0Cxt~sTRtU!y}Z=A^?B!rCAM%MTNr((*kKkqSYcV!dK4=4!xcvm$3BPIcVx+Czo zwpKEKgwZ?{+w5atdV??6rOnwqI{pF0~2=TydcNIYK5Zq4;P$UF(`LAj?r6tq* z%}s+h@cIUmWnWr4P1{C~$W6#acexjDUGmF_YLzM5BXwRQtGj2K=}a5&r@@suS?`-Y zxgv&rMwmT(i?gi)ciYpU?Ijg|40Ww{wgYX<9%IUiW72cVA(kaxF(XHW8negAx(h;5 zZ*Z+s!y9COw)|?3Iq*trvUJy8oKc2PY~-q3xZa4hmET~*!=vGm;P`g6J8%%3$`+S8;;SZC;deQRa_j_OB0`7# z6kZ)%Frjl3?wyJbA_R3X3d%uj@kOigVz5?Lb5YNvI2?ZbH> c5NRsl{`k*+>z$v3EbN5|d&Q@HlX9L#L@B|8(f|Me diff --git a/README.d/02-import-certs.avif b/README.d/02-import-certs.avif index 09fe58604b4e17f73b188e222eb458514693d5da..308be5b93a610328562c5b242af9f837b1e11829 100644 GIT binary patch delta 1901 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 a)^2$m7X(QQ=^GVZWty^P`GJNZV9JLgzR|q^ diff --git a/README.d/03-check-certs.avif b/README.d/03-check-certs.avif index 52c4df8105721f466da3108f442694ecbe13c3fc..adf1161c9646f9f4575624e675abf927a9b4da13 100644 GIT binary patch delta 4573 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 H@zfYi(OT={ delta 4784 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 K0mAWzW=}v29YWgx diff --git a/README.d/04-import-scripts.avif b/README.d/04-import-scripts.avif index c86a5c8ac6161a17d181165b83e0447f1178c67a..53439e4e5f832c7cd7e8a424f1b70e471ac8e31a 100644 GIT binary patch delta 3526 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 HncDe)5%vam delta 6131 zcmVI)5*2rzj*h6gK$o&k!%T19{&dV M;~lzn zd7j{JU>WQTwM?{z2UAQ8W@CnBW^SaumjL_<3=YY24?2j?f2xt1E1qZ;S_}fQV0Q1! zR8@d4g5oj^W}U~)Hb&9ZlXnY&Yyd6j561^gQXAsTHb7JYDDNB-vvHWdcEx=1H)}K*cG{B%?g9 zl_<#>4n4);z!_v(E5F@g7F04I9`srMc}MQ*2j{AU>?D-jmb9f|58O=c;t79_WlQv= zIoC!r;MZ%i6|3vpHNPC64H zw<)$KM!kW)_JFpD?a(?u?dFiBcOhCAFW|$j%T=2I_hSZ99eUl_U0&eq_p@$s%!WbyAM zcnVhRYtof-;A2YO91&v0*GGJbhT!ka_+Fsdt4q;^W?{Ξp>_32-=D>*TStIzLtS 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 delta 2757 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 LHeiK@{J7{S@=jI8 diff --git a/README.d/07-schedule-update.avif b/README.d/07-schedule-update.avif index cb43b48e0598a62d7974ea8ab3ada4ac6b3c36d9..7c96f3aa6f71be5f821c1eb1b78ef947e447a330 100644 GIT binary patch delta 1899 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 delta 1515 zcmV!4$Bk$*a^`{7_TiAlDgpYYj$|K0c7opYn3 zv+*X&pluNxC?&90QC_pRC$JOO_fgERsQwvOhqgR_Mrj<3^KHHibnDdMO&f-I56{=z0mD{+&E|y3B-7^^f#>gk zOPJm>2c11-4hMh6;uGaoxmDbf=Fifkw1S*bcFk(s5j>&>z;=-x(s|c4<;;;5~dwAf?gaq$~^h7>YEE} z{={9B{RIYhcTM07(_1BZ=*~{1a0ZLahC9R&D51E(*@^a8J`Kui26n&7Ea#R_PdQ68 zy0c5xKtkc*%$(E1@xE&kyd0eZ_8PNo9p^t*MN_kW^Ks+XhK+wsRE&#^IZ4$Nno^Z&U0iE*DqT`p<6vk!kRU!;XLA=#__(~i81c&VeTwapgs2#)FY@?Fr4|4sbuUN*(@t}-pn z%^OvXW6_xtJ#pdd|DT%sAFCesF2< zc`=r=RI^y2+)PePv4J(PpD)5*EFvokVvp3!ke@40;jy^f+%D4s~G&*lMU3k9(y5LoTi z`5)r!=Fxv>AWz03B^{x8@68&39VPF3(^}=_K1wcoYT|onyIhEuL1WpKL!!N0INqNs z8$;RXG$5d$-d$Qg)|Ri0g- z0X@{|BcwJr@am&GZv(|2DAf0r>Y}xuzVawSfH? zS|5L~sTZEY{i;^`!XJW_w(B(U>2QA%T|w5hC@jb1eL3#(A>Owjz>%5^Zd(`336z-r zqq6doOv4!V^o$7BUWj?_Izzi~Tkt*HN1GhAX`aQ<89ls>is2z<@V`6VI^t;chQ zkCvWqp#O8l3M8W!&T*0eYA}p|a*$Zn)#-oad|q=4%WbUg)tqt0*;`P<;@&#N_czTL zEmO&>q?07jw_kHLvbFD_RFMY<*b)GE*~t|(AskI?UYly7K&|w)gND8JZAK%>giS5& zFR*e)2G<2d-UBgJ_p?{&v<2eWZkw! diff --git a/README.d/09-install-scripts.avif b/README.d/09-install-scripts.avif index 467b9e4b50387a6e74c2ab74a6c81b2a48d4869e..00225b16e2ffeaea8b0513a34e8ee6765c79c188 100644 GIT binary patch delta 2027 zcmVJ2q2U1;9T(IfIT`xR<>1@WZ0;0p5-ld4x1M8-EOW6;thc9_+HcC1qEC5P|C zk}n4f^g8f7rPt9zn%S0nv{oiUOT8+>oA&=vWYeA;){f&p;QNolio<|+krIVd?7V4p zk8f_0CQ74g`dz_Wr)%Eh@oX1Q1Fo0=9{C<>=p)!D50xqtMowlow9RH|OzvkfiQJtt z80)8nz~@UgSnbkXJ`?N|1GFe6N#Py+A^av`5#v6(tzQRx-c6^nf6)%0_d=aG+F<>I z8vg&q){fn#nSu18L3-A$YAst#unO0uil?jAu^zF!G>3k{!e57g8gx}?Ttb9*HizdC zm+(-<54JaWHE%Ie;5dgorNg$DUjaCay=WVrTa*fkP}0^>_@>?|SBH(sG9t=6*ir+4 zJ*Ifw!kiq?f1_)Q`r*7?5S-3p% zHxyELWJ5_DkjbbUmdTN1zu+6@(Qx|7+G9AomMuJNm^%Ocml-lX2GI-Un*5Q;6N+c4 z$WBpPINmqMe_Dpi3D^@VMsTcOn5&tv`xI^R8}8Rg1l3m8SN4R+Jrbfq4oE1iG@`*J zq}8tV;A@Kb))A!t7TOKJec{eqM=ay4Qko;06G7^0_JFZ2xq~qiA|I%|%0ds82=>)M zWg~QWNGL(2jE+*~qS>=s!G9$I-~`Nc2-1rJ&KX`ee{bGtZ8&2=HFVR(l(3gQz71^m zb=(rBAG>X6i0Zn5<;huCRL!H^s)LTIz23m0zu!ZY31Gq619s->QAMaYO%0_}6Z&X6 zh8npd=f9FXZsN55)p|?T#tJN8sXjE;PSu3R~yOZ0HdZ}BNDje89CC})b9e(h@7O# za*+WKriQVZW;E@=dpSAdTdHZH0BLY;miN0(e;$cvMd-4m>E4G-H#Z5NX7Tcj#JEEQ zAA)Td0FFET_>6HH6b5+m0W;FMR~77jNtou1Np%DKqik5rbpf{O~dJ!+en^$;Dz%u-hZUjyW9C ze;3IZGtauyv1F9bXi(l(@#Zoi48C?@?37_z^LS(TG1uF(A^gc>ven{buLXTBJqX{2rNUI?}5jsjBqV?~H?z?<% zp6&nk3Ci7(Db}BcykHQpuSyC)^>j_Ak9mi8H0u_M^s;k9?&A*5$^6~@YR zWx!WXDaqX4mHbuVo|N7S+1!|vwa`3EN6t(gfm=Vo+JKZ9MPR<)14Cu#?+usP$f9=fpXh>x* zgHMB^jm$i6aLq=JW=5?mw@bzSWHE+jg}geMEDcqH%c+T2bt}a=*Ykn;!pLgvr?_`Q zQR&h;ZQzo}xj7sUAqa8{?k0J%(IHB|dBEj`thESR+0514LL|xy-;;#5ik}?fFxVfH zcs!oD7tc~%=bo0sU@llof9f$@1y8i~jChpC6TT48CD-ZMbcN1lRob?y-GO2fIwQIx zBh&)LBgiKx?ge~XC4vtf8R=PMz$w?1m0>IQanbR?6WNmo)`*_q zB!)h3?$8^_ha$(BHua&d=)MMKnEwaQ5>M%s^%Q z^Je+{&u$EL()!IgPekt{Hp)} delta 2098 zcmV-22+jBR61@|Ue*vSBfRz=iZDe6|5&#MbI3=qz!zQcfQ(C`%q~|1q~~Q%Fx@U6tQ)jh{DQy&DXO#uY1FlpR_G zRfck#kfuVNmP;-I-~gl;#;@hi+7Tm8mX+y69;fMUL@`6IR*p~np$g|=W+g%t>D;CB(_VB?|uLPn(8dbOumq6J+H^jPdo~(?g{16(^XMZ!S zC$Shzr!S5T8_;$xPS~>_^RkH6YE$wTA@F8cO-1 z@q7`hLl1D*yjE(iD>AXssOQLVnx$%n+cDzI5F@{hFP=hofW~^;TZ8YpKI)a}6Kh)0yEK5Kw##*Ohqbv&LH^9P9JbQIV+hPNv)MoK%VI^*Ugk0_ zz6{K;CDwEO)UC=V?EEN=}VGUmV0HC#By9rhcFkvOR- z*8y+iY{H4x`1h_25_Y(ge}~Z)KgJUtqsNYAs3J}}QjspH<$wtckulzCs$$Y%!}u~Q zK}8OKq$@>i{2D+yeb}feUUUXSB5Hr+<#|lZOVa7aP<~4rX^d z`+gB=QlRrux{P8#d!(S#x`wp+dxFoa@*{Gm0PgTb@+}zQO}NHeJ~Pz-4l7Z=82q@JS<`5w{kBBz`dPOKbray6lqcL>3 ze^Y;3zk!2ujPrI-c@#a-;~M2W;gCXJ`0-&ESm;k=?~6YM(2)|ojY+(s$M3E%?;854|^ja6Iedz*$ZTN zl~q8ImbF^8=~^8-pG)m+sTDTsvl-C7$M0XJWq(N_K3$-Ibiy9o`Wl~DwJOFEdMCjP zn>}5CFqpXJ`y>obl~tJ&lW2X*UQ#z`--t3T_k#1D+i#h-Q-;I~f&qnJBacXof0^?( z62bI*Q)qAx3_K1ia3p4?*P4QKt5F)o)NioBu5?YUf6!+GqpA63(xvh*XivMKyLSxhM4MNn>u`wxPSl5bPde0bpi7RLg1 z^(h!A@_}jAv#9q1#ct(C`1{U!5&_TISS{Gj`8$IxI|-xKD_IL(ySH>qz%J z><$1>;Qd{z1 z9^M2pyPH*O;EmZ|pDHYtpawtWtEy*7>-)%!4#LZfPXOSb4q%3UR04KX;i|{oYJy){kWOL|LB1(yjLaU_we;RGy%VAj-z3+#4 zkJ>vI>Y{6<GPEeOu=(3?od*OWAL!xqtoGU{C@T)Bpeg diff --git a/README.d/10-schedule-script.avif b/README.d/10-schedule-script.avif index 945a7df0e12bc2a6bb78f6148c5d974534510b57..27541b75d69575591c432fe49b06da2b47a5ebf3 100644 GIT binary patch delta 1550 zcmV+p2J!jX54R4Ge*qnlfRz;`ZDe6|5&#MbI3;pC*g!);q%w^RlPUo)e_#R=S`z=epHhw(~evt!%^uMj)r&7@jU}Nf= z#0KA>&%;8N3F!K`X-Z5k6Gzt&NZT9tgYK~t<>{Y_~sCos?3;mbIV5NQL0ej6^R83P_z+PQC9AR+L ziUF>#uY1%Hl|JmbCq(|XVgE419KkP%*b_H38~sfsrngj$HQI<-f1svrQY|bFW}Y%v zj3pR^A!`H33XiR-{WT}C!Me7D>@ZS-+Zv10!Ml{3n}v7;FAViLH}2R+M6RuR^v?xzVOltI25 zrVUk6|BFf+avZI#e^HbP6&(ZXsMq9c=*Q0qjb46+8182m3lJRN9QOUAV!q+Oe~>?* zRF?y1vJT$?g;~yz`gH0K3l%xErPzZJ#9bVeT)VjZyQ5%c`bJ@|iUT#cYK%wEOhg1A zkZp!NEO>ArP)Bv#p2Xd&&WwhT4gEZ@P`?s~OU|=n(f8^oe~KYE??AkdMvb>Gg0^BE z$wU10uc%v9Foh!Z&^1Ec62->F^b^V$;#q7dwIipqEJrPy`EhOa#kRL4Pi1;%XG}|$ zcnpfw!CvgqjX?#{I&jvy{Bl?!6bUN8Oca5_py$!07f$Sti=;%o77*Y^VxxIBDe;;s z;8Z(?h4Aube@vIufJk|12;ISn-xX9{nd~ExfJ}+ZPjtV(l|DEqzz&FkL&<)#EmJI& z*(zHx!HBdkR)iG@nAdV%)#fWsijt{=77&tUfkt&NuUqSn^MxBi0RAZJEqDs>voUf; zGfrK-leBm)L|hHq5r|}=`|uGop773mGiq7$dnV24f4@M)<4!&2W?C88mj_+#hETp( z!~FkL;P^BzN{Cpb_wyMePw zWZua(68y^P^3+Z2SoN2?z50l8SZnpaO*SXF@!uR13(T?(QqM2;rzz)1Br#3(F7eVl zCLxc@fBt~QE1Aq`qU`Gk{`U$SllXU(L*PZ;M$~;F`t8Jw_-*2B=!Iilla^G`HM7l}+(GOMIsO`ciuLU3EXV zq$e0I?Bg8d^!;pa8Z)LYQ&Pv*(aK6C$~Spcf1}c#HC(kFO1f^gGr%M|;ojqvI$iYn zfRc6-CWcxK?XWJWXs_v@uW(?93gM{FA#_u-R!$g$F}cL#Dr#!|)`Fs?PSAumQl`W( z>;tt(N_`V09 zf3-e&ShYWJc`Q{1_BZ-^04E`h>KFS76PB8&vt!-Dzy>1c$Uf4>|Fr7bfp1)T=rwAe z-d*#{j7e;JMs|_z2^H3>EDRvmQE)|k7Iuzz3rn-O>f|y;pz$@yrhl>d2iPC?1{!}Y zCDo#&kNvMw1YzcprtNX%I^1IRNg;+|e{tXg3`)f`pkwYJVh`f9;%6xgZs)ppI^r;X zc`&zrtLKE9J0&8~f;^)I1Rl!VsBi37gbUIc+21A}a7+zyDjFW+wR%dh)X@jV2uBMh z9Iqf|L=t%DS32?qjl7A)Q)7@2SF!My!wg AwEzGB delta 1714 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 D*@VR6 delta 2076 zcmV+%2;=v{5v>xCegX&+k${vI2per=VRRAz3JEwRvN~)aA)wMSgAkJ{0Um$MmfhFn z)eP|dEkt}WwIy=wZ6qtegg0)QQPA+U6Ml6!QdBB?1l07)KnfIV+w-N|La;3xg3+`a zS+pO@S~Z(o@3hi#f^vk~bQT5Z+k}*HSC}ZmMz#$NOy5>>56AE+OBAg#{aT!niQ$s2 zMmk8+-^m#PIb&Jqidy2`Jg9#S_hu+2h%7^D>ESYNvHSAY9j>L9Ks->=`#0iC2n*w{ z8|j#@;oZKaFwjN%8OI!1w!m5DnC8>FC_Q0eDp*e`K{0UgoAA#a8^LCa>)9)b9bYSW|w46_g{xdQqg7n~gR!Zug- zr6a~GkKdk1{c%Beqq=`Sl`=&tqJYI|RSrU98ir_N2p_2BgX(irbY*XRDA$cSY-$Q% zqBrhlJ9`T8>z_hM=Hgl%HTZvklPwr9MT8&ztCWCafKOwQ7Y=LoI;|7|*wVjkv|Xq{ z&v$k5G-on&X~HW_DDDl;IfNQ^IuB6O^3?rx{x<8%CP2)}onwDoL=|?^9etn=#j{0b z!|&QnmxG|x&*jW>dD&vQlyK;F{PH&{@xwt8`%SBi1XL}dvqz6gUKs=iTLv&w)Fa|1 zmsG~j5|LOJoqTRoX3}NDRVdXz5AuAGx`;eJq4)*H^3(@IX~Mbo--e$jcYiD;R1cV^ zjupW4IMEaF&}x4!SX_JnBmZeHQ9;5Xu4O`A@yp~o65k?Xm(_~6cc)s%&6DY?*4`89 z;L)K>KF~OX;I?|Xe}3gjxTIP(bZtr?fivn6q&wEIZ1n~sf-HKxVj}l%2q6`Qmsl8g z$U!P`_;}1X{b##NR@$iklY)h}i+&8_S9LRBH?vahE?s}I%n4!wU8dw+DTIIdMYAg; zV~v?Ze0&mPpCer2j%Z-glMMyczcL@UBAL}(`ig7pp_I0E-(hHV@`kSS59eY)H-#1) z6dwr|n1k6Zw@f|)SkmG75^2!$0jF}*C1wreg4TO9bY?*}2fIb_EQEAJKL;}kZV215 zjXN2ou>^mBxz2bLoJjooZQ{amE2kfr@bfOWr064|2ed8MmlnhAGM%_|I-bX>SuI3p zU4i7yjQyLv^e3M*sUMOjTN<%^HeOfpQFOGgRJ}y-!>H(MqgHiD#(kQ5GVQineh}|s z4V8i!hKKa2^X=5^&5?YD8DB zDt&8u*Wc_RMdbGo-WL`M_}Gr5>iy3eny*G?e*Mp`8HH}7aq*)CaYya8__u~2jP_i1 z{}X?GJri7*6ddHx$9QGIO`3|-!cs6V)(eTWD`0X(JBf~nm2F2 z;>_wR?b#jZZJ$&Peo=*?SaYi@MC)5)TLyn>){;55tJV7aJSj{5ljP=#F=q}-kpsaf zcE!NSh8g2#$l74+5xndU#7rg%1g_@dSg(2VCKR*M-(rschDP$Py~Ebt7_l6Amf+om~$x>9!oNa94KFK=h)h z7ma>$7z`sx+NA5*`cx2B#gxGY@;ObIj(0XbtD51^wU+iOmBS^O&)eHp)J}iz6#790 zi|&j=f#PQN-6I#h5JN@hsraRPV63q(8>jdJ_`mNG`OU?6BW-7mVyyboXN8YO4qN@nqgW{?Qp!6Pz2mdlQ*^{=y&m_KLc-d%nN*Cf*4yi%9*@wOFQhADMj zR)|3>T_2vUBU2+Thc@8&?wswcvjGh#V3|Z3YgM7DcH{{UKaSuAY<+a#A3kst(-rV( zIyN5ZM0fnTLJnr6y`%e64gUU=)a_cxZCHk8q{M3HZ| zvmg>uZ@%T>Pt9TYo{VY6%g?OyybjL;V!Wz87=YTp#fq-sSc* GtwP*Id<^XX diff --git a/README.d/hello-world.rsc b/README.d/hello-world.rsc index 17ec575..6404781 100644 --- a/README.d/hello-world.rsc +++ b/README.d/hello-world.rsc @@ -1,3 +1,3 @@ #!rsc by RouterOS -:put ("Hello World from " . [ / system identity get name ] . "!"); +:put ("Hello World from " . [ /system/identity/get name ] . "!"); diff --git a/README.md b/README.md index 23d1254..df3cb9e 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,9 @@ Make sure to install latest updates before you begin. Specific scripts may require even newer RouterOS version. +> â„šī¸ **Info**: The `main` branch is now RouterOS v7 only. If you are still +> running RouterOS v6 switch to `routeros-v6` branch! + Initial setup ------------- @@ -50,7 +53,7 @@ download the certificates. If you intend to download the scripts from a different location (for example from github.com) install the corresponding certificate chain. - / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem"; + /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem"; ![screenshot: download certs](README.d/01-download-certs.avif) @@ -63,16 +66,16 @@ files to your MikroTik device. Then we import the certificates. - / certificate import file-name=letsencrypt-R3.pem passphrase=""; + /certificate/import file-name=letsencrypt-R3.pem passphrase=""; ![screenshot: import certs](README.d/02-import-certs.avif) For basic verification we rename the certificates and print their count. Make sure the certificate count is **two**. - / certificate set name="R3" [ find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" ]; - / certificate set name="ISRG-Root-X1" [ find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ]; - / certificate print count-only where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6"; + /certificate/set name="R3" [ find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" ]; + /certificate/set name="ISRG-Root-X1" [ find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ]; + /certificate/print count-only where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6"; ![screenshot: check certs](README.d/03-check-certs.avif) @@ -82,14 +85,9 @@ All following commands will verify the server certificate. For validity the certificate's lifetime is checked with local time, so make sure the device's date and time is set correctly! -One extra step is required if you run RouterOS v6: - - :global ScriptUpdatesUrlSuffix "\?h=routeros-v6"; - Now let's download the main scripts and add them in configuration on the fly. - :global ScriptUpdatesUrlSuffix; - :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . $ScriptUpdatesUrlSuffix) output=user as-value]->"data"); }; + :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ /system/script/add name=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); }; ![screenshot: import scripts](README.d/04-import-scripts.avif) @@ -98,35 +96,24 @@ The configuration needs to be tweaked for your needs. Edit [`global-config`](global-config) (the one without `-overlay`). Save changes and exit with `Ctrl-o`. - / system script edit global-config-overlay source; + /system/script edit global-config-overlay source; ![screenshot: edit global-config-overlay](README.d/05-edit-global-config-overlay.avif) And finally load configuration and functions and add the scheduler. - / system script { run global-config; run global-functions; }; - / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-functions; }"; + /system/script { run global-config; run global-functions; }; + /system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }"; ![screenshot: run and schedule scripts](README.d/06-run-and-schedule-scripts.avif) The last step is optional: Add this scheduler **only** if you want the scripts to be updated automatically! - / system scheduler add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; + /system/scheduler/add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; ![screenshot: schedule update](README.d/07-schedule-update.avif) -### Changes for RouterOS v6 - -RouterOS v7 is the way to go, let's consider RouterOS v6 deprecated. -If you want to stay with RouterOS v6 for some time add these lines -to your `global-config-overlay`, if missing: - - # Use branch routeros-v6 with RouterOS v6: - :global ScriptUpdatesUrlSuffix "\?h=routeros-v6"; - -Then reload the configuration. - Updating scripts ---------------- @@ -155,7 +142,7 @@ Most scripts are designed to run regularly from added `check-routeros-update`, so let's run it every hour to make sure not to miss an update. - / system scheduler add name="check-routeros-update" interval=1h on-event="/ system script run check-routeros-update;"; + /system/scheduler/add name="check-routeros-update" interval=1h on-event="/system/script/run check-routeros-update;"; ![screenshot: schedule script](README.d/10-schedule-script.avif) @@ -164,8 +151,8 @@ in DNS use `dhcp-to-dns` with the events from dhcp server. For a regular cleanup add a scheduler entry. $ScriptInstallUpdate dhcp-to-dns,lease-script; - / ip dhcp-server set lease-script=lease-script [ find ]; - / system scheduler add name="dhcp-to-dns" interval=5m on-event="/ system script run dhcp-to-dns;"; + /ip/dhcp-server/set lease-script=lease-script [ find ]; + /system/scheduler/add name="dhcp-to-dns" interval=5m on-event="/system/script/run dhcp-to-dns;"; ![screenshot: setup lease script](README.d/11-setup-lease-script.avif) @@ -240,7 +227,7 @@ still use my scripts to manage and deploy yours, by specifying `base-url` This will fetch and install a script `hello-world.rsc` from the given url: - $ScriptInstallUpdate hello-world.rsc "base-url=https://git.eworm.de/cgit/routeros-scripts/plain/README.d/" + $ScriptInstallUpdate hello-world.rsc "base-url=https://git.eworm.de/cgit/routeros-scripts/plain/README.d/"; ![screenshot: install custom script](README.d/12-install-custom-script.avif) diff --git a/global-config.changes b/global-config.changes index 0ee4eba..4bb87a9 100644 --- a/global-config.changes +++ b/global-config.changes @@ -77,13 +77,13 @@ 68="Reintroduced 'global-wait' for functions in scheduler."; 69="Support hard lower limit for voltage in 'check-health'."; 70="MikroTik started pushing RouterOS v7. Changes are no longer required."; - 71="MikroTik is pushing RouterOS v7 even more, in parallel branches. If you want to keep RouterOS v6 for some time see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v6"; + 71="MikroTik is pushing RouterOS v7 even more, in parallel branches. If you want to keep RouterOS v6 for some time see https://git.eworm.de/cgit/routeros-scripts/about/#requirements"; 72="Introduced new script 'netwatch-dns' to manage DNS and DoH servers from netwatch."; 73="Renamed backup scripts ('cloud-backup' -> 'backup-cloud', 'email-backup' -> 'backup-email', 'upload-backup' -> 'backup-upload')."; 74="Extended 'hotspot-to-wpa', it can now read additional configuration from templates and hotspot users."; 75=("Finally merged the RouterOS v7 code into the main branch. " . [ $IfThenElse ([ $RequiredRouterOS "global-config.changes" "7.0" false ] = true) \ ("You may now drop '\$ScriptUpdatesUrlSuffix' from 'global-config-overlay'.") \ - ("Still running RouterOS v6, so last reminder to see https://git.eworm.de/cgit/routeros-scripts/about/#changes-for-routeros-v6") ]); + ("Still running RouterOS v6, so last reminder to see https://git.eworm.de/cgit/routeros-scripts/about/#requirements") ]); 76="Added an option to suppress notifications on host down with 'netwatch-notify'."; 77="Introduced new script 'firmware-upgrade-reboot'. Handle with care!"; 78="New documentation is online for notifications via Telegram & Matrix, variable inspection, ip address calculation and running scripts once."; From 44c7d56858da3a10ec9f990a499ec3339394da20 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:43:14 +0200 Subject: [PATCH 1049/2612] INITIAL-COMMANDS: RouterOS v7 path syntax --- INITIAL-COMMANDS.md | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 66db40c..e8be3e1 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -7,35 +7,30 @@ Initial commands > not aware of the procedure please follow > [the long way in detail](README.md#the-long-way-in-detail). -One extra step is required if you run RouterOS v6: - - :global ScriptUpdatesUrlSuffix "\?h=routeros-v6"; - -Then run the complete base installation: +Run the complete base installation: { - :global ScriptUpdatesUrlSuffix; - / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem" as-value; + /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem" as-value; :delay 1s; - / certificate import file-name=letsencrypt-R3.pem passphrase=""; - :if ([ :len [ / certificate find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ] ] != 2) do={ + /certificate/import file-name=letsencrypt-R3.pem passphrase=""; + :if ([ :len [ /certificate/find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ] ] != 2) do={ :error "Something is wrong with your certificates!"; }; - / file remove "letsencrypt-R3.pem"; + /file/remove "letsencrypt-R3.pem"; :delay 1s; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ - / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . $ScriptUpdatesUrlSuffix) output=user as-value]->"data"); + /system/script/add name=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); }; - / system script { run global-config; run global-functions; }; - / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-functions; }"; + /system/script { run global-config; run global-functions; }; + /system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }"; :global CertificateNameByCN; $CertificateNameByCN "R3"; $CertificateNameByCN "ISRG Root X1"; - } + }; Optional to update the scripts automatically: - / system scheduler add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; + /system/scheduler/add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; --- [◀ Go back to main README](README.md) From 6c2a7faedd0de6e01b0a4b9df078978722506b98 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:49:19 +0200 Subject: [PATCH 1050/2612] doc/accesslist-duplicates: RouterOS v7 path syntax --- doc/accesslist-duplicates.d/01-example.avif | Bin 5172 -> 5208 bytes doc/accesslist-duplicates.md | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/accesslist-duplicates.d/01-example.avif b/doc/accesslist-duplicates.d/01-example.avif index 9b26451f371110d1539602b9a7d5fe636be664bd..11b3fc5f21ace72fe8f36ff62b9439e90cd39a90 100644 GIT binary patch delta 4986 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 E$@uTM!2kdN delta 4950 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 Date: Wed, 11 May 2022 09:50:23 +0200 Subject: [PATCH 1051/2612] doc/backup-cloud: RouterOS v7 path syntax --- doc/backup-cloud.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index 6a15688..b0dc3ef 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -45,11 +45,11 @@ Usage and invocation Just run the script: - / system script run backup-cloud; + /system/script/run backup-cloud; Creating a scheduler may be an option: - / system scheduler add interval=1w name=backup-cloud on-event="/ system script run backup-cloud;" start-time=09:20:00; + /system/scheduler/add interval=1w name=backup-cloud on-event="/system/script/run backup-cloud;" start-time=09:20:00; See also -------- From 81b0ed6675e153c70f5acbcc02f6412cadcc0e7b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:51:23 +0200 Subject: [PATCH 1052/2612] doc/backup-email: RouterOS v7 path syntax --- doc/backup-email.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/backup-email.md b/doc/backup-email.md index 701f10a..e04a988 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -9,8 +9,8 @@ Send backup via e-mail Description ----------- -This script sends binary backup (`/ system backup save`) and complete -configuration export (`/ export terse show-sensitive`) via e-mail. +This script sends binary backup (`/system/backup/save`) and complete +configuration export (`/export terse show-sensitive`) via e-mail. Requirements and installation ----------------------------- @@ -36,11 +36,11 @@ Usage and invocation Just run the script: - / system script run backup-email; + /system/script/run backup-email; Creating a scheduler may be an option: - / system scheduler add interval=1w name=backup-email on-event="/ system script run backup-email;" start-time=09:15:00; + /system/scheduler/add interval=1w name=backup-email on-event="/system/script/run backup-email;" start-time=09:15:00; See also -------- From d4df7467b3c38cb9a9f8cc6b9d06ea5f54f986dd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:52:07 +0200 Subject: [PATCH 1053/2612] doc/backup-partition: RouterOS v7 path syntax --- doc/backup-partition.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/backup-partition.md b/doc/backup-partition.md index c31c780..b502330 100644 --- a/doc/backup-partition.md +++ b/doc/backup-partition.md @@ -27,11 +27,11 @@ Usage and invocation Just run the script: - / system script run backup-partition; + /system/script/run backup-partition; Creating a scheduler may be an option: - / system scheduler add interval=1w name=backup-partition on-event="/ system script run backup-partition;" start-time=09:30:00; + /system/scheduler/add interval=1w name=backup-partition on-event="/system/script/run backup-partition;" start-time=09:30:00; See also -------- From fedf74300d53896dfa6614a73d4200b3c9584597 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:54:12 +0200 Subject: [PATCH 1054/2612] doc/backup-upload: RouterOS v7 path syntax --- doc/backup-upload.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/backup-upload.md b/doc/backup-upload.md index a3620c4..58c1e56 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -9,8 +9,8 @@ Upload backup to server Description ----------- -This script uploads binary backup (`/ system backup save`) and complete -configuration export (`/ export terse show-sensitive`) to external server. +This script uploads binary backup (`/system/backup/save`) and complete +configuration export (`/export terse show-sensitive`) to external server. > âš ī¸ **Warning**: The used command can hit errors that a script can not handle. > This may result in script termination (where no notification is sent) or @@ -60,11 +60,11 @@ Usage and invocation Just run the script: - / system script run backup-upload; + /system/script/run backup-upload; Creating a scheduler may be an option: - / system scheduler add interval=1w name=backup-upload on-event="/ system script run backup-upload;" start-time=09:25:00; + /system/scheduler/add interval=1w name=backup-upload on-event="/system/script/run backup-upload;" start-time=09:25:00; See also -------- From fe88af2d5f265631932058e6ea32cff3f96b511e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:54:24 +0200 Subject: [PATCH 1055/2612] doc/capsman-download-packages: RouterOS v7 path syntax --- doc/capsman-download-packages.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index bac8a3c..0fdd6cb 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -24,7 +24,7 @@ Just install the script on CAPsMAN device: Optionally add a scheduler to run after startup: - / system scheduler add name=capsman-download-packages on-event="/ system script run capsman-download-packages;" start-time=startup; + /system/scheduler/add name=capsman-download-packages on-event="/system/script/run capsman-download-packages;" start-time=startup; Packages available in local storage in older version are downloaded unconditionally. The script tries to download missing packages by guessing @@ -35,7 +35,7 @@ Usage and invocation Run the script manually: - / system script run capsman-download-packages; + /system/script/run capsman-download-packages; ... or from scheduler. From b3ec0f7fb9926ebf8e3ad1e9ef1ee9f1b62ade14 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:54:35 +0200 Subject: [PATCH 1056/2612] doc/capsman-rolling-upgrade: RouterOS v7 path syntax --- doc/capsman-rolling-upgrade.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index 34e3c91..94a2a79 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -33,7 +33,7 @@ that script when required. Alternatively run it manually: - / system script run capsman-rolling-upgrade; + /system/script/run capsman-rolling-upgrade; See also -------- From c4831366892224d69aa16fbef43e5a0de421923e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:55:14 +0200 Subject: [PATCH 1057/2612] doc/certificate-renew-issued: RouterOS v7 path syntax --- doc/certificate-renew-issued.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/certificate-renew-issued.md b/doc/certificate-renew-issued.md index d7c4676..d8201a7 100644 --- a/doc/certificate-renew-issued.md +++ b/doc/certificate-renew-issued.md @@ -33,7 +33,7 @@ Usage and invocation Run the script to renew certificates issued from a local CA. - / system script run certificate-renew-issued; + /system/script/run certificate-renew-issued; Only scripts with a remaining lifetime of three weeks or less are renewed. The old certificate is revoked automatically. If a passphrase for a specific From c52f69b98d9ae280e172ea575c3224f0657d041b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:56:21 +0200 Subject: [PATCH 1058/2612] doc/check-certificates: RouterOS v7 path syntax --- doc/check-certificates.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/check-certificates.md b/doc/check-certificates.md index a553e6a..f8a4eae 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -44,15 +44,15 @@ Usage and invocation Just run the script: - / system script run check-certificates; + /system/script/run check-certificates; ... or create a scheduler for periodic execution: - / system scheduler add interval=1d name=check-certificates on-event="/ system script run check-certificates;" start-time=startup; + /system/scheduler/add interval=1d name=check-certificates on-event="/system/script/run check-certificates;" start-time=startup; Alternatively running on startup may be desired: - / system scheduler add name=check-certificates-startup on-event="/ system script run check-certificates;" start-time=startup; + /system/scheduler/add name=check-certificates-startup on-event="/system/script/run check-certificates;" start-time=startup; See also -------- From 6086064129692011a1e7c9a196f84cf5a63ef576 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:57:09 +0200 Subject: [PATCH 1059/2612] doc/check-health: RouterOS v7 path syntax --- doc/check-health.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/check-health.md b/doc/check-health.md index f6900ce..52efa4c 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -21,7 +21,7 @@ Note that bad initial state will not trigger an event. Only sensors available in hardware can be checked. See what your hardware supports: - / system health print; + /system/health/print; ### Sample notifications @@ -45,7 +45,7 @@ Requirements and installation Just install the script and create a scheduler: $ScriptInstallUpdate check-health; - / system scheduler add interval=1m name=check-health on-event="/ system script run check-health;" start-time=startup; + /system/scheduler/add interval=1m name=check-health on-event="/system/script/run check-health;" start-time=startup; Configuration ------------- From 578ef72c8910057426c838f15d2120f21c2e90d7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:57:50 +0200 Subject: [PATCH 1060/2612] doc/check-lte-firmware-upgrade: RouterOS v7 path syntax --- doc/check-lte-firmware-upgrade.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index 704a86b..6550734 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -30,7 +30,7 @@ Just install the script: ... and create a scheduler: - / system scheduler add interval=1d name=check-lte-firmware-upgrade on-event="/ system script run check-lte-firmware-upgrade;" start-time=startup; + /system/scheduler/add interval=1d name=check-lte-firmware-upgrade on-event="/system/script/run check-lte-firmware-upgrade;" start-time=startup; Configuration ------------- From 15035cd70d35e4c0b503d86c5e70e0e9058108bb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:58:53 +0200 Subject: [PATCH 1061/2612] doc/check-routeros-update: RouterOS v7 path syntax --- doc/check-routeros-update.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 0710b76..f43cec9 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -41,7 +41,7 @@ Just install the script: And add a scheduler for automatic update notification: - / system scheduler add interval=1d name=check-routeros-update on-event="/ system script run check-routeros-update;" start-time=startup; + /system/scheduler/add interval=1d name=check-routeros-update on-event="/system/script/run check-routeros-update;" start-time=startup; Configuration ------------- @@ -65,7 +65,7 @@ Usage and invocation Be notified when run from scheduler or run it manually: - / system script run check-routeros-update; + /system/script/run check-routeros-update; If an update is found you can install it right away. From 847892c09f17815d326b75a5ccb99965a0ade5cb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:59:32 +0200 Subject: [PATCH 1062/2612] doc/collect-wireless-mac: RouterOS v7 path syntax --- doc/collect-wireless-mac.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 5425f76..afdf73a 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -22,8 +22,8 @@ and modify it to your needs. Requirements and installation ----------------------------- -Depending on whether you use CAPsMAN (`/ caps-man`) or local wireless -interface (`/ interface wireless`) you need to install a different script. +Depending on whether you use CAPsMAN (`/caps-man`) or local wireless +interface (`/interface/wireless`) you need to install a different script. For CAPsMAN: From 2f52057e84f2488bb08c873d6a50be5917a8db79 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:00:56 +0200 Subject: [PATCH 1063/2612] doc/daily-psk: RouterOS v7 path syntax --- doc/daily-psk.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/daily-psk.md b/doc/daily-psk.md index d204691..e27c2c9 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -21,8 +21,8 @@ Requirements and installation Just install this script. -Depending on whether you use CAPsMAN (`/ caps-man`) or local wireless -interface (`/ interface wireless`) you need to install a different script. +Depending on whether you use CAPsMAN (`/caps-man`) or local wireless +interface (`/interface/wireless`) you need to install a different script. For CAPsMAN: @@ -34,8 +34,8 @@ For local interface: And add schedulers to run the script: - / system scheduler add interval=1d name=daily-psk-nightly on-event="/ system script run daily-psk.local;" start-date=may/23/2018 start-time=03:00:00; - / system scheduler add name=daily-psk-startup on-event="/ system script run daily-psk.local;" start-time=startup; + /system/scheduler/add interval=1d name=daily-psk-nightly on-event="/system/script/run daily-psk.local;" start-date=may/23/2018 start-time=03:00:00; + /system/scheduler/add name=daily-psk-startup on-event="/system/script/run daily-psk.local;" start-time=startup; These will update the passphrase on boot and nightly at 3:00. @@ -49,7 +49,7 @@ The configuration goes to `global-config-overlay`, these are the parameters: Then add an access list entry: - / interface wireless access-list add comment="Daily PSK" interface=wl-daily private-pre-shared-key="ToBeChangedDaily"; + /interface/wireless/access-list/add comment="Daily PSK" interface=wl-daily private-pre-shared-key="ToBeChangedDaily"; Also notification settings are required for e-mail, [matrix](mod/notification-matrix.md) and/or From d9201aa29a914a0d0e89bf106c6ab69939d32850 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:01:30 +0200 Subject: [PATCH 1064/2612] doc/dhcp-lease-comment: RouterOS v7 path syntax --- doc/dhcp-lease-comment.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/dhcp-lease-comment.md b/doc/dhcp-lease-comment.md index 8679bfa..bb9222e 100644 --- a/doc/dhcp-lease-comment.md +++ b/doc/dhcp-lease-comment.md @@ -15,8 +15,8 @@ from wireless access list. Requirements and installation ----------------------------- -Depending on whether you use CAPsMAN (`/ caps-man`) or local wireless -interface (`/ interface wireless`) you need to install a different script. +Depending on whether you use CAPsMAN (`/caps-man`) or local wireless +interface (`/interface/wireless`) you need to install a different script. For CAPsMAN: From 7aea231940caf043104df04638b4a2548149b042 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:02:15 +0200 Subject: [PATCH 1065/2612] doc/dhcp-to-dns: RouterOS v7 path syntax --- doc/dhcp-to-dns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 245b457..bde7f12 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -23,7 +23,7 @@ Then run it from dhcp server as lease script. You may want to use A scheduler cares about cleanup: - / system scheduler add interval=15m name=dhcp-to-dns on-event="/ system script run dhcp-to-dns;" start-time=startup; + /system/scheduler/add interval=15m name=dhcp-to-dns on-event="/system/script/run dhcp-to-dns;" start-time=startup; Configuration ------------- From 474c4f7a62faa763d3064bd668a1cf343bf32a63 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:03:01 +0200 Subject: [PATCH 1066/2612] doc/firmware-upgrade-reboot: RouterOS v7 path syntax --- doc/firmware-upgrade-reboot.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/firmware-upgrade-reboot.md b/doc/firmware-upgrade-reboot.md index c913d8e..0215ce9 100644 --- a/doc/firmware-upgrade-reboot.md +++ b/doc/firmware-upgrade-reboot.md @@ -21,7 +21,7 @@ Requirements and installation Just install the script and create a scheduler: $ScriptInstallUpdate firmware-upgrade-reboot; - / system scheduler add name=firmware-upgrade-reboot on-event="/ system script run firmware-upgrade-reboot;" start-time=startup; + /system/scheduler/add name=firmware-upgrade-reboot on-event="/system/script/run firmware-upgrade-reboot;" start-time=startup; Enjoy firmware being up to date and in sync with RouterOS. From 3e1802a1a032237f927b26e0dab3e26a284b7160 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:03:38 +0200 Subject: [PATCH 1067/2612] doc/global-wait: RouterOS v7 path syntax --- doc/global-wait.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/global-wait.md b/doc/global-wait.md index 2a7fbfa..ac3e5cc 100644 --- a/doc/global-wait.md +++ b/doc/global-wait.md @@ -27,7 +27,7 @@ Just install the script: ... and add it to your scheduler, for example in combination with the module to [manage VLANs on bridge ports](mod/bridge-port-vlan.md): - / system scheduler add name=bridge-port-vlan on-event="/ system script run global-wait; :global BridgePortVlan; \$BridgePortVlan default;" start-time=startup; + /system/scheduler/add name=bridge-port-vlan on-event="/system/script/run global-wait; :global BridgePortVlan; \$BridgePortVlan default;" start-time=startup; See also -------- From 060d12d273b0fabab36914138c06e02ee1043ba1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:04:20 +0200 Subject: [PATCH 1068/2612] doc/gps-track: RouterOS v7 path syntax --- doc/gps-track.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/gps-track.md b/doc/gps-track.md index 3b9c94f..c7d28f6 100644 --- a/doc/gps-track.md +++ b/doc/gps-track.md @@ -23,7 +23,7 @@ Just install the script: ... and create a scheduler: - / system scheduler add interval=1m name=gps-track on-event="/ system script run gps-track;" start-time=startup; + /system/scheduler/add interval=1m name=gps-track on-event="/system/script/run gps-track;" start-time=startup; Configuration ------------- @@ -32,7 +32,7 @@ The configuration goes to `global-config-overlay`, the only parameter is: * `GpsTrackUrl`: the url to send json data to -The configured coordinate format (see `/ system gps`) defines the format +The configured coordinate format (see `/system/gps`) defines the format sent to the server. --- From d68958dd77d8bb5d4dbf4c4504fef8a2ecd58439 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:05:47 +0200 Subject: [PATCH 1069/2612] doc/hotspot-to-wpa: RouterOS v7 path syntax --- doc/hotspot-to-wpa.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index 8733a7c..211d4fb 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -25,7 +25,7 @@ Then install the script: Configure your hotspot to use this script as `on-login` script: - / ip hotspot user profile set on-login=hotspot-to-wpa [ find ]; + /ip/hotspot/user/profile/set on-login=hotspot-to-wpa [ find ]; ### Automatic cleanup @@ -36,11 +36,11 @@ access list forever. Install the optional script for automatic cleanup: Create a scheduler: - / system scheduler add interval=1d name=hotspot-to-wpa-cleanup on-event="/ system script run hotspot-to-wpa-cleanup;" start-time=startup; + /system/scheduler/add interval=1d name=hotspot-to-wpa-cleanup on-event="/system/script/run hotspot-to-wpa-cleanup;" start-time=startup; And add the lease script to your wpa interfaces' dhcp server: - / ip dhcp-server set lease-script=lease-script [ find where name~"wpa" ]; + /ip/dhcp-server/set lease-script=lease-script [ find where name~"wpa" ]; Configuration ------------- @@ -51,8 +51,8 @@ entries are to be added. Create hotspot login credentials: - / ip hotspot user add add comment="Test User 1" name=user1 password=v3ry; - / ip hotspot user add add comment="Test User 2" name=user2 password=s3cr3t; + /ip/hotspot/user/add comment="Test User 1" name=user1 password=v3ry; + /ip/hotspot/user/add comment="Test User 2" name=user2 password=s3cr3t; Additionally templates can be created to give more options for access list: @@ -66,12 +66,12 @@ Additionally templates can be created to give more options for access list: For a hotspot called `example` the template could look like this: - / 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; The same settings are available in hotspot user's comment and take precedence over the template settings: - / ip hotspot user add comment="private-passphrase=ignore, ssid-regexp=^example\\\$, vlan-id=10, vlan-mode=use-tag" name=user password=v3ry-s3cr3t; + /ip/hotspot/user/add comment="private-passphrase=ignore, ssid-regexp=^example\\\$, vlan-id=10, vlan-mode=use-tag" name=user password=v3ry-s3cr3t; Usage and invocation -------------------- From ea619c8efcc16b4a5dfcc05f0ffca58cac60967a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:06:27 +0200 Subject: [PATCH 1070/2612] doc/ipsec-to-dns: RouterOS v7 path syntax --- doc/ipsec-to-dns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ipsec-to-dns.md b/doc/ipsec-to-dns.md index 349ae63..87ad21a 100644 --- a/doc/ipsec-to-dns.md +++ b/doc/ipsec-to-dns.md @@ -21,7 +21,7 @@ Just install the script: This script is run from scheduler: - / system scheduler add interval=1m name=ipsec-to-dns on-event="/ system script run ipsec-to-dns;" start-time=startup; + /system/scheduler/add interval=1m name=ipsec-to-dns on-event="/system/script/run ipsec-to-dns;" start-time=startup; Configuration ------------- From ad6dc85320ed6d4f6051203a5702b63cbf6a20b5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:07:33 +0200 Subject: [PATCH 1071/2612] doc/ipv6-update: RouterOS v7 path syntax --- doc/ipv6-update.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md index ae4eb6a..7c5a943 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -23,14 +23,14 @@ Just install the script: Your ISP needs to provide an IPv6 prefix, your device receives it via dhcp: - / ipv6 dhcp-client add add-default-route=yes interface=ppp-isp pool-name=isp request=prefix script=ipv6-update; + /ipv6/dhcp-client/add add-default-route=yes interface=ppp-isp pool-name=isp request=prefix script=ipv6-update; Note this already adds this script as `script`. The pool name (here: "`isp`") is important, we need it later. Also this expects there is an address assigned from pool to an interface: - / ipv6 address add from-pool=isp interface=br-local; + /ipv6/address/add from-pool=isp interface=br-local; Sometimes dhcp client is stuck on reconnect and needs to be released. Installing [ppp-on-up](ppp-on-up.md) may solve this. @@ -41,7 +41,7 @@ Configuration An address list entry is updated with current prefix and can be used in firewall rules, comment has to be "`ipv6-pool-`" and actual pool name: - / ipv6 firewall address-list add address=2003:cf:2f0f:de00::/56 comment=ipv6-pool-isp list=extern; + /ipv6/firewall/address-list/add address=2003:cf:2f0f:de00::/56 comment=ipv6-pool-isp list=extern; As this entry is mandatory it is created automatically if it does not exist, with the comment also set for list. @@ -50,13 +50,13 @@ Address list entries for specific interfaces can be updated as well. The interface needs to get its address from pool `isp` and the address list entry has to be associated to an interface in comment: - / ipv6 firewall address-list add address=2003:cf:2f0f:de01::/64 comment="ipv6-pool-isp, interface=br-local" list=local; + /ipv6/firewall/address-list/add address=2003:cf:2f0f:de01::/64 comment="ipv6-pool-isp, interface=br-local" list=local; Static DNS records need a special comment to be updated. Again it has to start with "`ipv6-pool-`" and actual pool name, followed by a comma, "`interface=`" and the name of interface this address is connected to: - / ip dns static add address=2003:cf:2f0f:de00:1122:3344:5566:7788 comment="ipv6-pool-isp, interface=br-local" name=test.example.com ttl=15m; + /ip/dns/static/add address=2003:cf:2f0f:de00:1122:3344:5566:7788 comment="ipv6-pool-isp, interface=br-local" name=test.example.com ttl=15m; See also -------- From 77ef9c09194c74e58ce16d1531be106b4a61fa72 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:08:11 +0200 Subject: [PATCH 1072/2612] doc/ip-addr-bridge: RouterOS v7 path syntax --- doc/ip-addr-bridge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ip-addr-bridge.md b/doc/ip-addr-bridge.md index 44dac6a..75685bb 100644 --- a/doc/ip-addr-bridge.md +++ b/doc/ip-addr-bridge.md @@ -19,7 +19,7 @@ Just install the script: ... and make it run from scheduler: - / system scheduler add name=ip-addr-bridge on-event="/ system script run ip-addr-bridge;" start-time=startup; + /system/scheduler/add name=ip-addr-bridge on-event="/system/script/run ip-addr-bridge;" start-time=startup; This will disable IP addresses on bridges without at lease one running port. The IP address is enabled if at least one port is running. From e25f13fe17e6dc6b75df8e39ecad3c5ce7cb2358 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:08:41 +0200 Subject: [PATCH 1073/2612] doc/lease-script: RouterOS v7 path syntax --- doc/lease-script.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/lease-script.md b/doc/lease-script.md index 16fc73e..a435d43 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -32,7 +32,7 @@ Just install the script: ... and add it as `lease-script` to your dhcp server: - / ip dhcp-server set lease-script=lease-script [ find ]; + /ip/dhcp-server/set lease-script=lease-script [ find ]; See also -------- From 36ec2e1595e1d7fb746c0ed050546d7196544ff8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:09:58 +0200 Subject: [PATCH 1074/2612] doc/leds-mode: RouterOS v7 path syntax --- doc/leds-mode.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/leds-mode.md b/doc/leds-mode.md index b525220..65f9f01 100644 --- a/doc/leds-mode.md +++ b/doc/leds-mode.md @@ -21,21 +21,21 @@ Usage and invocation To switch the device to dark mode: - / system script run leds-night-mode; + /system/script/run leds-night-mode; ... and back to normal mode: - / system script run leds-day-mode; + /system/script/run leds-day-mode; To toggle between the two modes: - / system script run leds-toggle-mode; + /system/script/run leds-toggle-mode; Add these schedulers to switch to dark mode in the evening and back to normal mode in the morning: - / system scheduler add interval=1d name=leds-day-mode on-event="/ system script run leds-day-mode;" start-time=07:00:00; - / system scheduler add interval=1d name=leds-night-mode on-event="/ system script run leds-night-mode;" start-time=21:00:00; + /system/scheduler/add interval=1d name=leds-day-mode on-event="/system/script/run leds-day-mode;" start-time=07:00:00; + /system/scheduler/add interval=1d name=leds-night-mode on-event="/system/script/run leds-night-mode;" start-time=21:00:00; The script `leds-toggle-mode` can be used from [mode button](mode-button.md) to toggle mode. From c5044e10cebf0b6d93550084afd1be3a91119bb4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:10:34 +0200 Subject: [PATCH 1075/2612] doc/log-forward: RouterOS v7 path syntax --- doc/log-forward.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/log-forward.md b/doc/log-forward.md index 1f3eae5..c91f09a 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -33,7 +33,7 @@ Just install the script: ... and add a scheduler: - / system scheduler add interval=1m name=log-forward on-event="/ system script run log-forward;" start-time=startup; + /system/scheduler/add interval=1m name=log-forward on-event="/system/script/run log-forward;" start-time=startup; Configuration ------------- From e88a547f60b6c8b8f3575751eb49b89ebb91c995 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:15:05 +0200 Subject: [PATCH 1076/2612] doc/mod/bridge-port-to: RouterOS v7 path syntax --- doc/mod/bridge-port-to.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/mod/bridge-port-to.md b/doc/mod/bridge-port-to.md index 02d1e8d..2b42a9b 100644 --- a/doc/mod/bridge-port-to.md +++ b/doc/mod/bridge-port-to.md @@ -22,20 +22,20 @@ Just install the module: Configuration ------------- -The configuration goes to ports' comments (`/ interface bridge port`). +The configuration goes to ports' comments (`/interface/bridge/port`). - / interface bridge port add bridge=br-guest comment="default=dhcp-client, alt=br-guest" disabled=yes interface=en1; - / interface bridge port add bridge=br-intern comment="default=br-intern, alt=br-guest" interface=en2; - / interface bridge port add bridge=br-guest comment="default=br-guest, extra=br-extra" interface=en3; + /interface/bridge/port/add bridge=br-guest comment="default=dhcp-client, alt=br-guest" disabled=yes interface=en1; + /interface/bridge/port/add bridge=br-intern comment="default=br-intern, alt=br-guest" interface=en2; + /interface/bridge/port/add bridge=br-guest comment="default=br-guest, extra=br-extra" interface=en3; Also dhcp client can be handled: - / ip dhcp-client add comment="toggle with bridge port" disabled=no interface=en1; + /ip/dhcp-client/add comment="toggle with bridge port" disabled=no interface=en1; Add a scheduler to start with default setup on system startup: $ScriptInstallUpdate global-wait; - / system scheduler add name=bridge-port-vlan on-event="/ system script run global-wait; :global BridgePortTo; \$BridgePortTo default;" start-time=startup; + /system/scheduler/add name=bridge-port-vlan on-event="/system/script/run global-wait; :global BridgePortTo; \$BridgePortTo default;" start-time=startup; Usage and invocation -------------------- From 21416c42ef2aa249a96abc83b880e46a9174a622 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:15:14 +0200 Subject: [PATCH 1077/2612] doc/mod/bridge-port-vlan: RouterOS v7 path syntax --- doc/mod/bridge-port-vlan.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/mod/bridge-port-vlan.md b/doc/mod/bridge-port-vlan.md index 290826e..0e6c28f 100644 --- a/doc/mod/bridge-port-vlan.md +++ b/doc/mod/bridge-port-vlan.md @@ -23,24 +23,24 @@ Configuration Using named VLANs you have to add comments in bridge vlan menu: - / interface bridge vlan add bridge=bridge comment=intern tagged=br-local vlan-ids=10; - / interface bridge vlan add bridge=bridge comment=geust tagged=br-local vlan-ids=20; - / interface bridge vlan add bridge=bridge comment=extra tagged=br-local vlan-ids=30; + /interface/bridge/vlan/add bridge=bridge comment=intern tagged=br-local vlan-ids=10; + /interface/bridge/vlan/add bridge=bridge comment=geust tagged=br-local vlan-ids=20; + /interface/bridge/vlan/add bridge=bridge comment=extra tagged=br-local vlan-ids=30; -The configuration goes to ports' comments (`/ interface bridge port`). +The configuration goes to ports' comments (`/interface/bridge/port`). - / interface bridge port add bridge=bridge comment="default=dhcp-client, alt=guest" disabled=yes interface=en1; - / interface bridge port add bridge=bridge comment="default=intern, alt=guest, extra=30" interface=en2; - / interface bridge port add bridge=bridge comment="default=guest, extra=extra" interface=en3; + /interface/bridge/port/add bridge=bridge comment="default=dhcp-client, alt=guest" disabled=yes interface=en1; + /interface/bridge/port/add bridge=bridge comment="default=intern, alt=guest, extra=30" interface=en2; + /interface/bridge/port/add bridge=bridge comment="default=guest, extra=extra" interface=en3; Also dhcp client can be handled: - / ip dhcp-client add comment="toggle with bridge port" disabled=no interface=en1; + /ip/dhcp-client/add comment="toggle with bridge port" disabled=no interface=en1; Add a scheduler to start with default setup on system startup: $ScriptInstallUpdate global-wait; - / system scheduler add name=bridge-port-vlan on-event="/ system script run global-wait; :global BridgePortVlan; \$BridgePortVlan default;" start-time=startup; + /system/scheduler/add name=bridge-port-vlan on-event="/system/script/run global-wait; :global BridgePortVlan; \$BridgePortVlan default;" start-time=startup; Usage and invocation -------------------- From f00ff997a446fa4f53d4a1906d5cf08e5008afcb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 12:03:56 +0200 Subject: [PATCH 1078/2612] doc/mod/inspectvar: RouterOS v7 path syntax --- doc/mod/inspectvar.d/inspectvar.avif | Bin 2891 -> 2838 bytes doc/mod/inspectvar.md | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mod/inspectvar.d/inspectvar.avif b/doc/mod/inspectvar.d/inspectvar.avif index d4a745f2c26446eb02c053a96294bfe35219a984..f1da1d4d1bd2685dd596c851d4100623463bd455 100644 GIT binary patch delta 2469 zcmV;W30n5c7M2!}egX;nk${yJ1Z`wtbP@mx3OHsmIGYFvXf%K_>l2eJ0f2w4tDLI( z`l6$)U(b9+RMP+* zNDtTQ$M|kdLcdUk`up0qNYxKD=>S>G2@dIexd6C8XVB1Fc#YfUQcAVr`|vs|d+Gnz zkS;~2j5|=;Z71|4)7;D2gvNhYs=K-yfC8moI(n;c@lr@>1E}H)ZN+L z$vNwor(BexXF)cC+BZ|NtsRN^5y{+R)&_Bivj_Zkr;gQ~B_(lLD!nRXS*~#H%I|kG zG=RGXoxeb>42+24P6|Y)v+;KUOV_yfTt+bs!n&jPQFJzc4JdDEt^`cXmSLaf$jqL_ zhlXjiSmkI&@sAt0numWGd507oE)vOH9$G?dn8VkUt)dDxgr?_N5qlHUrx#El;_Iva zODm(@w4?A{o!$@c{CgotaJ8SXJ(u-A(?h>3v?~dN3*zjtqiYg??sTyma@=Q@ieJ{@j0oI+P5RS#k-J3kZD( z9q}+LmH2nLf^{A4^s-)ik*1rGbL;M+T1oZJm{{ z2^FxUPZ2-Dd~rXOwpRSyW%Afv#LZAOEC?hK^pe)h8EZ6}x~{wX%-Um1UW(rT_wcx{vZ4Vh`8$u-EC zFpbQhW%3!z=kzzX<32zX0sWGX7iAM|Mv(kALm3!r5Pm##Xvax|i9hz%h;y_>6EXILqHXnQiNq#)ggIPHc zF_ujAj4OYy2{-?@R6*226w#eX)|)qS1vzN)WHkNf<1WOoPs`{dcvW%&I%H!V%Mq8Z zKWFGI4Q3aGl{zB(^T01g7D4*>LPQ(I-8~Xsw%&U_=5~rMjE9@-Dx*79TDrb05HC& zGbaaK_WDUe_rKKbj(D30e z+>>{4&Dl6bH?iR$%+*!38Ew%5!{HH`%4l}oe@f5Z)PuEaUf_Q|`R2!in_wKYWf4fMd${m>P}eKxC5Hvem-J)Rjoy;x8A*V#<(+>> z<}MtNE-XTRMA(>_;+O=x$!hCPPQLHLS6vj)n#*J@vso1;DI*`9NCo^nkdlk*O9ZY{++&T*?X)OZPwSSTXH!d@nUBQz$PAcVd0v@HLKuR#SFm-v8HR!ZrFlie=Y+q%bID{ zBayRA{*m5_xTh|w=SEdg{ONTU=H7et@759JnCM4!&sQ}l=bbp{B(ZHYS2}s2|SKN|L9GgiLaOp;3QTZFSTlWE~T0=!_`1u4+ zhEmt57^={t3UkxcQhrUt`uCUj!?{j6=n|!x3;nz^#Mj@R@NohXh6sQE1y&E~m~D;b zq-X=b5T8~xc_|3mq(G@FWseaVO`mU0LduvXhs{v55AwhNzv=Fx0WLMZFq8rkjkmNZ zPbVvISua-MY`BLEOMa++=CNq|<4Yl-)q|)1W>`No_W9Yh8ma=w27rr`p9Lu0IxL~4 zsAggw4#57x2W}D-kWPP+_4ZmD4tHHe?Nv)eE>&!szF*~=z7p^<9@p0~v|zaoqTzpld!?1!xFQ^?_uxb zA5%iMIl|0-Oi78e3=a@ir0@$=gpUw5>#2a6rn6FTx+ESq&K-Xs&Pa%5aMJ~8IVtIX z{IX!SjmMMP&OI2!g9+oJh{p3TAD<=3^T3PVTK9P7)cxb0hTxwk01}b3gW$kWA=6tp zKl|F**2Vgl^=4!+FDIC@6OD73P*06YOf`0mOux>_EON*8vK?#Jqr+8?tJ7BSZmJQW z|H`-_M8`fUqv?Ivj4su3cReVu#2uD7B;IYX(y`Lh delta 2523 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 diff --git a/doc/mod/inspectvar.md b/doc/mod/inspectvar.md index d3fb3b2..7782c8a 100644 --- a/doc/mod/inspectvar.md +++ b/doc/mod/inspectvar.md @@ -24,7 +24,7 @@ Usage and invocation Call the function `$InspectVar` with a variable as parameter: - $InspectVar $ModeButton + $InspectVar $ModeButton; ![InspectVar](inspectvar.d/inspectvar.avif) From 344ae8a55d0a797bc1601f08d0e492be1d45c478 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 13:12:32 +0200 Subject: [PATCH 1079/2612] doc/mod/ipcalc.d/ipcalc: RouterOS v7 path syntax --- doc/mod/ipcalc.d/ipcalc.avif | Bin 1791 -> 1729 bytes doc/mod/ipcalc.d/ipcalcreturn.avif | Bin 1283 -> 1247 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/mod/ipcalc.d/ipcalc.avif b/doc/mod/ipcalc.d/ipcalc.avif index 022f325bc4637fbb9e4cee8a8d9ad66eab3ba49e..fe726e8c323ea28cda327d70c16ad80fbfcdac4e 100644 GIT binary patch delta 1341 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 VOzhxFmE=C(S3DQ2F494|Ti{ZHy8{3K From 76127ed53c527641a31e069e2f525ac22982463f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:15:25 +0200 Subject: [PATCH 1080/2612] doc/mod/notification-matrix: RouterOS v7 path syntax --- .../notification-matrix.d/01-home-server.avif | Bin 2402 -> 2317 bytes .../02-access-token.avif | Bin 4278 -> 4105 bytes .../notification-matrix.d/03-join-room.avif | Bin 3143 -> 3166 bytes doc/mod/notification-matrix.md | 6 +++--- 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/mod/notification-matrix.d/01-home-server.avif b/doc/mod/notification-matrix.d/01-home-server.avif index 8a79ae6a1d304cc01e0f4c12021f9da3d0ee737f..683c7b581bbf141e83a831ddfec8c47a8383d6e0 100644 GIT binary patch delta 1952 zcmV;R2VeN&5{(j&egX&ck${vI2m5VgVRRAz3JEwRvN~)aA)wMS;}4T60eOGiZ|IDD ze+;%*l+A6S=w*NZxl0Xz5@XkUms0Ij%E*yqFI|c$`4B2iaYxL`e43M&BmUboenS61 z=Sj!$NJ%$zfB(9F(xdRYg75NfV`jWT@L|Ha121Ol%Zxv48pO>c^J!(3SzR&31-u@z z1$dq6U5)@_w3A=r`z_rfKqP;Si13$-`9z$|Z)uv$(wNiKK!Z|ZPFnkfc(!x%00g)W zheNsNk_fh?1SR1J8Usf#;iP;3u*iNd+vj&$V{c;U$F@EDMFGh@Wyp4)Rtx)sjGrWi zx%ufg9QSoGzBvBiEa>t<5iRAsFrneZPAjU{Zo-*_2z5E&hP*5~3x0pzv1b)AfLU6C zKS9!dGRYn6C=x?yI<0fb;NRH}G7KfuT%zJHs$vq?*S3iD&pYyt%}QnJ@Nv0LzoAHd zwdq^I%MqS#!cbW3jg3ze`q!Ox(po&DSfdJ9d@RKb&vi+IlA=OyqBAFH0|9ifPghoG zh;u9ORh^Gr`O_@8w?%(hb#M=GC%+=ALpy9`f0$+F4P4B#?~l)Uy~G!PN#ipPztmtrvWcq)KpX@lqXj|**njq3W zl#I*ivCniB2g`USj|co=nbM$hL^wk|U}hpC#VPoz1npTJTJ!L4bNL<(vjF2n%u*{O zcpQf%y##6y1+pvp@z=>CNHmV}3$*#9!$p+Q)wM`(=lsrGbw51Bc7yNw^l_a(g1z=` zs-9NsTwFAMA8~&ij5WKY5dsCWn{zV=7mz=uwJGgYS_jY<5m14cIJy2aNf^$ht%^wn zcRG|l5QATFLevwd%US%nquynC+Vp$($6gff6kLnP`;5k9?36wi-~NME{hQ5cT$-Sh z+j1=u+MfguG+xf*RQ%?2!;FGO26p)Y?z728q>$oBlaGgXdjMIRAox7#hXRXT_@hYoyo=@(&%s3sqI#XPQ=)G}|3j z5(pql;`&1XE}_0>y&IT~u#!@H0fZs+X6&hX98nJAJJq9rhIC&ZPdw8X47rc?5d*Bu zS22L@&XIqO5>dUO*B&#uj)i zKoJLLIk$__P*njfWUPt4xv0Eqz}7Tfj>e zOQL^5p4%Kx1<}XsXf^Kp2FHD%Bh^LrQbuYL&J(+=)+OLe%+`MF@awdTeB|Fy%&Kcu zu4YZiC6xQ{DBB{Jd|n1rOqq!oW#p2ug4(zaE%~f|^kpqCJ>u!yffvQ?j@YesHYBNU zHqpc;#OBxMUX?_XPjj514sP8g4jVafP-}mEVQYca_lFx=dv@UPL%AN`I!-}kR&3~18;=+XUt8!>#I-z0;MwhBs2rEkOTa%PC8mFWTJ)%O!*iiJ&(Hb{-^+x8G z-_%pC^`MT3oYxh8MIIVngc7jyAdi1gFDDC%T0SxUMZGxZhn9JUq)s*#k_?kMoVtZn zcTS;Km=h9bt8xCepfA=SqEMmzdv9O&M5ipRiutS^x<^nejh=DC@7i5FTgZQcV=7ts zN$p6qg#5}8F>apxUT6W{Bhj#fRxP0_IG{h~7A8&E6@z2kvjw~U=6Z@lsoG9NB+M+2dFu(P=|`1c4B zL44hBG;q|nf-V2D58)a~$76=0YRe7|ko(-_{u>BM+etGU`WnBTyo|BQM2wE8w9mn} mUoyw-H4G9LUuh(Z?k{qp6}^^JRGLXg_5;YOAXWUduvie=W6odz delta 2038 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 delta 4021 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 b_ah!0Uq(lM4ZRIr9YnIu@0w9$w69sf+swI9 diff --git a/doc/mod/notification-matrix.d/03-join-room.avif b/doc/mod/notification-matrix.d/03-join-room.avif index c7fad4e8f04277b9dc5e4d3a78646af120b60448..45974b86b5fc39c652591cebd32650bcc78f0b5f 100644 GIT binary patch delta 2873 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 diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index 91a39e5..3da5659 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -42,7 +42,7 @@ Your best bet is to query the server at `domain` with the [well-known uri](https://spec.matrix.org/latest/client-server-api/#well-known-uri). For "*matrix.org*" this query is: - / tool fetch "https://matrix.org/.well-known/matrix/client" output=user; + /tool/fetch "https://matrix.org/.well-known/matrix/client" output=user; ![home server](notification-matrix.d/01-home-server.avif) @@ -59,7 +59,7 @@ account must be sent to the home server via We use the home server discovered above, "*matrix-client.matrix.org*". The user is "*example*" and password is "*v3ry-s3cr3t*". - / tool fetch "https://matrix-client.matrix.org/_matrix/client/r0/login" http-method=post http-data="{\"type\":\"m.login.password\", \"user\":\"example\", \"password\":\"v3ry-s3cr3t\"}" output=user; + /tool/fetch "https://matrix-client.matrix.org/_matrix/client/r0/login" http-method=post http-data="{\"type\":\"m.login.password\", \"user\":\"example\", \"password\":\"v3ry-s3cr3t\"}" output=user; ![access token](notification-matrix.d/02-access-token.avif) @@ -80,7 +80,7 @@ this can be done with Make sure to replace room id ("*!*" is escaped with "*%21*") and access token with your data. - / tool fetch "https://matrix-client.matrix.org/_matrix/client/r0/rooms/%21WUcxpSjKyxSGelouhA:matrix.org/join?access_token=yt_ZXdvcm0tdGVzdA_NNqUyvKHRhBLZmnzVVSK_0xu6yN" http-method=post http-data="" output=user; + /tool/fetch "https://matrix-client.matrix.org/_matrix/client/r0/rooms/%21WUcxpSjKyxSGelouhA:matrix.org/join?access_token=yt_ZXdvcm0tdGVzdA_NNqUyvKHRhBLZmnzVVSK_0xu6yN" http-method=post http-data="" output=user; ![join room](notification-matrix.d/03-join-room.avif) From 95a75b3fa19f501fe5db8404a1c59a970cc8d7cd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:32:48 +0200 Subject: [PATCH 1081/2612] doc/mod/scriptrunonce: RouterOS v7 path syntax --- doc/mod/scriptrunonce.d/hello-world.rsc | 2 +- doc/mod/scriptrunonce.d/scriptrunonce.avif | Bin 2466 -> 2356 bytes doc/mod/scriptrunonce.md | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/mod/scriptrunonce.d/hello-world.rsc b/doc/mod/scriptrunonce.d/hello-world.rsc index 17ec575..6404781 100644 --- a/doc/mod/scriptrunonce.d/hello-world.rsc +++ b/doc/mod/scriptrunonce.d/hello-world.rsc @@ -1,3 +1,3 @@ #!rsc by RouterOS -:put ("Hello World from " . [ / system identity get name ] . "!"); +:put ("Hello World from " . [ /system/identity/get name ] . "!"); diff --git a/doc/mod/scriptrunonce.d/scriptrunonce.avif b/doc/mod/scriptrunonce.d/scriptrunonce.avif index 614c72c670ff87f31bbd59d11c73927d62630129..27ccd41fa5541090b5c12e9f50c653e14f6f0e47 100644 GIT binary patch delta 2055 zcmV+i2>AD+6SNYLe*qeifRz*?ZDe6|5&#MbI3=<=Y#o331rEXy|uaRzf#~dVA2?e=<;%>=+=q{V9X?* zVrWfD3^X@ufY<`RIVUTBQlzXr<5ekp$};v`~EW+|Dm)QIiZV`$85s zkbz2k5rV1GMaJq;N)c2LnG`!@*q)K`26Ts$MEQpByff_pQa5RTPr?hJYn&bEfCu{N zUAp;n_A=j4HtL=my4eQd7YpISxs*}}y}E+ywB?5;8I3%Q(bAs4KC|ks-nsfMPUB%< zbrP4Sd_S9mF4K5@srW4}9<|^29CL%bRVYX}d}9x!qt@nJz=yArBWJyC2>oCoh~%~t z)~ZvQeloU*Rq)z>_7OrFEyJ`A)h_P_Q0K`lw;Mqu^#{z{q`|^AV)kTP9UEbU!gAnR z(B|O+L(dG9W7`xyF|4K~>udcSdQcp2MprL{M60$*Nnn+HfvA1a&Y+3*T2huqit^RG zl*y*sd*$5871kZ0qB-$+O7GxhU)Ypwbm?Fdn9pbPwUh~e-3C*h)0H^*?S5aKN}2rT zhR}qYS;B31`#L*K1FroS&rwVvT53vd`^=@ER;F8y$U+eDxn{Oh#%V)oUF%VwHScDC zy}afV=rmZFv&u%62P`X*^oZf3};>P<< zPpcM(wy%|cmxq6maWi@qV2JtRhDle|*9l9APi~nzSk^GswbZWgiSzEGG(DD-whqn5 zpxo411yebIAe2FqQ7B?KYX5jNUA2fy22=3GFb9M@X}G}9ap4>74Kpjn@w>+8J@_dJ zD%i}%a#T*!JxS^MJ>BdW#zZ^Z``5vdR3D8%)Dy7n>ENZwf`S|%aZ+C3TeYx80! z#tPE3{Pbs#IXid4P1i0f-j30cpTejF<^+H9tK3suXQ^cfixbQC6wfXb4{UdoME1!Zp;YG&v3`%Oj1LNkCm@QtFw{bIHFVnABUR4hw z)G?PKlI*S~mQ}?K2d@Zf^!$utLUom6eup!Eb+L}WF9#X2cYHibgXCv;8y{&vv)t_ENJjiBWvO28ie*e~b`Y@|4rwEX)Bp0%(}$OnSTRc9hFBydVOCb88w@P?Z@-h?BEIMqrTJBe z;pH_)FGISZBoj4K%o4{B#{Ej zw64)mLqgdCYgZ}s0 zQ^CDIXclM;>+d+Oxz&vvVB@E(3*E5Drf}R@(Z4vI8MAo!)XIA}1*%~VO-;Jq%J9DsSG7$wx z&-8W@29L>|h==T_P}Xn=8E|f#;`A5}yPwV`TOmnyl^t-~gS2ug@oIJ$&SXEZ9x4AS z@oIu^GB<~sd#H%UP~dQfPo3j(Zb+R24nM-A0wZQki3v#l~-%)b*=6 zhFGI}nB|F$7JqF%=FMg0>CrlRv~;%cRKhufj$mnhz0EUwfsEeBsA-_;)9z~bj7{jZ zTHk>KCk_MJ5~i8}eP@5+Dt#}u7)#8T4x&$WN*3F#@I~S`Q}2>u6Vd}*&2ELn=$Qk& z+eLO6Z`C0W!Y{aLK*_Fv+B8P~I7vKDnmkIc{*#oF5o{CVO$ku+RtWWJC!1pu+w4#_ lo#R>h*_LYC1%R4Rwqnt=5*ghP);yMo1aYFjUSzgzv@b6A1*HH0 delta 2166 zcmV-+2#NQ!5~353e*uV*fRz-GZDe6|5&#MbI3=<=Y#-JVir2($N8M!?X8&M4%OY+xuvt}UJK{gN`A9;s~ zQTBjG#U-bH>p^9x`29q%MTpZM{WElB5OnbHXhZ;PU^HG@mI#DEv*cTQDc4KShe;2f zu0-efitEF~*RXC}HVz&%>3KvCvPwHhh)dXD6FR?H&8=@yfD(6q+^BWS^gc2>#?CsI z#Iaj`3E4L^e6Om~*))PoXzyp7RE>Lv3P^BZs2I0{AI;*P*F5+~EKCu{D$&IV(j zzkT&QtTwY9v*yuDzBG%j>*or14oeU}q;ZX&I%}FK46c24lpKleJpKW-D%&fc#gDw~ z;E@|UPj5nr#h9CaJ!MXVm1h08ZBaIJ7&PAEBb&B%KBcbhidjVyYx}W3ErTLVQTCll zGj;sdB@s}dv*acMHc5b#XvmAa$7j1`i*rTXu`xxV(w>dHf>#(4twhkcwO+)a)_-HI z(N#i>Un^|btXgwvCp=pF*Ap(1C(d!qTGE zvmFA4YHJ9STOtNH_HBCWMOmVn_W^6&+5z%o2KKxw9pVndjJHHvN@mXtyw=efw@m!4crI!w zt$OutO82*Yqa9;$Mu=Hgv@Zj@>?rVl8^Pl=-p>?LfjK%&-bn3vBxw@ zomq+Y$oL~IsQKmNppo8qI!w;efL;&lG1RhxwrB2t=vl_Zm{_fH)x(&gG|T^JanHI+ zb8~u99H>MY&|9nXglcWwlUpH*G{$mVyDzsts8>IgeI-~Y3bD@}W!H-^#+%Lf86-P~ z4b%<|i|iJDV9Yx|rP_L3MuQf@E=g7#f+K|n8*kZYSffJVDmE$TO{f8AQ!NYTox>sl z5g!|WHd-CpqBNo-JU|X4Q(j3 zOd|!`tO&Dh6JHAMKB$q70xZI+z^sE~5Qfx`Lp!f2-$j;!YBMFMcBIDzR5$A@TwXJO zLlT+n^z)hc%H!q5ta!+xcp}*0@5J3!YOc35j?Y%QoZy5Y>nbsYUcsYdNM=oOe*%Xc z`jtjes&cvXHS~6h2S&d#wIfuvCFolrEB3xYI+gR@3Khz6(I?JmM@)w-?s>1gXGTmB zqBxkz37i4JOnD3B`mvz0>*Q)Lk9!?|p+Ejioa>Hx@9%Kq9K}@+`Q$!35nkGZG<#Y} zrBSUb@jS&QJp4=M#T|FuBX{K3V&%RYIEmAJ5cT4NY{Y?%m`$kH>E^06zC**3gaK2& z@Mc^0+i|{D2aI{lcoJuvQ*N43M{km)IQZjy0W1rlyi~XKMfdOdy}nl9{ayoqT|7pC z*@<74#eCp(p+`?6J!!`ys*f>>RlkoO9(at;Uik-(akEQVkHz)DmE^UNGHt07;8bP~ zg;^?4pOaAMeS$tG+kLoG6=6r4udmKbO36Sma`w2QQnR2piJQ3*VdMY`2|lH*rNdch z`AtzFIe^Qt9SoFrzoD;~SyV57UHQ6j9Iy`z*zC{s9+FX`XpP!!#{L>YN8Olpd%63L zWIs7bZ1v7O_Gg)BCExy+4MB3!YepMWQ1A-vHCMU(Hc7fAy!LH>s4_|HAz`Dl4t zB%dU7p}F>T2VYHoPBEkcU64}BuS%iIzBY|mfQ(#wkq@xMv2RzmnIj;tn`e~_ z8@-$gRZn3Xksr=@AoCM!n`K{~PksB?!q9 Date: Wed, 11 May 2022 10:17:53 +0200 Subject: [PATCH 1082/2612] doc/mode-button: RouterOS v7 path syntax --- doc/mode-button.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/mode-button.md b/doc/mode-button.md index c1c059e..ef7754c 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -13,17 +13,17 @@ This script extend the functionality of mode button. Instead of just one you can trigger several actions by pressing the mode button several times. The hardware needs to have a mode button, see -`/ system routerboard mode-button`. Starting with RouterOS 6.47beta60 you +`/system/routerboard/mode-button`. Starting with RouterOS 6.47beta60 you can configure the reset button to act the same, see -`/ system routerboard reset-button`. +`/system/routerboard/reset-button`. Copy this code to terminal to check: ``` -:if ([ :len [ /system routerboard mode-button print as-value ] ] > 0) do={ +:if ([ :len [ /system/routerboard/mode-button/print as-value ] ] > 0) do={ :put "Mode button is supported."; } else={ - :if ([ :len [ /system routerboard reset-button print as-value ] ] > 0) do={ + :if ([ :len [ /system/routerboard/reset-button/print as-value ] ] > 0) do={ :put "Mode button is not supported, but reset button is."; } else={ :put "Neither mode button nor reset button is supported."; @@ -40,11 +40,11 @@ Just install the script: Then configure the mode button to run `mode-button`: - / system routerboard mode-button set enabled=yes on-event="/ system script run mode-button;"; + /system/routerboard/mode-button/set enabled=yes on-event="/system/script/run mode-button;"; To use the reset button instead: - / system routerboard reset-button set enabled=yes on-event="/ system script run mode-button;"; + /system/routerboard/reset-button/set enabled=yes on-event="/system/script/run mode-button;"; Configuration ------------- @@ -57,7 +57,7 @@ The configuration goes to `global-config-overlay`, these are the parameters: Usage and invocation -------------------- -Press the mode button. :) +Press the mode button. 😜 --- [◀ Go back to main README](../README.md) From 9ef2718c6dc209b5774193c76c9e18e019fac5d6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:19:11 +0200 Subject: [PATCH 1083/2612] doc/netwatch-dns: RouterOS v7 path syntax --- doc/netwatch-dns.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 4fbfc2b..798ad92 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -21,7 +21,7 @@ Just install the script: Then add a scheduler to run it periodically: - / system scheduler add interval=1m name=netwatch-dns on-event="/ system script run netwatch-dns;" start-time=startup; + /system/scheduler/add interval=1m name=netwatch-dns on-event="/system/script/run netwatch-dns;" start-time=startup; Configuration ------------- @@ -29,9 +29,9 @@ Configuration The DNS and DoH servers to be checked have to be added to netwatch with specific comment: - / tool netwatch add comment="doh, hostname=cloudflare-dns" host=1.1.1.1; - / tool netwatch add comment="dns, hostname=google-dns" host=8.8.8.8; - / tool netwatch add comment="doh, dns, hostname=quad-nine" host=9.9.9.10; + /tool/netwatch/add comment="doh, hostname=cloudflare-dns" host=1.1.1.1; + /tool/netwatch/add comment="dns, hostname=google-dns" host=8.8.8.8; + /tool/netwatch/add comment="doh, dns, hostname=quad-nine" host=9.9.9.10; This will configure *cloudflare-dns* for DoH (`https://1.1.1.1/dnsquery`), and *google-dns* and *quad-nine* for regular DNS (`8.8.8.8,9.9.9.10`) if up. @@ -39,15 +39,15 @@ If *cloudflare-dns* is down the script will fall back to *quad-nine* for DoH. Giving a specific query url for DoH is possible: - / tool netwatch add comment="doh, hostname=nextdns, doh-url=https://dns.nextdns.io/dns-query" host=199.247.16.158; + /tool/netwatch/add comment="doh, hostname=nextdns, doh-url=https://dns.nextdns.io/dns-query" host=199.247.16.158; Note that using a name in DoH url may introduce a chicken-and-egg issue! Sometimes using just one specific (possibly internal) DNS server may be desired, with fallback in case it fails. This is possible as well: - / tool netwatch add comment="dns, hostname=pi-hole" host=10.0.0.10; - / tool netwatch add comment="dns-fallback, hostname=cloudflare-dns" host=1.1.1.1; + /tool/netwatch/add comment="dns, hostname=pi-hole" host=10.0.0.10; + /tool/netwatch/add comment="dns-fallback, hostname=cloudflare-dns" host=1.1.1.1; Tips & Tricks ------------- @@ -57,7 +57,7 @@ Tips & Tricks Netwatch entries can be created to work with both - this script and [netwatch-notify](netwatch-notify.md). Just give options for both: - / tool netwatch add comment="doh, notify, hostname=cloudflare-dns" host=1.1.1.1; + /tool/netwatch/add comment="doh, notify, hostname=cloudflare-dns" host=1.1.1.1; Also this allows to update host address, see option `resolve`. From 7561c719d1ca8747c9fddf10d3f4dd473528848b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:24:18 +0200 Subject: [PATCH 1084/2612] doc/netwatch-notify: RouterOS v7 path syntax --- doc/netwatch-notify.md | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index b2f6dd0..85bfb73 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -10,7 +10,7 @@ Description ----------- This script sends notifications about host UP and DOWN events. In comparison -to just netwatch (`/ tool netwatch`) and its `up-script` and `down-script` +to just netwatch (`/tool/netwatch`) and its `up-script` and `down-script` this script implements a simple state machine and dependency model. Host down events are triggered only if the host is down for several checks and optional parent host is not down to avoid false alerts. @@ -29,14 +29,14 @@ Just install the script: Then add a scheduler to run it periodically: - / system scheduler add interval=1m name=netwatch-notify on-event="/ system script run netwatch-notify;" start-time=startup; + /system/scheduler/add interval=1m name=netwatch-notify on-event="/system/script/run netwatch-notify;" start-time=startup; Configuration ------------- The hosts to be checked have to be added to netwatch with specific comment: - / tool netwatch add comment="notify, hostname=example.com" host=[ :resolve "example.com" ]; + /tool/netwatch/add comment="notify, hostname=example.com" host=[ :resolve "example.com" ]; ### Hooks @@ -44,7 +44,7 @@ It is possible to run an up hook command (`up-hook`) or down hook command (`down-hook`) when a notification is triggered. This has to be added in comment, note that some characters need extra escaping: - / tool netwatch add comment=("notify, hostname=device, down-hook=/ interface ethernet \\{ disable \\\"en2\\\"; enable \\\"en2\\\"; \\}") host=10.0.0.20; + /tool/netwatch/add comment=("notify, hostname=device, down-hook=/interface/ethernet \\{ disable \\\"en2\\\"; enable \\\"en2\\\"; \\}") host=10.0.0.20; Also there is a `pre-down-hook` that fires at two thirds of failed checks required for the notification. The idea is to fix the issue before a @@ -54,15 +54,15 @@ notification is sent. The count threshould (default is 5 checks) is configurable as well: - / tool netwatch add comment="notify, hostname=example.com, count=10" host=104.18.144.11; + /tool/netwatch/add comment="notify, hostname=example.com, count=10" host=104.18.144.11; ### Parents & dependencies If the host is behind another checked host add a dependency, this will suppress notification if the parent host is down: - / tool netwatch add comment="notify, hostname=gateway" host=93.184.216.1; - / tool netwatch add comment="notify, hostname=example.com, parent=gateway" host=93.184.216.34; + /tool/netwatch/add comment="notify, hostname=gateway" host=93.184.216.1; + /tool/netwatch/add comment="notify, hostname=example.com, parent=gateway" host=93.184.216.34; Note that every configured parent in a chain increases the check count threshould by one. @@ -72,7 +72,7 @@ threshould by one. The host address can be updated dynamically. Give extra parameter `resolve` with a resolvable name: - / tool netwatch add comment="notify, hostname=example.com, resolve=example.com"; + /tool/netwatch/add comment="notify, hostname=example.com, resolve=example.com"; But be warned: Dynamic updates will probably cause issues if the name has more than one record in dns - a high rate of configuration changes (and flash @@ -84,7 +84,7 @@ Also suppressing the notification on host down is possible with parameter `no-down-notification`. This may be desired for devices that are usually powered off, but accessibility is of interest. - / tool netwatch add comment="notify, hostname=printer, no-down-notification" host=10.0.0.30; + /tool/netwatch/add comment="notify, hostname=printer, no-down-notification" host=10.0.0.30; Go and get your coffee â˜•ī¸ before sending the print job. @@ -101,8 +101,8 @@ Sometimes it is sufficient if one of a number of hosts is available. You can make `netwatch-notify` check for that by adding several items with same `hostname`. Note that `count` has to be multiplied to keep the actual time. - / tool netwatch add comment="notify, hostname=service, count=10" host=10.0.0.10; - / tool netwatch add comment="notify, hostname=service, count=10" host=10.0.0.20; + /tool/netwatch/add comment="notify, hostname=service, count=10" host=10.0.0.10; + /tool/netwatch/add comment="notify, hostname=service, count=10" host=10.0.0.20; ### Checking internet connectivity @@ -112,11 +112,11 @@ check `1.1.1.1` (Cloudflare DNS), `9.9.9.9` (Quad-nine DNS), `8.8.8.8` (Google DNS) or any other reliable address that indicates internet connectivity. - / tool netwatch add comment="notify, hostname=internet" host=1.1.1.1; + /tool/netwatch/add comment="notify, hostname=internet" host=1.1.1.1; A target like this suits well to be parent for other checks. - / tool netwatch add comment="notify, hostname=example.com, parent=internet" host=93.184.216.34; + /tool/netwatch/add comment="notify, hostname=example.com, parent=internet" host=93.184.216.34; ### Checking specific ISP @@ -124,12 +124,13 @@ Having several ISPs for redundancy a failed link may go unnoticed without proper monitoring. You can use routing-mark to monitor specific connections. Create a route and firewall mangle rule. - / ip route add distance=1 gateway=isp1 routing-mark=via-isp1; - / ip firewall mangle add action=mark-routing chain=output new-routing-mark=via-isp1 dst-address=1.0.0.1 passthrough=yes; + /routing/table/add fib name=via-isp1; + /ip/route/add distance=1 gateway=isp1 routing-table=via-isp1; + /ip/firewall/mangle/add action=mark-routing chain=output new-routing-mark=via-isp1 dst-address=1.0.0.1 passthrough=yes; Finally monitor the address with `netwatch-notify`. - / tool netwatch add comment="notify, hostname=quad-one via isp1" host=1.0.0.1; + /tool/netwatch/add comment="notify, hostname=quad-one via isp1" host=1.0.0.1; Note that *all* traffic to the given address is routed that way. In case of link failure this address is not available, so use something reliable but @@ -141,7 +142,7 @@ non-essential. In this example the address `1.0.0.1` is used, the same service Netwatch entries can be created to work with both - this script and [netwatch-dns](netwatch-dns.md). Just give options for both: - / tool netwatch add comment="doh, notify, hostname=cloudflare-dns" host=1.1.1.1; + /tool/netwatch/add comment="doh, notify, hostname=cloudflare-dns" host=1.1.1.1; See also -------- From 6f76a41962ccf7ad756e99c8155418d281ef5452 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:24:59 +0200 Subject: [PATCH 1085/2612] doc/netwatch-syslog: RouterOS v7 path syntax --- doc/netwatch-syslog.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/netwatch-syslog.md b/doc/netwatch-syslog.md index 9a28bb9..760d98f 100644 --- a/doc/netwatch-syslog.md +++ b/doc/netwatch-syslog.md @@ -16,8 +16,8 @@ Requirements and installation Let's assume there is a remote log action and associated logging rule: - / system logging action set remote=10.0.0.1 [ find where name="remote" ]; - / system logging add action=remote topics=info; + /system/logging/action/set remote=10.0.0.1 [ find where name="remote" ]; + /system/logging/add action=remote topics=info; Just install the script: @@ -25,7 +25,7 @@ Just install the script: ... and create a netwatch matching the IP address from logging action above: - / tool netwatch add down-script=netwatch-syslog host=10.0.0.1 up-script=netwatch-syslog; + /tool/netwatch/add down-script=netwatch-syslog host=10.0.0.1 up-script=netwatch-syslog; All logging rules are disabled when host is down. From 47b6f8941aaa71fcbcee5329118517ffe92b306d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:25:45 +0200 Subject: [PATCH 1086/2612] doc/ospf-to-leds: RouterOS v7 path syntax --- doc/ospf-to-leds.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ospf-to-leds.md b/doc/ospf-to-leds.md index 2fba33e..5ab5c75 100644 --- a/doc/ospf-to-leds.md +++ b/doc/ospf-to-leds.md @@ -22,7 +22,7 @@ Just install the script: ... and add a scheduler to run the script periodically: - / system scheduler add interval=20s name=ospf-to-leds on-event="/ system script run ospf-to-leds;" start-time=startup; + /system/scheduler/add interval=20s name=ospf-to-leds on-event="/system/script/run ospf-to-leds;" start-time=startup; Configuration ------------- @@ -30,7 +30,7 @@ Configuration The configuration goes to OSPF instance's comment. To visualize state for instance `default` via LED `user-led` set this: - / routing ospf instance set default comment="ospf-to-leds, leds=user-led"; + /routing/ospf/instance/set default comment="ospf-to-leds, leds=user-led"; --- [◀ Go back to main README](../README.md) From eb014b26b2053e993cfa9ec8e97bd48c53c848f9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:26:26 +0200 Subject: [PATCH 1087/2612] doc/packages-update: RouterOS v7 path syntax --- doc/packages-update.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/packages-update.md b/doc/packages-update.md index 243e72b..57f02d9 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -10,7 +10,7 @@ Description ----------- In rare cases RouterOS fails to properly downlaod package on update -(`/ system package update install`), resulting in borked system with missing +(`/system/package/update/install`), resulting in borked system with missing packages. This script tries to avoid this situation by doing some basic verification. @@ -35,7 +35,7 @@ Usage and invocation Alternatively run it manually: - / system script run packages-update; + /system/script/run packages-update; See also -------- From d9d2d67a4e66bd7df0bb0d3ae89f0acc88ed5b3b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:26:51 +0200 Subject: [PATCH 1088/2612] doc/ppp-on-up: RouterOS v7 path syntax --- doc/ppp-on-up.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ppp-on-up.md b/doc/ppp-on-up.md index ae58da5..7545c5e 100644 --- a/doc/ppp-on-up.md +++ b/doc/ppp-on-up.md @@ -24,7 +24,7 @@ Just install the script: ... and make it the `on-up` script for ppp profile: - / ppp profile set on-up=ppp-on-up [ find ]; + /ppp/profile/set on-up=ppp-on-up [ find ]; See also -------- From 45232019f4462d1a979eee5b935432888dbfad0b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:27:23 +0200 Subject: [PATCH 1089/2612] doc/rotate-ntp: RouterOS v7 path syntax --- doc/rotate-ntp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/rotate-ntp.md b/doc/rotate-ntp.md index 775b977..f548eba 100644 --- a/doc/rotate-ntp.md +++ b/doc/rotate-ntp.md @@ -36,7 +36,7 @@ addresses from pool if required. Alternatively a scheduler can be created: - / system scheduler add interval=5d name=rotate-ntp on-event="/ system script run rotate-ntp;" start-time=startup; + /system/scheduler/add interval=5d name=rotate-ntp on-event="/system/script/run rotate-ntp;" start-time=startup; --- [◀ Go back to main README](../README.md) From 25d11f798d63788dcfa89fecb4962d65edc25d1e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:28:24 +0200 Subject: [PATCH 1090/2612] doc/sms-action: RouterOS v7 path syntax --- doc/sms-action.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/sms-action.md b/doc/sms-action.md index 8442774..d2e3252 100644 --- a/doc/sms-action.md +++ b/doc/sms-action.md @@ -30,7 +30,7 @@ The configuration goes to `global-config-overlay`, this is the only parameter: Then enable SMS actions: - / tool sms set allowed-number=+491234567890 receive-enabled=yes secret=s3cr3t; + /tool/sms/set allowed-number=+491234567890 receive-enabled=yes secret=s3cr3t; Usage and invocation -------------------- From 06509f6af424a6a30aa2bc630729414d83e67593 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:28:35 +0200 Subject: [PATCH 1091/2612] doc/sms-forward: RouterOS v7 path syntax --- doc/sms-forward.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 9ebae69..80cb7ad 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -26,7 +26,7 @@ Just install the script: ... and add a scheduler to run it periodically: - / system scheduler add interval=2m name=sms-forward on-event="/ system script run sms-forward;" start-time=startup; + /system/scheduler/add interval=2m name=sms-forward on-event="/system/script/run sms-forward;" start-time=startup; Configuration ------------- @@ -36,7 +36,7 @@ Notification settings are required for e-mail, [telegram](mod/notification-telegram.md). Also you have to enable receiving of SMS: - / tool sms set receive-enabled=yes; + /tool/sms/set receive-enabled=yes; See also -------- From 4ca43dcde3de7680d83f989e398686da587550d5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:29:01 +0200 Subject: [PATCH 1092/2612] doc/ssh-keys-import: RouterOS v7 path syntax --- doc/ssh-keys-import.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ssh-keys-import.md b/doc/ssh-keys-import.md index 3dc8ccf..d83311f 100644 --- a/doc/ssh-keys-import.md +++ b/doc/ssh-keys-import.md @@ -22,7 +22,7 @@ Usage and invocation Copy files with extension "`pub`" containing public SSH keys for your device. Then run the script: - / system script run ssh-keys-import; + /system/script/run ssh-keys-import; Starting with an `authorized_keys` file you can split it on a shell: From c2637ee72c454c9df46ca3ac37a6eacc283a9cfe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:29:25 +0200 Subject: [PATCH 1093/2612] doc/super-mario-theme: RouterOS v7 path syntax --- doc/super-mario-theme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/super-mario-theme.md b/doc/super-mario-theme.md index 68484dc..8142cda 100644 --- a/doc/super-mario-theme.md +++ b/doc/super-mario-theme.md @@ -22,7 +22,7 @@ Usage and invocation Just run the script to play: - / system script run super-mario-theme; + /system/script/run super-mario-theme; For extra fun use it for dhcp lease script. :) From 347cb4f3b66634df0bfebfdf73ca111fe4dc7cb2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:29:49 +0200 Subject: [PATCH 1094/2612] doc/unattended-lte-firmware-upgrade: RouterOS v7 path syntax --- doc/unattended-lte-firmware-upgrade.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/unattended-lte-firmware-upgrade.md b/doc/unattended-lte-firmware-upgrade.md index 65801a6..63f2793 100644 --- a/doc/unattended-lte-firmware-upgrade.md +++ b/doc/unattended-lte-firmware-upgrade.md @@ -32,7 +32,7 @@ Usage and invocation Run the script if an upgrade for your LTE hardware is available: - / system script run unattended-lte-firmware-upgrade; + /system/script/run unattended-lte-firmware-upgrade; Then be patient, go for a coffee and wait for the upgrade process to finish. From f759a9a52e21b8bd3c2fa79991689ce3270a7723 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:31:03 +0200 Subject: [PATCH 1095/2612] doc/update-gre-address: RouterOS v7 path syntax --- doc/update-gre-address.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/update-gre-address.md b/doc/update-gre-address.md index c19e138..7e87743 100644 --- a/doc/update-gre-address.md +++ b/doc/update-gre-address.md @@ -26,7 +26,7 @@ Just install the script: ... and add a scheduler to run the script periodically: - / system scheduler add interval=30s name=update-gre-address on-event="/ system script run update-gre-address;" start-time=startup; + /system/scheduler/add interval=30s name=update-gre-address on-event="/system/script/run update-gre-address;" start-time=startup; Configuration ------------- @@ -34,7 +34,7 @@ Configuration The configuration goes to interface's comment. Add the client's IKEv2 certificate CN into the comment: - / interface gre set comment="ikev2-client1" gre-client1; + /interface/gre/set comment="ikev2-client1" gre-client1; --- [◀ Go back to main README](../README.md) From 09d926ed2fefb570d9810970306037910d6926d9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 10:31:17 +0200 Subject: [PATCH 1096/2612] doc/update-tunnelbroker: RouterOS v7 path syntax --- doc/update-tunnelbroker.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/update-tunnelbroker.md b/doc/update-tunnelbroker.md index 9dd7f19..bfe8e25 100644 --- a/doc/update-tunnelbroker.md +++ b/doc/update-tunnelbroker.md @@ -28,11 +28,11 @@ Configuration The configuration goes to interface's comment: - / interface 6to4 set comment="tunnelbroker, user=user, pass=s3cr3t, id=12345" tunnelbroker; + /interface/6to4/set comment="tunnelbroker, user=user, pass=s3cr3t, id=12345" tunnelbroker; Also enabling dynamic DNS in Mikrotik cloud is required: - / ip cloud set ddns-enabled=yes; + /ip/cloud/set ddns-enabled=yes; See also -------- From 5e481a768b4cea4534f5f775ce565a79cb1e3eb9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 18:39:44 +0200 Subject: [PATCH 1097/2612] notify about freeze of routeros-v7 branch --- global-config | 2 +- global-config.changes | 1 + global-functions | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/global-config b/global-config index 933ec2e..70d8a2f 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 79; +:global GlobalConfigVersion 80; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config.changes b/global-config.changes index 4bb87a9..e317b02 100644 --- a/global-config.changes +++ b/global-config.changes @@ -88,6 +88,7 @@ 77="Introduced new script 'firmware-upgrade-reboot'. Handle with care!"; 78="New documentation is online for notifications via Telegram & Matrix, variable inspection, ip address calculation and running scripts once."; 79="Introduced new script 'backup-partition' to save configuration to fallback partition."; + 80="The 'routeros-v7' branch will now freeze, and vanish any time in future. You already switched to 'main' branch, well done!"; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index a12eb5d..51c87bc 100644 --- a/global-functions +++ b/global-functions @@ -10,7 +10,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 79; +:global ExpectedConfigVersion 80; # global variables not to be changed by user :global GlobalFunctionsReady false; From 0e73f85c113e5866be2de2a281704eb8cdebd0c5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 May 2022 12:42:38 +0200 Subject: [PATCH 1098/2612] log-forward: do *not* wait to be fully connected Let's forward logs as early as possible. All notification functions are expected to handle notifications with queues, so nothing is lost. Just the opposite: Logs being rotated before forwarding becomes less likely. --- log-forward | 3 --- 1 file changed, 3 deletions(-) diff --git a/log-forward b/log-forward index 1aa0363..bb57522 100644 --- a/log-forward +++ b/log-forward @@ -27,7 +27,6 @@ :global ScriptLock; :global SendNotification2; :global SymbolForNotification; -:global WaitFullyConnected; $ScriptLock $0; @@ -40,8 +39,6 @@ $ScriptLock $0; $LogPrintExit2 info $0 ("Rate limit in action, not forwarding logs, if any!") true; } -$WaitFullyConnected; - :local Count 0; :local Duplicates false; :local Last [ $IfThenElse ([ :len $LogForwardLast ] > 0) [ $HexToNum $LogForwardLast ] -1 ]; From 194f14cc1394448575005f3d841ed54685ea879c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 May 2022 22:26:23 +0200 Subject: [PATCH 1099/2612] mod/bridge-port-vlan: remove left over comment --- mod/bridge-port-vlan | 1 - 1 file changed, 1 deletion(-) diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan index 6255dff..68bd2f2 100644 --- a/mod/bridge-port-vlan +++ b/mod/bridge-port-vlan @@ -8,7 +8,6 @@ :global BridgePortVlan; -# TODO :global BridgePortVlan do={ :local ConfigTo [ :tostr $1 ]; From 4e7c1df7ee2d4af96be78f76fc6d9a00e7f367ed Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 May 2022 22:27:01 +0200 Subject: [PATCH 1100/2612] mod/bridge-port-vlan: add interface down and up This helps the client to detect the change. --- mod/bridge-port-vlan | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan index 68bd2f2..b880c82 100644 --- a/mod/bridge-port-vlan +++ b/mod/bridge-port-vlan @@ -49,7 +49,10 @@ /ip/dhcp-client/disable $DHCPClient; :delay 200ms; } + /interface/ethernet/disable [ find where name=$BridgePortVal->"interface" ]; /interface/bridge/port/set disabled=no pvid=$Vlan $BridgePort; + :delay 500ms; + /interface/ethernet/enable [ find where name=$BridgePortVal->"interface" ]; } else={ $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \ " vlan " . $Vlan . ".") false; From 8c31a06b39fbb8c103a9f9e63be56f1bf47d914c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 16 May 2022 22:48:26 +0200 Subject: [PATCH 1101/2612] mod/bridge-port-to: add interface down and up This helps the client to detect the change. --- mod/bridge-port-to | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mod/bridge-port-to b/mod/bridge-port-to index c2ab55b..36b827b 100644 --- a/mod/bridge-port-to +++ b/mod/bridge-port-to @@ -42,7 +42,10 @@ /ip/dhcp-client/disable $DHCPClient; :delay 200ms; } + /interface/ethernet/disable [ find where name=$BridgePortVal->"interface" ]; /interface/bridge/port/set disabled=no bridge=$BridgeDefault $BridgePort; + :delay 500ms; + /interface/ethernet/enable [ find where name=$BridgePortVal->"interface" ]; } else={ $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ " bridge " . $BridgeDefault . ".") false; From 3139b14c67d2aacdba4001795c299283f9de5ebd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 17 May 2022 21:11:03 +0200 Subject: [PATCH 1102/2612] global-functions: $FlushEmailQueue: return if time is not synced The local system time is used in the mail header. We do not want the mails to be sent in the past, so return early (and thus wait for time being synced). --- global-functions | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/global-functions b/global-functions index 51c87bc..713a284 100644 --- a/global-functions +++ b/global-functions @@ -344,10 +344,16 @@ :global EitherOr; :global LogPrintExit2; + :global TimeIsSync; :local AllDone true; :local QueueLen [ :len $EmailQueue ]; + :if ([ $TimeIsSync ] = false) do={ + $LogPrintExit2 debug $0 ("Time is not synced, not flushing.") false; + :return false; + } + :if ([ :len [ /system/scheduler/find where name="FlushEmailQueue" ] ] > 0 && $QueueLen = 0) do={ $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; } From 89f4c91ccf35b65905dda8ce584d8a53faf6c957 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 May 2022 08:33:22 +0200 Subject: [PATCH 1103/2612] log-forward: change symbol for notification --- global-functions | 1 + log-forward | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 713a284..7266861 100644 --- a/global-functions +++ b/global-functions @@ -1082,6 +1082,7 @@ "incoming-envelope"="\F0\9F\93\A8"; "link"="\F0\9F\94\97"; "lock-with-ink-pen"="\F0\9F\94\8F"; + "memo"="\F0\9F\93\9D"; "mobile-phone"="\F0\9F\93\B1"; "pushpin"="\F0\9F\93\8C"; "scissors"="\E2\9C\82"; diff --git a/log-forward b/log-forward index bb57522..3867519 100644 --- a/log-forward +++ b/log-forward @@ -47,7 +47,7 @@ $ScriptLock $0; :local MessageDups [ :toarray "" ]; :local LogForwardFilterLogForwarding ("^" . [ $EscapeForRegEx ("Error sending e-mail <" . \ - [ $QuotedPrintable ("[" . $Identity . "] " . [ $SymbolForNotification "warning-sign" ] . \ + [ $QuotedPrintable ("[" . $Identity . "] " . [ $SymbolForNotification "memo" ] . \ "Log Forwarding") ] . ">:") ]); :foreach Message in=[ /log/find where (!(message="") and !(message~$LogForwardFilterLogForwarding) and \ !(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \ @@ -69,7 +69,7 @@ $ScriptLock $0; :if ($Count > 0) do={ $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "warning-sign" ] . "Log Forwarding"); \ + subject=([ $SymbolForNotification "memo" ] . "Log Forwarding"); \ message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) \ "this message" ("these " . $Count . " messages") ] . " after " . \ [ /system/resource/get uptime ] . " uptime." . [ $IfThenElse ($Duplicates = true) \ From 61c9b29ec33ef249bb7b4371b0a213fa4ff4e2c7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 20 May 2022 08:48:06 +0200 Subject: [PATCH 1104/2612] log-forward: use warning-sign for severity warning and up --- log-forward | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/log-forward b/log-forward index 3867519..55df2dc 100644 --- a/log-forward +++ b/log-forward @@ -19,6 +19,7 @@ :global LogForwardRateLimit; :global NotificationsWithSymbols; +:global CharacterReplace; :global EscapeForRegEx; :global HexToNum; :global IfThenElse; @@ -26,6 +27,7 @@ :global QuotedPrintable; :global ScriptLock; :global SendNotification2; +:global SymbolByUnicodeName; :global SymbolForNotification; $ScriptLock $0; @@ -43,12 +45,13 @@ $ScriptLock $0; :local Duplicates false; :local Last [ $IfThenElse ([ :len $LogForwardLast ] > 0) [ $HexToNum $LogForwardLast ] -1 ]; :local Messages ""; +:local Warning false; :local MessageVal; :local MessageDups [ :toarray "" ]; -:local LogForwardFilterLogForwarding ("^" . [ $EscapeForRegEx ("Error sending e-mail <" . \ - [ $QuotedPrintable ("[" . $Identity . "] " . [ $SymbolForNotification "memo" ] . \ - "Log Forwarding") ] . ">:") ]); +:local LogForwardFilterLogForwarding ("^" . [ $CharacterReplace [ $EscapeForRegEx ("Error sending e-mail <" . \ + [ $QuotedPrintable ("[" . $Identity . "] %SYMBOLREGEX%Log Forwarding") ] . ">:") ] "%SYMBOLREGEX%" \ + ("((" . [ $SymbolByUnicodeName "memo" ] . "|" . [ $SymbolByUnicodeName "warning-sign" ] . ") )?") ]); :foreach Message in=[ /log/find where (!(message="") and !(message~$LogForwardFilterLogForwarding) and \ !(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \ topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={ @@ -56,6 +59,9 @@ $ScriptLock $0; :if ($Last < [ $HexToNum ($MessageVal->".id") ]) do={ :local DupCount ($MessageDups->($MessageVal->"message")); + :if ($MessageVal->"topics" ~ "(emergency|alert|critical|error|warning)") do={ + :set Warning true; + } :if ($DupCount < 3) do={ :set Messages ($Messages . "\n" . [ $IfThenElse ($NotificationsWithSymbols = true) (" \E2\97\8F ") ] . \ $MessageVal->"time" . " " . [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message"); @@ -69,7 +75,8 @@ $ScriptLock $0; :if ($Count > 0) do={ $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "memo" ] . "Log Forwarding"); \ + subject=([ $SymbolForNotification [ $IfThenElse ($Warning = true) "warning-sign" "memo" ] ] . \ + "Log Forwarding"); \ message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) \ "this message" ("these " . $Count . " messages") ] . " after " . \ [ /system/resource/get uptime ] . " uptime." . [ $IfThenElse ($Duplicates = true) \ From 3d8ca10a91d394670a52137135c2bd56b07de8b9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Jun 2022 10:46:35 +0200 Subject: [PATCH 1105/2612] mod/bridge-port-to: re-enable interfaces with longer delay... ... and in one go to limit the overall runtime. Looks like IPv6 addresses are not flushed if the link down does not last long enough (~ 2 seconds on linux). This results on stale addresses after switching bridge, which breaks connectivity. --- mod/bridge-port-to | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mod/bridge-port-to b/mod/bridge-port-to index 36b827b..dec5eb1 100644 --- a/mod/bridge-port-to +++ b/mod/bridge-port-to @@ -17,6 +17,7 @@ :foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={ :local BridgePortVal [ /interface/bridge/port/get $BridgePort ]; + :local InterfaceReEnable [ :toarray "" ]; :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ :if ($Config = $BridgePortTo) do={ :local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; @@ -44,8 +45,7 @@ } /interface/ethernet/disable [ find where name=$BridgePortVal->"interface" ]; /interface/bridge/port/set disabled=no bridge=$BridgeDefault $BridgePort; - :delay 500ms; - /interface/ethernet/enable [ find where name=$BridgePortVal->"interface" ]; + :set InterfaceReEnable ($InterfaceReEnable, $BridgePortVal->"interface"); } else={ $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ " bridge " . $BridgeDefault . ".") false; @@ -53,5 +53,11 @@ } } } + :if ([ :len $InterfaceReEnable ] > 0) do={ + :delay 2s; + :foreach Interface in=$InterfaceReEnable do={ + /interface/ethernet/enable [ find where name=$Interface ]; + } + } } } From 9942918580a486cfabd6bdec8783fc8069372429 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Jun 2022 10:37:31 +0200 Subject: [PATCH 1106/2612] mod/bridge-port-vlan: re-enable interfaces with longer delay... ... and in one go to limit the overall runtime. Looks like IPv6 addresses are not flushed if the link down does not last long enough (~ 2 seconds on linux). This results on stale addresses after switching the vlan, which breaks connectivity. --- mod/bridge-port-vlan | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan index b880c82..13352b5 100644 --- a/mod/bridge-port-vlan +++ b/mod/bridge-port-vlan @@ -17,6 +17,7 @@ :foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={ :local BridgePortVal [ /interface/bridge/port/get $BridgePort ]; + :local InterfaceReEnable [ :toarray "" ]; :foreach Config,Vlan in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ :if ($Config = $ConfigTo) do={ :local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; @@ -51,8 +52,7 @@ } /interface/ethernet/disable [ find where name=$BridgePortVal->"interface" ]; /interface/bridge/port/set disabled=no pvid=$Vlan $BridgePort; - :delay 500ms; - /interface/ethernet/enable [ find where name=$BridgePortVal->"interface" ]; + :set InterfaceReEnable ($InterfaceReEnable, $BridgePortVal->"interface"); } else={ $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \ " vlan " . $Vlan . ".") false; @@ -60,5 +60,11 @@ } } } + :if ([ :len $InterfaceReEnable ] > 0) do={ + :delay 2s; + :foreach Interface in=$InterfaceReEnable do={ + /interface/ethernet/enable [ find where name=$Interface ]; + } + } } } From 09d88ad91c62bd00a24ea75d41d340e5bcc2d8b8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Jun 2022 10:55:11 +0200 Subject: [PATCH 1107/2612] mod/bridge-port-vlan: show vlan name in log message --- mod/bridge-port-vlan | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan index 13352b5..efdaab8 100644 --- a/mod/bridge-port-vlan +++ b/mod/bridge-port-vlan @@ -36,6 +36,7 @@ /ip/dhcp-client/enable $DHCPClient; } } else={ + :local VlanName $Vlan; :if ($Vlan != [ :tostr [ :tonum $Vlan ] ]) do={ :do { :set $Vlan ([ /interface/bridge/vlan/get [ find where comment=$Vlan ] vlan-ids ]->0); @@ -45,7 +46,7 @@ } :if ($BridgePortVal->"disabled" = true || $Vlan != $BridgePortVal->"pvid") do={ $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $ConfigTo . \ - " vlan " . $Vlan . ", disabling dhcp client.") false; + " vlan " . $Vlan . [ $IfThenElse ($Vlan != $VlanName) (" (" . $VlanName . ")") ] . ", disabling dhcp client.") false; :if ([ :len $DHCPClient ] = 1) do={ /ip/dhcp-client/disable $DHCPClient; :delay 200ms; From f0f05be8a9663fab7f1fcdf0931465654a77d9bd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Jun 2022 11:05:30 +0200 Subject: [PATCH 1108/2612] log-forward: inform about rate limit in notification --- log-forward | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/log-forward b/log-forward index 55df2dc..6ccf39c 100644 --- a/log-forward +++ b/log-forward @@ -74,15 +74,17 @@ $ScriptLock $0; } :if ($Count > 0) do={ + :set LogForwardRateLimit ($LogForwardRateLimit + 10); + $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification [ $IfThenElse ($Warning = true) "warning-sign" "memo" ] ] . \ "Log Forwarding"); \ - message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) \ - "this message" ("these " . $Count . " messages") ] . " after " . \ - [ /system/resource/get uptime ] . " uptime." . [ $IfThenElse ($Duplicates = true) \ - (" Multi-repeated messages have been skipped.") ] . "\n" . $Messages) }); + message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) "this message" \ + ("these " . $Count . " messages") ] . " after " . [ /system/resource/get uptime ] . " uptime." . \ + [ $IfThenElse ($Duplicates = true) (" Multi-repeated messages have been skipped.") ] . \ + [ $IfThenElse ($LogForwardRateLimit > 30) ("\nRate limit in action, delaying forwarding.") ] . \ + "\n" . $Messages) }); - :set LogForwardRateLimit ($LogForwardRateLimit + 10); :set LogForwardLast ($MessageVal->".id"); } else={ :if ($LogForwardRateLimit > 0) do={ From 648ce9c3bdbb9ce36359dc2fe6c9c2fafb207cae Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 5 Jun 2022 22:50:23 +0200 Subject: [PATCH 1109/2612] doc/mod/notification-matrix: how to use the function --- doc/mod/notification-matrix.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index 3da5659..c5003e0 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -90,6 +90,16 @@ Usage and invocation There's nothing special to do. Every script or function sending a notification will now send it to your Matrix account. +But of course you can send notifications directly or use a function in your +own scripts. Give it a try: + + $SendMatrix "Subject..." "Body..." + +Alternatively this sends a notification with all available and configured +methods: + + $SendNotification "Subject..." "Body..." + See also -------- From aa7e9adbd7dff399ffbf677ca7dc8e70bb6b18b6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 5 Jun 2022 22:50:57 +0200 Subject: [PATCH 1110/2612] doc/mod/notification-telegram: how to use the function --- doc/mod/notification-telegram.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index 435694e..3bb31a7 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -53,6 +53,16 @@ Usage and invocation There's nothing special to do. Every script or function sending a notification will now send it to your Telegram account. +But of course you can send notifications directly or use a function in your +own scripts. Give it a try: + + $SendTelegram "Subject..." "Body..." + +Alternatively this sends a notification with all available and configured +methods: + + $SendNotification "Subject..." "Body..." + See also -------- From e9780d9b4e07af9b09446fc74ae43f31aba1a233 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 Jun 2022 19:36:14 +0200 Subject: [PATCH 1111/2612] log-forward: fix the pattern excluding mail errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This looked smart, but did not work... đŸ¤Ē Unicode characters have to be in place to make $QuotedPrintable have an effect. So fix it... We have duplicate pattern if symbols are disabled, but that does not hurt. --- log-forward | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/log-forward b/log-forward index 6ccf39c..63c7ea7 100644 --- a/log-forward +++ b/log-forward @@ -19,7 +19,6 @@ :global LogForwardRateLimit; :global NotificationsWithSymbols; -:global CharacterReplace; :global EscapeForRegEx; :global HexToNum; :global IfThenElse; @@ -49,9 +48,11 @@ $ScriptLock $0; :local MessageVal; :local MessageDups [ :toarray "" ]; -:local LogForwardFilterLogForwarding ("^" . [ $CharacterReplace [ $EscapeForRegEx ("Error sending e-mail <" . \ - [ $QuotedPrintable ("[" . $Identity . "] %SYMBOLREGEX%Log Forwarding") ] . ">:") ] "%SYMBOLREGEX%" \ - ("((" . [ $SymbolByUnicodeName "memo" ] . "|" . [ $SymbolByUnicodeName "warning-sign" ] . ") )?") ]); +:local LogForwardFilterLogForwarding ("^Error sending e-mail <(" . \ + [ $EscapeForRegEx [ $QuotedPrintable ("[" . $Identity . "] " . \ + [ $SymbolForNotification "memo" ] . "Log Forwarding") ] ] . "|" . \ + [ $EscapeForRegEx [ $QuotedPrintable ("[" . $Identity . "] " . \ + [ $SymbolForNotification "warning-sign" ] . "Log Forwarding") ] ] . ")>:"); :foreach Message in=[ /log/find where (!(message="") and !(message~$LogForwardFilterLogForwarding) and \ !(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \ topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={ From 782bbb2c90860e36bac9242f35bcae9f8c768f96 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 Jun 2022 21:30:55 +0200 Subject: [PATCH 1112/2612] doc/mod/bridge-port-to: fix scheduler name --- doc/mod/bridge-port-to.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mod/bridge-port-to.md b/doc/mod/bridge-port-to.md index 2b42a9b..f86b21d 100644 --- a/doc/mod/bridge-port-to.md +++ b/doc/mod/bridge-port-to.md @@ -35,7 +35,7 @@ Also dhcp client can be handled: Add a scheduler to start with default setup on system startup: $ScriptInstallUpdate global-wait; - /system/scheduler/add name=bridge-port-vlan on-event="/system/script/run global-wait; :global BridgePortTo; \$BridgePortTo default;" start-time=startup; + /system/scheduler/add name=bridge-port-to on-event="/system/script/run global-wait; :global BridgePortTo; \$BridgePortTo default;" start-time=startup; Usage and invocation -------------------- From c7087ac4fe9d4cde0755b241ce5326ae5e11bb98 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 Jun 2022 21:20:10 +0200 Subject: [PATCH 1113/2612] rotate-ntp: do not flood the log on weak connection --- rotate-ntp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rotate-ntp b/rotate-ntp index 2a095f8..73b9d8a 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -11,6 +11,7 @@ :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :global NtpPool; +:global RotateNtpResolveFailed; :global LogPrintExit2; @@ -24,8 +25,14 @@ :do { :set Ntp1 [ :resolve ("0." . $NtpPool) ]; :set Ntp2 [ :resolve ("1." . $NtpPool) ]; + :set RotateNtpResolveFailed false; } on-error={ - $LogPrintExit2 warning $0 ("Resolving NTP server failed.") true; + :if ($RotateNtpResolveFailed != true) do={ + :set RotateNtpResolveFailed true; + $LogPrintExit2 warning $0 ("Resolving NTP server failed.") true; + } else={ + $LogPrintExit2 debug $0 ("Resolving NTP server failed.") true; + } } $LogPrintExit2 info $0 ("Updating NTP servers to " . $Ntp1 . " and " . $Ntp2) false; From dafeeabdb44cd71e8f5d1bf396b9ffab3b97f220 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 10 Jun 2022 11:21:33 +0200 Subject: [PATCH 1114/2612] rotate-ntp: update message to indicate resolve failed again --- rotate-ntp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rotate-ntp b/rotate-ntp index 73b9d8a..4446cba 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -31,7 +31,7 @@ :set RotateNtpResolveFailed true; $LogPrintExit2 warning $0 ("Resolving NTP server failed.") true; } else={ - $LogPrintExit2 debug $0 ("Resolving NTP server failed.") true; + $LogPrintExit2 debug $0 ("Resolving NTP server failed, again.") true; } } From e9f00df290ca563ae44b66b41d0830ab2ce24252 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Jun 2022 21:24:34 +0200 Subject: [PATCH 1115/2612] global-config-overlay: fix $GlobalConfigVersion... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks like I missed this in commit 5e481a768b4cea4534f5f775ce565a79cb1e3eb9. đŸ˜ŗ --- global-config-overlay | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config-overlay b/global-config-overlay index d5df364..48daf8e 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 79; +:global GlobalConfigVersion 80; # Copy configuration from global-config here and modify it. From 5b3b3e182b46f8434f083d1b46eee485f3d0116d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Jun 2022 09:59:22 +0200 Subject: [PATCH 1116/2612] mod/bridge-port-vlan: move reenable to correct level --- mod/bridge-port-vlan | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan index efdaab8..fbdcda7 100644 --- a/mod/bridge-port-vlan +++ b/mod/bridge-port-vlan @@ -15,9 +15,9 @@ :global LogPrintExit2; :global ParseKeyValueStore; + :local InterfaceReEnable [ :toarray "" ]; :foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={ :local BridgePortVal [ /interface/bridge/port/get $BridgePort ]; - :local InterfaceReEnable [ :toarray "" ]; :foreach Config,Vlan in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ :if ($Config = $ConfigTo) do={ :local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; @@ -61,11 +61,11 @@ } } } - :if ([ :len $InterfaceReEnable ] > 0) do={ - :delay 2s; - :foreach Interface in=$InterfaceReEnable do={ - /interface/ethernet/enable [ find where name=$Interface ]; - } + } + :if ([ :len $InterfaceReEnable ] > 0) do={ + :delay 2s; + :foreach Interface in=$InterfaceReEnable do={ + /interface/ethernet/enable [ find where name=$Interface ]; } } } From 5dc23dd26743b788b891b4f3fb3ea6a7dbbc5941 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Jun 2022 09:59:50 +0200 Subject: [PATCH 1117/2612] mod/bridge-port-to: move reenable to correct level --- mod/bridge-port-to | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mod/bridge-port-to b/mod/bridge-port-to index dec5eb1..415a04d 100644 --- a/mod/bridge-port-to +++ b/mod/bridge-port-to @@ -15,9 +15,9 @@ :global LogPrintExit2; :global ParseKeyValueStore; + :local InterfaceReEnable [ :toarray "" ]; :foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={ :local BridgePortVal [ /interface/bridge/port/get $BridgePort ]; - :local InterfaceReEnable [ :toarray "" ]; :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ :if ($Config = $BridgePortTo) do={ :local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; @@ -53,11 +53,11 @@ } } } - :if ([ :len $InterfaceReEnable ] > 0) do={ - :delay 2s; - :foreach Interface in=$InterfaceReEnable do={ - /interface/ethernet/enable [ find where name=$Interface ]; - } + } + :if ([ :len $InterfaceReEnable ] > 0) do={ + :delay 2s; + :foreach Interface in=$InterfaceReEnable do={ + /interface/ethernet/enable [ find where name=$Interface ]; } } } From 1e894289ea26a7f2b3a55b21787a7af09bbfc9ac Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Jun 2022 10:33:34 +0200 Subject: [PATCH 1118/2612] mod/bridge-port-vlan: log when re-enabling interfaces --- mod/bridge-port-vlan | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan index fbdcda7..f8acca8 100644 --- a/mod/bridge-port-vlan +++ b/mod/bridge-port-vlan @@ -11,6 +11,7 @@ :global BridgePortVlan do={ :local ConfigTo [ :tostr $1 ]; + :global CharacterReplace; :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; @@ -64,6 +65,8 @@ } :if ([ :len $InterfaceReEnable ] > 0) do={ :delay 2s; + $LogPrintExit2 info $0 ("Re-enabling interfaces: " . \ + [ $CharacterReplace [ :tostr $InterfaceReEnable ] ";" " " ]) false; :foreach Interface in=$InterfaceReEnable do={ /interface/ethernet/enable [ find where name=$Interface ]; } From 66b7fccd303137d68cf571e79a0ffd7ca82f4b6a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Jun 2022 10:33:58 +0200 Subject: [PATCH 1119/2612] mod/bridge-port-to: log when re-enabling interfaces --- mod/bridge-port-to | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mod/bridge-port-to b/mod/bridge-port-to index 415a04d..d53283d 100644 --- a/mod/bridge-port-to +++ b/mod/bridge-port-to @@ -11,6 +11,7 @@ :set BridgePortTo do={ :local BridgePortTo [ :tostr $1 ]; + :global CharacterReplace; :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; @@ -56,6 +57,8 @@ } :if ([ :len $InterfaceReEnable ] > 0) do={ :delay 2s; + $LogPrintExit2 info $0 ("Re-enabling interfaces: " . \ + [ $CharacterReplace [ :tostr $InterfaceReEnable ] ";" " " ]) false; :foreach Interface in=$InterfaceReEnable do={ /interface/ethernet/enable [ find where name=$Interface ]; } From b3de1fad3459aa886b3ca3e1f1f91066ab0730b6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 14 Jun 2022 21:17:01 +0200 Subject: [PATCH 1120/2612] drop script 'rotate-ntp' For RouterOS 6.x a separate package 'ntp' exists. This adds server functionality, but allows ip addresses for the client only. I added the script 'rotate-ntp' to update addresses from names... Now with RouterOS 7.x there's no extra package and the limitation does no longer exist. So let's just drop the script. This adds migration code, that... * removes the script from configuration * removes a scheduler from configuration * sets the configured ntp pool name for ntp client --- README.md | 1 - doc/rotate-ntp.md | 46 +++---------------------------------------- global-config | 6 +----- global-config-overlay | 2 +- global-config.changes | 2 ++ global-functions | 10 +--------- rotate-ntp | 39 +----------------------------------- 7 files changed, 9 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index df3cb9e..6eb035f 100644 --- a/README.md +++ b/README.md @@ -194,7 +194,6 @@ Available scripts * [Visualize OSPF state via LEDs](doc/ospf-to-leds.md) * [Manage system update](doc/packages-update.md) * [Run scripts on ppp connection](doc/ppp-on-up.md) -* [Rotate NTP servers](doc/rotate-ntp.md) * [Act on received SMS](doc/sms-action.md) * [Forward received SMS](doc/sms-forward.md) * [Import SSH keys](doc/ssh-keys-import.md) diff --git a/doc/rotate-ntp.md b/doc/rotate-ntp.md index f548eba..9a016a3 100644 --- a/doc/rotate-ntp.md +++ b/doc/rotate-ntp.md @@ -1,43 +1,3 @@ -Rotate NTP servers -================== - -[◀ Go back to main README](../README.md) - -> â„šī¸ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. - -Description ------------ - -RouterOS requires NTP servers to be configured by IP address. Servers from a -pool may appear and disappear, leaving broken NTP configuration. - -This script allows to rotate IP addresses from a given pool. - -Requirements and installation ------------------------------ - -Just install the script: - - $ScriptInstallUpdate rotate-ntp; - -Configuration -------------- - -The configuration goes to `global-config-overlay`, this is the parameter: - -* `NtpPool`: dns name of ntp server pool - -Usage and invocation --------------------- - -Just run the script to update the NTP configuration with actual IP -addresses from pool if required. - -Alternatively a scheduler can be created: - - /system/scheduler/add interval=5d name=rotate-ntp on-event="/system/script/run rotate-ntp;" start-time=startup; - ---- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +This script has been dropped as the limitation does no longer exist with +RouterOS 7.x, where you can enable a ntp server and use a name for the client +at the same time. diff --git a/global-config b/global-config index 70d8a2f..b1f4770 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 80; +:global GlobalConfigVersion 81; # This is used for DNS and backup file. :global Domain "example.com"; @@ -146,10 +146,6 @@ # add more here... }; -# This address should resolve ntp servers and is used to update -# ntp settings. A pool can rotate servers. -:global NtpPool "pool.ntp.org"; - # This is the address used to send gps data to. :global GpsTrackUrl "https://example.com/index.php"; diff --git a/global-config-overlay b/global-config-overlay index 48daf8e..eaa43f6 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 80; +:global GlobalConfigVersion 81; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index e317b02..04f88e7 100644 --- a/global-config.changes +++ b/global-config.changes @@ -89,6 +89,7 @@ 78="New documentation is online for notifications via Telegram & Matrix, variable inspection, ip address calculation and running scripts once."; 79="Introduced new script 'backup-partition' to save configuration to fallback partition."; 80="The 'routeros-v7' branch will now freeze, and vanish any time in future. You already switched to 'main' branch, well done!"; + 81="Dropped script 'rotate-ntp', as the limitation does no longer exist."; }; # Migration steps to be applied on script updates @@ -101,4 +102,5 @@ 66=":global ScriptInstallUpdate; :if ([ :len [ /system/script/find where name=\"bridge-port-to-default\" ] ] > 0) do={ /system/script/remove [ find where name~\"^bridge-port-to(-default|ggle)\\\$\" ]; \$ScriptInstallUpdate mod/bridge-port-to; }"; 67=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Script in=[ /system/script/find where name~\"^global-functions.d/\" ] do={ /system/script/set name=[ \$CharacterReplace [ /system/script/get \$Script name ] \"global-functions.d/\" \"mod/\" ] \$Script; }; \$ScriptInstallUpdate;"; 73=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Old,New in={ \"cloud-backup\"=\"backup-cloud\"; \"email-backup\"=\"backup-email\"; \"upload-backup\"=\"backup-upload\" } do={ /system/script/set name=\$New [ find where name=\$Old ]; :foreach Scheduler in=[ /system/scheduler/find where on-event~\$Old ] do={ /system/scheduler/set \$Scheduler name=[ \$CharacterReplace [ get \$Scheduler name ] \$Old \$New ] on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Old \$New ]; }; }; \$ScriptInstallUpdate;"; + 81=":global NtpPool; :if ([ :len [ /system/script/find where name=\"rotate-ntp\" ] ] > 0) do={ /system/script/remove [ find where name=\"rotate-ntp\" ]; /system/scheduler/remove [ find where name=\"rotate-ntp\" ]; /system/ntp/client/set servers=\$NtpPool; };"; }; diff --git a/global-functions b/global-functions index 7266861..c12bd54 100644 --- a/global-functions +++ b/global-functions @@ -10,7 +10,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 80; +:global ExpectedConfigVersion 81; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -1260,14 +1260,6 @@ :global TimeIsSync; :while ([ $TimeIsSync ] = false) do={ - :if ([ :len [ /system/script/find where name="rotate-ntp" ] ] > 0 && \ - ([ /system/resource/get uptime ] % (180 * 1000000000)) = 0s) do={ - :do { - /system/script/run rotate-ntp; - } on-error={ - $LogPrintExit2 debug $0 ("Running rotate-ntp failed.") false; - } - } :delay 1s; } } diff --git a/rotate-ntp b/rotate-ntp index 4446cba..9374129 100644 --- a/rotate-ntp +++ b/rotate-ntp @@ -1,39 +1,2 @@ #!rsc by RouterOS -# RouterOS script: rotate-ntp -# Copyright (c) 2013-2022 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# rotate the ntp servers -# https://git.eworm.de/cgit/routeros-scripts/about/doc/rotate-ntp.md - -:local 0 "rotate-ntp"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global NtpPool; -:global RotateNtpResolveFailed; - -:global LogPrintExit2; - -:local Ntp1; -:local Ntp2; - -:if ([ /system/ntp/client/get enabled ] != true) do={ - $LogPrintExit2 warning $0 ("NTP client is not enabled!") true; -} - -:do { - :set Ntp1 [ :resolve ("0." . $NtpPool) ]; - :set Ntp2 [ :resolve ("1." . $NtpPool) ]; - :set RotateNtpResolveFailed false; -} on-error={ - :if ($RotateNtpResolveFailed != true) do={ - :set RotateNtpResolveFailed true; - $LogPrintExit2 warning $0 ("Resolving NTP server failed.") true; - } else={ - $LogPrintExit2 debug $0 ("Resolving NTP server failed, again.") true; - } -} - -$LogPrintExit2 info $0 ("Updating NTP servers to " . $Ntp1 . " and " . $Ntp2) false; -/system/ntp/client/set servers=($Ntp1, $Ntp2); +# dummy for removal From 3002990319d44cdd41569b3258df7c04e4437149 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Jun 2022 23:56:36 +0200 Subject: [PATCH 1121/2612] fix typos: 'at lease' -> 'at least' --- doc/ip-addr-bridge.md | 2 +- global-functions | 4 ++-- mod/notification-matrix | 2 +- mod/notification-telegram | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/ip-addr-bridge.md b/doc/ip-addr-bridge.md index 75685bb..f0b593e 100644 --- a/doc/ip-addr-bridge.md +++ b/doc/ip-addr-bridge.md @@ -21,7 +21,7 @@ Just install the script: /system/scheduler/add name=ip-addr-bridge on-event="/system/script/run ip-addr-bridge;" start-time=startup; -This will disable IP addresses on bridges without at lease one running port. +This will disable IP addresses on bridges without at least one running port. The IP address is enabled if at least one port is running. Note that IP addresses on bridges without a single port (acting as loopback diff --git a/global-functions b/global-functions index c12bd54..0ac0a87 100644 --- a/global-functions +++ b/global-functions @@ -1031,7 +1031,7 @@ :return true; } -# send notification via e-mail - expects at lease two string arguments +# send notification via e-mail - expects at least two string arguments :set SendEMail do={ :global SendEMail2; @@ -1047,7 +1047,7 @@ ($NotificationFunctions->"email") ("\$NotificationFunctions->\"email\"") $Notification; } -# send notification via NotificationFunctions - expects at lease two string arguments +# send notification via NotificationFunctions - expects at least two string arguments :set SendNotification do={ :global SendNotification2; diff --git a/mod/notification-matrix b/mod/notification-matrix index c3cf24f..8a74a1c 100644 --- a/mod/notification-matrix +++ b/mod/notification-matrix @@ -140,7 +140,7 @@ } } -# send notification via Matrix - expects at lease two string arguments +# send notification via Matrix - expects at least two string arguments :set SendMatrix do={ :global SendMatrix2; diff --git a/mod/notification-telegram b/mod/notification-telegram index 230dd57..7b41c5e 100644 --- a/mod/notification-telegram +++ b/mod/notification-telegram @@ -147,7 +147,7 @@ } } -# send notification via telegram - expects at lease two string arguments +# send notification via telegram - expects at least two string arguments :set SendTelegram do={ :global SendTelegram2; From f628ef73fd6f5568007d8988ca2106757aff00dc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jun 2022 00:04:24 +0200 Subject: [PATCH 1122/2612] global-functions: $WaitTimeSync: drop declaration of unused function --- global-functions | 1 - 1 file changed, 1 deletion(-) diff --git a/global-functions b/global-functions index 0ac0a87..050045b 100644 --- a/global-functions +++ b/global-functions @@ -1256,7 +1256,6 @@ # wait for time to become synced :set WaitTimeSync do={ - :global LogPrintExit2; :global TimeIsSync; :while ([ $TimeIsSync ] = false) do={ From 0ee38a4303cb608d716c09b06cd7319ea7c5b398 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jun 2022 00:17:26 +0200 Subject: [PATCH 1123/2612] global-functions: rename internal function: $DefaultRouteIsReachable -> $IsDefaultRouteReachable --- global-functions | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/global-functions b/global-functions index 050045b..0440c31 100644 --- a/global-functions +++ b/global-functions @@ -22,7 +22,6 @@ :global CertificateNameByCN; :global CharacterReplace; :global CleanFilePath; -:global DefaultRouteIsReachable; :global DeviceInfo; :global DNSIsResolving; :global DownloadPackage; @@ -34,6 +33,7 @@ :global GetRandomNumber; :global HexToNum; :global IfThenElse; +:global IsDefaultRouteReachable; :global LogPrintExit2; :global MkDir; :global NotificationFunctions; @@ -183,14 +183,6 @@ :return $Path; } -# default route is reachable -:set DefaultRouteIsReachable do={ - :if ([ :len [ /ip/route/find where dst-address=0.0.0.0/0 active routing-table=main ] ] > 0) do={ - :return true; - } - :return false; -} - # get readable device info :set DeviceInfo do={ :global ExpectedConfigVersion; @@ -462,6 +454,14 @@ :return $3; } +# check if default route is reachable +:set IsDefaultRouteReachable do={ + :if ([ :len [ /ip/route/find where dst-address=0.0.0.0/0 active routing-table=main ] ] > 0) do={ + :return true; + } + :return false; +} + # log and print with same text, optionally exit :set LogPrintExit2 do={ :local Severity [ :tostr $1 ]; @@ -1208,9 +1208,9 @@ # wait for default route to be reachable :set WaitDefaultRouteReachable do={ - :global DefaultRouteIsReachable; + :global IsDefaultRouteReachable; - :while ([ $DefaultRouteIsReachable ] = false) do={ + :while ([ $IsDefaultRouteReachable ] = false) do={ :delay 1s; } } From 9aa82316c8926773724e2dde24d58594c96bb832 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jun 2022 00:18:59 +0200 Subject: [PATCH 1124/2612] global-functions: rename internal function: $DNSIsResolving -> $IsDNSResolving --- global-functions | 30 +++++++++++++++--------------- netwatch-notify | 4 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/global-functions b/global-functions index 0440c31..79aedb7 100644 --- a/global-functions +++ b/global-functions @@ -23,7 +23,6 @@ :global CharacterReplace; :global CleanFilePath; :global DeviceInfo; -:global DNSIsResolving; :global DownloadPackage; :global EitherOr; :global EscapeForRegEx; @@ -34,6 +33,7 @@ :global HexToNum; :global IfThenElse; :global IsDefaultRouteReachable; +:global IsDNSResolving; :global LogPrintExit2; :global MkDir; :global NotificationFunctions; @@ -225,18 +225,6 @@ ("\n Expected: " . $ExpectedConfigVersion) ]); } -# check if DNS is resolving -:set DNSIsResolving do={ - :global CharacterReplace; - - :do { - :resolve "low-ttl.eworm.de"; - } on-error={ - :return false; - } - :return true; -} - # download package from upgrade server :set DownloadPackage do={ :local PkgName [ :tostr $1 ]; @@ -462,6 +450,18 @@ :return false; } +# check if DNS is resolving +:set IsDNSResolving do={ + :global CharacterReplace; + + :do { + :resolve "low-ttl.eworm.de"; + } on-error={ + :return false; + } + :return true; +} + # log and print with same text, optionally exit :set LogPrintExit2 do={ :local Severity [ :tostr $1 ]; @@ -1217,9 +1217,9 @@ # wait for DNS to resolve :set WaitDNSResolving do={ - :global DNSIsResolving; + :global IsDNSResolving; - :while ([ $DNSIsResolving ] = false) do={ + :while ([ $IsDNSResolving ] = false) do={ :delay 1s; } } diff --git a/netwatch-notify b/netwatch-notify index 47b7fa1..45b0c76 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -12,8 +12,8 @@ :global NetwatchNotify; -:global DNSIsResolving; :global IfThenElse; +:global IsDNSResolving; :global LogPrintExit2; :global ParseKeyValueStore; :global ScriptLock; @@ -67,7 +67,7 @@ $ScriptLock $0; } :if ([ :typeof ($HostInfo->"resolve") ] = "str") do={ - :if ([ $DNSIsResolving ] = true) do={ + :if ([ $IsDNSResolving ] = true) do={ :do { :local Resolve [ :resolve ($HostInfo->"resolve") ]; :if ($Resolve != $HostVal->"host") do={ From b1ad89b1b5d387bdde9527d80f62fcb9c5c4d4e1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jun 2022 00:23:00 +0200 Subject: [PATCH 1125/2612] global-functions: rename internal function: $TimeIsSync -> $IsTimeSync --- global-functions | 66 ++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/global-functions b/global-functions index 79aedb7..9745591 100644 --- a/global-functions +++ b/global-functions @@ -34,6 +34,7 @@ :global IfThenElse; :global IsDefaultRouteReachable; :global IsDNSResolving; +:global IsTimeSync; :global LogPrintExit2; :global MkDir; :global NotificationFunctions; @@ -51,7 +52,6 @@ :global SendNotification2; :global SymbolByUnicodeName; :global SymbolForNotification; -:global TimeIsSync; :global UrlEncode; :global ValidateSyntax; :global VersionToNum; @@ -323,13 +323,13 @@ :global EmailQueue; :global EitherOr; + :global IsTimeSync; :global LogPrintExit2; - :global TimeIsSync; :local AllDone true; :local QueueLen [ :len $EmailQueue ]; - :if ([ $TimeIsSync ] = false) do={ + :if ([ $IsTimeSync ] = false) do={ $LogPrintExit2 debug $0 ("Time is not synced, not flushing.") false; :return false; } @@ -462,6 +462,34 @@ :return true; } +# check if system time is sync +:set IsTimeSync do={ + :global LogPrintExit2; + + :if ([ /system/ntp/client/get enabled ] = true) do={ + :do { + :if ([ /system/ntp/client/get status ] = "synchronized") do={ + :return true; + } + } on-error={ + :if ([ :typeof [ /system/ntp/client/get last-adjustment ] ] = "time") do={ + :return true; + } + } + :return false; + } + + :if ([ /ip/cloud/get ddns-enabled ] = true && [ /ip/cloud/get update-time ] = true) do={ + :if ([ :typeof [ /ip/cloud/get public-address ] ] = "ip") do={ + :return true; + } + :return false; + } + + $LogPrintExit2 debug $0 ("No time source configured! Returning gracefully...") false; + :return true; +} + # log and print with same text, optionally exit :set LogPrintExit2 do={ :local Severity [ :tostr $1 ]; @@ -1110,34 +1138,6 @@ :return ($Return . " "); } -# check if system time is sync -:set TimeIsSync do={ - :global LogPrintExit2; - - :if ([ /system/ntp/client/get enabled ] = true) do={ - :do { - :if ([ /system/ntp/client/get status ] = "synchronized") do={ - :return true; - } - } on-error={ - :if ([ :typeof [ /system/ntp/client/get last-adjustment ] ] = "time") do={ - :return true; - } - } - :return false; - } - - :if ([ /ip/cloud/get ddns-enabled ] = true && [ /ip/cloud/get update-time ] = true) do={ - :if ([ :typeof [ /ip/cloud/get public-address ] ] = "ip") do={ - :return true; - } - :return false; - } - - $LogPrintExit2 debug $0 ("No time source configured! Returning gracefully...") false; - :return true; -} - # url encoding :set UrlEncode do={ :local Input [ :tostr $1 ]; @@ -1256,9 +1256,9 @@ # wait for time to become synced :set WaitTimeSync do={ - :global TimeIsSync; + :global IsTimeSync; - :while ([ $TimeIsSync ] = false) do={ + :while ([ $IsTimeSync ] = false) do={ :delay 1s; } } From d8d7ace5e54a6fdcc38eeb38ca2da15bb716694f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jun 2022 00:10:51 +0200 Subject: [PATCH 1126/2612] global-functions: introduce function $IsFullyConnected --- global-functions | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/global-functions b/global-functions index 9745591..bf9538c 100644 --- a/global-functions +++ b/global-functions @@ -34,6 +34,7 @@ :global IfThenElse; :global IsDefaultRouteReachable; :global IsDNSResolving; +:global IsFullyConnected; :global IsTimeSync; :global LogPrintExit2; :global MkDir; @@ -462,6 +463,24 @@ :return true; } +# check if system is is fully connected (default route reachable, DNS resolving, time sync) +:set IsFullyConnected do={ + :global IsDefaultRouteReachable; + :global IsDNSResolving; + :global IsTimeSync; + + :if ([ $IsDefaultRouteReachable ] = false) do={ + :return false; + } + :if ([ $IsDNSResolving ] = false) do={ + :return false; + } + :if ([ $IsTimeSync ] = false) do={ + :return false; + } + :return true; +} + # check if system time is sync :set IsTimeSync do={ :global LogPrintExit2; From cf59e7c1a213a2ce45a48344deda2897dc5db1e4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jun 2022 01:01:18 +0200 Subject: [PATCH 1127/2612] mod/notification-matrix: only flush queue if fully connected The fetch command is not as reliable as it should be... Chances were that notifications were sent multiple times if stuck in background. Let's flush only if fully connected - and hope this fixes it. --- mod/notification-matrix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mod/notification-matrix b/mod/notification-matrix index 8a74a1c..f905839 100644 --- a/mod/notification-matrix +++ b/mod/notification-matrix @@ -13,8 +13,14 @@ :set FlushMatrixQueue do={ :global MatrixQueue; + :global IsFullyConnected; :global LogPrintExit2; + :if ([ $IsFullyConnected ] = false) do={ + $LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false; + :return false; + } + :local AllDone true; :local QueueLen [ :len $MatrixQueue ]; From 8b6f830fe89c9550ed877f50eb6ab59c8fa05911 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 17 Jun 2022 00:57:11 +0200 Subject: [PATCH 1128/2612] mod/notification-telegram: only flush queue if fully connected The fetch command is not as reliable as it should be... Chances were that notifications were sent multiple times if stuck in background. Let's flush only if fully connected - and hope this fixes it. --- mod/notification-telegram | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mod/notification-telegram b/mod/notification-telegram index 7b41c5e..493aa00 100644 --- a/mod/notification-telegram +++ b/mod/notification-telegram @@ -12,8 +12,14 @@ :set FlushTelegramQueue do={ :global TelegramQueue; + :global IsFullyConnected; :global LogPrintExit2; + :if ([ $IsFullyConnected ] = false) do={ + $LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false; + :return false; + } + :local AllDone true; :local QueueLen [ :len $TelegramQueue ]; From fcd6e61849e9df92d3696eb5c5596a0625881d2c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 28 Jun 2022 21:05:50 +0200 Subject: [PATCH 1129/2612] global-functions: $ScriptInstallUpdate: remove script on failure when installing --- global-functions | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index bf9538c..3a2497e 100644 --- a/global-functions +++ b/global-functions @@ -808,7 +808,13 @@ :set SourceNew ($Result->"data"); } } on-error={ - $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!") false; + :if ($ScriptVal->"source" = "#!rsc by RouterOS\n") do={ + $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . \ + "', removing dummy. Typo on installation?") false; + /system/script/remove $Script; + } else={ + $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!") false; + } } } } From 6fdf115dcf08fc79ea509f641546965ee2193c80 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 28 Jun 2022 21:53:39 +0200 Subject: [PATCH 1130/2612] README: How to remove a script... --- README.d/13-remove-script.avif | Bin 0 -> 1093 bytes README.md | 12 ++++++++++++ 2 files changed, 12 insertions(+) create mode 100644 README.d/13-remove-script.avif diff --git a/README.d/13-remove-script.avif b/README.d/13-remove-script.avif new file mode 100644 index 0000000000000000000000000000000000000000..a5c7dafc45453f0312829fb9915ce401a333a2ce GIT binary patch literal 1093 zcmZQzU{FXasVqn=%S>Yc0uY^>nP!-qnV9D5Xy^zO`jnemk_eIm0*#E6oFWL5fuSHX zxdg@r(K(q(Fk|=%GD~v7a*RMyE;A=T8N_p8U|m{)#<&G+yk+l$wCYipB@i?8j#g0kF5<;p`^X{zwe*egd{?>p))1+3I2!flS^~kwyX2h z-cNcLu%>;(mcOj0o%Sr0N?En^JG;a*Ju|-}^WHl?o);Gsz}grkw9mDD?tG`I8^vsw z7cSu3Z*%$DjYGHWi<&?Gs^8p{eyn9{ohrZdvw3|bv*%@8KAgyQ?_Xc;t%W~Rf1KR> zYRgv!#lGOHN9*{zI9u(uB~ChS#CW~<=)EA9A2T?${H096jJ>=5%J_OZ7i2%Gq6Y`%7Gc?F&w1OU;uA@?V;5pWPhe z;Wsl?b+^6x`^#1GA!oiEX0x$8-I8x_R+wgRD_N`x_>ms9Sl27#lugyIdv<4M z<=keEsjvCCESK-kof9`-?oRd4mlt6E}-h3HT}o+f1)n^7LHYR4&$9YCH$P|^PKa$4cP1>HnF(9 zIhgFZYiDIohj5qp!uCu-CT;`9TbyrF*XPW2jo!Jso_o2ysotmEcb7-)st*$PJnrkB cp{AVp?T_iX Date: Wed, 29 Jun 2022 12:53:02 +0200 Subject: [PATCH 1131/2612] mod/bridge-port-vlan: do not act on missing interface Happens on broken configuration or early boot... --- mod/bridge-port-vlan | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan index f8acca8..a79bda0 100644 --- a/mod/bridge-port-vlan +++ b/mod/bridge-port-vlan @@ -52,9 +52,12 @@ /ip/dhcp-client/disable $DHCPClient; :delay 200ms; } - /interface/ethernet/disable [ find where name=$BridgePortVal->"interface" ]; + :local Disable [ /interface/ethernet/find where name=$BridgePortVal->"interface" ]; + :if ([ :len $Disable ] > 0) do={ + /interface/ethernet/disable $Disable; + :set InterfaceReEnable ($InterfaceReEnable, $BridgePortVal->"interface"); + } /interface/bridge/port/set disabled=no pvid=$Vlan $BridgePort; - :set InterfaceReEnable ($InterfaceReEnable, $BridgePortVal->"interface"); } else={ $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \ " vlan " . $Vlan . ".") false; From f26fb7c05feb8a56d6c567d67a60ee0229569fd4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jun 2022 12:53:50 +0200 Subject: [PATCH 1132/2612] mod/bridge-port-to: do not act on missing interface Happens on broken configuration or early boot... --- mod/bridge-port-to | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mod/bridge-port-to b/mod/bridge-port-to index d53283d..efeb02a 100644 --- a/mod/bridge-port-to +++ b/mod/bridge-port-to @@ -44,9 +44,12 @@ /ip/dhcp-client/disable $DHCPClient; :delay 200ms; } - /interface/ethernet/disable [ find where name=$BridgePortVal->"interface" ]; + :local Disable [ /interface/ethernet/find where name=$BridgePortVal->"interface" ]; + :if ([ :len $Disable ] > 0) do={ + /interface/ethernet/disable $Disable; + :set InterfaceReEnable ($InterfaceReEnable, $BridgePortVal->"interface"); + } /interface/bridge/port/set disabled=no bridge=$BridgeDefault $BridgePort; - :set InterfaceReEnable ($InterfaceReEnable, $BridgePortVal->"interface"); } else={ $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ " bridge " . $BridgeDefault . ".") false; From e27a0166baeb8ce711b113499a08c75c2750493f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 30 Jun 2022 08:59:08 +0200 Subject: [PATCH 1133/2612] mod/bridge-port-vlan: re-enable interfaces by id --- mod/bridge-port-vlan | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan index a79bda0..a43d7d7 100644 --- a/mod/bridge-port-vlan +++ b/mod/bridge-port-vlan @@ -11,7 +11,6 @@ :global BridgePortVlan do={ :local ConfigTo [ :tostr $1 ]; - :global CharacterReplace; :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; @@ -55,7 +54,7 @@ :local Disable [ /interface/ethernet/find where name=$BridgePortVal->"interface" ]; :if ([ :len $Disable ] > 0) do={ /interface/ethernet/disable $Disable; - :set InterfaceReEnable ($InterfaceReEnable, $BridgePortVal->"interface"); + :set InterfaceReEnable ($InterfaceReEnable, $Disable); } /interface/bridge/port/set disabled=no pvid=$Vlan $BridgePort; } else={ @@ -68,10 +67,7 @@ } :if ([ :len $InterfaceReEnable ] > 0) do={ :delay 2s; - $LogPrintExit2 info $0 ("Re-enabling interfaces: " . \ - [ $CharacterReplace [ :tostr $InterfaceReEnable ] ";" " " ]) false; - :foreach Interface in=$InterfaceReEnable do={ - /interface/ethernet/enable [ find where name=$Interface ]; - } + $LogPrintExit2 info $0 ("Re-enabling interfaces...") false; + /interface/ethernet/enable $InterfaceReEnable; } } From 3434ea9d79e35f90b605a6397f8091da354be42b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 30 Jun 2022 08:59:27 +0200 Subject: [PATCH 1134/2612] mod/bridge-port-to: re-enable interfaces by id --- mod/bridge-port-to | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/mod/bridge-port-to b/mod/bridge-port-to index efeb02a..ae74824 100644 --- a/mod/bridge-port-to +++ b/mod/bridge-port-to @@ -11,7 +11,6 @@ :set BridgePortTo do={ :local BridgePortTo [ :tostr $1 ]; - :global CharacterReplace; :global IfThenElse; :global LogPrintExit2; :global ParseKeyValueStore; @@ -47,7 +46,7 @@ :local Disable [ /interface/ethernet/find where name=$BridgePortVal->"interface" ]; :if ([ :len $Disable ] > 0) do={ /interface/ethernet/disable $Disable; - :set InterfaceReEnable ($InterfaceReEnable, $BridgePortVal->"interface"); + :set InterfaceReEnable ($InterfaceReEnable, $Disable); } /interface/bridge/port/set disabled=no bridge=$BridgeDefault $BridgePort; } else={ @@ -60,10 +59,7 @@ } :if ([ :len $InterfaceReEnable ] > 0) do={ :delay 2s; - $LogPrintExit2 info $0 ("Re-enabling interfaces: " . \ - [ $CharacterReplace [ :tostr $InterfaceReEnable ] ";" " " ]) false; - :foreach Interface in=$InterfaceReEnable do={ - /interface/ethernet/enable [ find where name=$Interface ]; - } + $LogPrintExit2 info $0 ("Re-enabling interfaces...") false; + /interface/ethernet/enable $InterfaceReEnable; } } From b0992da03d0b70d569c4dfe289226f9494348a7c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Jul 2022 12:28:50 +0200 Subject: [PATCH 1135/2612] mod/ipcalc: remove empty line --- mod/ipcalc | 1 - 1 file changed, 1 deletion(-) diff --git a/mod/ipcalc b/mod/ipcalc index a3e1e00..ed83d3c 100644 --- a/mod/ipcalc +++ b/mod/ipcalc @@ -43,4 +43,3 @@ :return $Return; } - From eda75f0bbc400950d0d98ad7456096deb2a8e755 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Jul 2022 12:29:29 +0200 Subject: [PATCH 1136/2612] global-functions: introduce function $PrettyPrint ... to add trailing carriage return when printing to terminal: [admin@MikroTik] > $PrettyPrint [ $DeviceInfo ] Hostname: MikroTik Board name: hAP ac^2 Architecture: arm Model: RouterBOARD D52G-5HacD2HnD-TC Serial number: 8A2A09A221A1 RouterOS: Channel: testing Installed: 7.4rc1 RouterOS-Scripts: Current: 81 --- global-functions | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/global-functions b/global-functions index 3a2497e..daa6526 100644 --- a/global-functions +++ b/global-functions @@ -40,6 +40,7 @@ :global MkDir; :global NotificationFunctions; :global ParseKeyValueStore; +:global PrettyPrint; :global QuotedPrintable; :global RandomDelay; :global Read; @@ -648,6 +649,15 @@ :return $Result; } +# print lines with trailing carriage return +:set PrettyPrint do={ + :local Input [ :tostr $1 ]; + + :global CharacterReplace; + + :put [ $CharacterReplace $Input ("\n") ("\n\r") ]; +} + # convert string to quoted-printable :global QuotedPrintable do={ :local Input [ :tostr $1 ]; From 150feac4000d733912561a9d7678169670f64d35 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Jul 2022 12:40:07 +0200 Subject: [PATCH 1137/2612] mod/inspectvar: use $PrettyPrint --- mod/inspectvar | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/inspectvar b/mod/inspectvar index 2130bb1..2629b6e 100644 --- a/mod/inspectvar +++ b/mod/inspectvar @@ -8,10 +8,10 @@ # inspect variable and print on terminal :set InspectVar do={ - :global CharacterReplace; :global InspectVarReturn; + :global PrettyPrint; - :put [ $CharacterReplace [ $InspectVarReturn $1 ] ("\n") ("\n\r") ]; + $PrettyPrint [ $InspectVarReturn $1 ]; } # inspect variable and return formatted string From 597277dbe75bb9a87852d46c64b026b189c3528b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Jul 2022 12:42:21 +0200 Subject: [PATCH 1138/2612] mod/ipcalc: use $PrettyPrint --- mod/ipcalc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mod/ipcalc b/mod/ipcalc index ed83d3c..14bb1ea 100644 --- a/mod/ipcalc +++ b/mod/ipcalc @@ -11,15 +11,16 @@ :local Input [ :tostr $1 ]; :global IPCalcReturn; + :global PrettyPrint; :local Values [ $IPCalcReturn $1 ]; - :put ( \ - "Address: " . $Values->"address" . "\n\r" . \ - "Netmask: " . $Values->"netmask" . "\n\r" . \ - "Network: " . $Values->"network" . "\n\r" . \ - "HostMin: " . $Values->"hostmin" . "\n\r" . \ - "HostMax: " . $Values->"hostmax" . "\n\r" . \ + $PrettyPrint ( \ + "Address: " . $Values->"address" . "\n" . \ + "Netmask: " . $Values->"netmask" . "\n" . \ + "Network: " . $Values->"network" . "\n" . \ + "HostMin: " . $Values->"hostmin" . "\n" . \ + "HostMax: " . $Values->"hostmax" . "\n" . \ "Broadcast: " . $Values->"broadcast"); } From 9853943a365639f675fba0bb9c1d64b7edfd00d7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Jul 2022 13:16:47 +0200 Subject: [PATCH 1139/2612] doc/netwatch-dns: giving hostname in comment is not required --- doc/netwatch-dns.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 798ad92..119937f 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -29,9 +29,9 @@ Configuration The DNS and DoH servers to be checked have to be added to netwatch with specific comment: - /tool/netwatch/add comment="doh, hostname=cloudflare-dns" host=1.1.1.1; - /tool/netwatch/add comment="dns, hostname=google-dns" host=8.8.8.8; - /tool/netwatch/add comment="doh, dns, hostname=quad-nine" host=9.9.9.10; + /tool/netwatch/add comment="doh" host=1.1.1.1; + /tool/netwatch/add comment="dns" host=8.8.8.8; + /tool/netwatch/add comment="doh, dns" host=9.9.9.10; This will configure *cloudflare-dns* for DoH (`https://1.1.1.1/dnsquery`), and *google-dns* and *quad-nine* for regular DNS (`8.8.8.8,9.9.9.10`) if up. @@ -39,15 +39,15 @@ If *cloudflare-dns* is down the script will fall back to *quad-nine* for DoH. Giving a specific query url for DoH is possible: - /tool/netwatch/add comment="doh, hostname=nextdns, doh-url=https://dns.nextdns.io/dns-query" host=199.247.16.158; + /tool/netwatch/add comment="doh, ame=nextdns, doh-url=https://dns.nextdns.io/dns-query" host=199.247.16.158; Note that using a name in DoH url may introduce a chicken-and-egg issue! Sometimes using just one specific (possibly internal) DNS server may be desired, with fallback in case it fails. This is possible as well: - /tool/netwatch/add comment="dns, hostname=pi-hole" host=10.0.0.10; - /tool/netwatch/add comment="dns-fallback, hostname=cloudflare-dns" host=1.1.1.1; + /tool/netwatch/add comment="dns" host=10.0.0.10; + /tool/netwatch/add comment="dns-fallback" host=1.1.1.1; Tips & Tricks ------------- From 0a45e255629aff82f1c95be322d735e72e9b9831 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Jul 2022 13:29:00 +0200 Subject: [PATCH 1140/2612] doc/netwatch-dns: use default address for quad-nine --- doc/netwatch-dns.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 119937f..6f30225 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -31,10 +31,10 @@ specific comment: /tool/netwatch/add comment="doh" host=1.1.1.1; /tool/netwatch/add comment="dns" host=8.8.8.8; - /tool/netwatch/add comment="doh, dns" host=9.9.9.10; + /tool/netwatch/add comment="doh, dns" host=9.9.9.9; This will configure *cloudflare-dns* for DoH (`https://1.1.1.1/dnsquery`), and -*google-dns* and *quad-nine* for regular DNS (`8.8.8.8,9.9.9.10`) if up. +*google-dns* and *quad-nine* for regular DNS (`8.8.8.8,9.9.9.9`) if up. If *cloudflare-dns* is down the script will fall back to *quad-nine* for DoH. Giving a specific query url for DoH is possible: From 5a02c32d7d0c5d8b0951898e040b7918ff1b560a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Jul 2022 15:30:39 +0200 Subject: [PATCH 1141/2612] netwatch-notify: properly check for disabled state Looks like checking for 'disabled=no' fails with net netwatch in RouterOS 7.4... --- netwatch-notify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index 45b0c76..d9b8cf0 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -54,7 +54,7 @@ $ScriptLock $0; :set NetwatchNotify [ :toarray "" ]; } -:foreach Host in=[ /tool/netwatch/find where comment~"notify" disabled=no ] do={ +:foreach Host in=[ /tool/netwatch/find where comment~"notify" !disabled ] do={ :local HostVal [ /tool/netwatch/get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; From 19103cd3451a9a5a6be6faa8c2745754ddc40606 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Jul 2022 13:23:34 +0200 Subject: [PATCH 1142/2612] netwatch-notify: rename parameter: hostname -> name Starting with RouterOS 7.4 the netwatch tool has been extended, it can now do tcp and http probes. Rename the parameter for reasonable naming with services. --- doc/netwatch-dns.md | 2 +- doc/netwatch-notify.md | 28 ++++++++++++++-------------- global-config | 2 +- global-config-overlay | 2 +- global-config.changes | 2 ++ global-functions | 2 +- netwatch-notify | 6 +++--- 7 files changed, 23 insertions(+), 21 deletions(-) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 6f30225..8e897d1 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -57,7 +57,7 @@ Tips & Tricks Netwatch entries can be created to work with both - this script and [netwatch-notify](netwatch-notify.md). Just give options for both: - /tool/netwatch/add comment="doh, notify, hostname=cloudflare-dns" host=1.1.1.1; + /tool/netwatch/add comment="doh, notify, name=cloudflare-dns" host=1.1.1.1; Also this allows to update host address, see option `resolve`. diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 85bfb73..1352495 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -36,7 +36,7 @@ Configuration The hosts to be checked have to be added to netwatch with specific comment: - /tool/netwatch/add comment="notify, hostname=example.com" host=[ :resolve "example.com" ]; + /tool/netwatch/add comment="notify, name=example.com" host=[ :resolve "example.com" ]; ### Hooks @@ -44,7 +44,7 @@ It is possible to run an up hook command (`up-hook`) or down hook command (`down-hook`) when a notification is triggered. This has to be added in comment, note that some characters need extra escaping: - /tool/netwatch/add comment=("notify, hostname=device, down-hook=/interface/ethernet \\{ disable \\\"en2\\\"; enable \\\"en2\\\"; \\}") host=10.0.0.20; + /tool/netwatch/add comment=("notify, name=device, down-hook=/interface/ethernet \\{ disable \\\"en2\\\"; enable \\\"en2\\\"; \\}") host=10.0.0.20; Also there is a `pre-down-hook` that fires at two thirds of failed checks required for the notification. The idea is to fix the issue before a @@ -54,15 +54,15 @@ notification is sent. The count threshould (default is 5 checks) is configurable as well: - /tool/netwatch/add comment="notify, hostname=example.com, count=10" host=104.18.144.11; + /tool/netwatch/add comment="notify, name=example.com, count=10" host=104.18.144.11; ### Parents & dependencies If the host is behind another checked host add a dependency, this will suppress notification if the parent host is down: - /tool/netwatch/add comment="notify, hostname=gateway" host=93.184.216.1; - /tool/netwatch/add comment="notify, hostname=example.com, parent=gateway" host=93.184.216.34; + /tool/netwatch/add comment="notify, name=gateway" host=93.184.216.1; + /tool/netwatch/add comment="notify, name=example.com, parent=gateway" host=93.184.216.34; Note that every configured parent in a chain increases the check count threshould by one. @@ -72,7 +72,7 @@ threshould by one. The host address can be updated dynamically. Give extra parameter `resolve` with a resolvable name: - /tool/netwatch/add comment="notify, hostname=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 more than one record in dns - a high rate of configuration changes (and flash @@ -84,7 +84,7 @@ Also suppressing the notification on host down is possible with parameter `no-down-notification`. This may be desired for devices that are usually powered off, but accessibility is of interest. - /tool/netwatch/add comment="notify, hostname=printer, no-down-notification" host=10.0.0.30; + /tool/netwatch/add comment="notify, name=printer, no-down-notification" host=10.0.0.30; Go and get your coffee â˜•ī¸ before sending the print job. @@ -99,10 +99,10 @@ Tips & Tricks Sometimes it is sufficient if one of a number of hosts is available. You can make `netwatch-notify` check for that by adding several items with same -`hostname`. Note that `count` has to be multiplied to keep the actual time. +`name`. Note that `count` has to be multiplied to keep the actual time. - /tool/netwatch/add comment="notify, hostname=service, count=10" host=10.0.0.10; - /tool/netwatch/add comment="notify, hostname=service, count=10" host=10.0.0.20; + /tool/netwatch/add comment="notify, name=service, count=10" host=10.0.0.10; + /tool/netwatch/add comment="notify, name=service, count=10" host=10.0.0.20; ### Checking internet connectivity @@ -112,11 +112,11 @@ check `1.1.1.1` (Cloudflare DNS), `9.9.9.9` (Quad-nine DNS), `8.8.8.8` (Google DNS) or any other reliable address that indicates internet connectivity. - /tool/netwatch/add comment="notify, hostname=internet" host=1.1.1.1; + /tool/netwatch/add comment="notify, name=internet" host=1.1.1.1; A target like this suits well to be parent for other checks. - /tool/netwatch/add comment="notify, hostname=example.com, parent=internet" host=93.184.216.34; + /tool/netwatch/add comment="notify, name=example.com, parent=internet" host=93.184.216.34; ### Checking specific ISP @@ -130,7 +130,7 @@ Create a route and firewall mangle rule. Finally monitor the address with `netwatch-notify`. - /tool/netwatch/add comment="notify, hostname=quad-one via isp1" host=1.0.0.1; + /tool/netwatch/add comment="notify, name=quad-one via isp1" host=1.0.0.1; Note that *all* traffic to the given address is routed that way. In case of link failure this address is not available, so use something reliable but @@ -142,7 +142,7 @@ non-essential. In this example the address `1.0.0.1` is used, the same service Netwatch entries can be created to work with both - this script and [netwatch-dns](netwatch-dns.md). Just give options for both: - /tool/netwatch/add comment="doh, notify, hostname=cloudflare-dns" host=1.1.1.1; + /tool/netwatch/add comment="doh, notify, name=cloudflare-dns" host=1.1.1.1; See also -------- diff --git a/global-config b/global-config index b1f4770..d36e63b 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 81; +:global GlobalConfigVersion 82; # This is used for DNS and backup file. :global Domain "example.com"; diff --git a/global-config-overlay b/global-config-overlay index eaa43f6..5af0e09 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 81; +:global GlobalConfigVersion 82; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 04f88e7..1a72527 100644 --- a/global-config.changes +++ b/global-config.changes @@ -90,6 +90,7 @@ 79="Introduced new script 'backup-partition' to save configuration to fallback partition."; 80="The 'routeros-v7' branch will now freeze, and vanish any time in future. You already switched to 'main' branch, well done!"; 81="Dropped script 'rotate-ntp', as the limitation does no longer exist."; + 82="Renamed the comment parameter 'hostname' to just 'name' for 'netwatch-notify'."; }; # Migration steps to be applied on script updates @@ -103,4 +104,5 @@ 67=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Script in=[ /system/script/find where name~\"^global-functions.d/\" ] do={ /system/script/set name=[ \$CharacterReplace [ /system/script/get \$Script name ] \"global-functions.d/\" \"mod/\" ] \$Script; }; \$ScriptInstallUpdate;"; 73=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Old,New in={ \"cloud-backup\"=\"backup-cloud\"; \"email-backup\"=\"backup-email\"; \"upload-backup\"=\"backup-upload\" } do={ /system/script/set name=\$New [ find where name=\$Old ]; :foreach Scheduler in=[ /system/scheduler/find where on-event~\$Old ] do={ /system/scheduler/set \$Scheduler name=[ \$CharacterReplace [ get \$Scheduler name ] \$Old \$New ] on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Old \$New ]; }; }; \$ScriptInstallUpdate;"; 81=":global NtpPool; :if ([ :len [ /system/script/find where name=\"rotate-ntp\" ] ] > 0) do={ /system/script/remove [ find where name=\"rotate-ntp\" ]; /system/scheduler/remove [ find where name=\"rotate-ntp\" ]; /system/ntp/client/set servers=\$NtpPool; };"; + 82=":global CharacterReplace; :foreach Netwatch in=[ /tool/netwatch/find where comment~\"notify\" !disabled ] do={ /tool/netwatch/set \$Netwatch comment=[ \$CharacterReplace [ get \$Netwatch comment ] \"hostname=\" \"name=\" ]; };"; }; diff --git a/global-functions b/global-functions index daa6526..bab2716 100644 --- a/global-functions +++ b/global-functions @@ -10,7 +10,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 81; +:global ExpectedConfigVersion 82; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/netwatch-notify b/netwatch-notify index d9b8cf0..e1c8e43 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -59,7 +59,7 @@ $ScriptLock $0; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ - :local HostName ($HostInfo->"hostname"); + :local HostName ($HostInfo->"name"); :local Metric { "count"=0; "notified"=false }; :if ([ :typeof ($NetwatchNotify->$HostName) ] = "array") do={ @@ -72,7 +72,7 @@ $ScriptLock $0; :local Resolve [ :resolve ($HostInfo->"resolve") ]; :if ($Resolve != $HostVal->"host") do={ $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ - $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . \ + $HostInfo->"name") ("' for host '" . $HostInfo->"name") "" ] . \ "' resolves to different address " . $Resolve . ", updating.") false; /tool/netwatch/set host=$Resolve $Host; :set ($Metric->"resolve-failed") false; @@ -80,7 +80,7 @@ $ScriptLock $0; } on-error={ :if ($Metric->"resolve-failed" != true) do={ $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ - $HostInfo->"hostname") ("' for host '" . $HostInfo->"hostname") "" ] . "' failed.") false; + $HostInfo->"name") ("' for host '" . $HostInfo->"name") "" ] . "' failed.") false; :set ($Metric->"resolve-failed") true; } } From a7c94445454642ce57be4da9693f914da5d05c1a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Jul 2022 13:41:35 +0200 Subject: [PATCH 1143/2612] netwatch-notify: rename variable: $HostName -> $Name --- netwatch-notify | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index e1c8e43..e3f0633 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -59,11 +59,11 @@ $ScriptLock $0; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ - :local HostName ($HostInfo->"name"); + :local Name ($HostInfo->"name"); :local Metric { "count"=0; "notified"=false }; - :if ([ :typeof ($NetwatchNotify->$HostName) ] = "array") do={ - :set $Metric ($NetwatchNotify->$HostName); + :if ([ :typeof ($NetwatchNotify->$Name) ] = "array") do={ + :set $Metric ($NetwatchNotify->$Name); } :if ([ :typeof ($HostInfo->"resolve") ] = "str") do={ @@ -90,17 +90,17 @@ $ScriptLock $0; :if ($HostVal->"status" = "up") do={ :local Count ($Metric->"count"); :if ($Count > 0) do={ - $LogPrintExit2 info $0 ("Host " . $HostName . " (" . $HostVal->"host" . ") is up.") false; + $LogPrintExit2 info $0 ("Host " . $Name . " (" . $HostVal->"host" . ") is up.") false; :set ($Metric->"count") 0; } :if ($Metric->"notified" = true) do={ - :local Message ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ + :local Message ("Host " . $Name . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $HostName "up" ($HostInfo->"up-hook") ]); + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name "up" ($HostInfo->"up-hook") ]); } $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $HostName . " up"); \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $Name . " up"); \ message=$Message }); } :set ($Metric->"notified") false; @@ -125,26 +125,26 @@ $ScriptLock $0; } } $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ - ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . $Metric->"count" . " checks, " . \ + ("Host " . $Name . " (" . $HostVal->"host" . ") is down for " . $Metric->"count" . " checks, " . \ [ $IfThenElse ($ParentNotified = false) [ $IfThenElse ($Metric->"notified" = true) ("already notified.") \ ($Count - $Metric->"count" . " to go.") ] ("parent host " . $Parent . " is down.") ]) false; :if ((($Count * 2) - ($Metric->"count" * 3)) / 2 = 0 && [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ - $NetwatchNotifyHook $HostName "pre-down" ($HostInfo->"pre-down-hook"); + $NetwatchNotifyHook $Name "pre-down" ($HostInfo->"pre-down-hook"); } :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ - :local Message ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); + :local Message ("Host " . $Name . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $HostName "down" ($HostInfo->"down-hook") ]); + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name "down" ($HostInfo->"down-hook") ]); } :if ($HostInfo->"no-down-notification" != true) do={ $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down"); \ + subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $Name . " down"); \ message=$Message }); } :set ($Metric->"notified") true; } } - :set ($NetwatchNotify->$HostName) { + :set ($NetwatchNotify->$Name) { "count"=($Metric->"count"); "notified"=($Metric->"notified"); "parent"=($Metric->"parent"); From f50d155500011e449c42d9389333a91e0d23939b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Jul 2022 13:43:50 +0200 Subject: [PATCH 1144/2612] netwatch-notify: $NetwatchNotifyHook: rename variable: $Type -> $State --- netwatch-notify | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index e3f0633..112cf9e 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -21,9 +21,9 @@ :global SymbolForNotification; :local NetwatchNotifyHook do={ - :local Name [ :tostr $1 ]; - :local Type [ :tostr $2 ]; - :local Hook [ :tostr $3 ]; + :local Name [ :tostr $1 ]; + :local State [ :tostr $2 ]; + :local Hook [ :tostr $3 ]; :global LogPrintExit2; :global ValidateSyntax; @@ -32,15 +32,15 @@ :do { [ :parse $Hook ]; } on-error={ - $LogPrintExit2 warning $0 ("The " . $Type . "-hook for host " . $Name . " failed to run.") false; + $LogPrintExit2 warning $0 ("The " . $State . "-hook for host " . $Name . " failed to run.") false; :return ("The hook failed to run."); } } else={ - $LogPrintExit2 warning $0 ("The " . $Type . "-hook for host " . $Name . " failed syntax validation.") false; + $LogPrintExit2 warning $0 ("The " . $State . "-hook for host " . $Name . " failed syntax validation.") false; :return ("The hook failed syntax validation."); } - $LogPrintExit2 info $0 ("Ran hook on host " . $Name . " " . $Type . ": " . $Hook) false; + $LogPrintExit2 info $0 ("Ran hook on host " . $Name . " " . $State . ": " . $Hook) false; :return ("Ran hook:\n" . $Hook); } From e8f5f9217ce07f8eda531997f0aec399b77cd874 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Jul 2022 13:57:11 +0200 Subject: [PATCH 1145/2612] netwatch-notify: properly handle services (http-get & tcp-conn) --- .../notification-01-down.svg | 4 +-- doc/netwatch-notify.d/notification-02-up.svg | 4 +-- netwatch-notify | 32 ++++++++++--------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/doc/netwatch-notify.d/notification-01-down.svg b/doc/netwatch-notify.d/notification-01-down.svg index 5cab5fe..40821b2 100644 --- a/doc/netwatch-notify.d/notification-01-down.svg +++ b/doc/netwatch-notify.d/notification-01-down.svg @@ -159,10 +159,10 @@ Host example.com (93.184.216.34) is down since + id="tspan2281">The host example.com (93.184.216.34) is down jun/08/2021 06:55:03. + id="tspan2283">since jun/08/2021 06:55:03. diff --git a/doc/netwatch-notify.d/notification-02-up.svg b/doc/netwatch-notify.d/notification-02-up.svg index 8e03981..0454830 100644 --- a/doc/netwatch-notify.d/notification-02-up.svg +++ b/doc/netwatch-notify.d/notification-02-up.svg @@ -159,11 +159,11 @@ Host example.com (93.184.216.34) is up since + id="tspan2246">The host example.com (93.184.216.34) is up jun/08/2021 07:01:00. + id="tspan2248">since jun/08/2021 07:01:00. "type" ~ "^(http-get|tcp-conn)\$") "service" "host" ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ @@ -72,7 +74,7 @@ $ScriptLock $0; :local Resolve [ :resolve ($HostInfo->"resolve") ]; :if ($Resolve != $HostVal->"host") do={ $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ - $HostInfo->"name") ("' for host '" . $HostInfo->"name") "" ] . \ + $HostInfo->"name") ("' for " . $Type . " '" . $HostInfo->"name") "" ] . \ "' resolves to different address " . $Resolve . ", updating.") false; /tool/netwatch/set host=$Resolve $Host; :set ($Metric->"resolve-failed") false; @@ -80,7 +82,7 @@ $ScriptLock $0; } on-error={ :if ($Metric->"resolve-failed" != true) do={ $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ - $HostInfo->"name") ("' for host '" . $HostInfo->"name") "" ] . "' failed.") false; + $HostInfo->"name") ("' for " . $Type . " '" . $HostInfo->"name") "" ] . "' failed.") false; :set ($Metric->"resolve-failed") true; } } @@ -90,14 +92,14 @@ $ScriptLock $0; :if ($HostVal->"status" = "up") do={ :local Count ($Metric->"count"); :if ($Count > 0) do={ - $LogPrintExit2 info $0 ("Host " . $Name . " (" . $HostVal->"host" . ") is up.") false; + $LogPrintExit2 info $0 ("The " . $Type . " " . $Name . " (" . $HostVal->"host" . ") is up.") false; :set ($Metric->"count") 0; } :if ($Metric->"notified" = true) do={ - :local Message ("Host " . $Name . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ + :local Message ("The " . $Type . " " . $Name . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name "up" ($HostInfo->"up-hook") ]); + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "up" ($HostInfo->"up-hook") ]); } $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $Name . " up"); \ @@ -125,16 +127,16 @@ $ScriptLock $0; } } $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ - ("Host " . $Name . " (" . $HostVal->"host" . ") is down for " . $Metric->"count" . " checks, " . \ + ("The " . $Type . " " . $Name . " (" . $HostVal->"host" . ") is down for " . $Metric->"count" . " checks, " . \ [ $IfThenElse ($ParentNotified = false) [ $IfThenElse ($Metric->"notified" = true) ("already notified.") \ - ($Count - $Metric->"count" . " to go.") ] ("parent host " . $Parent . " is down.") ]) false; + ($Count - $Metric->"count" . " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]) false; :if ((($Count * 2) - ($Metric->"count" * 3)) / 2 = 0 && [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ - $NetwatchNotifyHook $Name "pre-down" ($HostInfo->"pre-down-hook"); + $NetwatchNotifyHook $Name $Type "pre-down" ($HostInfo->"pre-down-hook"); } :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ - :local Message ("Host " . $Name . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); + :local Message ("The " . $Type . " " . $Name . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name "down" ($HostInfo->"down-hook") ]); + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "down" ($HostInfo->"down-hook") ]); } :if ($HostInfo->"no-down-notification" != true) do={ $SendNotification2 ({ origin=$0; \ From 5767fceb393a51690920e4c2df02916409bab03f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Jul 2022 16:31:49 +0200 Subject: [PATCH 1146/2612] netwatch-notify: quote the host/service name --- doc/netwatch-notify.d/notification-01-down.svg | 2 +- doc/netwatch-notify.d/notification-02-up.svg | 2 +- netwatch-notify | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/netwatch-notify.d/notification-01-down.svg b/doc/netwatch-notify.d/notification-01-down.svg index 40821b2..3a9133e 100644 --- a/doc/netwatch-notify.d/notification-01-down.svg +++ b/doc/netwatch-notify.d/notification-01-down.svg @@ -159,7 +159,7 @@ The host example.com (93.184.216.34) is down + id="tspan2281">The host 'example.com' (93.184.216.34) is down The host example.com (93.184.216.34) is up + id="tspan2246">The host 'example.com' (93.184.216.34) is up "status" = "up") do={ :local Count ($Metric->"count"); :if ($Count > 0) do={ - $LogPrintExit2 info $0 ("The " . $Type . " " . $Name . " (" . $HostVal->"host" . ") is up.") false; + $LogPrintExit2 info $0 ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . ") is up.") false; :set ($Metric->"count") 0; } :if ($Metric->"notified" = true) do={ - :local Message ("The " . $Type . " " . $Name . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ + :local Message ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "up" ($HostInfo->"up-hook") ]); @@ -127,14 +127,14 @@ $ScriptLock $0; } } $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ - ("The " . $Type . " " . $Name . " (" . $HostVal->"host" . ") is down for " . $Metric->"count" . " checks, " . \ + ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . ") is down for " . $Metric->"count" . " checks, " . \ [ $IfThenElse ($ParentNotified = false) [ $IfThenElse ($Metric->"notified" = true) ("already notified.") \ ($Count - $Metric->"count" . " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]) false; :if ((($Count * 2) - ($Metric->"count" * 3)) / 2 = 0 && [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ $NetwatchNotifyHook $Name $Type "pre-down" ($HostInfo->"pre-down-hook"); } :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ - :local Message ("The " . $Type . " " . $Name . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); + :local Message ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "down" ($HostInfo->"down-hook") ]); } From 8e6eff30db8197e11cc47d6ca7f0752c63d1f0a1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Jul 2022 16:36:00 +0200 Subject: [PATCH 1147/2612] netwatch-notify: also support the name from property --- netwatch-notify | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index 445e329..c7575ea 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -12,6 +12,7 @@ :global NetwatchNotify; +:global EitherOr; :global IfThenElse; :global IsDNSResolving; :global LogPrintExit2; @@ -61,7 +62,7 @@ $ScriptLock $0; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ - :local Name ($HostInfo->"name"); + :local Name [ $EitherOr ($HostInfo->"name") ($HostVal->"name") ]; :local Metric { "count"=0; "notified"=false }; :if ([ :typeof ($NetwatchNotify->$Name) ] = "array") do={ From 3a7bb1e2392839884a67ab4acfa9260b9c50b221 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Jul 2022 11:36:27 +0200 Subject: [PATCH 1148/2612] netwatch-notify: break long lines --- netwatch-notify | 60 +++++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index c7575ea..a725fc3 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -34,15 +34,18 @@ :do { [ :parse $Hook ]; } on-error={ - $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . "' failed to run.") false; + $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . \ + "' failed to run.") false; :return ("The hook failed to run."); } } else={ - $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . "' failed syntax validation.") false; + $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . \ + "' failed syntax validation.") false; :return ("The hook failed syntax validation."); } - $LogPrintExit2 info $0 ("Ran hook on " . $Type . " '" . $Name . "' " . $State . ": " . $Hook) false; + $LogPrintExit2 info $0 ("Ran hook on " . $Type . " '" . $Name . "' " . $State . ": " . \ + $Hook) false; :return ("Ran hook:\n" . $Hook); } @@ -74,16 +77,18 @@ $ScriptLock $0; :do { :local Resolve [ :resolve ($HostInfo->"resolve") ]; :if ($Resolve != $HostVal->"host") do={ - $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ - $HostInfo->"name") ("' for " . $Type . " '" . $HostInfo->"name") "" ] . \ - "' resolves to different address " . $Resolve . ", updating.") false; + $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ + ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ + $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ + ", updating.") false; /tool/netwatch/set host=$Resolve $Host; :set ($Metric->"resolve-failed") false; } } on-error={ :if ($Metric->"resolve-failed" != true) do={ - $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse ($HostInfo->"resolve" != \ - $HostInfo->"name") ("' for " . $Type . " '" . $HostInfo->"name") "" ] . "' failed.") false; + $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \ + ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ + $HostInfo->"name") "" ] . "' failed.") false; :set ($Metric->"resolve-failed") true; } } @@ -93,17 +98,21 @@ $ScriptLock $0; :if ($HostVal->"status" = "up") do={ :local Count ($Metric->"count"); :if ($Count > 0) do={ - $LogPrintExit2 info $0 ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . ") is up.") false; + $LogPrintExit2 info $0 ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . \ + ") is up.") false; :set ($Metric->"count") 0; } :if ($Metric->"notified" = true) do={ - :local Message ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ - "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); + :local Message ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . \ + ") is up since " . $HostVal->"since" . ".\n" . \ + "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "up" ($HostInfo->"up-hook") ]); + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "up" \ + ($HostInfo->"up-hook") ]); } $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $Name . " up"); \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . \ + $Name . " up"); \ message=$Message }); } :set ($Metric->"notified") false; @@ -122,26 +131,33 @@ $ScriptLock $0; :set Parent ($HostInfo->"parent"); :local ParentNotified false; :while ($ParentNotified = false && [ :len $Parent ] > 0) do={ - :set ParentNotified [ $IfThenElse (($NetwatchNotify->$Parent->"notified") = true) true false ]; + :set ParentNotified [ $IfThenElse (($NetwatchNotify->$Parent->"notified") = true) \ + true false ]; :if ($ParentNotified = false) do={ :set Parent ($NetwatchNotify->$Parent->"parent"); } } $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ - ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . ") is down for " . $Metric->"count" . " checks, " . \ - [ $IfThenElse ($ParentNotified = false) [ $IfThenElse ($Metric->"notified" = true) ("already notified.") \ - ($Count - $Metric->"count" . " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]) false; - :if ((($Count * 2) - ($Metric->"count" * 3)) / 2 = 0 && [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ + ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . ") is down for " . \ + $Metric->"count" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ + ($Metric->"notified" = true) ("already notified.") ($Count - $Metric->"count" . \ + " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]) false; + :if ((($Count * 2) - ($Metric->"count" * 3)) / 2 = 0 && \ + [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ $NetwatchNotifyHook $Name $Type "pre-down" ($HostInfo->"pre-down-hook"); } - :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ - :local Message ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); + :if ($ParentNotified = false && $Metric->"count" >= $Count && \ + $Metric->"notified" != true) do={ + :local Message ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . \ + ") is down since " . $HostVal->"since" . "."); :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "down" ($HostInfo->"down-hook") ]); + :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "down" \ + ($HostInfo->"down-hook") ]); } :if ($HostInfo->"no-down-notification" != true) do={ $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $Name . " down"); \ + subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . \ + $Name . " down"); \ message=$Message }); } :set ($Metric->"notified") true; From 447e1d99f982d43f42d1e2fe3053e747c5df234a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Jul 2022 11:36:16 +0200 Subject: [PATCH 1149/2612] netwatch-dns: break long lines --- netwatch-dns | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/netwatch-dns b/netwatch-dns index 64c2d8e..67e0408 100644 --- a/netwatch-dns +++ b/netwatch-dns @@ -48,7 +48,8 @@ $ScriptLock $0; } else={ :if ([ :len $DnsFallback ] > 0) do={ :if ($DnsFallback != $DnsCurrent) do={ - $LogPrintExit2 info $0 ("Updating DNS servers to fallback: " . [ :tostr $DnsFallback ]) false; + $LogPrintExit2 info $0 ("Updating DNS servers to fallback: " . \ + [ :tostr $DnsFallback ]) false; /ip/dns/set servers=$DnsFallback; /ip/dns/cache/flush; } @@ -62,8 +63,10 @@ $ScriptLock $0; :local HostVal [ /tool/netwatch/get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; - :if ($HostVal->"status" = "up" && $HostInfo->"doh" = true && $HostInfo->"disabled" != true && $DohServer = "") do={ - :set DohServer [ $EitherOr ($HostInfo->"doh-url") ("https://" . $HostVal->"host" . "/dns-query") ]; + :if ($HostVal->"status" = "up" && $HostInfo->"doh" = true && \ + $HostInfo->"disabled" != true && $DohServer = "") do={ + :set DohServer [ $EitherOr ($HostInfo->"doh-url") \ + ("https://" . $HostVal->"host" . "/dns-query") ]; } } From 68ae4fca0d36bfd0720200fb8671951e1985bf8f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Jul 2022 12:26:58 +0200 Subject: [PATCH 1150/2612] global-config-overlay: update wording --- global-config-overlay | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config-overlay b/global-config-overlay index 5af0e09..06d369e 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -10,7 +10,7 @@ # Comment or remove to disable news and change notifications. :global GlobalConfigVersion 82; -# Copy configuration from global-config here and modify it. +# Copy configuration from global-config, paste and modify it here. # End of global-config-overlay From a1606402d1628e7998601c29e6f1043c34a30ebc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Jul 2022 12:54:40 +0200 Subject: [PATCH 1151/2612] global-config: new setting to disable news and change notifications... ... and also drop the version from global-config and global-config-overlay. --- README.d/05-edit-global-config-overlay.avif | Bin 6602 -> 5124 bytes doc/backup-cloud.d/notification.svg | 2 +- doc/backup-upload.d/notification.svg | 2 +- doc/check-routeros-update.d/notification.svg | 2 +- global-config | 5 ++-- global-config-overlay | 5 ---- global-config.changes | 1 + global-functions | 24 ++++++++----------- 8 files changed, 16 insertions(+), 25 deletions(-) diff --git a/README.d/05-edit-global-config-overlay.avif b/README.d/05-edit-global-config-overlay.avif index e08fde82b9fb85072bcee6310daf92cbbf795da5..f2f0f2d88aa5534ce9ffed56b2e2b95dd7ce8539 100644 GIT binary patch delta 4637 zcmV+&65{R3GlVFRegYEek$_490Q8Z}NEQetr`gx{(Li{ z=o!WB-Pp3gLOFN;2|Xxaaa?Y!(L2A6bdy7IWO)k%8ZQ!R$Ss37C*L{MO;aUUWXfXX zm$aP{EWQ+wuZ#?85N1|p@YQF`!g_alY=13YuF>YS0pLJa8@_l#cwM^Lvu1)?>;78- zEBpBFOnV&FFh&s+@VFM&nf4)vb1kwt126P>?D?od_1=TaVsjBr1ejz7E9V?seM$*z z4vPm*g}>O5;~aTa7pYr}M31pH+7^J|=Ace~048N{amfNmYZxy^96DL7-Y~|O=YRRn zq`N`Vmt4v+n_FqgQC{g{Dy2_dX{q=P;N*2YzD-%d^H}Jv(#L&W^9M7~0;xYzE%S1k zs|C7-zM2i>8i+ld{;~z<$fomgHiCBx&(-5=ZnR`NFZV9q$4)IC%0DfnX)Y%{i9i)k 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 T+?rdUD0KZurt5w{MFAE@!q5IZ delta 6127 zcmVlbLYM^iK;<|Ih`lG@Zx@g#RqC7sx55!n zUFMyH>8}SlNu&IIy=X%26Ca9a?N`s(+-83v-Q1{XgoWBMXfO)Jf!n_^Q5__|Yj0xe zWJez~);|fHJ`^qmumFx!0P(kMjzG)(5*tL|PTJQQTC1+ek`gkrAGj%hye*B=*mE#k zp@?fW@oe>XY9yO|MKda}h!1Ui+i<%g>GXsy3rNkc+9>Fi3*fYLa_;(8`D%!`*SCLS z%?o*_WK+nBUmPz3QQ;r|yUQQ^S-HC^9rLgyh7d%P#&i=V?wB#nDEeS@8}dIoa;Lq( zovWahV5eFK<6a(&9@dsW;4~Uv&!GlwQRTlr22K;7aD;iATQa7^3Y#~}c+r1xI9%sq zOYC55?Jprbm!jHIBKt>%=^CLVLe$*@$?+2)zzsX&wJuWf`ASdh49<6FcRL;rtGdM$$X z^%%IS4m;)?!a}^Jg$5J4LgV-R4kthavyhV@C1OPtg_wcH)32#qjG*SSZXpgmq z%DRfTsWv6^(-GWj_gsCRs~~ z!svLw9i&KIMU7X2q#Wyr7W03)E}Rd{1Q%Z*hjlitd8Lq+dC94=?H;OF6YK#z?!9^& zFz_Jkj3U~8a#VO;1W>Qda<>N4lA6Cfaw$~Kdy7gV2o}bpOPLQzUoSg^GPT;R+u71e)4StF3BmPfx8 z-}sx>BYSGG6JteKnHW1(#{(6u>>G<~0q1WoU9BqLlQ)^|1pWlp@g^I9>7p*z5km^P zBC{WX5p5oSkilU#sw+7aPycP{hIOa7-Pt=b5xz7XsYH-?Jb}nU(PtqxHcZE(Cm1K5 zJpKF#5_|FsQ1~R+N%(&v5z0Wk$GP{~vc{zE`R_^6w4USuy4i0qpZBwe<#tF5(7_vw z!2#tIVqHq!Kuq_<$7jgTjlaC@mwr~EFORYSo7L1r!wC})XN=#I7*P!a;&glY8mXRR z+v5H<9pvE|>oy-woKD0e7V{!U$lqiie2ua{8aIc$s%&0dQ>}lro`)472XC7@%g z2dAcj0`-5H(ABWjPqq+v);s=!TVX9 z<788Nk&17c29kfYv^i)Z8(v>!0L<3Uq6s8ia|iSm5c6&B=Lf5AZZ>6inu}}S*kVj` zc#FX?gOm3}NEcc{b*Iq;r^Vfioqh1Zj1LT9>|EL;*@x6!s@1MW_KWXyH{UfbS(A_5 z9Rpn*IiC2rn%0`=kN9+qcfVKf_<+Qr@RIS=VE2(TD!+d`(4KHb2-we?A)-!Sha6ha z#rsbIFrC4nv1smMa#k@?)R$eixjNPy1!EV6(`a;8*-qh7)t$9NxSI|(`gP{9oqfpg zP4G&f8*vA;dSmF^cidcWm5+}g##=zoecm+vmr%2WB~Vxn2ReJyoW_b5o4B!6-s?f- zGp<#k8k~QXs2BxwfUFtOpG97avbgWxCbF{4KI{sfmfzZ56CAtThS?vbsAf9Z#jS*L zUadr2WU#cxdcw%sGcI?vz15b+^X2iLBW*2|>cj6C0J_%(EFF90WF#9CFsQ4lG z6Bzut+94oIQ>s*QBhaX*Mz@t2N0NnGexvPnP);!7Fop0s-j1}l8yHvLu>G}UKrVvh z@=;p4bUf$4*+s^3z6-M2K92li18ki>Q@{oWN_Oaq(bg3nJD(%`98ciPc% zO0jXCuU*e00>bfLO=Ejh!R8C{@%y_*5WAyM@m$bd=EJvR^rtXZ3Vv(p3vwPM*Rz@N zM71@M|J{|g5~y?$gY?F-A2$q?)`*tGt8IV3z}TzQnLwgEaWY^^0S<-WY<%TTb2j)- zopP+9%!2Rf!2Bre7cr1)M6}#O1aJY@7+60d{%Fj8XdY}EpKoZ12{{)R=(r7~Hpn+A zQ-{(dT$?9R)NhJ`V-l|AvubX<>Y*u2a)2GG0^3Pu7t0V-o8B}}Bl~NdLF5Id9iM-O zwbPyg2orj3bno>?eva7WRT5pjiJS%7H98OJ``ywte0XmGO^D{af>}~$E>w$gk|hx) z3Q|<+^4|z<9U1RstHr7PWzorq)8QChl@YBkVw0)SpXHf%JX^wm$V>D`CJgdlojNze z_%Oc{uub24V34)f(^v^63UAs!lIeeTr|l2lForUJ%D4EqU;OWL)^e1b=#}YcHIK@= zYRk?bv@_e=zB`%8BjFM7`ZRh^(Rrr5S$7lC^}_1!uLHPRxD;>d|>GiQ5fd;%4_`R|HMksOEl5vo|S}P3k?a23&Gn z!zH_ucuh|e4WN{$kzNd$xT$JV2Ozmd)}*u*1<%VN-^;qIS|u=n&qfh!0>SfnylKBu zx4}@Y9uUXF(@|W@k5_+qsM#|G+xK$j@6c8eKad)$l8`eNF=D0;9Xz{xh}^Pl|0n0d zDe)K#otVb_?kP8EV!xYe9_!Fzcm}0o6u0t$s|=(Oh{6?%kb_rW;@fw8@h`%q@1&q;A(FB;+QJ^p$t(39F3XD&_cokP#m#6XkZ^%3- zIoJWzFi;LasG=E}@?_eoxPC13E6!kyUV)pd}?v}X6 zX&N~EWWU6r>3bu<%#5%GlxQ3bHYL~|p9C8<#IE*ycPpO@cFaardspd=cT$f6@>6Bf7UH;^711a&;}VKmx8F+ zHs@<;c$4woYt%YM!IzQCpf14f0>}LZd2kWG7!=WuMLM|z1Bj=mXX(Smdmcpi+5PHA z`IOpKX5L2*u)OHJtL~o?&uRTxE;{FI-sBO_U=5nt}^gB$^=kdftMgy3|NtyuK=key3YUG-p zn4m@5oe7p@TVT8qhkzzA)sjDA8n7aHct)@KW(g;>c1`n{Qz$8v$G$C^Hc)xPDR_k> z6r_K^Jdkx;%X2xc`YoC1r?&z01YrD$5xNFhZBv3%rew|wZsQqaF`HgWMPuU4lvBKk zW3bU$32(z{S!)tCcRUc@$Uo=BB4u&4EVbdFI&c2HNi5OwL%)|m=+>$8Tl~2T=7+=5 zJ1<7{{~2TAYg2mom@QE5C7@|(XAg=k(93_72B%A73C`(ycuO7{%52?gfd1F-orb%# zYy6ly>l73Z7Awc2%`BIQw$akV$Dl&z+^Gl8_MFaEfDl3C8`#PkB3<~r21{&*a1Nvi zZqsX!6NPmA8k$nsMSeni4~EpX-zL);fgJ0{kaGZXN0j#(8(L0|8_s8A#L_p8DC~cl z4DZF|K7M20k^BAq_{Zt~1pWX@1BNH78hTU@L)OT}IK;IcDd5EYgzCC+XfU_4i9{0s z%nhb@G`IixWzQ=?922OP7BJP>)X=O&H@$85+4^J?RFey5;za|Rb$6JmzOJvK)N z6G#gdwcT^wND08|aj4Wdww@HuYNmf^b;%)4POEG4Qv1LDsDlYjBtU4b|IaslTFbu1 zgln`Rly~2+^KHTKNZlC5BLjfd$e_t)31uOutX$W7E$}2^#_Y&y_nW1L-F?q+SP74^ z#o9SdQYa6mJQNrjf`gbcK3nRSXUVYeH0??brcaL zkzlG}&9&!^m;B&LU7_>@#zR*&RL!D)W42n@&EV@7h(W#tu-UK6MJ*O94FS}wJjH&H z;7Wxt>|aD}T%^5e)4OjEXgFl&DU0h#*S}%1cgl2Ua-vVPGY)CU2FPq)rM9cWWo^Kt z716i4#At=(ra@>rB+LV}F}HuFZj6H9^Evl0IIaw|0gtH-jh3xGRh&O!!j|Tmq(I+` zZlr(!pZe!&!Pi|l&abRc@rX~5`t9t(_}4Yn7Oy4tLe!zzpB)|9ySc!o-G>Pz4Cwtb`gZWM2kn4rVE{s4MVAn~ zb91C_Xb`ANIa{CT`W?fqf5l3Wf@y@2ZCI;;JsqUuorI{nlUPH z)0_<9!56G&@C~J6O$OQFQ7w`U>hzKH3 z9-=42sO|%cg%|Z%d7;DRQ8CWpJ+4wTNaW1X9i43ETiy|gOh#gtmD{bfk+~aN?FrWO zs`TpX(Vr>enYVxVjG<#H`|otCbkHXySusa5vdDpr+fc!;cOqVqyLn{unkFq1hatlj zSz`qP#HOytU{kRc--=g7dN(Cg&M4SYP1?4xM!SC(V21)#yV&F6Z5C&A_{E?pv%Ex`Fo(Am8eT$i%WNnu!#x0Z1aOFmgecvA; z%UlX*d3S?TQR6PO>FQ#E1@0pEokPi^=82kU8y>9;NZzv!&!yK5}9_#3DA zOX6bv6RhRE1J0**ZA5a}FIc~u)=Qgm(F6M-=O=LYq@LH4OaJlJF5!MtS}hoaJKWqru- zPwIauFjer9_UqK?YU+@00bSAKae5bY-BW+qJBa38KB+u}3DpVF7@Vn+l|B5sh^^|_ zNhdx;1H=mCHpg(7eBkMrToikv*o^ZH{oBpjJ!3y^7?y&rwUqKepz~1IFsFPgS3+Sl z>;sEQ;z1$8>dbG|^|0EHL4Z;BJDU=x_TGQx29j*r?o^UAWJcnMO!z=8{TKp+1oDkW z7vQGd#nx4>beZHCqdJP=U4uWr8^1Z!CX`Z2x0}DZtwY3jN{u-@%%lMpyF7njx?*uigGN!+Tx4Z&lzfSDb%X z#288q&`$g&``kt4fdF^Z;@i-Rbo|qvykI}ZG70WNEdhFCnt;0B{8g|(e)z_ znJ#5Ulyh6??PgLb)DLv;+RsJw=Qq6x$c#Vsr730PghJqy|vAxx5gSFUOqUk0u#5oao zPDRh$r@NC8)ULcP$x#-=R6KuWY|G(F z+lO#l32(0dISu1wgg{DnfDdAAADn)`yl$}`-QxA-TF=k1 zAZ;qd#EsfEk-Ru);1V4TYsz}(2Nf}hv&Smc;S&u~x%puJPC}p5#cFFbtG=k{95Xa$ zdu}ZbeM0rkqxDuhF(YJ-E!BVD@<;0gLOd{ay#0X$w2xc-kgNs)yI@U@`_AEMf#X8U zGDD$7z1GD-4Olw-!=U(1_6K7s->QEns`zU znzdzJ!S6VmiK*u&nM$u>as}3rJz5A{fV_a5yFRHV&vux{?IHtc?3*(M6j#lU#@=jioeb0*4ZZKc4AF9+qvbkm Current: 78 + id="tspan13491"> Version: 83 Current: 78 + id="tspan10793"> Version: 83 Current: 78 + id="tspan13565"> Version: 83 "revision") ] . \ "\nSerial number: " . $RouterBoard->"serial-number") ] . \ [ $IfThenElse ([ :len ($License->"level") ] > 0) \ - ("\nLicense: " . $License->"level") ] . \ + ("\nLicense: " . $License->"level") ] . \ "\nRouterOS:" . \ "\n Channel: " . $Update->"channel" . \ "\n Installed: " . $Update->"installed-version" . \ @@ -220,11 +219,9 @@ ("\n Available: " . $Update->"latest-version") ] . \ [ $IfThenElse ($RouterBoard->"routerboard" = true && \ $RouterBoard->"current-firmware" != $RouterBoard->"upgrade-firmware") \ - ("\n Firmware: " . $RouterBoard->"current-firmware") ] . \ + ("\n Firmware: " . $RouterBoard->"current-firmware") ] . \ "\nRouterOS-Scripts:" . \ - "\n Current: " . $GlobalConfigVersion . \ - [ $IfThenElse ($GlobalConfigVersion != $ExpectedConfigVersion) \ - ("\n Expected: " . $ExpectedConfigVersion) ]); + "\n Version: " . $ExpectedConfigVersion); } # download package from upgrade server @@ -753,9 +750,9 @@ :local NewComment [ :tostr $2 ]; :global ExpectedConfigVersion; - :global GlobalConfigVersion; :global Identity; :global IDonate; + :global NoNewsAndChangesNotification; :global NotificationsWithSymbols; :global ScriptUpdatesBaseUrl; :global ScriptUpdatesFetch; @@ -926,16 +923,15 @@ } :if ($SentConfigChangesNotification != $ExpectedConfigVersion && \ - $GlobalConfigVersion < $ExpectedConfigVersion) do={ - :local NotificationMessage ("Current configuration on " . $Identity . \ - " is out of date. Please update global-config-overlay, then increase " . \ - "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \ - ") to " . $ExpectedConfigVersion . " and re-run global-config."); + $NoNewsAndChangesNotification != true) do={ + :local NotificationMessage ("The configuration version on " . $Identity . " increased " . \ + "to " . $ExpectedConfigVersion . ", current configuration may need modification. " . \ + "Please review and update global-config-overlay, then re-run global-config."); $LogPrintExit2 info $0 ($NotificationMessage) false; :if ([ :len $GlobalConfigChanges ] > 0) do={ :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); - :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ + :for I from=($ExpectedConfigVersionBefore + 1) to=$ExpectedConfigVersion do={ :local Change ($GlobalConfigChanges->[ :tostr $I ]); :set NotificationMessage ($NotificationMessage . "\n " . \ [ $IfThenElse ($NotificationsWithSymbols = true) ("\E2\97\8F") "*" ] . " " . $Change); From bbe8c02b5b9d17447d0d16d9eb5195883650a007 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Jul 2022 22:05:26 +0200 Subject: [PATCH 1152/2612] README: show a sample news and changes notification --- README.d/news-and-changes-notification.svg | 203 +++++++++++++++++++++ README.md | 5 + 2 files changed, 208 insertions(+) create mode 100644 README.d/news-and-changes-notification.svg diff --git a/README.d/news-and-changes-notification.svg b/README.d/news-and-changes-notification.svg new file mode 100644 index 0000000..6359e07 --- /dev/null +++ b/README.d/news-and-changes-notification.svg @@ -0,0 +1,203 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + [MikroTik] 📌 News and configuration changes + +The configuration version on MikroTik increased to 84, +current configuration may need modification. Please +review and update global-config-overlay, then re-run +global-config. + +Changes: + ● Introduced new setting to disable news and change +notifications, dropped version from configuration. + + + + + diff --git a/README.md b/README.md index b4d0bdf..d0f8a06 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,11 @@ everything is up-to-date it will not produce any output. ![screenshot: update scripts](README.d/08-update-scripts.avif) +If the update includes news or requires configuration changes a notification +is sent - in addition to terminal output and log messages. + +![news and changes notification](README.d/news-and-changes-notification.svg) + Adding a script --------------- From 61598c81e961862c0ac14d2ee8082d3cc956edb4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Jul 2022 08:30:25 +0200 Subject: [PATCH 1153/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index a427aed..04021c4 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -33,6 +33,7 @@ Add yourself to the list, * Oleksandr Yukhymchuk * Peter Holtkamp * Reiner Vehrenkamp +* Simon Hitzemann * Sunny Chu (@sunnychuchu) * Zac Kornilakis From 0ed68824fde075a9db02d77f276fcf79050e4d39 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 11 Jul 2022 10:38:01 +0200 Subject: [PATCH 1154/2612] check-routeros-update: drop check for package... ... as wireless package is bundled with the system with RouterOS 7.x. --- check-routeros-update | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index 3d4f14a..acca9b9 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -39,12 +39,10 @@ $ScriptLock $0; $WaitFullyConnected; -:if ([ :len [ /system/package/find where name="wireless" disabled=no ] ] > 0) do={ - :if ([ /interface/wireless/cap/get enabled ] = true && \ - [ /caps-man/manager/get enabled ] = false && \ - $SafeUpdateOnCap != true) do={ - $LogPrintExit2 error $0 ("System is managed by CAPsMAN, not checking for RouterOS version.") true; - } +:if ([ /interface/wireless/cap/get enabled ] = true && \ + [ /caps-man/manager/get enabled ] = false && \ + $SafeUpdateOnCap != true) do={ + $LogPrintExit2 error $0 ("System is managed by CAPsMAN, not checking for RouterOS version.") true; } :if ([ :len [ /system/scheduler/find where name="reboot-for-update" ] ] > 0) do={ From cb20b8c3807cbdd840d4017f466e1e82e3a9b8a5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 11 Jul 2022 10:39:43 +0200 Subject: [PATCH 1155/2612] daily-psk: properly check for disabled state The property 'disabled' can be undefined, which evaluates to enabled - but is not matched by 'disabled=no'. --- daily-psk.local | 2 +- daily-psk.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/daily-psk.local b/daily-psk.local index 23df467..e2a5886 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -69,7 +69,7 @@ $WaitFullyConnected; $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; - :if ([ :len [ /interface/wireless/find where name=$IntName disabled=no ] ] = 1) do={ + :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; diff --git a/daily-psk.template b/daily-psk.template index aa05748..bd457dc 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -74,7 +74,7 @@ $WaitFullyConnected; /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; /caps-man/access-list/set $AccList private-passphrase=$NewPsk; - :if ([ :len [ /interface/wireless/find where name=$IntName disabled=no ] ] = 1) do={ + :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ :if ([ :len [ /caps-man/interface/find where configuration=$Configuration ] ] > 0) do={ :foreach SeenSsid in=$Seen do={ :if ($SeenSsid = $Ssid) do={ From 876f8a0f8211d0bbaf04b2117986a50d854052c9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 11 Jul 2022 10:31:45 +0200 Subject: [PATCH 1156/2612] netwatch-dns: properly check for disabled state The property 'disabled' can be undefined, which evaluates to enabled - but is not matched by 'disabled=no'. --- netwatch-dns | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netwatch-dns b/netwatch-dns index 67e0408..82a8599 100644 --- a/netwatch-dns +++ b/netwatch-dns @@ -25,7 +25,7 @@ $ScriptLock $0; :local DnsFallback [ :toarray "" ]; :local DnsCurrent [ /ip/dns/get servers ]; -:foreach Host in=[ /tool/netwatch/find where comment~"dns" disabled=no ] do={ +:foreach Host in=[ /tool/netwatch/find where comment~"dns" !disabled ] do={ :local HostVal [ /tool/netwatch/get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; @@ -59,7 +59,7 @@ $ScriptLock $0; :local DohServer ""; :local DohCurrent [ /ip/dns/get use-doh-server ]; -:foreach Host in=[ /tool/netwatch/find where comment~"doh" disabled=no ] do={ +:foreach Host in=[ /tool/netwatch/find where comment~"doh" !disabled ] do={ :local HostVal [ /tool/netwatch/get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; From f9442ceaa2442686ef616578e7f6cd9fa851a4d7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 11 Jul 2022 16:22:18 +0200 Subject: [PATCH 1157/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 04021c4..e88ebdc 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -22,6 +22,7 @@ Add yourself to the list, [donate with PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)! * Abdul Mannan Abbasi +* Andrea Ruffini Perico * Andrew Cox * Christoph Boss (@Kampfwurst) * Devin Dean (@dd2594gh) From deacda86305e336d3a4b1f617f7c4a6a9e2be560 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 11 Jul 2022 17:16:25 +0200 Subject: [PATCH 1158/2612] =?UTF-8?q?give=20a=20heart=20for=20contribution?= =?UTF-8?q?s=20=E2=9D=A4=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTIONS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index e88ebdc..2620f2b 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -3,7 +3,7 @@ Past Contributions [◀ Go back to main README](README.md) -Thanks a lot for your contributions! +Thanks a lot for your contributions! â¤ī¸ ## Patches From 5b2ea9b1a4f57bc7c61d06cd8b1e0a6452f031a8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 11 Jul 2022 17:18:18 +0200 Subject: [PATCH 1159/2612] ... and another one --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d0f8a06..c7f3312 100644 --- a/README.md +++ b/README.md @@ -270,7 +270,7 @@ support! Contribute ---------- -Thanks a lot for [past contributions](CONTRIBUTIONS.md)! +Thanks a lot for [past contributions](CONTRIBUTIONS.md)! â¤ī¸ ### Patches, issues and whishlist From 073f43220407d3995bbdf554340a8ba2f089ac94 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:30:06 +0200 Subject: [PATCH 1160/2612] accesslist-duplicates: update initialization of empty array Having the parenthesis here is important for valid syntax! --- accesslist-duplicates.capsman | 4 ++-- accesslist-duplicates.local | 4 ++-- accesslist-duplicates.template | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman index e1f83a3..848ca52 100644 --- a/accesslist-duplicates.capsman +++ b/accesslist-duplicates.capsman @@ -14,8 +14,8 @@ :global Read; -:local Seen [ :toarray "" ]; -:local Shown [ :toarray "" ]; +:local Seen ({}); +:local Shown ({}); :foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Mac [ /caps-man/access-list/get $AccList mac-address ]; diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local index c1bf2a2..67f16f3 100644 --- a/accesslist-duplicates.local +++ b/accesslist-duplicates.local @@ -14,8 +14,8 @@ :global Read; -:local Seen [ :toarray "" ]; -:local Shown [ :toarray "" ]; +:local Seen ({}); +:local Shown ({}); :foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template index 8ad8e8f..8676551 100644 --- a/accesslist-duplicates.template +++ b/accesslist-duplicates.template @@ -15,8 +15,8 @@ :global Read; -:local Seen [ :toarray "" ]; -:local Shown [ :toarray "" ]; +:local Seen ({}); +:local Shown ({}); :foreach AccList in=[ /%PATH%/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Mac [ /%PATH%/access-list/get $AccList mac-address ]; From 3006e965988771e5f3aa3e531af7c2f23070c94e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:31:29 +0200 Subject: [PATCH 1161/2612] backup-email: update initialization of empty array Having the parenthesis here is important for valid syntax! --- backup-email | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backup-email b/backup-email index 55f2309..7cdf55e 100644 --- a/backup-email +++ b/backup-email @@ -50,7 +50,7 @@ $WaitFullyConnected; :local FilePath ($0 . "/" . $FileName); :local BackupFile "none"; :local ConfigFile "none"; -:local Attach [ :toarray "" ]; +:local Attach ({}); # binary backup :if ($BackupSendBinary = true) do={ From eae9a7b956a4050caeacb58b6f6176087f3c2b0a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:31:44 +0200 Subject: [PATCH 1162/2612] check-health: update initialization of empty array Having the parenthesis here is important for valid syntax! --- check-health | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-health b/check-health index 903c496..5da7d2a 100644 --- a/check-health +++ b/check-health @@ -35,10 +35,10 @@ } :if ([ :typeof $CheckHealthLast ] != "array") do={ - :set CheckHealthLast [ :toarray "" ]; + :set CheckHealthLast ({}); } :if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ - :set CheckHealthTemperatureNotified [ :toarray "" ]; + :set CheckHealthTemperatureNotified ({}); } $ScriptLock $0; From 2d30f4e4629de5a24803d34960c77d60f7490834 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:32:11 +0200 Subject: [PATCH 1163/2612] check-lte-firmware-upgrade: update initialization of empty array Having the parenthesis here is important for valid syntax! --- check-lte-firmware-upgrade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 759b138..c039dad 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -13,7 +13,7 @@ :global SentLteFirmwareUpgradeNotification; :if ([ :typeof $SentLteFirmwareUpgradeNotification ] != "array") do={ - :global SentLteFirmwareUpgradeNotification [ :toarray "" ]; + :global SentLteFirmwareUpgradeNotification ({}); } :local CheckInterface do={ From 99a8148d17f5000f7fd4065246eda03dbcbedf58 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:32:23 +0200 Subject: [PATCH 1164/2612] daily-psk: update initialization of empty array Having the parenthesis here is important for valid syntax! --- daily-psk.capsman | 2 +- daily-psk.local | 2 +- daily-psk.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/daily-psk.capsman b/daily-psk.capsman index 9f81be5..6e89ff2 100644 --- a/daily-psk.capsman +++ b/daily-psk.capsman @@ -55,7 +55,7 @@ $WaitFullyConnected; ($DailyPskSecrets->2->$WeekDay)); } -:local Seen [ :toarray "" ]; +:local Seen ({}); :local Date [ /system/clock/get date ]; :local NewPsk [ $GeneratePSK $Date ]; diff --git a/daily-psk.local b/daily-psk.local index e2a5886..3876430 100644 --- a/daily-psk.local +++ b/daily-psk.local @@ -55,7 +55,7 @@ $WaitFullyConnected; ($DailyPskSecrets->2->$WeekDay)); } -:local Seen [ :toarray "" ]; +:local Seen ({}); :local Date [ /system/clock/get date ]; :local NewPsk [ $GeneratePSK $Date ]; diff --git a/daily-psk.template b/daily-psk.template index bd457dc..af05cd7 100644 --- a/daily-psk.template +++ b/daily-psk.template @@ -56,7 +56,7 @@ $WaitFullyConnected; ($DailyPskSecrets->2->$WeekDay)); } -:local Seen [ :toarray "" ]; +:local Seen ({}); :local Date [ /system/clock/get date ]; :local NewPsk [ $GeneratePSK $Date ]; From 9a89cd54077dbb77c1130396d6218ec8fa735594 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:32:44 +0200 Subject: [PATCH 1165/2612] global-functions: update initialization of empty array Having the parenthesis here is important for valid syntax! --- global-functions | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/global-functions b/global-functions index 94f3763..8ef158a 100644 --- a/global-functions +++ b/global-functions @@ -585,7 +585,7 @@ # prepare NotificationFunctions array :if ([ :typeof $NotificationFunctions ] != "array") do={ - :set NotificationFunctions [ :toarray "" ]; + :set NotificationFunctions ({}); } # send notification via e-mail - expects one array argument @@ -612,7 +612,7 @@ } :if ([ :typeof $EmailQueue ] = "nothing") do={ - :set EmailQueue [ :toarray "" ]; + :set EmailQueue ({}); } :local Signature [ /system/note/get note ]; :set ($EmailQueue->[ :len $EmailQueue ]) { @@ -634,7 +634,7 @@ :if ([ :typeof $Source ] != "array") do={ :set Source [ :tostr $1 ]; } - :local Result [ :toarray "" ]; + :local Result ({}); :foreach KeyValue in=[ :toarray $Source ] do={ :if ([ :find $KeyValue "=" ]) do={ :set ($Result->[ :pick $KeyValue 0 [ :find $KeyValue "=" ] ]) \ @@ -974,10 +974,10 @@ :global ScriptLockOrder; :if ([ :typeof $ScriptLockOrder ] = "nothing") do={ - :set ScriptLockOrder [ :toarray "" ]; + :set ScriptLockOrder ({}); } :if ([ :typeof ($ScriptLockOrder->$Script) ] = "nothing") do={ - :set ($ScriptLockOrder->$Script) [ :toarray "" ]; + :set ($ScriptLockOrder->$Script) ({}); } :local JobCount do={ @@ -1052,7 +1052,7 @@ } } - :set ($ScriptLockOrder->$Script) [ :toarray "" ]; + :set ($ScriptLockOrder->$Script) ({}); } :if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={ @@ -1065,7 +1065,7 @@ :if ([ $TicketCount $Script ] >= [ $JobCount $Script ]) do={ $LogPrintExit2 error $0 ("More tickets than running scripts '" . $Script . "', resetting!") false; - :set ($ScriptLockOrder->$Script) [ :toarray "" ]; + :set ($ScriptLockOrder->$Script) ({}); /system/script/job/remove [ find where script=$Script ]; } From 49147c83ca2a52666e2c98762005dfb403e3d149 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:33:38 +0200 Subject: [PATCH 1166/2612] lease-script: update initialization of empty array Having the parenthesis here is important for valid syntax! --- lease-script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lease-script b/lease-script index fa03e11..cc1b6e5 100644 --- a/lease-script +++ b/lease-script @@ -31,7 +31,7 @@ $ScriptLock $0 false 10; $LogPrintExit2 debug $0 ("More invocations are waiting, exiting early.") true; } -:local RunOrder [ :toarray "" ]; +:local RunOrder ({}); :foreach Script in=[ /system/script/find where source~("\n# provides: lease-script, ") ] do={ :local Name [ /system/script/get $Script name ]; From 164ebe8c8ac57800af31c27d49d45a042fa96d8e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:33:58 +0200 Subject: [PATCH 1167/2612] log-forward: update initialization of empty array Having the parenthesis here is important for valid syntax! --- log-forward | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log-forward b/log-forward index 63c7ea7..6ccad4f 100644 --- a/log-forward +++ b/log-forward @@ -46,7 +46,7 @@ $ScriptLock $0; :local Messages ""; :local Warning false; :local MessageVal; -:local MessageDups [ :toarray "" ]; +:local MessageDups ({}); :local LogForwardFilterLogForwarding ("^Error sending e-mail <(" . \ [ $EscapeForRegEx [ $QuotedPrintable ("[" . $Identity . "] " . \ From 8436a189191060429fe3296aaafd9376ed9ad966 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:34:25 +0200 Subject: [PATCH 1168/2612] mod/bridge-port-to: update initialization of empty array Having the parenthesis here is important for valid syntax! --- mod/bridge-port-to | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/bridge-port-to b/mod/bridge-port-to index ae74824..3f62e6f 100644 --- a/mod/bridge-port-to +++ b/mod/bridge-port-to @@ -15,7 +15,7 @@ :global LogPrintExit2; :global ParseKeyValueStore; - :local InterfaceReEnable [ :toarray "" ]; + :local InterfaceReEnable ({}); :foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={ :local BridgePortVal [ /interface/bridge/port/get $BridgePort ]; :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ From 34ea2764695ad008fbb1ea4308160584491e7bc5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:34:37 +0200 Subject: [PATCH 1169/2612] mod/bridge-port-vlan: update initialization of empty array Having the parenthesis here is important for valid syntax! --- mod/bridge-port-vlan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan index a43d7d7..9a6e08a 100644 --- a/mod/bridge-port-vlan +++ b/mod/bridge-port-vlan @@ -15,7 +15,7 @@ :global LogPrintExit2; :global ParseKeyValueStore; - :local InterfaceReEnable [ :toarray "" ]; + :local InterfaceReEnable ({}); :foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={ :local BridgePortVal [ /interface/bridge/port/get $BridgePort ]; :foreach Config,Vlan in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ From 7f85e6971332f1c6f628fe04b9da7a36c59bd2d7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:34:51 +0200 Subject: [PATCH 1170/2612] mod/notification-matrix: update initialization of empty array Having the parenthesis here is important for valid syntax! --- mod/notification-matrix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-matrix b/mod/notification-matrix index f905839..c4dd27b 100644 --- a/mod/notification-matrix +++ b/mod/notification-matrix @@ -129,7 +129,7 @@ $LogPrintExit2 info $0 ("Failed sending Matrix notification! Queuing...") false; :if ([ :typeof $MatrixQueue ] = "nothing") do={ - :set MatrixQueue [ :toarray "" ]; + :set MatrixQueue ({}); } :local Text ([ $SymbolForNotification "alarm-clock" ] . \ "This message was queued since " . [ /system/clock/get date ] . \ From f34c353b5f575bdaf20c7cd2a372e0118362d815 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:35:03 +0200 Subject: [PATCH 1171/2612] mod/notification-telegram: update initialization of empty array Having the parenthesis here is important for valid syntax! --- mod/notification-telegram | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-telegram b/mod/notification-telegram index 493aa00..8c4cd65 100644 --- a/mod/notification-telegram +++ b/mod/notification-telegram @@ -139,7 +139,7 @@ $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; :if ([ :typeof $TelegramQueue ] = "nothing") do={ - :set TelegramQueue [ :toarray "" ]; + :set TelegramQueue ({}); } :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ [ $EscapeMD ("This message was queued since " . [ /system/clock/get date ] . \ From 8a85a258fc787932c7c00423091bb758ec9cbe02 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:35:18 +0200 Subject: [PATCH 1172/2612] netwatch-dns: update initialization of empty array Having the parenthesis here is important for valid syntax! --- netwatch-dns | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netwatch-dns b/netwatch-dns index 82a8599..7ec1bb4 100644 --- a/netwatch-dns +++ b/netwatch-dns @@ -21,8 +21,8 @@ $ScriptLock $0; $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; } -:local DnsServers [ :toarray "" ]; -:local DnsFallback [ :toarray "" ]; +:local DnsServers ({}); +:local DnsFallback ({}); :local DnsCurrent [ /ip/dns/get servers ]; :foreach Host in=[ /tool/netwatch/find where comment~"dns" !disabled ] do={ From d6337fcc9733b6a780cf44d2b367f1700464507e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:35:32 +0200 Subject: [PATCH 1173/2612] netwatch-notify: update initialization of empty array Having the parenthesis here is important for valid syntax! --- netwatch-notify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index a725fc3..3b84a06 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -56,7 +56,7 @@ $ScriptLock $0; } :if ([ :typeof $NetwatchNotify ] = "nothing") do={ - :set NetwatchNotify [ :toarray "" ]; + :set NetwatchNotify ({}); } :foreach Host in=[ /tool/netwatch/find where comment~"notify" !disabled ] do={ From 6fa15257003394d495f84a8dedebadfa8e1fa375 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Jul 2022 11:35:46 +0200 Subject: [PATCH 1174/2612] sms-forward: update initialization of empty array Having the parenthesis here is important for valid syntax! --- sms-forward | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sms-forward b/sms-forward index b392805..aa2e71c 100644 --- a/sms-forward +++ b/sms-forward @@ -33,7 +33,7 @@ $WaitFullyConnected; :while ([ :len [ /tool/sms/inbox/find ] ] > 0) do={ :local Phone [ /tool/sms/inbox/get ([ find ]->0) phone ]; :local Messages ""; - :local Delete [ :toarray "" ]; + :local Delete ({}); :foreach Sms in=[ /tool/sms/inbox/find where phone=$Phone ] do={ :local SmsVal [ /tool/sms/inbox/get $Sms ]; From ce03f447699677c456018c84a71accd615d01ea5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 18 Jul 2022 23:46:49 +0200 Subject: [PATCH 1175/2612] check-routeros-update: use a better check for valid version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the latest version in long-term branch is 0.0... And the script is sending downgrade notifications. 😝 Obviously that is not a valid version... With this changen a version has to be 7.0 and above to be considered valid. --- check-routeros-update | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/check-routeros-update b/check-routeros-update index acca9b9..9e1de8e 100644 --- a/check-routeros-update +++ b/check-routeros-update @@ -53,10 +53,6 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; /system/package/update/check-for-updates without-paging as-value; :local Update [ /system/package/update/get ]; -:if ([ :len ($Update->"latest-version") ] = 0) do={ - $LogPrintExit2 info $0 ("An empty string is not a valid version.") true; -} - :if ([ $ScriptFromTerminal $0 ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={ $LogPrintExit2 info $0 ("System is already up to date.") true; } @@ -65,6 +61,10 @@ $LogPrintExit2 debug $0 ("Checking for updates...") false; :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; :local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); +:if ($NumLatest < 117505792) do={ + $LogPrintExit2 info $0 ("The version '" . ($Update->"latest-version") . "' is not a valid version.") true; +} + :if ($NumInstalled < $NumLatest) do={ :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; From 518cc24108e7cfcd2836ab62fe7ff70836060fde Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 21 Jul 2022 13:21:51 +0200 Subject: [PATCH 1176/2612] global-functions: $IsFullyConnected: remove trailing space --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 8ef158a..1acf11f 100644 --- a/global-functions +++ b/global-functions @@ -472,7 +472,7 @@ } :if ([ $IsDNSResolving ] = false) do={ :return false; - } + } :if ([ $IsTimeSync ] = false) do={ :return false; } From ed7b48061a72011f43bf862c8036a0294d7a7eb2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 21 Jul 2022 13:22:58 +0200 Subject: [PATCH 1177/2612] global-functions: $IsTimeSync: drop old code In RouterOS 7.x the ntp client and server are bundled and unique and can not be unavailable. Also it does no longer have a 'last-adjustment' property... --- global-functions | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/global-functions b/global-functions index 1acf11f..6f1a6c5 100644 --- a/global-functions +++ b/global-functions @@ -484,14 +484,8 @@ :global LogPrintExit2; :if ([ /system/ntp/client/get enabled ] = true) do={ - :do { - :if ([ /system/ntp/client/get status ] = "synchronized") do={ - :return true; - } - } on-error={ - :if ([ :typeof [ /system/ntp/client/get last-adjustment ] ] = "time") do={ - :return true; - } + :if ([ /system/ntp/client/get status ] = "synchronized") do={ + :return true; } :return false; } From 329e606b9366ce81da09c6f36f68edc4c8c98384 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 21 Jul 2022 13:35:14 +0200 Subject: [PATCH 1178/2612] global-functions: $IsTimeSync: drop the extra condition... ... as ddns is not required to be enabled. The public address is available anyway, but not set in DNS. --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 6f1a6c5..cfec740 100644 --- a/global-functions +++ b/global-functions @@ -490,7 +490,7 @@ :return false; } - :if ([ /ip/cloud/get ddns-enabled ] = true && [ /ip/cloud/get update-time ] = true) do={ + :if ([ /ip/cloud/get update-time ] = true) do={ :if ([ :typeof [ /ip/cloud/get public-address ] ] = "ip") do={ :return true; } From 82f27268b3800cf11cc7f53802a70ecd87d82f06 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 21 Jul 2022 13:36:37 +0200 Subject: [PATCH 1179/2612] global-functions: $IsTimeSync: cache a positive result The functions do not rely on perfectly synced time. About the right time is fine, that should make sure certificates are valid and mails are sent with reasonable headers. So cache the result if system is fine for later use. --- global-functions | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/global-functions b/global-functions index cfec740..8d44957 100644 --- a/global-functions +++ b/global-functions @@ -481,10 +481,17 @@ # check if system time is sync :set IsTimeSync do={ + :global IsTimeSyncCached; + :global LogPrintExit2; + :if ($IsTimeSyncCached = true) do={ + :return true; + } + :if ([ /system/ntp/client/get enabled ] = true) do={ :if ([ /system/ntp/client/get status ] = "synchronized") do={ + :set IsTimeSyncCached true; :return true; } :return false; @@ -492,6 +499,7 @@ :if ([ /ip/cloud/get update-time ] = true) do={ :if ([ :typeof [ /ip/cloud/get public-address ] ] = "ip") do={ + :set IsTimeSyncCached true; :return true; } :return false; From 50178e2a3c6067c4148e3f814b60e51d1c8ced69 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 21 Jul 2022 13:59:06 +0200 Subject: [PATCH 1180/2612] capsman-download-packages: use proper array syntax --- capsman-download-packages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/capsman-download-packages b/capsman-download-packages index 1e901d8..b745f14 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -62,7 +62,7 @@ $WaitFullyConnected; } } -:foreach Log in=[ /log/find where topics=({"caps", "error"}) \ +:foreach Log in=[ /log/find where topics=({"caps"; "error"}) \ message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \ "-.*\\.npk', no such file") ] do={ :local Message [ /log/get $Log message ]; From 50d7e1fa41b8f8a6a1379de5521798346fd1ae9f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 4 Aug 2022 00:16:35 +0200 Subject: [PATCH 1181/2612] check-lte-firmware-upgrade: use $0 for $ScriptFromTerminal --- check-lte-firmware-upgrade | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index c039dad..62943ee 100644 --- a/check-lte-firmware-upgrade +++ b/check-lte-firmware-upgrade @@ -41,13 +41,13 @@ } :if (($Firmware->"installed") = ($Firmware->"latest")) do={ - :if ([ $ScriptFromTerminal "check-lte-firmware-upgrade" ] = true) do={ + :if ([ $ScriptFromTerminal $0 ] = true) do={ $LogPrintExit2 info $0 ("No firmware upgrade available for LTE interface " . $IntName . ".") false; } :return true; } - :if ([ $ScriptFromTerminal "check-lte-firmware-upgrade" ] = true && \ + :if ([ $ScriptFromTerminal $0 ] = true && \ [ :len [ /system/script/find where name="unattended-lte-firmware-upgrade" ] ] > 0) do={ :put ("Do you want to start unattended lte firmware upgrade for interface " . $IntName . "? [y/N]"); :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ From e31a99a301cb61433b21f138b1dbe00469bee9b1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 4 Aug 2022 00:41:16 +0200 Subject: [PATCH 1182/2612] unattended-lte-firmware-upgrade: try without extra reset Testing with R11e-LTE6 I can see the interface being reset by the upgrade. So the extra reset is no longer required? Trying without. --- unattended-lte-firmware-upgrade | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index d38b917..087e32d 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -18,16 +18,22 @@ :if ([ :typeof $Firmware ] = "array") do={ :if (($Firmware->"installed") != ($Firmware->"latest")) do={ :log info ("Scheduling LTE firmware upgrade for interface " . $IntName . "."); + :global LTEFirmwareUpgrade do={ :global LTEFirmwareUpgrade; :set LTEFirmwareUpgrade; + /system/scheduler/remove ($1 . "-firmware-upgrade"); /interface/lte/firmware-upgrade $1 upgrade=yes; - :log info ("LTE firmware upgrade finished, waiting for installation before reset."); + :log info ("LTE firmware upgrade on '" . $1 . "' finished, waiting for reset."); :delay 150s; - /interface/lte/at-chat $1 input="AT+RESET"; - :log info ("Reset device, waiting to finish and reconnect."); + :local Firmware [ /interface/lte/firmware-upgrade $1 once as-value ]; + :if (($Firmware->"installed") != ($Firmware->"latest")) do={ + :log warning ("LTE firmware versions still differ. Resetting again..."); + /interface/lte/at-chat $1 input="AT+RESET"; + } } + /system/scheduler/add name=($IntName . "-firmware-upgrade") start-time=startup interval=2s \ on-event=(":global LTEFirmwareUpgrade; \$LTEFirmwareUpgrade \"" . $IntName . "\";"); } else={ From 0562198c55cea78e984b07e7f753e198fb3bb7a5 Mon Sep 17 00:00:00 2001 From: Michael Gisbers Date: Thu, 4 Aug 2022 00:47:27 +0200 Subject: [PATCH 1183/2612] global-functions: $GetRandom20CharHex: use :rndstr This is available in RouterOS 7.x... Signed-off-by: Christian Hesse --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 8d44957..01c9160 100644 --- a/global-functions +++ b/global-functions @@ -402,7 +402,7 @@ # generate random 20 chars hex (0-9 and a-f) :set GetRandom20CharHex do={ - :return ([ /certificate/scep-server/otp/generate minutes-valid=0 as-value ]->"password"); + :return [ :rndstr length=20 from="0123456789abcdef" ]; } # generate random number From 28be6d097d84badd99ba1c75f789a1a86fe4bfdb Mon Sep 17 00:00:00 2001 From: Michael Gisbers Date: Thu, 4 Aug 2022 00:53:47 +0200 Subject: [PATCH 1184/2612] global-functions: $GetRandomNumber: use :rndnum This is available in RouterOS 7.x... Signed-off-by: Christian Hesse --- global-functions | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/global-functions b/global-functions index 01c9160..cd8342b 100644 --- a/global-functions +++ b/global-functions @@ -407,15 +407,9 @@ # generate random number :set GetRandomNumber do={ - :local Max 4294967295; - :if ([ :typeof $1 ] != "nothing" ) do={ - :set Max ([ :tonum $1 ] + 1); - } + :global EitherOr; - :global GetRandom20CharHex; - :global HexToNum; - - :return ([ $HexToNum [ :pick [ $GetRandom20CharHex ] 0 15 ] ] % $Max); + :return [ :rndnum from=0 to=[ $EitherOr [ :tonum $1 ] 4294967295 ] ]; } # convert from hex (string) to num From c9a7421d6c75ee54396c7b7733b9715521d029ed Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 4 Aug 2022 22:24:23 +0200 Subject: [PATCH 1185/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 2620f2b..54b3228 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -34,6 +34,7 @@ Add yourself to the list, * Oleksandr Yukhymchuk * Peter Holtkamp * Reiner Vehrenkamp +* Richard Österreicher * Simon Hitzemann * Sunny Chu (@sunnychuchu) * Zac Kornilakis From 83372d8b074194c011151f6c7cfc8bb2702731ec Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 15 Aug 2022 17:13:56 +0200 Subject: [PATCH 1186/2612] logo: optimize the svg file --- logo.svg | 143 +++++++++---------------------------------------------- 1 file changed, 22 insertions(+), 121 deletions(-) diff --git a/logo.svg b/logo.svg index f0923fd..f572033 100644 --- a/logo.svg +++ b/logo.svg @@ -1,122 +1,23 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + + From c126a5a86b06b759bf2bcb96f851e571084088ac Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 15 Aug 2022 21:31:13 +0200 Subject: [PATCH 1187/2612] check-health: increase default temperature deviation Some devices (with bad temperature sensort?) still product a flood of notifications... Try to avoid that. --- global-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config b/global-config index febef52..3d34ed2 100644 --- a/global-config +++ b/global-config @@ -103,7 +103,7 @@ board-temperature2=50; } # This is deviation on recovery threshold against notification flooding. -:global CheckHealthTemperatureDeviation 2; +:global CheckHealthTemperatureDeviation 3; :global CheckHealthVoltageLow 115; :global CheckHealthVoltagePercent 10; From 50a115f23a0948ad21571b873b4e0a1d79e7258e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 Jun 2022 22:59:32 +0200 Subject: [PATCH 1188/2612] cleanup dummy script from rotate-ntp removal --- rotate-ntp | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 rotate-ntp diff --git a/rotate-ntp b/rotate-ntp deleted file mode 100644 index 9374129..0000000 --- a/rotate-ntp +++ /dev/null @@ -1,2 +0,0 @@ -#!rsc by RouterOS -# dummy for removal From a7ec92e358493e72ead03486fab8f8b88ffdfe03 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 22 Aug 2022 16:58:31 +0200 Subject: [PATCH 1189/2612] optimize all svg files... ... and also update all version numbers to match current release. --- README.d/news-and-changes-notification.svg | 237 +++------------ doc/backup-cloud.d/notification.svg | 256 +++-------------- doc/backup-upload.d/notification.svg | 251 +++------------- doc/check-certificates.d/notification.svg | 231 +++------------ .../notification-01-voltage.svg | 206 +++----------- .../notification-02-temperature-high.svg | 191 ++----------- .../notification-03-temperature-ok.svg | 191 ++----------- .../notification-04-psu-fail.svg | 191 ++----------- doc/check-health.d/notification-05-psu-ok.svg | 191 ++----------- .../notification.svg | 216 +++----------- doc/check-routeros-update.d/notification.svg | 269 +++--------------- doc/collect-wireless-mac.d/notification.svg | 246 +++------------- doc/daily-psk.d/notification.svg | 238 +++------------- doc/log-forward.d/notification.svg | 223 +++------------ .../notification-01-down.svg | 196 ++----------- doc/netwatch-notify.d/notification-02-up.svg | 201 +++---------- doc/sms-forward.d/notification.svg | 206 +++----------- 17 files changed, 598 insertions(+), 3142 deletions(-) diff --git a/README.d/news-and-changes-notification.svg b/README.d/news-and-changes-notification.svg index 6359e07..ab8d611 100644 --- a/README.d/news-and-changes-notification.svg +++ b/README.d/news-and-changes-notification.svg @@ -1,203 +1,40 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] 📌 News and configuration changes - -The configuration version on MikroTik increased to 84, -current configuration may need modification. Please -review and update global-config-overlay, then re-run -global-config. - -Changes: - ● Introduced new setting to disable news and change -notifications, dropped version from configuration. - - - + + + + + + [MikroTik] 📌 News and configuration changes + +The configuration version on MikroTik increased to 84, +current configuration may need modification. Please +review and update global-config-overlay, then re-run +global-config. + +Changes: + ● Introduced new setting to disable news and change +notifications, dropped version from configuration. + diff --git a/doc/backup-cloud.d/notification.svg b/doc/backup-cloud.d/notification.svg index 23d78e5..a0eed63 100644 --- a/doc/backup-cloud.d/notification.svg +++ b/doc/backup-cloud.d/notification.svg @@ -1,216 +1,46 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] 💾☁ Cloud backup - -Uploaded backup for MikroTik to cloud. - -Hostname: MikroTik -Board name: CHR -Architecture: x86_64 -RouterOS: - Channel: stable - Installed: 7.1.3 -RouterOS-Scripts: - Version: 83 - -Name: cloud-20220224-092419 -Size: 370767 B (362 KiB) -Download key: LLDBfPcWXxmSetWilqeJX5V + + + + + + [MikroTik] 💾☁ Cloud backup + +Uploaded backup for MikroTik to cloud. + +Hostname: MikroTik +Board name: CHR +Architecture: x86_64 +RouterOS: + Channel: stable + Installed: 7.4.1 +RouterOS-Scripts: + Version: 83 + +Name: cloud-20220224-092419 +Size: 370767 B (362 KiB) +Download key: LLDBfPcWXxmSetWilqeJX5V + diff --git a/doc/backup-upload.d/notification.svg b/doc/backup-upload.d/notification.svg index b8af90e..73b34bd 100644 --- a/doc/backup-upload.d/notification.svg +++ b/doc/backup-upload.d/notification.svg @@ -1,212 +1,45 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] 💾âŦ† Backup & Config upload - -Backup and config export upload for MikroTik. - -Hostname: MikroTik -Board name: CHR -Architecture: x86_64 -RouterOS: - Channel: stable - Installed: 7.1.3 -RouterOS-Scripts: - Version: 83 - -Backup file: MikroTik_example_com.backup -Config file: MikroTik_example_com.rsc + + + + + + [MikroTik] 💾âŦ† Backup & Config upload + +Backup and config export upload for MikroTik. + +Hostname: MikroTik +Board name: CHR +Architecture: x86_64 +RouterOS: + Channel: stable + Installed: 7.4.1 +RouterOS-Scripts: + Version: 83 + +Backup file: MikroTik_example_com.backup +Config file: MikroTik_example_com.rsc + diff --git a/doc/check-certificates.d/notification.svg b/doc/check-certificates.d/notification.svg index a299963..e1d8baa 100644 --- a/doc/check-certificates.d/notification.svg +++ b/doc/check-certificates.d/notification.svg @@ -1,196 +1,41 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] 🔏 Certificate renewed - -A certificate on MikroTik has been renewed. - -Name: example.com -CommonName: example.com -Private key: available -Fingerprint: cc54cdd01fcd7698ecb71213874be776906eb33d26cd57754d168632f14c4c8b -Issuer: R3 -Validity: may/22/2021 22:29:34 to aug/20/2021 22:29:34 -Expires in: 11w 5d 08:18:06 + + + + + + [MikroTik] 🔏 Certificate renewed + +A certificate on MikroTik has been renewed. + +Name: example.com +CommonName: example.com +Private key: available +Fingerprint: cc54cdd01fcd7698ecb71213874be776906eb33d26cd57754d168632f14c4c8b +Issuer: R3 +Validity: may/22/2021 22:29:34 to aug/20/2021 22:29:34 +Expires in: 11w 5d 08:18:06 + diff --git a/doc/check-health.d/notification-01-voltage.svg b/doc/check-health.d/notification-01-voltage.svg index b762f61..4c9caad 100644 --- a/doc/check-health.d/notification-01-voltage.svg +++ b/doc/check-health.d/notification-01-voltage.svg @@ -1,176 +1,36 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] ⚡📉 Health warning: voltage - -The voltage on MikroTik jumped more than 10%. - -old value: 16.2V -new value: 12.4V + + + + + + [MikroTik] ⚡📉 Health warning: voltage + +The voltage on MikroTik jumped more than 10%. + +old value: 16.2V +new value: 12.4V + diff --git a/doc/check-health.d/notification-02-temperature-high.svg b/doc/check-health.d/notification-02-temperature-high.svg index 15250f8..0ab9488 100644 --- a/doc/check-health.d/notification-02-temperature-high.svg +++ b/doc/check-health.d/notification-02-temperature-high.svg @@ -1,164 +1,33 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] đŸ”Ĩ Health warning: temperature - -The temperature on MikroTik is above threshold: 51°C + + + + + + [MikroTik] đŸ”Ĩ Health warning: temperature + +The temperature on MikroTik is above threshold: 51°C + diff --git a/doc/check-health.d/notification-03-temperature-ok.svg b/doc/check-health.d/notification-03-temperature-ok.svg index d517e57..180d13f 100644 --- a/doc/check-health.d/notification-03-temperature-ok.svg +++ b/doc/check-health.d/notification-03-temperature-ok.svg @@ -1,164 +1,33 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] ✅ Health recovery: temperature - -The temperature on MikroTik dropped below threshold: 48°C + + + + + + [MikroTik] ✅ Health recovery: temperature + +The temperature on MikroTik dropped below threshold: 48°C + diff --git a/doc/check-health.d/notification-04-psu-fail.svg b/doc/check-health.d/notification-04-psu-fail.svg index 5d5d573..f7efe4b 100644 --- a/doc/check-health.d/notification-04-psu-fail.svg +++ b/doc/check-health.d/notification-04-psu-fail.svg @@ -1,164 +1,33 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] ❌ Health warning: psu1-state - -The power supply unit 'psu1-state' on MikroTik failed! + + + + + + [MikroTik] ❌ Health warning: psu1-state + +The power supply unit 'psu1-state' on MikroTik failed! + diff --git a/doc/check-health.d/notification-05-psu-ok.svg b/doc/check-health.d/notification-05-psu-ok.svg index aae56c9..0a3f05c 100644 --- a/doc/check-health.d/notification-05-psu-ok.svg +++ b/doc/check-health.d/notification-05-psu-ok.svg @@ -1,164 +1,33 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] ✅ Health recovery: psu1-state - -The power supply unit 'psu1-state' on MikroTik recovered! + + + + + + [MikroTik] ✅ Health recovery: psu1-state + +The power supply unit 'psu1-state' on MikroTik recovered! + diff --git a/doc/check-lte-firmware-upgrade.d/notification.svg b/doc/check-lte-firmware-upgrade.d/notification.svg index 70aad88..5992462 100644 --- a/doc/check-lte-firmware-upgrade.d/notification.svg +++ b/doc/check-lte-firmware-upgrade.d/notification.svg @@ -1,184 +1,38 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] ✨ LTE firmware upgrade - -A new firmware version R11e-LTE6_V027 is available -for LTE interface lte on MikroTik. - -Interface: MikroTik R11e-LTE6 -Installed: R11e-LTE6_V025 -Available: R11e-LTE6_V027 + + + + + + [MikroTik] ✨ LTE firmware upgrade + +A new firmware version R11e-LTE6_V033 is available +for LTE interface lte on MikroTik. + +Interface: MikroTik R11e-LTE6 +Installed: R11e-LTE6_V027 +Available: R11e-LTE6_V033 + diff --git a/doc/check-routeros-update.d/notification.svg b/doc/check-routeros-update.d/notification.svg index 7a1ecba..d4dbc43 100644 --- a/doc/check-routeros-update.d/notification.svg +++ b/doc/check-routeros-update.d/notification.svg @@ -1,230 +1,45 @@ - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] ✨ RouterOS update - -A new RouterOS version 7.1.3 is available for MikroTik. - -Hostname: MikroTik -Board name: CHR -Architecture: x86_64 -RouterOS: - Channel: stable - Installed: 7.1.2 - Available: 7.1.3 -RouterOS-Scripts: - Version: 83 - -🔗 https://mikrotik.com/download/changelogs/stable-release-tree + + + + + + [MikroTik] ✨ RouterOS update + +A new RouterOS version 7.4.1 is available for MikroTik. + +Hostname: MikroTik +Board name: CHR +Architecture: x86_64 +RouterOS: + Channel: stable + Installed: 7.3.1 + Available: 7.4.1 +RouterOS-Scripts: + Version: 83 + +🔗 https://mikrotik.com/download/changelogs/stable-release-tree + diff --git a/doc/collect-wireless-mac.d/notification.svg b/doc/collect-wireless-mac.d/notification.svg index fe1d20f..aae8cc5 100644 --- a/doc/collect-wireless-mac.d/notification.svg +++ b/doc/collect-wireless-mac.d/notification.svg @@ -1,208 +1,44 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] 📱 48:F1:7F:D0:E5:4E connected to Wifi - -A device with unknown MAC address connected to Wifi -on MikroTik. - -Controller: MikroTik -Interface: wl5-wifi -SSID: Wifi -MAC: 48:F1:7F:D0:E5:4E -Vendor: Intel Corporate -Hostname: host-523c8e0e -Address: 192.168.20.254 -DNS name: host-523c8e0e.dhcp.MikroTik.example.com -Date: jun/15/2021 09:21:56 + + + + + + [MikroTik] 📱 48:F1:7F:D0:E5:4E connected to Wifi + +A device with unknown MAC address connected to Wifi +on MikroTik. + +Controller: MikroTik +Interface: wl5-wifi +SSID: Wifi +MAC: 48:F1:7F:D0:E5:4E +Vendor: Intel Corporate +Hostname: host-523c8e0e +Address: 192.168.20.254 +DNS name: host-523c8e0e.dhcp.MikroTik.example.com +Date: jun/15/2021 09:21:56 + diff --git a/doc/daily-psk.d/notification.svg b/doc/daily-psk.d/notification.svg index 6c7d13a..77cf955 100644 --- a/doc/daily-psk.d/notification.svg +++ b/doc/daily-psk.d/notification.svg @@ -1,204 +1,40 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] 📅 daily PSK Guest-Wifi - -This is the daily PSK on MikroTik: - -SSID: Guest-Wifi -PSK: S3cr3tStr1ng -Date: jun/17/2021 - -A client device specific rule must not exist! - 🔗 https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi?scale=8&level=1&ssid=Guest-Wifi&pass=S3cr3tStr1ng + + + + + + [MikroTik] 📅 daily PSK Guest-Wifi + +This is the daily PSK on MikroTik: + +SSID: Guest-Wifi +PSK: S3cr3tStr1ng +Date: jun/17/2021 + +A client device specific rule must not exist! + 🔗 https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi?scale=8&level=1&ssid=Guest-Wifi&pass=S3cr3tStr1ng + diff --git a/doc/log-forward.d/notification.svg b/doc/log-forward.d/notification.svg index 373144b..9527411 100644 --- a/doc/log-forward.d/notification.svg +++ b/doc/log-forward.d/notification.svg @@ -1,192 +1,37 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] ⚠ Log Forwarding - -The log on MikroTik contains these 3 messages after 6d23:55:18 uptime. - - ● 13:24:02 script;error backup-cloud: Failed uploading backup for MikroTik to cloud! - ● 13:24:17 system;info;account user admin logged in from 192.168.88.177 via ssh - ● 13:24:57 system;info;account user admin logged out from 192.168.88.177 via ssh + + + + + + [MikroTik] ⚠ Log Forwarding + +The log on MikroTik contains these 3 messages after 6d23:55:18 uptime. + + ● 13:24:02 script;error backup-cloud: Failed uploading backup for MikroTik to cloud! + ● 13:24:17 system;info;account user admin logged in from 192.168.88.177 via ssh + ● 13:24:57 system;info;account user admin logged out from 192.168.88.177 via ssh + diff --git a/doc/netwatch-notify.d/notification-01-down.svg b/doc/netwatch-notify.d/notification-01-down.svg index 3a9133e..13988a3 100644 --- a/doc/netwatch-notify.d/notification-01-down.svg +++ b/doc/netwatch-notify.d/notification-01-down.svg @@ -1,168 +1,34 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] ❌ Netwatch Notify: example.com down - -The host 'example.com' (93.184.216.34) is down -since jun/08/2021 06:55:03. + + + + + + [MikroTik] ❌ Netwatch Notify: example.com down + +The host 'example.com' (93.184.216.34) is down +since jun/08/2021 06:55:03. + diff --git a/doc/netwatch-notify.d/notification-02-up.svg b/doc/netwatch-notify.d/notification-02-up.svg index 64e5e2d..32dfbcc 100644 --- a/doc/netwatch-notify.d/notification-02-up.svg +++ b/doc/netwatch-notify.d/notification-02-up.svg @@ -1,172 +1,35 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] ✅ Netwatch Notify: example.com up - -The host 'example.com' (93.184.216.34) is up -since jun/08/2021 07:01:00. -It was down for 6 checks since jun/08/2021 06:55:03. + + + + + + [MikroTik] ✅ Netwatch Notify: example.com up + +The host 'example.com' (93.184.216.34) is up +since jun/08/2021 07:01:00. +It was down for 6 checks since jun/08/2021 06:55:03. + diff --git a/doc/sms-forward.d/notification.svg b/doc/sms-forward.d/notification.svg index 298b43e..4b94850 100644 --- a/doc/sms-forward.d/notification.svg +++ b/doc/sms-forward.d/notification.svg @@ -1,176 +1,36 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + + + + + + + - [MikroTik] 📨 SMS Forwarding from 7277 - -Received this message by MikroTik from 7277: - -On Jun/12/2021 13:44:10 GMT -0 type class-0: -Welcome to our network! + + + + + + [MikroTik] 📨 SMS Forwarding from 7277 + +Received this message by MikroTik from 7277: + +On Jun/12/2021 13:44:10 GMT -0 type class-0: +Welcome to our network! + From 8f7a0c2a0698fd8fc9596697de61d5abc7311466 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Aug 2022 12:51:07 +0200 Subject: [PATCH 1190/2612] global-functions: $SymbolByUnicodeName: add 'earth' --- global-functions | 1 + 1 file changed, 1 insertion(+) diff --git a/global-functions b/global-functions index cd8342b..ad9f39e 100644 --- a/global-functions +++ b/global-functions @@ -1131,6 +1131,7 @@ "chart-increasing"="\F0\9F\93\88"; "cloud"="\E2\98\81"; "cross-mark"="\E2\9D\8C"; + "earth"="\F0\9F\8C\8D"; "fire"="\F0\9F\94\A5"; "floppy-disk"="\F0\9F\92\BE"; "high-voltage-sign"="\E2\9A\A1"; From e820323e7836f4f258b4af8af4e49f3d088bc18e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Aug 2022 12:52:59 +0200 Subject: [PATCH 1191/2612] global-config: add earth symbol in hello-world message for mode button --- global-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config b/global-config index 3d34ed2..a2afd66 100644 --- a/global-config +++ b/global-config @@ -128,7 +128,7 @@ # Run different commands with multiple mode-button presses. :global ModeButton { 1="/system/script/run leds-toggle-mode;"; - 2=":global SendNotification; :global Identity; \$SendNotification (\"Hello...\") (\"Hello world, \" . \$Identity . \" calling!\");"; + 2=":global Identity; :global SendNotification; :global SymbolForNotification; \$SendNotification ([ \$SymbolForNotification \"earth\" ] . \"Hello...\") (\"Hello world, \" . \$Identity . \" calling!\");"; 3="/system/shutdown;"; 4="/system/reboot;"; 5=":global BridgePortVlan; \$BridgePortVlan alt;"; From a7f8aa95d0bb676e47023cd8afecbf8dafcec176 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Sep 2022 08:53:11 +0200 Subject: [PATCH 1192/2612] netwatch-notify: show dns name (resolve option) in message --- netwatch-notify | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 3b84a06..305baba 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -63,6 +63,8 @@ $ScriptLock $0; :local HostVal [ /tool/netwatch/get $Host ]; :local Type [ $IfThenElse ($HostVal->"type" ~ "^(http-get|tcp-conn)\$") "service" "host" ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; + :local HostDetails ($HostVal->"host" . \ + [ $IfThenElse ([ :len ($HostInfo->"resolve") ] > 0) (", " . $HostInfo->"resolve") ]); :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ :local Name [ $EitherOr ($HostInfo->"name") ($HostVal->"name") ]; @@ -98,12 +100,12 @@ $ScriptLock $0; :if ($HostVal->"status" = "up") do={ :local Count ($Metric->"count"); :if ($Count > 0) do={ - $LogPrintExit2 info $0 ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . \ - ") is up.") false; + $LogPrintExit2 info $0 \ + ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is up.") false; :set ($Metric->"count") 0; } :if ($Metric->"notified" = true) do={ - :local Message ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . \ + :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ ") is up since " . $HostVal->"since" . ".\n" . \ "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ @@ -138,7 +140,7 @@ $ScriptLock $0; } } $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ - ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . ") is down for " . \ + ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is down for " . \ $Metric->"count" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ ($Metric->"notified" = true) ("already notified.") ($Count - $Metric->"count" . \ " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]) false; @@ -148,7 +150,7 @@ $ScriptLock $0; } :if ($ParentNotified = false && $Metric->"count" >= $Count && \ $Metric->"notified" != true) do={ - :local Message ("The " . $Type . " '" . $Name . "' (" . $HostVal->"host" . \ + :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ ") is down since " . $HostVal->"since" . "."); :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "down" \ From ff0b05ea20b4448a2c21d9550fd6ec2adeda41a9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Sep 2022 12:22:45 +0200 Subject: [PATCH 1193/2612] global-functions: $GetRandom20CharHex: add optional parameter for length --- global-functions | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index ad9f39e..f02da9e 100644 --- a/global-functions +++ b/global-functions @@ -402,7 +402,9 @@ # generate random 20 chars hex (0-9 and a-f) :set GetRandom20CharHex do={ - :return [ :rndstr length=20 from="0123456789abcdef" ]; + :global EitherOr; + + :return [ :rndstr length=[ $EitherOr [ :tonum $1 ] 20 ] from="0123456789abcdef" ]; } # generate random number From 8f32887a1ac2e844072a4ff41b17f8f5de04b6b2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Sep 2022 12:28:45 +0200 Subject: [PATCH 1194/2612] global-functions: introduce $GetRandom20CharAlNum --- global-functions | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/global-functions b/global-functions index f02da9e..5bbe7c4 100644 --- a/global-functions +++ b/global-functions @@ -28,6 +28,7 @@ :global EscapeForRegEx; :global FlushEmailQueue; :global GetMacVendor; +:global GetRandom20CharAlNum; :global GetRandom20CharHex; :global GetRandomNumber; :global HexToNum; @@ -400,6 +401,13 @@ } } +# generate random 20 chars alphabetical (A-Z & a-z) and numerical (0-9) +:set GetRandom20CharAlNum do={ + :global EitherOr; + + :return [ :rndstr length=[ $EitherOr [ :tonum $1 ] 20 ] from="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" ]; +} + # generate random 20 chars hex (0-9 and a-f) :set GetRandom20CharHex do={ :global EitherOr; From 95274e0d23d956c48be2fdecd502a05e00bcd359 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Sep 2022 21:54:14 +0200 Subject: [PATCH 1195/2612] netwatch-notify: rename variable --- netwatch-notify | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 305baba..994a8d1 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -98,8 +98,8 @@ $ScriptLock $0; } :if ($HostVal->"status" = "up") do={ - :local Count ($Metric->"count"); - :if ($Count > 0) do={ + :local CountDown ($Metric->"count"); + :if ($CountDown > 0) do={ $LogPrintExit2 info $0 \ ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is up.") false; :set ($Metric->"count") 0; @@ -107,7 +107,7 @@ $ScriptLock $0; :if ($Metric->"notified" = true) do={ :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ ") is up since " . $HostVal->"since" . ".\n" . \ - "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); + "It was down for " . $CountDown . " checks since " . ($Metric->"since") . "."); :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "up" \ ($HostInfo->"up-hook") ]); @@ -124,10 +124,10 @@ $ScriptLock $0; :set ($Metric->"count") ($Metric->"count" + 1); :set ($Metric->"parent") ($HostInfo->"parent"); :set ($Metric->"since") ($HostVal->"since"); - :local Count [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; + :local CountDown [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; :local Parent ($HostInfo->"parent"); :while ([ :len $Parent ] > 0) do={ - :set Count ($Count + 1); + :set CountDown ($CountDown + 1); :set Parent ($NetwatchNotify->$Parent->"parent"); } :set Parent ($HostInfo->"parent"); @@ -142,13 +142,13 @@ $ScriptLock $0; $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is down for " . \ $Metric->"count" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ - ($Metric->"notified" = true) ("already notified.") ($Count - $Metric->"count" . \ + ($Metric->"notified" = true) ("already notified.") ($CountDown - $Metric->"count" . \ " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]) false; - :if ((($Count * 2) - ($Metric->"count" * 3)) / 2 = 0 && \ + :if ((($CountDown * 2) - ($Metric->"count" * 3)) / 2 = 0 && \ [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ $NetwatchNotifyHook $Name $Type "pre-down" ($HostInfo->"pre-down-hook"); } - :if ($ParentNotified = false && $Metric->"count" >= $Count && \ + :if ($ParentNotified = false && $Metric->"count" >= $CountDown && \ $Metric->"notified" != true) do={ :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ ") is down since " . $HostVal->"since" . "."); From 6f772e92a616acb15bdef8ab7b7bfdb9d002bfeb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Sep 2022 21:54:57 +0200 Subject: [PATCH 1196/2612] netwatch-notify: rename array element --- netwatch-notify | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 994a8d1..0451823 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -69,7 +69,7 @@ $ScriptLock $0; :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ :local Name [ $EitherOr ($HostInfo->"name") ($HostVal->"name") ]; - :local Metric { "count"=0; "notified"=false }; + :local Metric { "count-down"=0; "notified"=false }; :if ([ :typeof ($NetwatchNotify->$Name) ] = "array") do={ :set $Metric ($NetwatchNotify->$Name); } @@ -98,11 +98,11 @@ $ScriptLock $0; } :if ($HostVal->"status" = "up") do={ - :local CountDown ($Metric->"count"); + :local CountDown ($Metric->"count-down"); :if ($CountDown > 0) do={ $LogPrintExit2 info $0 \ ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is up.") false; - :set ($Metric->"count") 0; + :set ($Metric->"count-down") 0; } :if ($Metric->"notified" = true) do={ :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ @@ -121,10 +121,10 @@ $ScriptLock $0; :set ($Metric->"parent") ($HostInfo->"parent"); :set ($Metric->"since"); } else={ - :set ($Metric->"count") ($Metric->"count" + 1); + :set ($Metric->"count-down") ($Metric->"count-down" + 1); :set ($Metric->"parent") ($HostInfo->"parent"); :set ($Metric->"since") ($HostVal->"since"); - :local CountDown [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; + :local CountDown [ $IfThenElse ([ :tonum ($HostInfo->"count-down") ] > 0) ($HostInfo->"count-down") 5 ]; :local Parent ($HostInfo->"parent"); :while ([ :len $Parent ] > 0) do={ :set CountDown ($CountDown + 1); @@ -141,14 +141,14 @@ $ScriptLock $0; } $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is down for " . \ - $Metric->"count" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ - ($Metric->"notified" = true) ("already notified.") ($CountDown - $Metric->"count" . \ + $Metric->"count-down" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ + ($Metric->"notified" = true) ("already notified.") ($CountDown - $Metric->"count-down" . \ " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]) false; - :if ((($CountDown * 2) - ($Metric->"count" * 3)) / 2 = 0 && \ + :if ((($CountDown * 2) - ($Metric->"count-down" * 3)) / 2 = 0 && \ [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ $NetwatchNotifyHook $Name $Type "pre-down" ($HostInfo->"pre-down-hook"); } - :if ($ParentNotified = false && $Metric->"count" >= $CountDown && \ + :if ($ParentNotified = false && $Metric->"count-down" >= $CountDown && \ $Metric->"notified" != true) do={ :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ ") is down since " . $HostVal->"since" . "."); @@ -166,7 +166,7 @@ $ScriptLock $0; } } :set ($NetwatchNotify->$Name) { - "count"=($Metric->"count"); + "count-down"=($Metric->"count-down"); "notified"=($Metric->"notified"); "parent"=($Metric->"parent"); "resolve-failed"=($Metric->"resolve-failed"); From a6645b3e75d55ad0028f349a8c4de5618e77beb7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Sep 2022 22:02:46 +0200 Subject: [PATCH 1197/2612] netwatch-notify: add new array element to count up-checks --- netwatch-notify | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index 0451823..dbf6e10 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -69,7 +69,7 @@ $ScriptLock $0; :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ :local Name [ $EitherOr ($HostInfo->"name") ($HostVal->"name") ]; - :local Metric { "count-down"=0; "notified"=false }; + :local Metric { "count-down"=0; "count-up"=0; "notified"=false }; :if ([ :typeof ($NetwatchNotify->$Name) ] = "array") do={ :set $Metric ($NetwatchNotify->$Name); } @@ -104,6 +104,7 @@ $ScriptLock $0; ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is up.") false; :set ($Metric->"count-down") 0; } + :set ($Metric->"count-up") ($Metric->"count-up" + 1); :if ($Metric->"notified" = true) do={ :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ ") is up since " . $HostVal->"since" . ".\n" . \ @@ -122,6 +123,7 @@ $ScriptLock $0; :set ($Metric->"since"); } else={ :set ($Metric->"count-down") ($Metric->"count-down" + 1); + :set ($Metric->"count-up") 0; :set ($Metric->"parent") ($HostInfo->"parent"); :set ($Metric->"since") ($HostVal->"since"); :local CountDown [ $IfThenElse ([ :tonum ($HostInfo->"count-down") ] > 0) ($HostInfo->"count-down") 5 ]; @@ -167,6 +169,7 @@ $ScriptLock $0; } :set ($NetwatchNotify->$Name) { "count-down"=($Metric->"count-down"); + "count-up"=($Metric->"count-up"); "notified"=($Metric->"notified"); "parent"=($Metric->"parent"); "resolve-failed"=($Metric->"resolve-failed"); From 5aff4019fe00f9c5781efb0cd1a37863b8eacab5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 7 Sep 2022 22:16:11 +0200 Subject: [PATCH 1198/2612] netwatch-notify: do not (yet) notify if parent is up recently Monitoring a VPN (or similar) may be tricky: This used to send notifications if the physical connection recovered, but the VPN and/or its routing did not yet. Let's work around and send notification only if the parent is up for at least three checks. --- netwatch-notify | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index dbf6e10..1d285de 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -128,6 +128,7 @@ $ScriptLock $0; :set ($Metric->"since") ($HostVal->"since"); :local CountDown [ $IfThenElse ([ :tonum ($HostInfo->"count-down") ] > 0) ($HostInfo->"count-down") 5 ]; :local Parent ($HostInfo->"parent"); + :local ParentUp false; :while ([ :len $Parent ] > 0) do={ :set CountDown ($CountDown + 1); :set Parent ($NetwatchNotify->$Parent->"parent"); @@ -137,6 +138,7 @@ $ScriptLock $0; :while ($ParentNotified = false && [ :len $Parent ] > 0) do={ :set ParentNotified [ $IfThenElse (($NetwatchNotify->$Parent->"notified") = true) \ true false ]; + :set ParentUp ($NetwatchNotify->$Parent->"count-up"); :if ($ParentNotified = false) do={ :set Parent ($NetwatchNotify->$Parent->"parent"); } @@ -151,7 +153,7 @@ $ScriptLock $0; $NetwatchNotifyHook $Name $Type "pre-down" ($HostInfo->"pre-down-hook"); } :if ($ParentNotified = false && $Metric->"count-down" >= $CountDown && \ - $Metric->"notified" != true) do={ + ($ParentUp = false || $ParentUp > 2) && $Metric->"notified" != true) do={ :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ ") is down since " . $HostVal->"since" . "."); :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ From a1af9577ca2e1300aa920ff5b05cd4a4492f5f88 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 9 Sep 2022 14:02:02 +0200 Subject: [PATCH 1199/2612] global-functions: $ScriptInstallUpdate: prepare for future certificate chain --- global-functions | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/global-functions b/global-functions index 5bbe7c4..e66415b 100644 --- a/global-functions +++ b/global-functions @@ -777,6 +777,10 @@ $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; } + :if ([ $CertificateAvailable "E1" ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; + } + :foreach Script in=$Scripts do={ :if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={ $LogPrintExit2 info $0 ("Adding new script: " . $Script) false; From e927c6b08bf5b8d845dc34015fe8765fb8fa7376 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 12 Sep 2022 15:41:15 +0200 Subject: [PATCH 1200/2612] global-functions: $GetMacVendor: switched to Let's Encrypt (R3) So let's check for the correct one, and drop the other. --- certs/Cloudflare Inc ECC CA-3.pem | 166 ------------------------------ global-functions | 2 +- 2 files changed, 1 insertion(+), 167 deletions(-) delete mode 100644 certs/Cloudflare Inc ECC CA-3.pem diff --git a/certs/Cloudflare Inc ECC CA-3.pem b/certs/Cloudflare Inc ECC CA-3.pem deleted file mode 100644 index e2de16a..0000000 --- a/certs/Cloudflare Inc ECC CA-3.pem +++ /dev/null @@ -1,166 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 0a:37:87:64:5e:5f:b4:8c:22:4e:fd:1b:ed:14:0c:3c - Signature Algorithm: sha256WithRSAEncryption - Issuer: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root - Validity - Not Before: Jan 27 12:48:08 2020 GMT - Not After : Dec 31 23:59:59 2024 GMT - Subject: C = US, O = "Cloudflare, Inc.", CN = Cloudflare Inc ECC CA-3 - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (256 bit) - pub: - 04:b9:ad:4d:66:99:14:0b:46:ec:1f:81:d1:2a:50: - 1e:9d:03:15:2f:34:12:7d:2d:96:b8:88:38:9b:85: - 5f:8f:bf:bb:4d:ef:61:46:c4:c9:73:d4:24:4f:e0: - ee:1c:ce:6c:b3:51:71:2f:6a:ee:4c:05:09:77:d3: - 72:62:a4:9b:d7 - ASN1 OID: prime256v1 - NIST CURVE: P-256 - X509v3 extensions: - X509v3 Subject Key Identifier: - A5:CE:37:EA:EB:B0:75:0E:94:67:88:B4:45:FA:D9:24:10:87:96:1F - X509v3 Authority Key Identifier: - keyid:E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 - - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - Authority Information Access: - OCSP - URI:http://ocsp.digicert.com - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://crl3.digicert.com/Omniroot2025.crl - - X509v3 Certificate Policies: - Policy: 2.16.840.1.114412.1.1 - CPS: https://www.digicert.com/CPS - Policy: 2.16.840.1.114412.1.2 - Policy: 2.23.140.1.2.1 - Policy: 2.23.140.1.2.2 - Policy: 2.23.140.1.2.3 - - Signature Algorithm: sha256WithRSAEncryption - 05:24:1d:dd:1b:b0:2a:eb:98:d6:85:e3:39:4d:5e:6b:57:9d: - 82:57:fc:eb:e8:31:a2:57:90:65:05:be:16:44:38:5a:77:02: - b9:cf:10:42:c6:e1:92:a4:e3:45:27:f8:00:47:2c:68:a8:56: - 99:53:54:8f:ad:9e:40:c1:d0:0f:b6:d7:0d:0b:38:48:6c:50: - 2c:49:90:06:5b:64:1d:8b:cc:48:30:2e:de:08:e2:9b:49:22: - c0:92:0c:11:5e:96:92:94:d5:fc:20:dc:56:6c:e5:92:93:bf: - 7a:1c:c0:37:e3:85:49:15:fa:2b:e1:74:39:18:0f:b7:da:f3: - a2:57:58:60:4f:cc:8e:94:00:fc:46:7b:34:31:3e:4d:47:82: - 81:3a:cb:f4:89:5d:0e:ef:4d:0d:6e:9c:1b:82:24:dd:32:25: - 5d:11:78:51:10:3d:a0:35:23:04:2f:65:6f:9c:c1:d1:43:d7: - d0:1e:f3:31:67:59:27:dd:6b:d2:75:09:93:11:24:24:14:cf: - 29:be:e6:23:c3:b8:8f:72:3f:e9:07:c8:24:44:53:7a:b3:b9: - 61:65:a1:4c:0e:c6:48:00:c9:75:63:05:87:70:45:52:83:d3: - 95:9d:45:ea:f0:e8:31:1d:7e:09:1f:0a:fe:3e:dd:aa:3c:5e: - 74:d2:ac:b1 ------BEGIN CERTIFICATE----- -MIIDzTCCArWgAwIBAgIQCjeHZF5ftIwiTv0b7RQMPDANBgkqhkiG9w0BAQsFADBa -MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl -clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTIw -MDEyNzEyNDgwOFoXDTI0MTIzMTIzNTk1OVowSjELMAkGA1UEBhMCVVMxGTAXBgNV -BAoTEENsb3VkZmxhcmUsIEluYy4xIDAeBgNVBAMTF0Nsb3VkZmxhcmUgSW5jIEVD -QyBDQS0zMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEua1NZpkUC0bsH4HRKlAe -nQMVLzQSfS2WuIg4m4Vfj7+7Te9hRsTJc9QkT+DuHM5ss1FxL2ruTAUJd9NyYqSb -16OCAWgwggFkMB0GA1UdDgQWBBSlzjfq67B1DpRniLRF+tkkEIeWHzAfBgNVHSME -GDAWgBTlnVkwgkdYzKz6CFQ2hns6tQRN8DAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0l -BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYI -KwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j -b20wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL09t -bmlyb290MjAyNS5jcmwwbQYDVR0gBGYwZDA3BglghkgBhv1sAQEwKjAoBggrBgEF -BQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzALBglghkgBhv1sAQIw -CAYGZ4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggEB -AAUkHd0bsCrrmNaF4zlNXmtXnYJX/OvoMaJXkGUFvhZEOFp3ArnPEELG4ZKk40Un -+ABHLGioVplTVI+tnkDB0A+21w0LOEhsUCxJkAZbZB2LzEgwLt4I4ptJIsCSDBFe -lpKU1fwg3FZs5ZKTv3ocwDfjhUkV+ivhdDkYD7fa86JXWGBPzI6UAPxGezQxPk1H -goE6y/SJXQ7vTQ1unBuCJN0yJV0ReFEQPaA1IwQvZW+cwdFD19Ae8zFnWSfda9J1 -CZMRJCQUzym+5iPDuI9yP+kHyCREU3qzuWFloUwOxkgAyXVjBYdwRVKD05WdRerw -6DEdfgkfCv4+3ao8XnTSrLE= ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 33554617 (0x20000b9) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root - Validity - Not Before: May 12 18:46:00 2000 GMT - Not After : May 12 23:59:00 2025 GMT - Subject: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:a3:04:bb:22:ab:98:3d:57:e8:26:72:9a:b5:79: - d4:29:e2:e1:e8:95:80:b1:b0:e3:5b:8e:2b:29:9a: - 64:df:a1:5d:ed:b0:09:05:6d:db:28:2e:ce:62:a2: - 62:fe:b4:88:da:12:eb:38:eb:21:9d:c0:41:2b:01: - 52:7b:88:77:d3:1c:8f:c7:ba:b9:88:b5:6a:09:e7: - 73:e8:11:40:a7:d1:cc:ca:62:8d:2d:e5:8f:0b:a6: - 50:d2:a8:50:c3:28:ea:f5:ab:25:87:8a:9a:96:1c: - a9:67:b8:3f:0c:d5:f7:f9:52:13:2f:c2:1b:d5:70: - 70:f0:8f:c0:12:ca:06:cb:9a:e1:d9:ca:33:7a:77: - d6:f8:ec:b9:f1:68:44:42:48:13:d2:c0:c2:a4:ae: - 5e:60:fe:b6:a6:05:fc:b4:dd:07:59:02:d4:59:18: - 98:63:f5:a5:63:e0:90:0c:7d:5d:b2:06:7a:f3:85: - ea:eb:d4:03:ae:5e:84:3e:5f:ff:15:ed:69:bc:f9: - 39:36:72:75:cf:77:52:4d:f3:c9:90:2c:b9:3d:e5: - c9:23:53:3f:1f:24:98:21:5c:07:99:29:bd:c6:3a: - ec:e7:6e:86:3a:6b:97:74:63:33:bd:68:18:31:f0: - 78:8d:76:bf:fc:9e:8e:5d:2a:86:a7:4d:90:dc:27: - 1a:39 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Subject Key Identifier: - E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:3 - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - Signature Algorithm: sha1WithRSAEncryption - 85:0c:5d:8e:e4:6f:51:68:42:05:a0:dd:bb:4f:27:25:84:03: - bd:f7:64:fd:2d:d7:30:e3:a4:10:17:eb:da:29:29:b6:79:3f: - 76:f6:19:13:23:b8:10:0a:f9:58:a4:d4:61:70:bd:04:61:6a: - 12:8a:17:d5:0a:bd:c5:bc:30:7c:d6:e9:0c:25:8d:86:40:4f: - ec:cc:a3:7e:38:c6:37:11:4f:ed:dd:68:31:8e:4c:d2:b3:01: - 74:ee:be:75:5e:07:48:1a:7f:70:ff:16:5c:84:c0:79:85:b8: - 05:fd:7f:be:65:11:a3:0f:c0:02:b4:f8:52:37:39:04:d5:a9: - 31:7a:18:bf:a0:2a:f4:12:99:f7:a3:45:82:e3:3c:5e:f5:9d: - 9e:b5:c8:9e:7c:2e:c8:a4:9e:4e:08:14:4b:6d:fd:70:6d:6b: - 1a:63:bd:64:e6:1f:b7:ce:f0:f2:9f:2e:bb:1b:b7:f2:50:88: - 73:92:c2:e2:e3:16:8d:9a:32:02:ab:8e:18:dd:e9:10:11:ee: - 7e:35:ab:90:af:3e:30:94:7a:d0:33:3d:a7:65:0f:f5:fc:8e: - 9e:62:cf:47:44:2c:01:5d:bb:1d:b5:32:d2:47:d2:38:2e:d0: - fe:81:dc:32:6a:1e:b5:ee:3c:d5:fc:e7:81:1d:19:c3:24:42: - ea:63:39:a9 ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ -RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD -VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX -DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y -ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy -VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr -mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr -IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK -mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu -XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy -dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye -jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 -BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 -DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 -9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx -jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 -Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz -ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS -R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE----- diff --git a/global-functions b/global-functions index e66415b..df286b5 100644 --- a/global-functions +++ b/global-functions @@ -383,7 +383,7 @@ :global LogPrintExit2; :do { - :if ([ $CertificateAvailable "Cloudflare Inc ECC CA-3" ] = false) do={ + :if ([ $CertificateAvailable "R3" ] = false) do={ $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; } :local Vendor ([ /tool/fetch check-certificate=yes-without-crl \ From 3988c7029096913348ebcc2f2b443c4a85325f8b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Sep 2022 11:05:16 +0200 Subject: [PATCH 1201/2612] doc/netwatch-dns: fix example command... This broke with: * doc/netwatch-dns: giving hostname in comment is not required 9853943a365639f675fba0bb9c1d64b7edfd00d7 --- doc/netwatch-dns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 8e897d1..e8caaa1 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -39,7 +39,7 @@ If *cloudflare-dns* is down the script will fall back to *quad-nine* for DoH. Giving a specific query url for DoH is possible: - /tool/netwatch/add comment="doh, ame=nextdns, doh-url=https://dns.nextdns.io/dns-query" host=199.247.16.158; + /tool/netwatch/add comment="doh, doh-url=https://dns.nextdns.io/dns-query" host=199.247.16.158; Note that using a name in DoH url may introduce a chicken-and-egg issue! From 220dd8f892ee3f0864ea13838642bc40a574dcb5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 13 Sep 2022 09:01:40 +0200 Subject: [PATCH 1202/2612] netwatch-dns: support downloading / importing certificate --- doc/netwatch-dns.md | 7 +++++++ netwatch-dns | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index e8caaa1..65d0488 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -43,6 +43,13 @@ Giving a specific query url for DoH is possible: Note that using a name in DoH url may introduce a chicken-and-egg issue! +Importing a certificate automatically is possible, at least if available in +the repository (see `certs` sub directory). + + /tool/netwatch/add comment="doh, doh-cert=DigiCert TLS Hybrid ECC SHA384 2020 CA1" host=1.1.1.1; + /tool/netwatch/add comment="doh, doh-cert=DigiCert TLS Hybrid ECC SHA384 2020 CA1" host=9.9.9.9; + /tool/netwatch/add comment="doh, doh-cert=GTS CA 1C3" host=8.8.8.8; + Sometimes using just one specific (possibly internal) DNS server may be desired, with fallback in case it fails. This is possible as well: diff --git a/netwatch-dns b/netwatch-dns index 7ec1bb4..f828de0 100644 --- a/netwatch-dns +++ b/netwatch-dns @@ -10,6 +10,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:global CertificateAvailable; :global EitherOr; :global LogPrintExit2; :global ParseKeyValueStore; @@ -58,6 +59,7 @@ $ScriptLock $0; :local DohServer ""; :local DohCurrent [ /ip/dns/get use-doh-server ]; +:local DohCert ""; :foreach Host in=[ /tool/netwatch/find where comment~"doh" !disabled ] do={ :local HostVal [ /tool/netwatch/get $Host ]; @@ -67,12 +69,19 @@ $ScriptLock $0; $HostInfo->"disabled" != true && $DohServer = "") do={ :set DohServer [ $EitherOr ($HostInfo->"doh-url") \ ("https://" . $HostVal->"host" . "/dns-query") ]; + :set DohCert ($HostInfo->"doh-cert"); } } :if ($DohServer != "") do={ :if ($DohServer != $DohCurrent) do={ $LogPrintExit2 info $0 ("Updating DoH server: " . $DohServer) false; + :if ([ :len $DohCert ] > 0) do={ + /ip/dns/set use-doh-server=""; + :if ([ $CertificateAvailable $DohCert ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; + } + } /ip/dns/set use-doh-server=$DohServer; /ip/dns/cache/flush; } From f2457513399799a5183f00738081a606efd39afc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 15 Sep 2022 21:49:06 +0200 Subject: [PATCH 1203/2612] global-functions: $FlushEmailQueue: do not flush with resolver issues Flushing the mail queue with resolver issues can flood the log with messages like: e-mail;error Error sending e-mail <=?utf-8?Q?[MikroTik] =F0=9F=92=BE=E2=98=81 Cloud backup?=>: DNS resolve failed Try to avoid this... --- global-functions | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/global-functions b/global-functions index df286b5..8d8ac1c 100644 --- a/global-functions +++ b/global-functions @@ -323,6 +323,7 @@ :global EmailQueue; :global EitherOr; + :global IsDNSResolving; :global IsTimeSync; :global LogPrintExit2; @@ -334,6 +335,11 @@ :return false; } + :if ([ :typeof [ :toip [ /tool/e-mail/get address ] ] ] != "ip" && [ $IsDNSResolving ] = false) do={ + $LogPrintExit2 debug $0 ("Server address is a DNS name and resolving fails, not flushing.") false; + :return false; + } + :if ([ :len [ /system/scheduler/find where name="FlushEmailQueue" ] ] > 0 && $QueueLen = 0) do={ $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; } From 3f92edb5c1a5415de5e9ebfd4a5139cb687d3956 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 15 Sep 2022 21:56:31 +0200 Subject: [PATCH 1204/2612] global-functions: $FlushEmailQueue: use $0 for scheduler name --- global-functions | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/global-functions b/global-functions index 8d8ac1c..7c8bfdc 100644 --- a/global-functions +++ b/global-functions @@ -340,11 +340,11 @@ :return false; } - :if ([ :len [ /system/scheduler/find where name="FlushEmailQueue" ] ] > 0 && $QueueLen = 0) do={ + :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; } - /system/scheduler/set interval=($QueueLen . "m") [ find where name="FlushEmailQueue" ]; + /system/scheduler/set interval=($QueueLen . "m") [ find where name=$0 ]; :foreach Id,Message in=$EmailQueue do={ :if ([ :typeof $Message ] = "array" ) do={ @@ -374,10 +374,10 @@ } :if ($AllDone = true && $QueueLen = [ :len $EmailQueue ]) do={ - /system/scheduler/remove [ find where name="FlushEmailQueue" ]; + /system/scheduler/remove [ find where name=$0 ]; :set EmailQueue; } else={ - /system/scheduler/set interval=1m [ find where name="FlushEmailQueue" ]; + /system/scheduler/set interval=1m [ find where name=$0 ]; } } @@ -634,8 +634,8 @@ [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \ attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") }; - :if ([ :len [ /system/scheduler/find where name="FlushEmailQueue" ] ] = 0) do={ - /system/scheduler/add name=FlushEmailQueue interval=1s start-time=startup \ + :if ([ :len [ /system/scheduler/find where name="\$FlushEmailQueue" ] ] = 0) do={ + /system/scheduler/add name="\$FlushEmailQueue" interval=1s start-time=startup \ on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); } } From 47e4f292cba0059f55eb7e3aec1ca0d237ecf4b3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 15 Sep 2022 21:59:06 +0200 Subject: [PATCH 1205/2612] mod/notification-telegram: $FlushTelegramQueue: use $0 for scheduler name --- mod/notification-telegram | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mod/notification-telegram b/mod/notification-telegram index 8c4cd65..849740b 100644 --- a/mod/notification-telegram +++ b/mod/notification-telegram @@ -23,7 +23,7 @@ :local AllDone true; :local QueueLen [ :len $TelegramQueue ]; - :if ([ :len [ /system/scheduler/find where name="FlushTelegramQueue" ] ] > 0 && $QueueLen = 0) do={ + :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ $LogPrintExit2 warning $0 ("Flushing Telegram messages from scheduler, but queue is empty.") false; } @@ -45,7 +45,7 @@ } :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ - /system/scheduler/remove [ find where name="FlushTelegramQueue" ]; + /system/scheduler/remove [ find where name=$0 ]; :set TelegramQueue; } } @@ -146,8 +146,8 @@ " " . [ /system/clock/get time ] . " and may be obsolete.") "plain" ]) ]); :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; parsemode=$ParseMode; text=$Text; silent=($Notification->"silent") }; - :if ([ :len [ /system/scheduler/find where name="FlushTelegramQueue" ] ] = 0) do={ - /system/scheduler/add name=FlushTelegramQueue interval=1m start-time=startup \ + :if ([ :len [ /system/scheduler/find where name="\$FlushTelegramQueue" ] ] = 0) do={ + /system/scheduler/add name="\$FlushTelegramQueue" interval=1m start-time=startup \ on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;"); } } From c33e813f20839cb3bc0f56003ca5336229bfa430 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 15 Sep 2022 22:01:08 +0200 Subject: [PATCH 1206/2612] mod/notification-matrix: $FlushMatrixQueue: use $0 for scheduler name --- mod/notification-matrix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mod/notification-matrix b/mod/notification-matrix index c4dd27b..5a5f8cf 100644 --- a/mod/notification-matrix +++ b/mod/notification-matrix @@ -24,7 +24,7 @@ :local AllDone true; :local QueueLen [ :len $MatrixQueue ]; - :if ([ :len [ /system/scheduler/find where name="FlushMatrixQueue" ] ] > 0 && $QueueLen = 0) do={ + :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ $LogPrintExit2 warning $0 ("Flushing Matrix messages from scheduler, but queue is empty.") false; } @@ -46,7 +46,7 @@ } :if ($AllDone = true && $QueueLen = [ :len $MatrixQueue ]) do={ - /system/scheduler/remove [ find where name="FlushMatrixQueue" ]; + /system/scheduler/remove [ find where name=$0 ]; :set MatrixQueue; } } @@ -139,8 +139,8 @@ :set ($MatrixQueue->[ :len $MatrixQueue ]) { room=$Room; \ accesstoken=$AccessToken; homeserver=$HomeServer; \ plain=$Plain; formatted=$Formatted }; - :if ([ :len [ /system/scheduler/find where name="FlushMatrixQueue" ] ] = 0) do={ - /system/scheduler/add name=FlushMatrixQueue interval=1m start-time=startup \ + :if ([ :len [ /system/scheduler/find where name="\$FlushMatrixQueue" ] ] = 0) do={ + /system/scheduler/add name="\$FlushMatrixQueue" interval=1m start-time=startup \ on-event=(":global FlushMatrixQueue; \$FlushMatrixQueue;"); } } From 84b5e77860e2705c257273395cf21ea4e3da5ccf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 20 Sep 2022 09:17:57 +0200 Subject: [PATCH 1207/2612] global-functions: $GetMacVendor: detect locally administered addresses https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local_(U/L_bit) --- global-functions | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/global-functions b/global-functions index 7c8bfdc..3f7a65e 100644 --- a/global-functions +++ b/global-functions @@ -388,6 +388,10 @@ :global CertificateAvailable; :global LogPrintExit2; + :if ([ :tonum ("0x" . [ :pick $Mac 0 [ :find $Mac ":" ] ]) ] & 2 = 2) do={ + :return "locally administered"; + } + :do { :if ([ $CertificateAvailable "R3" ] = false) do={ $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; From 493e4fc8c116e094a420adb4cb2383065cf02443 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 20 Sep 2022 22:40:47 +0200 Subject: [PATCH 1208/2612] netwatch-notify: use a counter for resolve failures This should relax the error message a bit as it is not triggered on first failure. --- netwatch-notify | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/netwatch-notify b/netwatch-notify index 1d285de..f95f426 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -69,7 +69,7 @@ $ScriptLock $0; :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ :local Name [ $EitherOr ($HostInfo->"name") ($HostVal->"name") ]; - :local Metric { "count-down"=0; "count-up"=0; "notified"=false }; + :local Metric { "count-down"=0; "count-up"=0; "notified"=false; "resolve-failcnt"=0 }; :if ([ :typeof ($NetwatchNotify->$Name) ] = "array") do={ :set $Metric ($NetwatchNotify->$Name); } @@ -84,14 +84,14 @@ $ScriptLock $0; $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ ", updating.") false; /tool/netwatch/set host=$Resolve $Host; - :set ($Metric->"resolve-failed") false; + :set ($Metric->"resolve-failcnt") 0; } } on-error={ - :if ($Metric->"resolve-failed" != true) do={ + :set ($Metric->"resolve-failcnt") ($Metric->"resolve-failcnt" + 1); + :if ($Metric->"resolve-failcnt" = 3) do={ $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \ ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ $HostInfo->"name") "" ] . "' failed.") false; - :set ($Metric->"resolve-failed") true; } } } @@ -174,7 +174,7 @@ $ScriptLock $0; "count-up"=($Metric->"count-up"); "notified"=($Metric->"notified"); "parent"=($Metric->"parent"); - "resolve-failed"=($Metric->"resolve-failed"); + "resolve-failcnt"=($Metric->"resolve-failcnt"); "since"=($Metric->"since") }; } } From fb9aca90f01756a70a24a12da3d50be8819be587 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 21 Sep 2022 16:36:54 +0200 Subject: [PATCH 1209/2612] unattended-lte-firmware-upgrade: increase delay before extra reset --- unattended-lte-firmware-upgrade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade index 087e32d..fafda62 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade @@ -26,7 +26,7 @@ /system/scheduler/remove ($1 . "-firmware-upgrade"); /interface/lte/firmware-upgrade $1 upgrade=yes; :log info ("LTE firmware upgrade on '" . $1 . "' finished, waiting for reset."); - :delay 150s; + :delay 240s; :local Firmware [ /interface/lte/firmware-upgrade $1 once as-value ]; :if (($Firmware->"installed") != ($Firmware->"latest")) do={ :log warning ("LTE firmware versions still differ. Resetting again..."); From a05b8c18813e1b31dfee79c199953854ec4b67bc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Sep 2022 15:38:31 +0200 Subject: [PATCH 1210/2612] Makefile: add a clean target --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 930c1ae..b0737ab 100644 --- a/Makefile +++ b/Makefile @@ -23,3 +23,6 @@ all: $(CAPSMAN) $(LOCAL) $(HTML) sed -e '/\/interface\/wireless/d' -e 's/%PATH%/caps-man/' -e 's/%TEMPL%/$(suffix $@)/' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ + +clean: + rm -f $(HTML) From 562c565fcf10fff454e82bd3eb718f6b4cbc5a1d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Sep 2022 15:01:03 +0200 Subject: [PATCH 1211/2612] global-functions: $FlushEmailQueue: do not flush if sending --- global-functions | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/global-functions b/global-functions index 3f7a65e..a93b883 100644 --- a/global-functions +++ b/global-functions @@ -330,6 +330,11 @@ :local AllDone true; :local QueueLen [ :len $EmailQueue ]; + :if ([ /tool/e-mail/get last-status ] = "in-progress") do={ + $LogPrintExit2 debug $0 ("Sending mail in currently in progress, not flushing.") false; + :return false; + } + :if ([ $IsTimeSync ] = false) do={ $LogPrintExit2 debug $0 ("Time is not synced, not flushing.") false; :return false; From eccc187014da0ee71bdfc94bfc105e6d4b4524ed Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Sep 2022 15:07:30 +0200 Subject: [PATCH 1212/2612] introduce 'mod/notification-email', split off from global-functions --- README.md | 1 + doc/backup-cloud.md | 3 +- doc/backup-email.md | 10 ++- doc/backup-upload.md | 3 +- doc/check-certificates.md | 9 +- doc/check-health.md | 3 +- doc/check-lte-firmware-upgrade.md | 3 +- doc/check-routeros-update.md | 3 +- doc/collect-wireless-mac.md | 3 +- doc/daily-psk.md | 3 +- doc/log-forward.md | 3 +- doc/mod/notification-email.md | 63 ++++++++++++++ doc/mod/notification-matrix.md | 1 + doc/mod/notification-telegram.md | 1 + doc/netwatch-notify.md | 3 +- doc/sms-forward.md | 7 +- global-config | 8 +- global-config.changes | 2 + global-functions | 129 +---------------------------- mod/notification-email | 133 ++++++++++++++++++++++++++++++ 20 files changed, 240 insertions(+), 151 deletions(-) create mode 100644 doc/mod/notification-email.md create mode 100644 mod/notification-email diff --git a/README.md b/README.md index c7f3312..be52699 100644 --- a/README.md +++ b/README.md @@ -218,6 +218,7 @@ Available modules * [Manage VLANs on bridge ports](doc/mod/bridge-port-vlan.md) * [Inspect variables](doc/mod/inspectvar.md) * [IP address calculation](doc/mod/ipcalc.md) +* [Send notifications via e-mail](doc/mod/notification-email.md) * [Send notifications via Matrix](doc/mod/notification-matrix.md) * [Send notifications via Telegram](doc/mod/notification-telegram.md) * [Download script and run it once](doc/mod/scriptrunonce.md) diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index b0dc3ef..130e3f6 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -36,7 +36,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupPassword`: password to encrypt the backup with * `BackupRandomDelay`: delay up to amount of seconds when run from scheduler -Also notification settings are required for e-mail, +Also notification settings are required for +[e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). diff --git a/doc/backup-email.md b/doc/backup-email.md index e04a988..ab2b9b5 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -15,9 +15,12 @@ configuration export (`/export terse show-sensitive`) via e-mail. Requirements and installation ----------------------------- -Just install the script: +Just install the script and the required module: - $ScriptInstallUpdate backup-email; + $ScriptInstallUpdate mod/notification-email,backup-email; + +Also make sure you configure +[sending notifications via e-mail](mod/notification-email.md). Configuration ------------- @@ -29,8 +32,6 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupPassword`: password to encrypt the backup with * `BackupRandomDelay`: delay up to amount of seconds when run from scheduler -Also valid e-mail settings are required to send mails. - Usage and invocation -------------------- @@ -47,6 +48,7 @@ See also * [Upload backup to Mikrotik cloud](backup-cloud.md) * [Save configuration to fallback partition](doc/backup-partition.md) +* [Send notifications via e-mail](mod/notification-email.md) * [Upload backup to server](backup-upload.md) --- diff --git a/doc/backup-upload.md b/doc/backup-upload.md index 58c1e56..34df1c6 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -41,7 +41,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `BackupUploadUser`: username for server authentication * `BackupUploadPass`: password for server authentication -Also notification settings are required for e-mail, +Also notification settings are required for +[e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). diff --git a/doc/check-certificates.md b/doc/check-certificates.md index f8a4eae..5198e52 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -26,10 +26,6 @@ Just install the script: Configuration ------------- -The expiry notifications just require notification settings for e-mail, -[matrix](mod/notification-matrix.md) and/or -[telegram](mod/notification-telegram.md). - For automatic download and renewal of certificates you need configuration in `global-config-overlay`, these are the parameters: @@ -39,6 +35,11 @@ in `global-config-overlay`, these are the parameters: Certificates on the web server should be named `CN.pem` (`PEM` format) or `CN.p12` (`PKCS#12` format). +Also notification settings are required for +[e-mail](mod/notification-email.md), +[matrix](mod/notification-matrix.md) and/or +[telegram](mod/notification-telegram.md). + Usage and invocation -------------------- diff --git a/doc/check-health.md b/doc/check-health.md index 52efa4c..9ee16bb 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -56,7 +56,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `CheckHealthVoltageLow`: value (in volt*10) giving a hard lower limit * `CheckHealthVoltagePercent`: percentage value to trigger voltage jumps -Also notification settings are required for e-mail, +Also notification settings are required for +[e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index 6550734..f3b3bfc 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -35,7 +35,8 @@ Just install the script: Configuration ------------- -Notification setting are required for e-mail, +Also notification settings are required for +[e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index f43cec9..edffcbb 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -56,7 +56,8 @@ safe versions from a web server. The configuration goes to * `SafeUpdateUrl`: url to check for safe update, the channel (`long-term`, `stable` or `testing`) is appended -Also notification settings are required for e-mail, +Also notification settings are required for +[e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index afdf73a..e6ef990 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -40,7 +40,8 @@ On first run a disabled access list entry acting as marker (with comment "`--- collected above ---`") is added. Move this entry to define where new entries are to be added. -Also notification settings are required for e-mail, +Also notification settings are required for +[e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). diff --git a/doc/daily-psk.md b/doc/daily-psk.md index e27c2c9..62c26ee 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -51,7 +51,8 @@ Then add an access list entry: /interface/wireless/access-list/add comment="Daily PSK" interface=wl-daily private-pre-shared-key="ToBeChangedDaily"; -Also notification settings are required for e-mail, +Also notification settings are required for +[e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). diff --git a/doc/log-forward.md b/doc/log-forward.md index c91f09a..40a4135 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -46,7 +46,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `LogForwardIncludeMessage`: define message text to be forwarded (even if filter matches) -Also notification settings are required for e-mail, +Also notification settings are required for +[e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). diff --git a/doc/mod/notification-email.md b/doc/mod/notification-email.md new file mode 100644 index 0000000..4e0ba04 --- /dev/null +++ b/doc/mod/notification-email.md @@ -0,0 +1,63 @@ +Send notifications via e-mail +============================= + +[◀ Go back to main README](../../README.md) + +> â„šī¸ī¸ **Info**: This module can not be used on its own but requires the base +> installation. See [main README](../../README.md) for details. + +Description +----------- + +This module adds support for sending notifications via e-mail. A queue is +used to make sure notifications are not lost on failure but sent later. + +Requirements and installation +----------------------------- + +Just install the module: + + $ScriptInstallUpdate mod/notification-email; + +Also you need a valid e-mail account with smtp login credentials. + +Configuration +------------- + +Set up your device's +[e-mail settings](https://wiki.mikrotik.com/wiki/Manual:Tools/email). + +Then edit `global-config-overlay`, add `EmailGeneralTo` with a valid +recipient address. Finally reload the configuration. + +### Sending to several recipients + +Sending notifications to several recipients is possible as well. Add +`EmailGeneralCc` on top, which can have a single mail address or a comma +separated list. + +Usage and invocation +-------------------- + +There's nothing special to do. Every script or function sending a notification +will now send it to your e-mail account. + +But of course you can send notifications directly or use a function in your +own scripts. Give it a try: + + $SendEMail "Subject..." "Body..." + +Alternatively this sends a notification with all available and configured +methods: + + $SendNotification "Subject..." "Body..." + +See also +-------- + +* [Send notifications via Matrix](notification-matrix.md) +* [Send notifications via Telegram](notification-telegram.md) + +--- +[◀ Go back to main README](../../README.md) +[▲ Go back to top](#top) diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index c5003e0..b1f520e 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -103,6 +103,7 @@ methods: See also -------- +* [Send notifications via e-mail](notification-email.md) * [Send notifications via Telegram](notification-telegram.md) --- diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index 3bb31a7..2b1abe9 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -66,6 +66,7 @@ methods: See also -------- +* [Send notifications via e-mail](notification-email.md) * [Send notifications via Matrix](notification-matrix.md) --- diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 1352495..032106a 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -88,7 +88,8 @@ powered off, but accessibility is of interest. Go and get your coffee â˜•ī¸ before sending the print job. -Also notification settings are required for e-mail, +Also notification settings are required for +[e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or [telegram](mod/notification-telegram.md). diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 80cb7ad..f75b78f 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -31,10 +31,11 @@ Just install the script: Configuration ------------- -Notification settings are required for e-mail, +Notification settings are required for +[e-mail](mod/notification-email.md), [matrix](mod/notification-matrix.md) and/or -[telegram](mod/notification-telegram.md). Also you have to enable receiving -of SMS: +[telegram](mod/notification-telegram.md). +Also you have to enable receiving of SMS: /tool/sms/set receive-enabled=yes; diff --git a/global-config b/global-config index a2afd66..6ed2a45 100644 --- a/global-config +++ b/global-config @@ -15,9 +15,11 @@ :global PrefixInZone true; :global ServerNameInZone false; -# These addresses are used to send e-mails to. The to-address needs -# to be filled; cc-address can be empty, one address or a comma -# separated list of addresses. +# You can send e-mail notifications. Configure the system's mail settings +# (/tool/e-mail), then install the module: +# $ScriptInstallUpdate mod/notification-email +# The to-address needs to be filled; cc-address can be empty, one address +# or a comma separated list of addresses. :global EmailGeneralTo ""; :global EmailGeneralCc ""; #:global EmailGeneralTo "mail@example.com"; diff --git a/global-config.changes b/global-config.changes index 0356772..6dc8df6 100644 --- a/global-config.changes +++ b/global-config.changes @@ -92,6 +92,7 @@ 81="Dropped script 'rotate-ntp', as the limitation does no longer exist."; 82="Renamed the comment parameter 'hostname' to just 'name' for 'netwatch-notify'."; 83="Introduced new setting to disable news and change notifications, dropped version from configuration."; + 84="Support for e-mail notifications moved to a module. It is installed automatically if required."; }; # Migration steps to be applied on script updates @@ -106,4 +107,5 @@ 73=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Old,New in={ \"cloud-backup\"=\"backup-cloud\"; \"email-backup\"=\"backup-email\"; \"upload-backup\"=\"backup-upload\" } do={ /system/script/set name=\$New [ find where name=\$Old ]; :foreach Scheduler in=[ /system/scheduler/find where on-event~\$Old ] do={ /system/scheduler/set \$Scheduler name=[ \$CharacterReplace [ get \$Scheduler name ] \$Old \$New ] on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Old \$New ]; }; }; \$ScriptInstallUpdate;"; 81=":global NtpPool; :if ([ :len [ /system/script/find where name=\"rotate-ntp\" ] ] > 0) do={ /system/script/remove [ find where name=\"rotate-ntp\" ]; /system/scheduler/remove [ find where name=\"rotate-ntp\" ]; /system/ntp/client/set servers=\$NtpPool; };"; 82=":global CharacterReplace; :foreach Netwatch in=[ /tool/netwatch/find where comment~\"notify\" !disabled ] do={ /tool/netwatch/set \$Netwatch comment=[ \$CharacterReplace [ get \$Netwatch comment ] \"hostname=\" \"name=\" ]; };"; + 84=":global ScriptInstallUpdate; :global EmailGeneralTo; :if ([ /tool/e-mail/get address ] != \"0.0.0.0\" && [ :len \$EmailGeneralTo ] > 0) do={ \$ScriptInstallUpdate mod/notification-email; }"; }; diff --git a/global-functions b/global-functions index a93b883..8fc3386 100644 --- a/global-functions +++ b/global-functions @@ -10,7 +10,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 83; +:global ExpectedConfigVersion 84; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -26,7 +26,6 @@ :global DownloadPackage; :global EitherOr; :global EscapeForRegEx; -:global FlushEmailQueue; :global GetMacVendor; :global GetRandom20CharAlNum; :global GetRandom20CharHex; @@ -49,8 +48,6 @@ :global ScriptFromTerminal; :global ScriptInstallUpdate; :global ScriptLock; -:global SendEMail; -:global SendEMail2; :global SendNotification; :global SendNotification2; :global SymbolByUnicodeName; @@ -318,74 +315,6 @@ :return $Return; } -# flush e-mail queue -:set FlushEmailQueue do={ - :global EmailQueue; - - :global EitherOr; - :global IsDNSResolving; - :global IsTimeSync; - :global LogPrintExit2; - - :local AllDone true; - :local QueueLen [ :len $EmailQueue ]; - - :if ([ /tool/e-mail/get last-status ] = "in-progress") do={ - $LogPrintExit2 debug $0 ("Sending mail in currently in progress, not flushing.") false; - :return false; - } - - :if ([ $IsTimeSync ] = false) do={ - $LogPrintExit2 debug $0 ("Time is not synced, not flushing.") false; - :return false; - } - - :if ([ :typeof [ :toip [ /tool/e-mail/get address ] ] ] != "ip" && [ $IsDNSResolving ] = false) do={ - $LogPrintExit2 debug $0 ("Server address is a DNS name and resolving fails, not flushing.") false; - :return false; - } - - :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ - $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; - } - - /system/scheduler/set interval=($QueueLen . "m") [ find where name=$0 ]; - - :foreach Id,Message in=$EmailQueue do={ - :if ([ :typeof $Message ] = "array" ) do={ - :local Attach [ $EitherOr ($Message->"attach") "" ]; - :while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; } - /tool/e-mail/send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \ - body=($Message->"body") file=$Attach; - :local Wait true; - :do { - :delay 1s; - :local Status [ /tool/e-mail/get last-status ]; - :if ($Status = "succeeded") do={ - :set ($EmailQueue->$Id); - :set Wait false; - :if (($Message->"remove-attach") = true) do={ - :foreach File in=[ :toarray $Attach ] do={ - /file/remove $File; - } - } - } - :if ($Status = "failed") do={ - :set AllDone false; - :set Wait false; - } - } while=($Wait = true); - } - } - - :if ($AllDone = true && $QueueLen = [ :len $EmailQueue ]) do={ - /system/scheduler/remove [ find where name=$0 ]; - :set EmailQueue; - } else={ - /system/scheduler/set interval=1m [ find where name=$0 ]; - } -} - # get MAC vendor :set GetMacVendor do={ :local Mac [ :tostr $1 ]; @@ -609,46 +538,6 @@ :set NotificationFunctions ({}); } -# send notification via e-mail - expects one array argument -:set ($NotificationFunctions->"email") do={ - :local Notification $1; - - :global Identity; - :global EmailGeneralTo; - :global EmailGeneralToOverride; - :global EmailGeneralCc; - :global EmailGeneralCcOverride; - :global EmailQueue; - - :global EitherOr; - :global IfThenElse; - :global QuotedPrintable; - - :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; - :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; - - :local EMailSettings [ /tool/e-mail/get ]; - :if ([ :len $To ] = 0 || ($EMailSettings->"address") = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={ - :return false; - } - - :if ([ :typeof $EmailQueue ] = "nothing") do={ - :set EmailQueue ({}); - } - :local Signature [ /system/note/get note ]; - :set ($EmailQueue->[ :len $EmailQueue ]) { - to=$To; cc=$Cc; - subject=[ $QuotedPrintable ("[" . $Identity . "] " . ($Notification->"subject")) ]; - body=(($Notification->"message") . \ - [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ - [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \ - attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") }; - :if ([ :len [ /system/scheduler/find where name="\$FlushEmailQueue" ] ] = 0) do={ - /system/scheduler/add name="\$FlushEmailQueue" interval=1s start-time=startup \ - on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); - } -} - # parse key value store :set ParseKeyValueStore do={ :local Source $1; @@ -1115,22 +1004,6 @@ :return true; } -# send notification via e-mail - expects at least two string arguments -:set SendEMail do={ - :global SendEMail2; - - $SendEMail2 ({ subject=$1; message=$2; link=$3 }); -} - -# send notification via e-mail - expects one array argument -:set SendEMail2 do={ - :local Notification $1; - - :global NotificationFunctions; - - ($NotificationFunctions->"email") ("\$NotificationFunctions->\"email\"") $Notification; -} - # send notification via NotificationFunctions - expects at least two string arguments :set SendNotification do={ :global SendNotification2; diff --git a/mod/notification-email b/mod/notification-email new file mode 100644 index 0000000..0c07beb --- /dev/null +++ b/mod/notification-email @@ -0,0 +1,133 @@ +#!rsc by RouterOS +# RouterOS script: mod/notification-email +# Copyright (c) 2013-2022 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global FlushEmailQueue; +:global NotificationFunctions; +:global SendEMail; +:global SendEMail2; + +# flush e-mail queue +:set FlushEmailQueue do={ + :global EmailQueue; + + :global EitherOr; + :global IsDNSResolving; + :global IsTimeSync; + :global LogPrintExit2; + + :local AllDone true; + :local QueueLen [ :len $EmailQueue ]; + + :if ([ /tool/e-mail/get last-status ] = "in-progress") do={ + $LogPrintExit2 debug $0 ("Sending mail in currently in progress, not flushing.") false; + :return false; + } + + :if ([ $IsTimeSync ] = false) do={ + $LogPrintExit2 debug $0 ("Time is not synced, not flushing.") false; + :return false; + } + + :if ([ :typeof [ :toip [ /tool/e-mail/get address ] ] ] != "ip" && [ $IsDNSResolving ] = false) do={ + $LogPrintExit2 debug $0 ("Server address is a DNS name and resolving fails, not flushing.") false; + :return false; + } + + :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ + $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; + } + + /system/scheduler/set interval=($QueueLen . "m") [ find where name=$0 ]; + + :foreach Id,Message in=$EmailQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :local Attach [ $EitherOr ($Message->"attach") "" ]; + :while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; } + /tool/e-mail/send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \ + body=($Message->"body") file=$Attach; + :local Wait true; + :do { + :delay 1s; + :local Status [ /tool/e-mail/get last-status ]; + :if ($Status = "succeeded") do={ + :set ($EmailQueue->$Id); + :set Wait false; + :if (($Message->"remove-attach") = true) do={ + :foreach File in=[ :toarray $Attach ] do={ + /file/remove $File; + } + } + } + :if ($Status = "failed") do={ + :set AllDone false; + :set Wait false; + } + } while=($Wait = true); + } + } + + :if ($AllDone = true && $QueueLen = [ :len $EmailQueue ]) do={ + /system/scheduler/remove [ find where name=$0 ]; + :set EmailQueue; + } else={ + /system/scheduler/set interval=1m [ find where name=$0 ]; + } +} + +# send notification via e-mail - expects one array argument +:set ($NotificationFunctions->"email") do={ + :local Notification $1; + + :global Identity; + :global EmailGeneralTo; + :global EmailGeneralToOverride; + :global EmailGeneralCc; + :global EmailGeneralCcOverride; + :global EmailQueue; + + :global EitherOr; + :global IfThenElse; + :global QuotedPrintable; + + :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; + :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; + + :local EMailSettings [ /tool/e-mail/get ]; + :if ([ :len $To ] = 0 || ($EMailSettings->"address") = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={ + :return false; + } + + :if ([ :typeof $EmailQueue ] = "nothing") do={ + :set EmailQueue ({}); + } + :local Signature [ /system/note/get note ]; + :set ($EmailQueue->[ :len $EmailQueue ]) { + to=$To; cc=$Cc; + subject=[ $QuotedPrintable ("[" . $Identity . "] " . ($Notification->"subject")) ]; + body=(($Notification->"message") . \ + [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ + [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \ + attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") }; + :if ([ :len [ /system/scheduler/find where name="\$FlushEmailQueue" ] ] = 0) do={ + /system/scheduler/add name="\$FlushEmailQueue" interval=1s start-time=startup \ + on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); + } +} + +# send notification via e-mail - expects at least two string arguments +:set SendEMail do={ + :global SendEMail2; + + $SendEMail2 ({ subject=$1; message=$2; link=$3 }); +} + +# send notification via e-mail - expects one array argument +:set SendEMail2 do={ + :local Notification $1; + + :global NotificationFunctions; + + ($NotificationFunctions->"email") ("\$NotificationFunctions->\"email\"") $Notification; +} From bfe2cbf575e4682db86c04044e90f7f997f7de04 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Sep 2022 19:50:16 +0200 Subject: [PATCH 1213/2612] drop 'netwatch-syslog' To filter in firewall you should use something like this: /ip/firewall/filter/add action=reject chain=output out-interface-list=WAN port=514 protocol=udp reject-with=icmp-admin-prohibited; /ip/firewall/filter/add action=reject chain=forward out-interface-list=WAN port=514 protocol=udp reject-with=icmp-admin-prohibited; --- README.md | 1 - doc/netwatch-syslog.md | 37 ++++--------------------------------- global-config.changes | 1 + global-functions | 2 +- netwatch-syslog | 17 ----------------- 5 files changed, 6 insertions(+), 52 deletions(-) delete mode 100644 netwatch-syslog diff --git a/README.md b/README.md index be52699..c670fd0 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,6 @@ Available scripts * [Mode button with multiple presses](doc/mode-button.md) * [Manage DNS and DoH servers from netwatch](doc/netwatch-dns.md) * [Notify on host up and down](doc/netwatch-notify.md) -* [Manage remote logging](doc/netwatch-syslog.md) * [Visualize OSPF state via LEDs](doc/ospf-to-leds.md) * [Manage system update](doc/packages-update.md) * [Run scripts on ppp connection](doc/ppp-on-up.md) diff --git a/doc/netwatch-syslog.md b/doc/netwatch-syslog.md index 760d98f..6a337d4 100644 --- a/doc/netwatch-syslog.md +++ b/doc/netwatch-syslog.md @@ -1,34 +1,5 @@ -Manage remote logging -===================== +This script has been dropped. Filtering in firewall is advised, which should +look something like this: -[◀ Go back to main README](../README.md) - -Description ------------ - -RouterOS supports sending log messages via network to a remote syslog server. -If the server is not available no log messages (with potentially sensitive -information) should be sent. This script disables remote logging by -availability. - -Requirements and installation ------------------------------ - -Let's assume there is a remote log action and associated logging rule: - - /system/logging/action/set remote=10.0.0.1 [ find where name="remote" ]; - /system/logging/add action=remote topics=info; - -Just install the script: - - $ScriptInstallUpdate netwatch-syslog; - -... and create a netwatch matching the IP address from logging action above: - - /tool/netwatch/add down-script=netwatch-syslog host=10.0.0.1 up-script=netwatch-syslog; - -All logging rules are disabled when host is down. - ---- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) + /ip/firewall/filter/add action=reject chain=output out-interface-list=WAN port=514 protocol=udp reject-with=icmp-admin-prohibited; + /ip/firewall/filter/add action=reject chain=forward out-interface-list=WAN port=514 protocol=udp reject-with=icmp-admin-prohibited; diff --git a/global-config.changes b/global-config.changes index 6dc8df6..4bd302f 100644 --- a/global-config.changes +++ b/global-config.changes @@ -93,6 +93,7 @@ 82="Renamed the comment parameter 'hostname' to just 'name' for 'netwatch-notify'."; 83="Introduced new setting to disable news and change notifications, dropped version from configuration."; 84="Support for e-mail notifications moved to a module. It is installed automatically if required."; + 85="Dropped 'netwatch-syslog', filtering in firewall is advised."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 8fc3386..e24cf3c 100644 --- a/global-functions +++ b/global-functions @@ -10,7 +10,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 84; +:global ExpectedConfigVersion 85; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/netwatch-syslog b/netwatch-syslog deleted file mode 100644 index 1d9f37b..0000000 --- a/netwatch-syslog +++ /dev/null @@ -1,17 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: netwatch-syslog -# Copyright (c) 2013-2022 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# requires: dont-require-permissions=yes -# -# manage remote logging facilities -# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-syslog.md - -:local Remote [ /system/logging/action/get ([ find where target=remote ]->0) remote ]; - -if ([ /tool/netwatch/get [ find where host=$Remote up-script="netwatch-syslog" down-script="netwatch-syslog" ] status ] = "up") do={ - /system/logging/set disabled=no [ find where action=remote disabled=yes ]; -} else={ - /system/logging/set disabled=yes [ find where action=remote disabled=no ]; -} From 10bf3c758fb4f92e0b66719c98eba3d7be98ef81 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 23 Sep 2022 20:04:19 +0200 Subject: [PATCH 1214/2612] drop 'learn-mac-based-vlan' and 'manage-umts' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was undocumented and scripts did never catch up with general quality expectations, for example global-config and global functions were not used. If you need the code get it from git history. 😜 --- README.md | 4 ---- learn-mac-based-vlan | 13 ------------- manage-umts | 29 ----------------------------- 3 files changed, 46 deletions(-) delete mode 100644 learn-mac-based-vlan delete mode 100644 manage-umts diff --git a/README.md b/README.md index c670fd0..56d39e8 100644 --- a/README.md +++ b/README.md @@ -206,10 +206,6 @@ Available scripts * [Update GRE configuration with dynamic addresses](doc/update-gre-address.md) * [Update tunnelbroker configuration](doc/update-tunnelbroker.md) -[comment]: # (TODO: currently undocumented) -[comment]: # (* learn-mac-based-vlan) -[comment]: # (* manage-umts) - Available modules ----------------- diff --git a/learn-mac-based-vlan b/learn-mac-based-vlan deleted file mode 100644 index ce8957d..0000000 --- a/learn-mac-based-vlan +++ /dev/null @@ -1,13 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: learn-mac-based-vlan -# Copyright (c) 2013-2022 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# learn MAC address for MAC-based-VLAN - -:local NewVlanId 33; - -:if ([ :len [ /interface/ethernet/switch/mac-based-vlan/find where src-mac-address=$leaseActMAC ] ] = 0 ) do={ - :log info ("MAC-based-VLAN: learning MAC address " . $leaseActMAC . " for VLAN " . $NewVlanId . "."); - /interface/ethernet/switch/mac-based-vlan/add src-mac-address=$leaseActMAC new-customer-vid=$NewVlanId; -} diff --git a/manage-umts b/manage-umts deleted file mode 100644 index 0cd3e8f..0000000 --- a/manage-umts +++ /dev/null @@ -1,29 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: manage-umts -# Copyright (c) 2013-2022 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# manage UMTS interface based on ethernet and wireless status - -:local EtherInt "en1"; -:local WlanInt "wl-station"; -:local UmtsInt "t-mobile"; - -:local EtherStatus [ /interface/ethernet/get $EtherInt running ]; -:local WlanStatus [ /interface/wireless/get $WlanInt running ]; - -:if ($EtherStatus = true || $WlanStatus = true) do={ - :if ([ /interface/get $UmtsInt disabled ] = false) do={ - :log info ("Ethernet (" . $EtherInt . " / " . $EtherStatus . ") or " . \ - "wireless (" . $WlanInt . " / " . $WlanStatus . ") is running, " . \ - "UMTS interface " . $UmtsInt . " is enabled. Disabling..."); - /interface/set disabled=yes $UmtsInt; - } -} else={ - :if ([ /interface/get $UmtsInt disabled ] = true) do={ - :log info ("Neither ethernet (" . $EtherInt . ") nor wireless (" . \ - $WlanInt . ") interface is running, UMTS interface " . $UmtsInt . \ - " is disabled. Enabling..."); - /interface/set disabled=no $UmtsInt; - } -} From 5120aa096f3b5479797b1361b08044959675cdb5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 25 Sep 2022 18:57:00 +0200 Subject: [PATCH 1215/2612] global-functions: $ScriptInstallUpdate: drop code for permission workaround This is no longer used as 'netwatch-syslog' is gone. --- global-functions | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/global-functions b/global-functions index e24cf3c..c9abf88 100644 --- a/global-functions +++ b/global-functions @@ -744,11 +744,8 @@ :if ($SourceNew != $ScriptVal->"source") do={ :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ :if ([ $ValidateSyntax $SourceNew ] = true) do={ - :local DontRequirePermissions \ - ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); $LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; - /system/script/set owner=($ScriptVal->"name") source=$SourceNew \ - dont-require-permissions=$DontRequirePermissions $Script; + /system/script/set owner=($ScriptVal->"name") source=$SourceNew $Script; :if ($ScriptVal->"name" = "global-config") do={ :set ReloadGlobalConfig true; } From b18ca62dbda8e9a9aa876f17310c2087eacdb19a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Sep 2022 08:39:25 +0200 Subject: [PATCH 1216/2612] global-functions: $ScriptInstallUpdate: drop dead code... --- global-functions | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/global-functions b/global-functions index c9abf88..2006a10 100644 --- a/global-functions +++ b/global-functions @@ -667,7 +667,6 @@ :global ScriptUpdatesBaseUrl; :global ScriptUpdatesFetch; :global ScriptUpdatesUrlSuffix; - :global SentConfigChangesNotification; :global CertificateAvailable; :global IfThenElse; @@ -833,8 +832,7 @@ } } - :if ($SentConfigChangesNotification != $ExpectedConfigVersion && \ - $NoNewsAndChangesNotification != true) do={ + :if ($NoNewsAndChangesNotification != true) do={ :local NotificationMessage ("The configuration version on " . $Identity . " increased " . \ "to " . $ExpectedConfigVersion . ", current configuration may need modification. " . \ "Please review and update global-config-overlay, then re-run global-config."); @@ -865,7 +863,6 @@ $SendNotification2 ({ origin=$0; \ subject=([ $SymbolForNotification "pushpin" ] . "News and configuration changes"); \ message=$NotificationMessage; link=$Link }); - :set SentConfigChangesNotification $ExpectedConfigVersion; } :set GlobalConfigChanges; From 10182949eab4c990ae8f6402ca030d19ea2b3cb0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Sep 2022 08:44:05 +0200 Subject: [PATCH 1217/2612] global-functions: $ScriptInstallUpdate: disable notification only... ... if requested, but keep output and logs. --- global-functions | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/global-functions b/global-functions index 2006a10..f4c47d7 100644 --- a/global-functions +++ b/global-functions @@ -832,24 +832,24 @@ } } - :if ($NoNewsAndChangesNotification != true) do={ - :local NotificationMessage ("The configuration version on " . $Identity . " increased " . \ - "to " . $ExpectedConfigVersion . ", current configuration may need modification. " . \ - "Please review and update global-config-overlay, then re-run global-config."); - $LogPrintExit2 info $0 ($NotificationMessage) false; + :local NotificationMessage ("The configuration version on " . $Identity . " increased " . \ + "to " . $ExpectedConfigVersion . ", current configuration may need modification. " . \ + "Please review and update global-config-overlay, then re-run global-config."); + $LogPrintExit2 info $0 ($NotificationMessage) false; - :if ([ :len $GlobalConfigChanges ] > 0) do={ - :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); - :for I from=($ExpectedConfigVersionBefore + 1) to=$ExpectedConfigVersion do={ - :local Change ($GlobalConfigChanges->[ :tostr $I ]); - :set NotificationMessage ($NotificationMessage . "\n " . \ - [ $IfThenElse ($NotificationsWithSymbols = true) ("\E2\97\8F") "*" ] . " " . $Change); - $LogPrintExit2 info $0 ("Change " . $I . ": " . $Change) false; - } - } else={ - :set NotificationMessage ($NotificationMessage . "\n\nNews and changes are not available."); + :if ([ :len $GlobalConfigChanges ] > 0) do={ + :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); + :for I from=($ExpectedConfigVersionBefore + 1) to=$ExpectedConfigVersion do={ + :local Change ($GlobalConfigChanges->[ :tostr $I ]); + :set NotificationMessage ($NotificationMessage . "\n " . \ + [ $IfThenElse ($NotificationsWithSymbols = true) ("\E2\97\8F") "*" ] . " " . $Change); + $LogPrintExit2 info $0 ("Change " . $I . ": " . $Change) false; } + } else={ + :set NotificationMessage ($NotificationMessage . "\n\nNews and changes are not available."); + } + :if ($NoNewsAndChangesNotification != true) do={ :local Link; :if ($IDonate != true) do={ :set NotificationMessage ($NotificationMessage . \ From dd22dfd26d01a39aab352d21db205c97a20dbcfa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 29 Sep 2022 10:31:54 +0200 Subject: [PATCH 1218/2612] backup-email: check if dependency for sending e-mail is installed --- backup-email | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backup-email b/backup-email index 7cdf55e..34e15e1 100644 --- a/backup-email +++ b/backup-email @@ -30,6 +30,10 @@ :global WaitForFile; :global WaitFullyConnected; +:if ([ :typeof $SendEMail2 ] = "nothing") do={ + $LogPrintExit2 error $0 ("The module for sending notifications via e-mail is not installed.") true; +} + :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; From ebaa9b617d2033f50ecaeaaf6013b499f10e9a28 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 8 Oct 2022 22:38:31 +0200 Subject: [PATCH 1219/2612] update-tunnelbroker: add error handling for fetch command --- update-tunnelbroker | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/update-tunnelbroker b/update-tunnelbroker index 0075273..93a829c 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -38,9 +38,13 @@ $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; } $LogPrintExit2 info $0 ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress) false; - /tool/fetch check-certificate=yes-without-crl \ - ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ - user=($Comment->"user") password=($Comment->"pass") output=none as-value; + :do { + /tool/fetch check-certificate=yes-without-crl \ + ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ + user=($Comment->"user") password=($Comment->"pass") output=none as-value; + } on-error={ + $LogPrintExit2 error $0 ("Failed sending the local address to tunnelbroker! Wrong credentials?") true; + } /interface/6to4/set $Interface local-address=$PublicAddress; } else={ $LogPrintExit2 debug $0 ("All tunnelbroker configuration is up to date for interface " . $InterfaceVal->"name" . ".") false; From 16e93018ef4de9400421a335b4493bee9cd198ef Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 8 Oct 2022 23:03:29 +0200 Subject: [PATCH 1220/2612] update-tunnelbroker: work around timing issue Looks like fetch command has a timing issue with the tunnelbroker endpoint... We have to try several times to work around this. Consider the update failed on third error. --- update-tunnelbroker | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/update-tunnelbroker b/update-tunnelbroker index 93a829c..eecd02b 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -32,17 +32,26 @@ :local InterfaceVal [ /interface/6to4/get $Interface ]; :if ($PublicAddress != $InterfaceVal->"local-address") do={ + :local I 0; + :local Success false; :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; :if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; } $LogPrintExit2 info $0 ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress) false; - :do { - /tool/fetch check-certificate=yes-without-crl \ - ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ - user=($Comment->"user") password=($Comment->"pass") output=none as-value; - } on-error={ + :while ($I < 3 && $Success = false) do={ + :do { + /tool/fetch check-certificate=yes-without-crl \ + ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ + user=($Comment->"user") password=($Comment->"pass") output=none as-value; + :set Success true; + } on-error={ + :delay 10s; + :set I ($I + 1); + } + } + :if ($Success = false) do={ $LogPrintExit2 error $0 ("Failed sending the local address to tunnelbroker! Wrong credentials?") true; } /interface/6to4/set $Interface local-address=$PublicAddress; From c95cbdbc1e849f8044b00f85f9a29e064af1ccd1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 9 Oct 2022 00:00:50 +0200 Subject: [PATCH 1221/2612] doc/update-tunnelbroker: give more hints on expected config --- doc/update-tunnelbroker.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/update-tunnelbroker.md b/doc/update-tunnelbroker.md index bfe8e25..4da4fa8 100644 --- a/doc/update-tunnelbroker.md +++ b/doc/update-tunnelbroker.md @@ -28,7 +28,10 @@ Configuration The configuration goes to interface's comment: - /interface/6to4/set comment="tunnelbroker, user=user, pass=s3cr3t, id=12345" tunnelbroker; + /interface/6to4/set comment="tunnelbroker, user=user, id=12345, pass=s3cr3t" tunnelbroker; + +You should know you user name from login. The `id` is the tunnel's numeric +id, `pass` is the *update key* found on the tunnel's advanced tab. Also enabling dynamic DNS in Mikrotik cloud is required: From e7995fa06b023918fa40de10d4a299ee4a89b2f0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 9 Oct 2022 19:45:18 +0200 Subject: [PATCH 1222/2612] update-tunnelbroker: get public address from website This is a good condidate: https://showipv6.de/ We can drop the cloud code, which seems to be unreliable in somd situations. --- doc/update-tunnelbroker.md | 4 ---- update-tunnelbroker | 23 +++++++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/doc/update-tunnelbroker.md b/doc/update-tunnelbroker.md index 4da4fa8..3338e2b 100644 --- a/doc/update-tunnelbroker.md +++ b/doc/update-tunnelbroker.md @@ -33,10 +33,6 @@ The configuration goes to interface's comment: You should know you user name from login. The `id` is the tunnel's numeric id, `pass` is the *update key* found on the tunnel's advanced tab. -Also enabling dynamic DNS in Mikrotik cloud is required: - - /ip/cloud/set ddns-enabled=yes; - See also -------- diff --git a/update-tunnelbroker b/update-tunnelbroker index eecd02b..8562d58 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -17,16 +17,22 @@ :global LogPrintExit2; :global ParseKeyValueStore; -:if ([ /ip/cloud/get ddns-enabled ] != true) do={ - $LogPrintExit2 error $0 ("IP cloud DDNS is not enabled.") true; +:if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false || \ + [ $CertificateAvailable "R3" ] = false) do={ + $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; } -# Get the current ip address from cloud -/ip/cloud/force-update; -:while ([ /ip/cloud/get status ] != "updated") do={ - :delay 1s; +:local PublicAddress; +:do { + :set PublicAddress ([ /tool/fetch check-certificate=yes-without-crl \ + "https://ipv4.showipv6.de/short" output=user as-value ]->"data"); +} on-error={ + $LogPrintExit2 error $0 ("Failed getting public address.") true; +} + +:if ([ :len [ /ip/address find where address~("^" . $PublicAddress . "/") ] ] < 1) do={ + $LogPrintExit2 warning $0 ("The address " . $PublicAddress . " is not configured on your device. NAT by ISP?") false; } -:local PublicAddress [ /ip/cloud/get public-address ]; :foreach Interface in=[ /interface/6to4/find where comment~"^tunnelbroker" !disabled ] do={ :local InterfaceVal [ /interface/6to4/get $Interface ]; @@ -36,9 +42,6 @@ :local Success false; :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; - :if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ - $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; - } $LogPrintExit2 info $0 ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress) false; :while ($I < 3 && $Success = false) do={ :do { From 493d534706a2180660f83270d907ac4678d4796c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 9 Oct 2022 23:15:06 +0200 Subject: [PATCH 1223/2612] update-tunnelbroker: drop extra detection, use response from update Why hammer on another service? The tunnelbroker response contains the address we need. So send the update every time, and use that information. --- update-tunnelbroker | 59 +++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/update-tunnelbroker b/update-tunnelbroker index 8562d58..b936dcf 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -17,48 +17,39 @@ :global LogPrintExit2; :global ParseKeyValueStore; -:if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false || \ - [ $CertificateAvailable "R3" ] = false) do={ +:if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; } -:local PublicAddress; -:do { - :set PublicAddress ([ /tool/fetch check-certificate=yes-without-crl \ - "https://ipv4.showipv6.de/short" output=user as-value ]->"data"); -} on-error={ - $LogPrintExit2 error $0 ("Failed getting public address.") true; -} - -:if ([ :len [ /ip/address find where address~("^" . $PublicAddress . "/") ] ] < 1) do={ - $LogPrintExit2 warning $0 ("The address " . $PublicAddress . " is not configured on your device. NAT by ISP?") false; -} - :foreach Interface in=[ /interface/6to4/find where comment~"^tunnelbroker" !disabled ] do={ + :local I 0; + :local Response ""; :local InterfaceVal [ /interface/6to4/get $Interface ]; + :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; + + :while ($I < 3 && $Response = "") do={ + :do { + :set Response ([ /tool/fetch check-certificate=yes-without-crl \ + ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ + user=($Comment->"user") password=($Comment->"pass") output=user as-value ]->"data"); + } on-error={ + :delay 10s; + :set I ($I + 1); + } + } + + :if (!($Response~"^(good|nochg) ")) do={ + $LogPrintExit2 error $0 ("Failed sending the local address to tunnelbroker or unexpected response!") true; + } + + :local PublicAddress [ :pick $Response ([ :find $Response " " ] + 1) [ :find $Response "\n" ] ]; :if ($PublicAddress != $InterfaceVal->"local-address") do={ - :local I 0; - :local Success false; - :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; + :if ([ :len [ /ip/address find where address~("^" . $PublicAddress . "/") ] ] < 1) do={ + $LogPrintExit2 warning $0 ("The address " . $PublicAddress . " is not configured on your device. NAT by ISP?") false; + } - $LogPrintExit2 info $0 ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress) false; - :while ($I < 3 && $Success = false) do={ - :do { - /tool/fetch check-certificate=yes-without-crl \ - ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ - user=($Comment->"user") password=($Comment->"pass") output=none as-value; - :set Success true; - } on-error={ - :delay 10s; - :set I ($I + 1); - } - } - :if ($Success = false) do={ - $LogPrintExit2 error $0 ("Failed sending the local address to tunnelbroker! Wrong credentials?") true; - } + $LogPrintExit2 info $0 ("Local address changed, updating tunnel configuration with address: " . $PublicAddress) false; /interface/6to4/set $Interface local-address=$PublicAddress; - } else={ - $LogPrintExit2 debug $0 ("All tunnelbroker configuration is up to date for interface " . $InterfaceVal->"name" . ".") false; } } From 640cb811195579a3444d53531160f2bbb88e2d55 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 14 Oct 2022 22:39:21 +0200 Subject: [PATCH 1224/2612] netwatch-notify: fix the count... This broke in commit 6f772e92a616acb15bdef8ab7b7bfdb9d002bfeb ("netwatch-notify: rename array element") where not only the array element but also the option was renamed. --- netwatch-notify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwatch-notify b/netwatch-notify index f95f426..27e0759 100644 --- a/netwatch-notify +++ b/netwatch-notify @@ -126,7 +126,7 @@ $ScriptLock $0; :set ($Metric->"count-up") 0; :set ($Metric->"parent") ($HostInfo->"parent"); :set ($Metric->"since") ($HostVal->"since"); - :local CountDown [ $IfThenElse ([ :tonum ($HostInfo->"count-down") ] > 0) ($HostInfo->"count-down") 5 ]; + :local CountDown [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; :local Parent ($HostInfo->"parent"); :local ParentUp false; :while ([ :len $Parent ] > 0) do={ From 2f8e8b74487b36fe8ed233570115767ca3a13ec6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 18 Oct 2022 22:36:03 +0200 Subject: [PATCH 1225/2612] update-gre-address: strip "CN=" from peer's id The prefix "CN=" is now added in RouterOS 7.6... Let's match with and without the prefix in comment. --- update-gre-address | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/update-gre-address b/update-gre-address index d1402e3..a94616a 100644 --- a/update-gre-address +++ b/update-gre-address @@ -11,13 +11,14 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:global CharacterReplace; :global LogPrintExit2; /interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; :foreach Peer in=[ /ip/ipsec/active-peers/find ] do={ :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; - :local GreInt [ /interface/gre/find where comment=$PeerVal->"id" ]; + :local GreInt [ /interface/gre/find where comment=($PeerVal->"id") or comment=[ $CharacterReplace ($PeerVal->"id") "CN=" "" ] ]; :if ([ :len $GreInt ] > 0) do={ :local GreIntVal [ /interface/gre/get $GreInt ]; :if ([ :typeof ($PeerVal->"dynamic-address") ] = "str" && \ From 621154ab83eadc612af3423dc86cad94bdc69609 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 19 Oct 2022 08:45:40 +0200 Subject: [PATCH 1226/2612] ipsec-to-dns: remove debug output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Oops... đŸ˜ŗ This sneaked in with initial commit 862417b8d32f6eef1c05ba9137fe2a7f14436987 ("add 'ipsec-to-dns'"). --- ipsec-to-dns | 2 -- 1 file changed, 2 deletions(-) diff --git a/ipsec-to-dns b/ipsec-to-dns index c6cfdc4..cf36987 100644 --- a/ipsec-to-dns +++ b/ipsec-to-dns @@ -47,9 +47,7 @@ :foreach Peer in=[ /ip/ipsec/active-peers/find where !(dynamic-address=[]) ] do={ :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; :local Comment ($CommentPrefix . $PeerVal->"id"); -:put ($PeerVal->"id"); :local HostName [ :pick ($PeerVal->"id") 0 [ :find ($PeerVal->"id" . ".") "." ] ]; -:put $HostName; :local Fqdn ($HostName . "." . $Zone); :local DnsRecord [ /ip/dns/static/find where name=$Fqdn ]; From bff6689b103287f44c573e3134b9b9a64c36c0a8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 19 Oct 2022 08:50:00 +0200 Subject: [PATCH 1227/2612] ipsec-to-dns: strip "CN=" from peer's id --- ipsec-to-dns | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ipsec-to-dns b/ipsec-to-dns index cf36987..705b5e7 100644 --- a/ipsec-to-dns +++ b/ipsec-to-dns @@ -46,8 +46,9 @@ :foreach Peer in=[ /ip/ipsec/active-peers/find where !(dynamic-address=[]) ] do={ :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; - :local Comment ($CommentPrefix . $PeerVal->"id"); - :local HostName [ :pick ($PeerVal->"id") 0 [ :find ($PeerVal->"id" . ".") "." ] ]; + :local PeerId [ $CharacterReplace ($PeerVal->"id") "CN=" "" ]; + :local Comment ($CommentPrefix . $PeerId); + :local HostName [ :pick $PeerId 0 [ :find ($PeerId . ".") "." ] ]; :local Fqdn ($HostName . "." . $Zone); :local DnsRecord [ /ip/dns/static/find where name=$Fqdn ]; From fe87e9551d07ff33c62ce0f7611113c2218343a7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 19 Oct 2022 11:50:52 +0200 Subject: [PATCH 1228/2612] firmware-upgrade-reboot: update wording, give version --- firmware-upgrade-reboot | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware-upgrade-reboot b/firmware-upgrade-reboot index 27bbe41..7f27bea 100644 --- a/firmware-upgrade-reboot +++ b/firmware-upgrade-reboot @@ -15,7 +15,8 @@ :local RouterBoard [ /system/routerboard/get ]; :if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ - $LogPrintExit2 info $0 ("Firmware is already up to date.") true; + $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; From 4106b199bfa7e55517480271ff8418a0de8db99c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 19 Oct 2022 22:44:45 +0200 Subject: [PATCH 1229/2612] mod/notification-telegram: drop 'Telegram' from wording --- mod/notification-telegram | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-telegram b/mod/notification-telegram index 849740b..471dc10 100644 --- a/mod/notification-telegram +++ b/mod/notification-telegram @@ -121,7 +121,7 @@ } :if ($Truncated = true) do={ :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ - [ $EscapeMD ("The Telegram message was too long and has been truncated, cut off " . \ + [ $EscapeMD ("The message was too long and has been truncated, cut off " . \ (($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%!") "plain" ]); } :set Text [ $UrlEncode $Text ]; From 8c89fb0a4e02f3eed2f5e4df2e01874285ed53bb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 19 Oct 2022 21:40:56 +0200 Subject: [PATCH 1230/2612] README: update notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- âœ‚ī¸ ---- 📌 News and configuration changes The configuration version on MikroTik increased to 85, current configuration may need modification. Please review and update global-config-overlay, then re-run global-config. Changes: ● Support for e-mail notifications moved to a module. It is installed automatically if required. ● Dropped 'netwatch-syslog', filtering in firewall is advised. ---- âœ‚ī¸ ---- --- README.d/news-and-changes-notification.avif | Bin 0 -> 14720 bytes README.d/news-and-changes-notification.svg | 40 -------------------- README.md | 2 +- 3 files changed, 1 insertion(+), 41 deletions(-) create mode 100644 README.d/news-and-changes-notification.avif delete mode 100644 README.d/news-and-changes-notification.svg diff --git a/README.d/news-and-changes-notification.avif b/README.d/news-and-changes-notification.avif new file mode 100644 index 0000000000000000000000000000000000000000..547c15cbc88b2f5a8a9ea5b80cf33a5005d3dfd7 GIT binary patch literal 14720 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%0D5C*Bw5JX{ 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 - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] 📌 News and configuration changes - -The configuration version on MikroTik increased to 84, -current configuration may need modification. Please -review and update global-config-overlay, then re-run -global-config. - -Changes: - ● Introduced new setting to disable news and change -notifications, dropped version from configuration. - - diff --git a/README.md b/README.md index 56d39e8..a664c06 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ everything is up-to-date it will not produce any output. If the update includes news or requires configuration changes a notification is sent - in addition to terminal output and log messages. -![news and changes notification](README.d/news-and-changes-notification.svg) +![news and changes notification](README.d/news-and-changes-notification.avif) Adding a script --------------- From 3733e0a9190ef741db6529f95732b8e1b7aab14f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Oct 2022 10:22:16 +0200 Subject: [PATCH 1231/2612] doc/backup-cloud: update notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- âœ‚ī¸ ---- đŸ’žâ˜ī¸ Cloud backup Uploaded backup for MikroTik to cloud. Hostname: MikroTik Board name: CHR Architecture: x86_64 RouterOS: Channel: stable Installed: 7.6 RouterOS-Scripts: Version: 85 Name: cloud-20221020-092419 Size: 370767 B (362 KiB) Download key: LLDBfPcWXxmSetWilqeJX5V ---- âœ‚ī¸ ---- --- doc/backup-cloud.d/notification.avif | Bin 0 -> 11615 bytes doc/backup-cloud.d/notification.svg | 46 --------------------------- doc/backup-cloud.md | 2 +- 3 files changed, 1 insertion(+), 47 deletions(-) create mode 100644 doc/backup-cloud.d/notification.avif delete mode 100644 doc/backup-cloud.d/notification.svg diff --git a/doc/backup-cloud.d/notification.avif b/doc/backup-cloud.d/notification.avif new file mode 100644 index 0000000000000000000000000000000000000000..623ea3bc66f6fd7fb58f06e503008c28d4823050 GIT binary patch literal 11615 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 KwHA&s@BaZbz7r1s literal 0 HcmV?d00001 diff --git a/doc/backup-cloud.d/notification.svg b/doc/backup-cloud.d/notification.svg deleted file mode 100644 index a0eed63..0000000 --- a/doc/backup-cloud.d/notification.svg +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] 💾☁ Cloud backup - -Uploaded backup for MikroTik to cloud. - -Hostname: MikroTik -Board name: CHR -Architecture: x86_64 -RouterOS: - Channel: stable - Installed: 7.4.1 -RouterOS-Scripts: - Version: 83 - -Name: cloud-20220224-092419 -Size: 370767 B (362 KiB) -Download key: LLDBfPcWXxmSetWilqeJX5V - - diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index 130e3f6..26f7db7 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -19,7 +19,7 @@ This script uploads ### Sample notification -![backup-cloud notification](backup-cloud.d/notification.svg) +![backup-cloud notification](backup-cloud.d/notification.avif) Requirements and installation ----------------------------- From 98844d85d532a25613f61d9402646ced89ed01cf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Oct 2022 10:24:40 +0200 Subject: [PATCH 1232/2612] doc/backup-upload: update notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- âœ‚ī¸ ---- 💾âŦ†ī¸ Backup & Config upload Backup and config export upload for MikroTik. Hostname: MikroTik Board name: CHR Architecture: x86_64 RouterOS: Channel: stable Installed: 7.6 RouterOS-Scripts: Version: 85 Backup file: MikroTik_example_com.backup Config file: MikroTik_example_com.rsc ---- âœ‚ī¸ ---- --- doc/backup-upload.d/notification.avif | Bin 0 -> 11674 bytes doc/backup-upload.d/notification.svg | 45 -------------------------- doc/backup-upload.md | 2 +- 3 files changed, 1 insertion(+), 46 deletions(-) create mode 100644 doc/backup-upload.d/notification.avif delete mode 100644 doc/backup-upload.d/notification.svg diff --git a/doc/backup-upload.d/notification.avif b/doc/backup-upload.d/notification.avif new file mode 100644 index 0000000000000000000000000000000000000000..277cab4d065268aa631dfcc2c4cb2e9a6b6c97c9 GIT binary patch literal 11674 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 - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] 💾âŦ† Backup & Config upload - -Backup and config export upload for MikroTik. - -Hostname: MikroTik -Board name: CHR -Architecture: x86_64 -RouterOS: - Channel: stable - Installed: 7.4.1 -RouterOS-Scripts: - Version: 83 - -Backup file: MikroTik_example_com.backup -Config file: MikroTik_example_com.rsc - - diff --git a/doc/backup-upload.md b/doc/backup-upload.md index 34df1c6..ab07862 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -19,7 +19,7 @@ configuration export (`/export terse show-sensitive`) to external server. ### Sample notification -![backup-upload notification](backup-upload.d/notification.svg) +![backup-upload notification](backup-upload.d/notification.avif) Requirements and installation ----------------------------- From fadf4d5008eaa7391b9c88aa5f65197f058c0c39 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Oct 2022 10:18:05 +0200 Subject: [PATCH 1233/2612] doc/check-certificates: update notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- âœ‚ī¸ ---- 🔏 Certificate renewed A certificate on MikroTik has been renewed. Name: example.com CommonName: example.com Private key: available Fingerprint: cc54cdd01fcd7698ecb71213874be776906eb33d26cd57754d168632f14c4c8b Issuer: R3 Validity: sep/08/2022 03:50:56 to dec/07/2022 03:50:55 Expires in: 8w 3d 12:03:30 ---- âœ‚ī¸ ---- --- doc/check-certificates.d/notification.avif | Bin 0 -> 12960 bytes doc/check-certificates.d/notification.svg | 41 --------------------- doc/check-certificates.md | 2 +- 3 files changed, 1 insertion(+), 42 deletions(-) create mode 100644 doc/check-certificates.d/notification.avif delete mode 100644 doc/check-certificates.d/notification.svg diff --git a/doc/check-certificates.d/notification.avif b/doc/check-certificates.d/notification.avif new file mode 100644 index 0000000000000000000000000000000000000000..a458b7ccfb5b6e472e370e76742d45788ffb6389 GIT binary patch literal 12960 zcmXwfV{j!*({^kp8{1Ac$;P&^v2C2#wsB(Hwr$(k*v7`mxA*ha+f&n5_tjn9{comf z1_T6z*v#3(-q6+34CJ5uhqjhxKW!}y&E$lB3jL$*ZB3mG|BL+-Y6}w^$Nz7FfY@6a zJO7{kAKF+N{a+a*drN2A|HVN6X+ldIfboBxC zMR5N)reOai|I0CSW&SAwumSw9rIn?-$t>w zbhrGE0f&Ks`3DGwu0KTri2qq2An3*b8%H~18~1;e5ka8*|4~?$_O^!q#s0~^!5~1v zf*}4)6>Do^=!^ye2g^xuLMV=cGH1#1*9bKpG!)xVa9cqdfOdB>w`?dok(2NYxjG4B z=^pvS;QQYAqDQ}gH?rvj!x`^+zgX&1(jBNBi4B)=F#ZPz*7gf~Fwaw3hE(J@O7@-R zj*g+{oay2NIZaYIJmOV}^d0FqRbR|aeD1Yb8fMNiu8WvlH6T`+T_6k|7B3;A?oZ@|WnWxdJ$_%E)hjkAF4{)^3OhVl z8H�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�)t0ROpiiBUVZCU~#E?bW z!dSyLe#{otA+Y;Nk?^$h4LZnD9P<5=#e619JanNyW?1YwQxF->pH4?zXY`Zq+nbMo znQL}YG#)S2Zc0^^E!P`UONwnA4J4#`)pMDAViyrhCZZ;vzYq&}jb1j79^?2PRp)n8 zO=b;87IR^G0d+j7(( z9zVRGj|*BL#+k3y#)ZqqBC2Ioq~&n^1XZRS)w%0u52j(}ojI#ToP{m)jhpd%$1?0_ zHa)3qOlUL4Wybw-KfuiiGja2j*u{bziNw% zJBisGn`lonrD0+otvFFOA*E?0?Q=sgzWIdRHhP=Z2Y+_HNU`_01`Om|T4UF($$_hm z{0f=Dg>&%RT==UZIS{&fMZSCk{yDZ@u2`Zk@(b={z(NIlWu>fIyud2|O8jG6^{Vt9 zsU7+Y*@_BAa>od1=31G4*on}sEqGGiwP0{uui=K#pv1NxU~Kdh91*+f+bZcRqa`mF zV(SI_tM@8x#bJpSGiIn=95X=+i&MFUL<0BKUf$w*oK4M;^Pn#=NtT+D?BaVbs>#9^ z*@|)qIyH$=abIN;j4BO%MCYWn@TFcOm*MO<^`c61o*06oWbS1zKP)>lX7$9wb8%aA zNTJu0SatKs(?z56o)4G%GJLdQ7HZXJcT~^LB&Hn+QE$tUO{Cum=T^}d3(Do2fc+;M zm33c!xrCf*>vD2q6kF`Y9sTpfMw+y52Q%xXd|UXKq?yb3-pT8ocdG7O7nkf0t`kAL zOqnzW(JaK>A5pwuVLz7}+(ed*1dAL3($XDDvQ97Zyh=XR(AN2%u(%a(Bc&{nxuJl& zqFyEgFYLWBx00t7y58D9!8##Gq^Au(bAt07ff1YwnhYCx#qRqxN)7NxU)J^S3rfK72i<5hI zE7dafUBjvYkV*=L8wdmz1sAjpRp!IC)|HR?hxB!P=IQ*yAHFS+vmp4h zSJdDsED5V7 z&Hlx0Cg~&-K1bvO1i|+b|B*@hL1}u#{WXG - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] 🔏 Certificate renewed - -A certificate on MikroTik has been renewed. - -Name: example.com -CommonName: example.com -Private key: available -Fingerprint: cc54cdd01fcd7698ecb71213874be776906eb33d26cd57754d168632f14c4c8b -Issuer: R3 -Validity: may/22/2021 22:29:34 to aug/20/2021 22:29:34 -Expires in: 11w 5d 08:18:06 - - diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 5198e52..e8c295a 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -14,7 +14,7 @@ certificates that are still about to expire. ### Sample notification -![check-certificates notification](check-certificates.d/notification.svg) +![check-certificates notification](check-certificates.d/notification.avif) Requirements and installation ----------------------------- From 692ed21262486c237e44feed79f1237797e640f4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Oct 2022 10:33:39 +0200 Subject: [PATCH 1234/2612] doc/check-health: update notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- âœ‚ī¸ ---- ⚡📉 Health warning: voltage The voltage on MikroTik jumped more than 10%. old value: 16.2V new value: 12.4V ---- âœ‚ī¸ ---- đŸ”Ĩ Health warning: temperature The temperature on MikroTik is above threshold: 51°C ---- âœ‚ī¸ ---- ✅ Health recovery: temperature The temperature on MikroTik dropped below threshold: 47°C ---- âœ‚ī¸ ---- ❌ Health warning: psu1-state The power supply unit 'psu1-state' on MikroTik failed! ---- âœ‚ī¸ ---- ✅ Health recovery: psu1-state The power supply unit 'psu1-state' on MikroTik recovered! ---- âœ‚ī¸ ---- --- .../notification-01-voltage.avif | Bin 0 -> 4053 bytes .../notification-01-voltage.svg | 36 ------------------ .../notification-02-temperature-high.avif | Bin 0 -> 3615 bytes .../notification-02-temperature-high.svg | 33 ---------------- .../notification-03-temperature-ok.avif | Bin 0 -> 3763 bytes .../notification-03-temperature-ok.svg | 33 ---------------- .../notification-04-psu-fail.avif | Bin 0 -> 3544 bytes .../notification-04-psu-fail.svg | 33 ---------------- .../notification-05-psu-ok.avif | Bin 0 -> 3561 bytes doc/check-health.d/notification-05-psu-ok.svg | 33 ---------------- doc/check-health.md | 10 ++--- 11 files changed, 5 insertions(+), 173 deletions(-) create mode 100644 doc/check-health.d/notification-01-voltage.avif delete mode 100644 doc/check-health.d/notification-01-voltage.svg create mode 100644 doc/check-health.d/notification-02-temperature-high.avif delete mode 100644 doc/check-health.d/notification-02-temperature-high.svg create mode 100644 doc/check-health.d/notification-03-temperature-ok.avif delete mode 100644 doc/check-health.d/notification-03-temperature-ok.svg create mode 100644 doc/check-health.d/notification-04-psu-fail.avif delete mode 100644 doc/check-health.d/notification-04-psu-fail.svg create mode 100644 doc/check-health.d/notification-05-psu-ok.avif delete mode 100644 doc/check-health.d/notification-05-psu-ok.svg diff --git a/doc/check-health.d/notification-01-voltage.avif b/doc/check-health.d/notification-01-voltage.avif new file mode 100644 index 0000000000000000000000000000000000000000..f4d6005810b7809a073cb8805df66d51b916e1e9 GIT binary patch literal 4053 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 qNq5HTnD&%7QZh;mS(uALkl - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] ⚡📉 Health warning: voltage - -The voltage on MikroTik jumped more than 10%. - -old value: 16.2V -new value: 12.4V - - diff --git a/doc/check-health.d/notification-02-temperature-high.avif b/doc/check-health.d/notification-02-temperature-high.avif new file mode 100644 index 0000000000000000000000000000000000000000..1a93610d49c1e033adf38663f322830188e30348 GIT binary patch literal 3615 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 - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] đŸ”Ĩ Health warning: temperature - -The temperature on MikroTik is above threshold: 51°C - - diff --git a/doc/check-health.d/notification-03-temperature-ok.avif b/doc/check-health.d/notification-03-temperature-ok.avif new file mode 100644 index 0000000000000000000000000000000000000000..3bb9c68c4786ca4400bdd8428442e597321daefc GIT binary patch literal 3763 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 S8aG=g6&y#DUezSJ6aEkW-^#ZD literal 0 HcmV?d00001 diff --git a/doc/check-health.d/notification-03-temperature-ok.svg b/doc/check-health.d/notification-03-temperature-ok.svg deleted file mode 100644 index 180d13f..0000000 --- a/doc/check-health.d/notification-03-temperature-ok.svg +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] ✅ Health recovery: temperature - -The temperature on MikroTik dropped below threshold: 48°C - - diff --git a/doc/check-health.d/notification-04-psu-fail.avif b/doc/check-health.d/notification-04-psu-fail.avif new file mode 100644 index 0000000000000000000000000000000000000000..a4e52a9a7168132b13fa7b541d1d12592c8fdfe2 GIT binary patch literal 3544 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 E4^NtXtpET3 literal 0 HcmV?d00001 diff --git a/doc/check-health.d/notification-04-psu-fail.svg b/doc/check-health.d/notification-04-psu-fail.svg deleted file mode 100644 index f7efe4b..0000000 --- a/doc/check-health.d/notification-04-psu-fail.svg +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] ❌ Health warning: psu1-state - -The power supply unit 'psu1-state' on MikroTik failed! - - diff --git a/doc/check-health.d/notification-05-psu-ok.avif b/doc/check-health.d/notification-05-psu-ok.avif new file mode 100644 index 0000000000000000000000000000000000000000..bcc5a3905a7e02bbcf1e587c7a737eb474975717 GIT binary patch literal 3561 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 Y+UH4>Eqb!7=eCOD$Yk - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] ✅ Health recovery: psu1-state - -The power supply unit 'psu1-state' on MikroTik recovered! - - diff --git a/doc/check-health.md b/doc/check-health.md index 9ee16bb..d84693a 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -27,17 +27,17 @@ hardware supports: #### Voltage -![check-health notification voltage](check-health.d/notification-01-voltage.svg) +![check-health notification voltage](check-health.d/notification-01-voltage.avif) #### Temperature -![check-health notification](check-health.d/notification-02-temperature-high.svg) -![check-health notification](check-health.d/notification-03-temperature-ok.svg) +![check-health notification](check-health.d/notification-02-temperature-high.avif) +![check-health notification](check-health.d/notification-03-temperature-ok.avif) #### PSU state -![check-health notification](check-health.d/notification-04-psu-fail.svg) -![check-health notification](check-health.d/notification-05-psu-ok.svg) +![check-health notification](check-health.d/notification-04-psu-fail.avif) +![check-health notification](check-health.d/notification-05-psu-ok.avif) Requirements and installation ----------------------------- From 863cf9cae02bdd7f9f2938c6a7fca2cd9911924d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Oct 2022 10:36:56 +0200 Subject: [PATCH 1235/2612] doc/check-lte-firmware-upgrade: update notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- âœ‚ī¸ ---- ✨ LTE firmware upgrade A new firmware version R11e-LTE6_V033 is available for LTE interface lte on MikroTik. Interface: MikroTik R11e-LTE6 Installed: R11e-LTE6_V027 Available: R11e-LTE6_V033 ---- âœ‚ī¸ ---- --- .../notification.avif | Bin 0 -> 5279 bytes .../notification.svg | 38 ------------------ doc/check-lte-firmware-upgrade.md | 2 +- 3 files changed, 1 insertion(+), 39 deletions(-) create mode 100644 doc/check-lte-firmware-upgrade.d/notification.avif delete mode 100644 doc/check-lte-firmware-upgrade.d/notification.svg diff --git a/doc/check-lte-firmware-upgrade.d/notification.avif b/doc/check-lte-firmware-upgrade.d/notification.avif new file mode 100644 index 0000000000000000000000000000000000000000..4e28c365aec3a8508af1336dcf09781d1fba3e42 GIT binary patch literal 5279 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 - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] ✨ LTE firmware upgrade - -A new firmware version R11e-LTE6_V033 is available -for LTE interface lte on MikroTik. - -Interface: MikroTik R11e-LTE6 -Installed: R11e-LTE6_V027 -Available: R11e-LTE6_V033 - - diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index f3b3bfc..8443ea0 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -19,7 +19,7 @@ upgrades. Currently supported LTE hardware: ### Sample notification -![check-lte-firmware-upgrade notification](check-lte-firmware-upgrade.d/notification.svg) +![check-lte-firmware-upgrade notification](check-lte-firmware-upgrade.d/notification.avif) Requirements and installation ----------------------------- From 6940f851b02a4286789c003608fe7194816006f0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Oct 2022 10:39:52 +0200 Subject: [PATCH 1236/2612] doc/check-routeros-update: update notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- âœ‚ī¸ ---- ✨ RouterOS update A new RouterOS version 7.6 is available for MikroTik. Hostname: MikroTik Board name: CHR Architecture: x86_64 RouterOS: Channel: stable Installed: 7.5 Available: 7.6 RouterOS-Scripts: Version: 85 🔗 https://mikrotik.com/download/changelogs/stable-release-tree ---- âœ‚ī¸ ---- --- doc/check-routeros-update.d/notification.avif | Bin 0 -> 6850 bytes doc/check-routeros-update.d/notification.svg | 45 ------------------ doc/check-routeros-update.md | 2 +- 3 files changed, 1 insertion(+), 46 deletions(-) create mode 100644 doc/check-routeros-update.d/notification.avif delete mode 100644 doc/check-routeros-update.d/notification.svg diff --git a/doc/check-routeros-update.d/notification.avif b/doc/check-routeros-update.d/notification.avif new file mode 100644 index 0000000000000000000000000000000000000000..517ebeb6c15759403a0b69ea9d9d3c978f8dadf1 GIT binary patch literal 6850 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 - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] ✨ RouterOS update - -A new RouterOS version 7.4.1 is available for MikroTik. - -Hostname: MikroTik -Board name: CHR -Architecture: x86_64 -RouterOS: - Channel: stable - Installed: 7.3.1 - Available: 7.4.1 -RouterOS-Scripts: - Version: 83 - -🔗 https://mikrotik.com/download/changelogs/stable-release-tree - - diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index edffcbb..735fc5a 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -30,7 +30,7 @@ automatically is supported. ### Sample notification -![check-routeros-update notification](check-routeros-update.d/notification.svg) +![check-routeros-update notification](check-routeros-update.d/notification.avif) Requirements and installation ----------------------------- From dddbd3da2777e5e7fe4d61f5f96ce236a7ceee8c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Oct 2022 10:42:36 +0200 Subject: [PATCH 1237/2612] doc/collect-wireless-mac: update notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- âœ‚ī¸ ---- 📱 48:F1:7F:D0:E5:4E connected to Wifi A device with unknown MAC address connected to Wifi on MikroTik. Controller: MikroTik Interface: wl5-wifi SSID: Wifi MAC: 48:F1:7F:D0:E5:4E Vendor: Intel Corporate Hostname: host-523c8e0e Address: 192.168.20.254 DNS name: host-523c8e0e.dhcp.MikroTik.example.com Date: oct/20/2022 09:21:56 ---- âœ‚ī¸ ---- --- doc/collect-wireless-mac.d/notification.avif | Bin 0 -> 13403 bytes doc/collect-wireless-mac.d/notification.svg | 44 ------------------- doc/collect-wireless-mac.md | 2 +- 3 files changed, 1 insertion(+), 45 deletions(-) create mode 100644 doc/collect-wireless-mac.d/notification.avif delete mode 100644 doc/collect-wireless-mac.d/notification.svg diff --git a/doc/collect-wireless-mac.d/notification.avif b/doc/collect-wireless-mac.d/notification.avif new file mode 100644 index 0000000000000000000000000000000000000000..33fa9cb059572dd44f6e3acc486e73fb55e47e73 GIT binary patch literal 13403 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 literal 0 HcmV?d00001 diff --git a/doc/collect-wireless-mac.d/notification.svg b/doc/collect-wireless-mac.d/notification.svg deleted file mode 100644 index aae8cc5..0000000 --- a/doc/collect-wireless-mac.d/notification.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] 📱 48:F1:7F:D0:E5:4E connected to Wifi - -A device with unknown MAC address connected to Wifi -on MikroTik. - -Controller: MikroTik -Interface: wl5-wifi -SSID: Wifi -MAC: 48:F1:7F:D0:E5:4E -Vendor: Intel Corporate -Hostname: host-523c8e0e -Address: 192.168.20.254 -DNS name: host-523c8e0e.dhcp.MikroTik.example.com -Date: jun/15/2021 09:21:56 - - diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index e6ef990..f5c8a5c 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -17,7 +17,7 @@ and modify it to your needs. ### Sample notification -![collect-wireless-mac notification](collect-wireless-mac.d/notification.svg) +![collect-wireless-mac notification](collect-wireless-mac.d/notification.avif) Requirements and installation ----------------------------- From 694f4e28942e55a2da173bc0260a857c33f7d767 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Oct 2022 10:46:40 +0200 Subject: [PATCH 1238/2612] doc/daily-psk: update notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- âœ‚ī¸ ---- 📅 daily PSK Guest-Wifi This is the daily PSK on MikroTik: SSID: Guest-Wifi PSK: S3cr3tStr1ng Date: oct/18/2022 A client device specific rule must not exist! 🔗 https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi?scale=8&level=1&ssid=Guest-Wifi&pass=S3cr3tStr1ng ---- âœ‚ī¸ ---- --- doc/daily-psk.d/notification.avif | Bin 0 -> 7485 bytes doc/daily-psk.d/notification.svg | 40 ------------------------------ doc/daily-psk.md | 2 +- 3 files changed, 1 insertion(+), 41 deletions(-) create mode 100644 doc/daily-psk.d/notification.avif delete mode 100644 doc/daily-psk.d/notification.svg diff --git a/doc/daily-psk.d/notification.avif b/doc/daily-psk.d/notification.avif new file mode 100644 index 0000000000000000000000000000000000000000..b71372881b5693b2a530afd0292a397da1f9996d GIT binary patch literal 7485 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 - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] 📅 daily PSK Guest-Wifi - -This is the daily PSK on MikroTik: - -SSID: Guest-Wifi -PSK: S3cr3tStr1ng -Date: jun/17/2021 - -A client device specific rule must not exist! - 🔗 https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi?scale=8&level=1&ssid=Guest-Wifi&pass=S3cr3tStr1ng - - diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 62c26ee..67f0212 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -14,7 +14,7 @@ passphrase to a pseudo-random string daily. ### Sample notification -![daily-psk notification](daily-psk.d/notification.svg) +![daily-psk notification](daily-psk.d/notification.avif) Requirements and installation ----------------------------- From 4f8a2bd8e27ec420412659a56de0f2874141af18 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Oct 2022 10:51:16 +0200 Subject: [PATCH 1239/2612] doc/log-forward: update notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- âœ‚ī¸ ---- âš ī¸ Log Forwarding The log on MikroTik contains these 3 messages after 6d23:55:18 uptime. ● 13:24:02 script;error backup-cloud: Failed uploading backup for MikroTik to cloud! ● 13:24:17 system;info;account user admin logged in from 192.168.88.177 via ssh ● 13:24:57 system;info;account user admin logged out from 192.168.88.177 via ssh ---- âœ‚ī¸ ---- --- doc/log-forward.d/notification.avif | Bin 0 -> 6326 bytes doc/log-forward.d/notification.svg | 37 ---------------------------- doc/log-forward.md | 2 +- 3 files changed, 1 insertion(+), 38 deletions(-) create mode 100644 doc/log-forward.d/notification.avif delete mode 100644 doc/log-forward.d/notification.svg diff --git a/doc/log-forward.d/notification.avif b/doc/log-forward.d/notification.avif new file mode 100644 index 0000000000000000000000000000000000000000..d332ca56918b37679439aed55636e0083faf0da0 GIT binary patch literal 6326 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 literal 0 HcmV?d00001 diff --git a/doc/log-forward.d/notification.svg b/doc/log-forward.d/notification.svg deleted file mode 100644 index 9527411..0000000 --- a/doc/log-forward.d/notification.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] ⚠ Log Forwarding - -The log on MikroTik contains these 3 messages after 6d23:55:18 uptime. - - ● 13:24:02 script;error backup-cloud: Failed uploading backup for MikroTik to cloud! - ● 13:24:17 system;info;account user admin logged in from 192.168.88.177 via ssh - ● 13:24:57 system;info;account user admin logged out from 192.168.88.177 via ssh - - diff --git a/doc/log-forward.md b/doc/log-forward.md index 40a4135..649298a 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -22,7 +22,7 @@ and forwards them via notification. ### Sample notification -![log-forward notification](log-forward.d/notification.svg) +![log-forward notification](log-forward.d/notification.avif) Requirements and installation ----------------------------- From ee7836263f00bd5cb704099db50e1d9560ede457 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Oct 2022 10:56:10 +0200 Subject: [PATCH 1240/2612] doc/netwatch-notify: update notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- âœ‚ī¸ ---- ❌ Netwatch Notify: example.com down The host 'example.com' (93.184.216.34) is down since oct/19/2022 16:27:03. ---- âœ‚ī¸ ---- ✅ Netwatch Notify: example.com up The host 'example.com' (93.184.216.34) is up since oct/19/2022 17:03:00. It was down for 6 checks since oct/19/2022 16:27:03. ---- âœ‚ī¸ ---- --- .../notification-01-down.avif | Bin 0 -> 4340 bytes .../notification-01-down.svg | 34 ----------------- doc/netwatch-notify.d/notification-02-up.avif | Bin 0 -> 4862 bytes doc/netwatch-notify.d/notification-02-up.svg | 35 ------------------ doc/netwatch-notify.md | 4 +- 5 files changed, 2 insertions(+), 71 deletions(-) create mode 100644 doc/netwatch-notify.d/notification-01-down.avif delete mode 100644 doc/netwatch-notify.d/notification-01-down.svg create mode 100644 doc/netwatch-notify.d/notification-02-up.avif delete mode 100644 doc/netwatch-notify.d/notification-02-up.svg diff --git a/doc/netwatch-notify.d/notification-01-down.avif b/doc/netwatch-notify.d/notification-01-down.avif new file mode 100644 index 0000000000000000000000000000000000000000..d050e607641451dbe3c39e4dfc7d14d17409d7e3 GIT binary patch literal 4340 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 - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - [MikroTik] ❌ Netwatch Notify: example.com down - -The host 'example.com' (93.184.216.34) is down -since jun/08/2021 06:55:03. - - diff --git a/doc/netwatch-notify.d/notification-02-up.avif b/doc/netwatch-notify.d/notification-02-up.avif new file mode 100644 index 0000000000000000000000000000000000000000..8dcf26afb44afb637ce909b912f19c7fd7ced02b GIT binary patch literal 4862 zcmXv|1y~dA*B#y65+W(15m2N{I!B6>qXvwPF#+lB(ISj4K|oqc=|)mOkdy{NYNXVM zzwi0q_j%rP?m6eV_W}R_b_e8JxUDC|0dQac5DIY+g+go{bQDDu@1|7E5PXPcp1dRM2|A(%S*Z&(s4u>G2|9M#VKO4jq2L9Kn003C`@81u=dH?`Wt>5#< z5Qy7_@+&A{v|HAhfTTc;DWtc1Mzm?7qI0AmJYeC>(*geuhJmB{Kf&c*azrep+ zDB%!q$Ug;#kdW{mNNqhum4n&u82~^7hPfi#z^>l+lgR-1LH7~^1P- zp}6-~?LqBqk<Jr;41;1WY zs8tQC6~XfhF_oNj=%m?YgNlPr#ese^K>}UkaZ2*dJREe2)l!NJW3Eq0MMb4if;~C; zF*tDzPmHv?X2MGNMBqIP+s>0CLx(vu)z`fyP|V3NKuy=03^`CasUe%;P>zl=1FI#W z+UFRZrLdv09!_io_=3WHaE!(AS+zpp8>fFE(f1)z)=~-K}eQ$P0&G= zm7Ugkx4-K=L|MxF5trMJN%XwRaxU_4bEK-hRlU1}@rOq|e`KsHv8yCE-e#cAl2w@# zKdsT!SqSWcYl5+1XyjvOs{6XQdS0oKZ&wiZ934mE=9MX+H$NmTCrSkYx7WzgFPLAm87djrCqwYaO)&*Dybsz1I)&gKx11pni1VW? zzh&TW#8>^O&)F%wPfya9`(~O87#xV zMfQvJwq6(Zlldbbd2-hbUbvcc(%V)mrlwy82pztdNS8M^WnUS;+O=^SIq>^cX=HK6 zUTD$1tAgLwH_5tq3q^EC`|ih-%7^mp_}Nh>tMy~aJ>Kavjw)lGBJ^0GYJ6H07>2xx zDtyM_pTgQY)Rl(4HJ~bzX^@Xm=MZY#*Hf2%uc}8tLDad?-&I}2mY@4aJx7f7oG}QK zlXYVnCh;&_byaAOUHthA3be_aqJD={=pFS?YQHAts1#rQ18Mh2@)$+oh^6ajHI{w@ z%;nmCXJ&o-Zi%;7HV=lyC1S3l_erW{8^I_2{2OUQV*0~{h;(_?&rX$Z$O9g;Wo$eC zoh3+*6!s-bg%sNxKP7@=-NhHX#R{3M=FQ zW(kA)w^Pa}7a}70faQv_F0GCaT2QZ_PWDptaiTxX=TqvQa#J~k8ASFR6f-tgzTUGG zxcVmMFOj;<9j#O>vCFOAzaMXB&XczD0>sOv z-D`ScQX{yc!OR96?%iJen;G}XJIVhy-!$A?O}M@;#MujpJNj&5wK5V($8xKq4*oD7 zKdFm5K0O$y*L0b3V;bzE?A{|nm&|S!15|&$mz*7Dma%!Vjbl8JJWG2%@&~*_oeI7a zwQ>IG8@wv;DI zPx$#|y0{Hlq8hE?B5AoZ8)%Y2tDi|UA~}*w=iNAFo>w-~jqCdAv$D8Xd-mo&PKT%k zrAY54*M^z$n@`bbit@+XS%`4b&=<7Ce@W>a^CQ;2@KGwh?;tc4;RzlAK+hV7LLMCD z65)A)wK`Ke*OC{`-&M!0x)o^+6)%yrZBi=Y0uZv-$+4ocB^I2PhdRdRe#NOn zcG!#W$e%!QZxgOv%ql6hs%#xe(B&CDuLJ_1Sic1c*JacuOMj}{V@{@O_|XLL;1tQH zU$v(k#yElpjq8tg-WNsyDk+Q;cEr7X>j0;E?N-ZGvWT?mCiSjrMhuJ<)u^BtaZ^RRnd31td!$ zMvV#MDGtNWmAj1p)wX(_H5d^)VFt~qzuPfFCY$lK-2BGrePV2=J6E9(L2VvtfF;u8 zeTO8yO;+ST+GN})!m!Chx^4YW488#q1EN$E=~=cN`{SIJ(JO7QKm`sBZKX8{f4!&L zyb1EiRIiBZ>viTmdy~fW2~Z)G*XHZw8_h#%2i>FWhr6o1`s>qy-y-c4_|E5liSbHb zLDEhP-?4r7=zFeY8@RG^i}NVcg7&DvF2<%Klaq3fW_Q{<0Tb(ri~I!mP1R<=`QYUZ zCGa-abJ;(cXm

    " . "
    " . \
         [ $PrepareText ($Notification->"message") ] . "
    "); :if ([ :len ($Notification->"link") ] > 0) do={ + :local Label [ $ProtocolStrip ($Notification->"link") ]; :set Plain ($Plain . "\n" . [ $SymbolForNotification "link" ] . \ - "[" . $Notification->"link" . "](" . $Notification->"link" . ")"); + "[" . $Label . "](" . $Notification->"link" . ")"); :set Formatted ($Formatted . "
    " . [ $SymbolForNotification "link" ] . \ "
    "link") ] . "\">" . \ - [ $PrepareText ($Notification->"link") ] . ""); + [ $PrepareText $Label ] . ""); } :do { From ee54956a6909190eceb5eae696ad8590720bc3c3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 19 Apr 2024 09:09:13 +0200 Subject: [PATCH 2184/2612] mod/notification-telegram: string protocol for display --- mod/notification-telegram.rsc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index c78a8ad..745367a 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -76,6 +76,7 @@ :global EitherOr; :global IfThenElse; :global LogPrint; + :global ProtocolStrip; :global SymbolForNotification; :global UrlEncode; @@ -117,7 +118,7 @@ ($Notification->"subject")) "plain" ] . "__*\n\n"); :local LenSubject [ :len $Text ]; :local LenMessage [ :len ($Notification->"message") ]; - :local LenLink [ :len ($Notification->"link") ]; + :local LenLink ([ :len ($Notification->"link") ] * 2); :local LenSum ($LenSubject + $LenMessage + $LenLink); :if ($LenSum > 3968) do={ :set Text ($Text . [ $EscapeMD ([ :pick ($Notification->"message") 0 (3840 - $LenSubject - $LenLink) ] . "...") "body" ]); @@ -126,7 +127,9 @@ :set Text ($Text . [ $EscapeMD ($Notification->"message") "body" ]); } :if ($LenLink > 0) do={ - :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD ($Notification->"link") "plain" ]); + :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . \ + "[" . [ $EscapeMD [ $ProtocolStrip ($Notification->"link") ] "plain" ] . "]" . \ + "(" . [ $EscapeMD ($Notification->"link") "plain" ] . ")"); } :if ($Truncated = true) do={ :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ From b0cd53f813be602edf59db2ec18e085d84fbebeb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 19 Apr 2024 10:05:52 +0200 Subject: [PATCH 2185/2612] netwatch-notify: allow to suppress resolve failure --- doc/netwatch-notify.md | 9 +++++++++ netwatch-notify.rsc | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 90cd830..2db32bb 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -104,6 +104,15 @@ powered off, but accessibility is of interest. Go and get your coffee â˜•ī¸ before sending the print job. +### No log on failed resolve + +A message is writting to log after three failed attemts to resolve a host. +However this can cause some noise for hosts that are expected to have +failures, for example when the name is dynamically added by +[`dhcp-to-dns`](dhcp-to-dns.md). This can be suppressed: + + /tool/netwatch/add comment="notify, name=client, resolve=client.dhcp.example.com, no-resolve-fail" host=10.0.0.0; + ### Add a note in notification For some extra information it is possible to add a text note. This is diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 0b6c366..9b0beb9 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -116,7 +116,7 @@ } } on-error={ :set ($Metric->"resolve-failcnt") ($Metric->"resolve-failcnt" + 1); - :if ($Metric->"resolve-failcnt" = 3) do={ + :if ($Metric->"resolve-failcnt" = 3 && $HostInfo->"no-resolve-fail" != true) do={ $LogPrint warning $ScriptName ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \ ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ $HostInfo->"name") "" ] . "' failed."); From 0f2a4aedab31a7f697158d3d34ac6ce08756ebce Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 19 Apr 2024 11:34:35 +0200 Subject: [PATCH 2186/2612] global-functions: $CertificateDownload: remove with find... ... to make sure this does not break when the file does no longer exist. Starting with RouterOS 7.15rc1 the file is automatically removed on import. --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 3b9f27c..66765bf 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -151,7 +151,7 @@ $WaitForFile $FileName; /certificate/import file-name=$FileName passphrase="" as-value; :delay 1s; - /file/remove $FileName; + /file/remove [ find where name=$FileName ]; :foreach Cert in=[ /certificate/find where name~("^" . $FileName . "_[0-9]+\$") ] do={ $CertificateNameByCN [ /certificate/get $Cert common-name ]; From e42f8843bd3e25657d7af1ced4a4ce0270817358 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 19 Apr 2024 11:53:32 +0200 Subject: [PATCH 2187/2612] INITIAL-COMMANDS: remove the certificate file with find Required as RouterOS 7.15rc1 removes it automatically. --- INITIAL-COMMANDS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 0320fe8..4a12197 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -23,7 +23,7 @@ Run the complete base installation: :if ([ :len [ /certificate/find where fingerprint="46494e30379059df18be52124305e606fc59070e5b21076ce113954b60517cda" or fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470" ] ] != 2) do={ :error "Something is wrong with your certificates!"; }; - /file/remove "letsencrypt-E1.pem"; + /file/remove [ find where name="letsencrypt-E1.pem" ]; :delay 1s; /system/script/set name=("global-config-overlay-" . [ /system/clock/get date ] . "-" . [ /system/clock/get time ]) [ find where name="global-config-overlay" ]; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ From de8da38a0cf60be3f79f5a64ad766343c18cb2a2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 19 Apr 2024 11:59:03 +0200 Subject: [PATCH 2188/2612] README: remove left over certificate file But use find as RouterOS 7.15rc1 removes it automatically. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4516736..a92f71d 100644 --- a/README.md +++ b/README.md @@ -91,11 +91,12 @@ a sensitive property, the passphrase. For basic verification we rename the certificates and print them by fingerprint. Make sure exactly these two certificates ("*E1*" and -"*ISRG-Root-X2*") are shown. +"*ISRG-Root-X2*") are shown. Also remove the left over file. /certificate/set name="E1" [ find where common-name="E1" ]; /certificate/set name="ISRG-Root-X2" [ find where common-name="ISRG Root X2" ]; /certificate/print proplist=name where fingerprint="46494e30379059df18be52124305e606fc59070e5b21076ce113954b60517cda" or fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470"; + /file/remove [ find where name="letsencrypt-E1.pem" ]; ![screenshot: check certs](README.d/03-check-certs.avif) From b0e4449e4f3f6318bbe9ad83fe1b8e30a77ea1ab Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 19 Apr 2024 12:00:13 +0200 Subject: [PATCH 2189/2612] README: show fingerprints in output This is not scrictly necessary, as we filter by fingerprint already... But it gives better overview and feeling. --- README.d/03-check-certs.avif | Bin 9339 -> 12089 bytes README.md | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/README.d/03-check-certs.avif b/README.d/03-check-certs.avif index 33bdc408e4dcd3c35e95c87109926d801f8c9fe8..0477c398b41b439ec6eff03c8bcd2357f2637857 100644 GIT binary patch delta 10851 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 delta 8079 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�Ibb~WfBjIbKo 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 g9gomMY$x< Date: Tue, 23 Apr 2024 10:43:19 +0200 Subject: [PATCH 2190/2612] netwatch-notify: log to debug... ... instead of discarding the message completely. --- netwatch-notify.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 9b0beb9..17682f0 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -116,8 +116,9 @@ } } on-error={ :set ($Metric->"resolve-failcnt") ($Metric->"resolve-failcnt" + 1); - :if ($Metric->"resolve-failcnt" = 3 && $HostInfo->"no-resolve-fail" != true) do={ - $LogPrint warning $ScriptName ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \ + :if ($Metric->"resolve-failcnt" = 3) do={ + $LogPrint [ $IfThenElse ($HostInfo->"no-resolve-fail" != true) warning debug ] \ + $ScriptName ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \ ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ $HostInfo->"name") "" ] . "' failed."); } From db1faf1091ed300931793e2e198acf83e8eca4d2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Apr 2024 13:41:36 +0200 Subject: [PATCH 2191/2612] backup-upload: remove temporary directory --- backup-upload.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/backup-upload.rsc b/backup-upload.rsc index 63e5b7f..1b9058d 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -158,4 +158,5 @@ :set PackagesUpdateBackupFailure true; :error false; } + /file/remove $DirName; } on-error={ } From b3b7643661b13856437ff75cca0bb48f1e1aa0bc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Apr 2024 18:03:08 +0200 Subject: [PATCH 2192/2612] backup-upload: no early exit... --- backup-upload.rsc | 1 - 1 file changed, 1 deletion(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 1b9058d..1dc98d5 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -156,7 +156,6 @@ :if ($Failed = 1) do={ :set PackagesUpdateBackupFailure true; - :error false; } /file/remove $DirName; } on-error={ } From 505074e6d333f9696eb1b2e6afc90a59a5e1e1d6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Apr 2024 14:09:21 +0200 Subject: [PATCH 2193/2612] backup-cloud: no early exit... ... as we want to make sure the directory (and its content) is removed. --- backup-cloud.rsc | 1 - 1 file changed, 1 deletion(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 8e29c67..1085f05 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -79,7 +79,6 @@ 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={ } From 5f1656b7ce439e6567803299eaddca215e8cb7cf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Apr 2024 13:53:04 +0200 Subject: [PATCH 2194/2612] backup-cloud: clean up and simplify code --- backup-cloud.rsc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 1085f05..bdc6c34 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -49,13 +49,11 @@ :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={ + + :local Backup ([ /system/backup/cloud/find ]->0); + :if ([ :typeof $Backup ] = "id") do={ /system/backup/cloud/upload-file action=create-and-upload \ - password=$BackupPassword replace=[ get ([ find ]->0) name ]; + password=$BackupPassword replace=$Backup; } else={ /system/backup/cloud/upload-file action=create-and-upload \ password=$BackupPassword; From 57ebcfb41cbd078ba62c7d4e7e921ffdae834521 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Apr 2024 17:37:28 +0200 Subject: [PATCH 2195/2612] backup-cloud: retry on error... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's see if brute force helps. đŸ¤Ē --- backup-cloud.rsc | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index bdc6c34..88dd345 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -47,19 +47,23 @@ :error false; } - :execute { - :global BackupPassword; + :local I 5; + :do { + :execute { + :global BackupPassword; - :local Backup ([ /system/backup/cloud/find ]->0); - :if ([ :typeof $Backup ] = "id") do={ - /system/backup/cloud/upload-file action=create-and-upload \ - password=$BackupPassword replace=$Backup; - } else={ - /system/backup/cloud/upload-file action=create-and-upload \ - password=$BackupPassword; - } - /file/add name="tmpfs/backup-cloud/done"; - } as-string; + :local Backup ([ /system/backup/cloud/find ]->0); + :if ([ :typeof $Backup ] = "id") do={ + /system/backup/cloud/upload-file action=create-and-upload \ + password=$BackupPassword replace=$Backup; + } else={ + /system/backup/cloud/upload-file action=create-and-upload \ + password=$BackupPassword; + } + /file/add name="tmpfs/backup-cloud/done"; + } as-string; + :set I ($I - 1); + } while=([ $WaitForFile "tmpfs/backup-cloud/done" 200ms ] = false && $I > 0); :if ([ $WaitForFile "tmpfs/backup-cloud/done" ] = true) do={ :local Cloud [ /system/backup/cloud/get ([ find ]->0) ]; From 4006d07222511b94fd84aa4578a0b857a59639d5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Apr 2024 14:20:30 +0200 Subject: [PATCH 2196/2612] global-functions: $FetchHuge: remove temporary directory --- global-functions.rsc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 66765bf..b0bde7e 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -406,13 +406,13 @@ :set CheckCert [ $IfThenElse ($CheckCert = false) "no" "yes-without-crl" ]; - :local FileName ("tmpfs/" . [ $CleanName $ScriptName ]); - :if ([ $MkDir $FileName ] = false) do={ + :local DirName ("tmpfs/" . [ $CleanName $ScriptName ]); + :if ([ $MkDir $DirName ] = false) do={ $LogPrint error $0 ("Failed creating directory!"); :return false; } - :set FileName ($FileName . "/" . [ $CleanName $0 ] . "-" . [ $GetRandom20CharAlNum ]); + :local FileName ($DirName . "/" . [ $CleanName $0 ] . "-" . [ $GetRandom20CharAlNum ]); :do { /tool/fetch check-certificate=$CheckCert $Url dst-path=$FileName \ http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) as-value; @@ -421,6 +421,7 @@ /file/remove $FileName; } $LogPrint debug $0 ("Failed downloading from: " . $Url); + /file/remove $DirName; :return false; } $WaitForFile $FileName; @@ -432,7 +433,7 @@ :set Return ($Return . ([ /file/read offset=$VarSize chunk-size=32768 file=$FileName as-value ]->"data")); :set VarSize [ :len $Return ]; } - /file/remove $FileName; + /file/remove $DirName; :return $Return; } From f1ad80873498e314bbc04f3f2be5feff33d7e9ff Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Apr 2024 14:26:05 +0200 Subject: [PATCH 2197/2612] mod/ssh-keys-import: create directory later --- mod/ssh-keys-import.rsc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index f37c28b..e920762 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -38,11 +38,6 @@ :return false; } - :if ([ $MkDir "tmpfs/ssh-keys-import" ] = false) do={ - $LogPrint warning $0 ("Creating directory 'tmpfs/ssh-keys-import' failed!"); - :return false; - } - :local FingerPrintMD5 [ :convert from=base64 transform=md5 to=hex ($KeyVal->1) ]; :if ([ :len [ /user/ssh-keys/find where user=$User key-owner~("\\bmd5=" . $FingerPrintMD5 . "\\b") ] ] > 0) do={ @@ -51,6 +46,11 @@ :return false; } + :if ([ $MkDir "tmpfs/ssh-keys-import" ] = false) do={ + $LogPrint warning $0 ("Creating directory 'tmpfs/ssh-keys-import' failed!"); + :return false; + } + :local FileName ("tmpfs/ssh-keys-import/key-" . [ $GetRandom20CharAlNum 6 ] . ".pub"); /file/add name=$FileName contents=($Key . ", md5=" . $FingerPrintMD5); $WaitForFile $FileName; From b0f58696f334c9c378229f68f7e5e6d69a4b6af7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Apr 2024 14:30:42 +0200 Subject: [PATCH 2198/2612] mod/ssh-keys-import: remove temporary directory --- mod/ssh-keys-import.rsc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index e920762..6272a93 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -59,8 +59,10 @@ /user/ssh-keys/import public-key-file=$FileName user=$User; $LogPrint info $0 ("Imported ssh public key (" . $KeyVal->2 . ", " . $KeyVal->0 . ", " . \ "MD5:" . $FingerPrintMD5 . ") for user '" . $User . "'."); + /file/remove "tmpfs/ssh-keys-import"; } on-error={ $LogPrint warning $0 ("Failed importing key."); + /file/remove "tmpfs/ssh-keys-import"; :return false; } } From 755db5d66db8e24872fb7bf959e09b047f7cd5f9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Apr 2024 14:50:57 +0200 Subject: [PATCH 2199/2612] global-functions: $CleanName: do not start with a dash --- global-functions.rsc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index b0bde7e..5135fc1 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -230,11 +230,19 @@ :for I from=0 to=([ :len $Input ] - 1) do={ :local Char [ :pick $Input $I ]; :if ([ :typeof [ find "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-" $Char ] ] = "nil") do={ - :set Char "-"; - } - :if ($Char != "-" || [ :pick $Return ([ :len $Return ] - 1) ] != "-") do={ - :set Return ($Return . $Char); + :do { + :if ([ :len $Return ] = 0) do={ + :error true; + } + :if ([ :pick $Return ([ :len $Return ] - 1) ] = "-") do={ + :error true; + } + :set Char "-"; + } on-error={ + :set Char ""; + } } + :set Return ($Return . $Char); } :return $Return; } From e7cdb2d7f454fa093b6b9be3e38a86a90d344d55 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Apr 2024 23:59:11 +0200 Subject: [PATCH 2200/2612] mod/notification-matrix: format date & time italic --- mod/notification-matrix.rsc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 9442f54..196633a 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -139,11 +139,12 @@ :if ([ :typeof $MatrixQueue ] = "nothing") do={ :set MatrixQueue ({}); } - :local Text ([ $SymbolForNotification "alarm-clock" ] . \ - "This message was queued since " . [ /system/clock/get date ] . \ - " " . [ /system/clock/get time ] . " and may be obsolete."); - :set Plain ($Plain . "\n" . $Text); - :set Formatted ($Formatted . "
    " . $Text); + :local Symbol [ $SymbolForNotification "alarm-clock" ]; + :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); + :set Plain ($Plain . "\n" . $Symbol . "This message was queued since *" . \ + $DateTime . "* and may be obsolete."); + :set Formatted ($Formatted . "
    " . $Symbol . "This message was queued since " . \ + $DateTime . " and may be obsolete."); :set ($MatrixQueue->[ :len $MatrixQueue ]) { headers=$Headers; \ accesstoken=$AccessToken; homeserver=$HomeServer; room=$Room; \ plain=$Plain; formatted=$Formatted }; From d6e315580bf354e7a5620955c707e604d3cdaf9e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Apr 2024 00:18:07 +0200 Subject: [PATCH 2201/2612] mod/notification-telegram: capitalize Telegram in message --- mod/notification-telegram.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 745367a..440e0dd 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -149,7 +149,7 @@ "&parse_mode=MarkdownV2&text=" . [ $UrlEncode $Text ]) as-value ]->"data"); :set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1; } on-error={ - $LogPrint info $0 ("Failed sending telegram notification! Queuing..."); + $LogPrint info $0 ("Failed sending Telegram notification! Queuing..."); :if ([ :typeof $TelegramQueue ] = "nothing") do={ :set TelegramQueue ({}); From 4b6cd7ba2911b44f8d0890c19c5342ce28a6b3a8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Apr 2024 08:15:56 +0200 Subject: [PATCH 2202/2612] mod/notification-telegram: use proper variable naming... ... in local escaping function. --- mod/notification-telegram.rsc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 440e0dd..efde85a 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -81,24 +81,26 @@ :global UrlEncode; :local EscapeMD do={ + :local Text [ :tostr $1 ]; + :local Mode [ :tostr $2 ]; + :global CharacterReplace; :global IfThenElse; - :local Return $1; :local Chars { - "body"={ "\\"; "`" }; + "body"={ "\\"; "`" }; "plain"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">"; "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; } - :foreach Char in=($Chars->$2) do={ - :set Return [ $CharacterReplace $Return $Char ("\\" . $Char) ]; + :foreach Char in=($Chars->$Mode) do={ + :set Text [ $CharacterReplace $Text $Char ("\\" . $Char) ]; } - :if ($2 = "body") do={ - :return ("```\n" . $Return . "\n```"); + :if ($Mode = "body") do={ + :return ("```\n" . $Text . "\n```"); } - :return $Return; + :return $Text; } :local ChatId [ $EitherOr ($Notification->"chatid") \ From f8856ae7423d2b969b02094cc002e75388ee6374 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Apr 2024 08:24:06 +0200 Subject: [PATCH 2203/2612] mod/notification-telegram: support excluding characters from escaping... ... to support formatting in plain text. Handle with care, this can break the request if done wrong! --- mod/notification-telegram.rsc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index efde85a..858ab1b 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -83,6 +83,7 @@ :local EscapeMD do={ :local Text [ :tostr $1 ]; :local Mode [ :tostr $2 ]; + :local Excl [ :tostr $3 ]; :global CharacterReplace; :global IfThenElse; @@ -93,7 +94,9 @@ "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; } :foreach Char in=($Chars->$Mode) do={ - :set Text [ $CharacterReplace $Text $Char ("\\" . $Char) ]; + :if ([ :typeof [ :find $Excl $Char ] ] = "nil") do={ + :set Text [ $CharacterReplace $Text $Char ("\\" . $Char) ]; + } } :if ($Mode = "body") do={ From 0fd1e506badcce5580fc6505c423e4fe65db4d1e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 25 Apr 2024 23:59:38 +0200 Subject: [PATCH 2204/2612] mod/notification-telegram: format date & time italic --- mod/notification-telegram.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 858ab1b..4c2fd94 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -160,8 +160,8 @@ :set TelegramQueue ({}); } :set Text ($Text . "\n" . [ $SymbolForNotification "alarm-clock" ] . \ - [ $EscapeMD ("This message was queued since " . [ /system/clock/get date ] . \ - " " . [ /system/clock/get time ] . " and may be obsolete.") "plain" ]); + [ $EscapeMD ("This message was queued since _" . [ /system/clock/get date ] . \ + " " . [ /system/clock/get time ] . "_ and may be obsolete.") "plain" "_" ]); :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; text=$Text; silent=($Notification->"silent"); replyto=($Notification->"replyto") }; :if ([ :len [ /system/scheduler/find where name="_FlushTelegramQueue" ] ] = 0) do={ From 40f13b6ca45a15def2e63bab22d87ddf398c3cc7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Apr 2024 13:34:30 +0200 Subject: [PATCH 2205/2612] mod/notification-telegram: format percentage italic --- mod/notification-telegram.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 4c2fd94..9a628ce 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -138,8 +138,8 @@ } :if ($Truncated = true) do={ :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ - [ $EscapeMD ("The message was too long and has been truncated, cut off " . \ - (($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%!") "plain" ]); + [ $EscapeMD ("The message was too long and has been truncated, cut off _" . \ + (($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%_!") "plain" "_" ]); } :do { From 6ba1faca4c156097448c766098688cc5c4ef6045 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 26 Apr 2024 20:50:08 +0200 Subject: [PATCH 2206/2612] telegram-chat: shorten the message --- telegram-chat.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index c1a1cbc..f8dcd42 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -81,7 +81,7 @@ } :if ($Data = false) do={ - $LogPrint warning $ScriptName ("Failed getting updates from Telegram."); + $LogPrint warning $ScriptName ("Failed getting updates."); :error false; } From 52ec6b7ea19256e47d9ffd1519ef9d7799ca48ba Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Apr 2024 17:57:22 +0200 Subject: [PATCH 2207/2612] global-functions: $WaitForFile: use fewer steps --- global-functions.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 5135fc1..1c36e2a 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1520,10 +1520,10 @@ :set FileName [ $CleanFilePath $FileName ]; :local I 1; - :local Delay ([ :totime [ $EitherOr $WaitTime 2s ] ] / 20); + :local Delay ([ :totime [ $EitherOr $WaitTime 2s ] ] / 10); :while ([ :len [ /file/find where name=$FileName ] ] = 0) do={ - :if ($I >= 20) do={ + :if ($I >= 10) do={ :return false; } :delay $Delay; From 517ed7bf8cefe47e6c409915a4b27384f081715d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Apr 2024 17:55:48 +0200 Subject: [PATCH 2208/2612] global-functions: $WaitForFile: respect minimum delay --- global-functions.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 1c36e2a..9c009ae 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1517,10 +1517,11 @@ :global CleanFilePath; :global EitherOr; + :global MAX; :set FileName [ $CleanFilePath $FileName ]; :local I 1; - :local Delay ([ :totime [ $EitherOr $WaitTime 2s ] ] / 10); + :local Delay ([ :totime [ $MAX [ $EitherOr $WaitTime 2s ] 100ms ] ] / 10); :while ([ :len [ /file/find where name=$FileName ] ] = 0) do={ :if ($I >= 10) do={ From eae8dbbb378dbfe43c83e77529895747da0e260e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Apr 2024 17:59:41 +0200 Subject: [PATCH 2209/2612] global-functions: $WaitForFile: drop extra conversion --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 9c009ae..e8163ed 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1521,7 +1521,7 @@ :set FileName [ $CleanFilePath $FileName ]; :local I 1; - :local Delay ([ :totime [ $MAX [ $EitherOr $WaitTime 2s ] 100ms ] ] / 10); + :local Delay ([ $MAX [ $EitherOr $WaitTime 2s ] 100ms ] / 10); :while ([ :len [ /file/find where name=$FileName ] ] = 0) do={ :if ($I >= 10) do={ From fb7170f3121dd9e25cc320e5f0c98d1829e49d33 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 May 2024 12:30:13 +0200 Subject: [PATCH 2210/2612] global-functions: $IsTimeSync: log just once --- global-functions.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index e8163ed..5cc665c 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -673,7 +673,7 @@ :global IsTimeSyncCached; :global IsTimeSyncResetNtp; - :global LogPrint; + :global LogPrintOnce; :if ($IsTimeSyncCached = true) do={ :return true; @@ -702,7 +702,7 @@ :if ([ /system/license/get ]->"level" = "free" || \ [ /system/resource/get ]->"board-name" = "x86") do={ - $LogPrint debug $0 ("No ntp client configured, relying on RTC for CHR free license and x86."); + $LogPrintOnce debug $0 ("No ntp client configured, relying on RTC for CHR free license and x86."); :return true; } @@ -714,7 +714,7 @@ :return false; } - $LogPrint debug $0 ("No time source configured! Returning gracefully..."); + $LogPrintOnce debug $0 ("No time source configured! Returning gracefully..."); :return true; } From 2745597b93901d34a4ade63d789c984adccd8b54 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 8 May 2024 14:25:02 +0200 Subject: [PATCH 2211/2612] global-functions: $IsTimeSync: add (one time) warning on failed ntp sync --- global-functions.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/global-functions.rsc b/global-functions.rsc index 5cc665c..b1833b1 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -693,6 +693,7 @@ :return false; } + $LogPrintOnce warning $0 ("The ntp client is configured, but did not sync."); :set IsTimeSyncResetNtp $Uptime; /system/ntp/client/set enabled=no; :delay 20ms; From c87a7519fe03249b8dbc5da3233e593c0290095d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 10 May 2024 13:17:02 +0200 Subject: [PATCH 2212/2612] fw-addr-lists: add 'strongips' list from blocklist.de --- certs/Certum-Domain-Validation-CA-SHA2.pem | 176 +++++++++++++++++++++ doc/fw-addr-lists.md | 4 +- global-config.rsc | 2 + global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 5 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 certs/Certum-Domain-Validation-CA-SHA2.pem diff --git a/certs/Certum-Domain-Validation-CA-SHA2.pem b/certs/Certum-Domain-Validation-CA-SHA2.pem new file mode 100644 index 0000000..0cc17ac --- /dev/null +++ b/certs/Certum-Domain-Validation-CA-SHA2.pem @@ -0,0 +1,176 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 279744 (0x444c0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA + Validity + Not Before: Oct 22 12:07:37 2008 GMT + Not After : Dec 31 12:07:37 2029 GMT + Subject: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:e3:fb:7d:a3:72:ba:c2:f0:c9:14:87:f5:6b:01: + 4e:e1:6e:40:07:ba:6d:27:5d:7f:f7:5b:2d:b3:5a: + c7:51:5f:ab:a4:32:a6:61:87:b6:6e:0f:86:d2:30: + 02:97:f8:d7:69:57:a1:18:39:5d:6a:64:79:c6:01: + 59:ac:3c:31:4a:38:7c:d2:04:d2:4b:28:e8:20:5f: + 3b:07:a2:cc:4d:73:db:f3:ae:4f:c7:56:d5:5a:a7: + 96:89:fa:f3:ab:68:d4:23:86:59:27:cf:09:27:bc: + ac:6e:72:83:1c:30:72:df:e0:a2:e9:d2:e1:74:75: + 19:bd:2a:9e:7b:15:54:04:1b:d7:43:39:ad:55:28: + c5:e2:1a:bb:f4:c0:e4:ae:38:49:33:cc:76:85:9f: + 39:45:d2:a4:9e:f2:12:8c:51:f8:7c:e4:2d:7f:f5: + ac:5f:eb:16:9f:b1:2d:d1:ba:cc:91:42:77:4c:25: + c9:90:38:6f:db:f0:cc:fb:8e:1e:97:59:3e:d5:60: + 4e:e6:05:28:ed:49:79:13:4b:ba:48:db:2f:f9:72: + d3:39:ca:fe:1f:d8:34:72:f5:b4:40:cf:31:01:c3: + ec:de:11:2d:17:5d:1f:b8:50:d1:5e:19:a7:69:de: + 07:33:28:ca:50:95:f9:a7:54:cb:54:86:50:45:a9: + f9:49 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 08:76:CD:CB:07:FF:24:F6:C5:CD:ED:BB:90:BC:E2:84:37:46:75:F7 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + Signature Value: + a6:a8:ad:22:ce:01:3d:a6:a3:ff:62:d0:48:9d:8b:5e:72:b0: + 78:44:e3:dc:1c:af:09:fd:23:48:fa:bd:2a:c4:b9:55:04:b5: + 10:a3:8d:27:de:0b:82:63:d0:ee:de:0c:37:79:41:5b:22:b2: + b0:9a:41:5c:a6:70:e0:d4:d0:77:cb:23:d3:00:e0:6c:56:2f: + e1:69:0d:0d:d9:aa:bf:21:81:50:d9:06:a5:a8:ff:95:37:d0: + aa:fe:e2:b3:f5:99:2d:45:84:8a:e5:42:09:d7:74:02:2f:f7: + 89:d8:99:e9:bc:27:d4:47:8d:ba:0d:46:1c:77:cf:14:a4:1c: + b9:a4:31:c4:9c:28:74:03:34:ff:33:19:26:a5:e9:0d:74:b7: + 3e:97:c6:76:e8:27:96:a3:66:dd:e1:ae:f2:41:5b:ca:98:56: + 83:73:70:e4:86:1a:d2:31:41:ba:2f:be:2d:13:5a:76:6f:4e: + e8:4e:81:0e:3f:5b:03:22:a0:12:be:66:58:11:4a:cb:03:c4: + b4:2a:2a:2d:96:17:e0:39:54:bc:48:d3:76:27:9d:9a:2d:06: + a6:c9:ec:39:d2:ab:db:9f:9a:0b:27:02:35:29:b1:40:95:e7: + f9:e8:9c:55:88:19:46:d6:b7:34:f5:7e:ce:39:9a:d9:38:f1: + 51:f7:4f:2c +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 26:dd:d2:2b:46:c9:c4:4d:5a:69:4d:39:80:7e:72:ad + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA + Validity + Not Before: Sep 11 12:00:00 2014 GMT + Not After : Jun 9 10:46:39 2027 GMT + Subject: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Domain Validation CA SHA2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a1:25:63:df:8d:e4:20:07:d9:54:d1:d1:04:f6: + 17:e2:3e:47:fb:c3:74:25:b8:c4:bf:12:12:bc:e0: + 70:d1:39:05:c2:17:b3:f7:82:70:a0:4e:07:fe:10: + 2a:ff:db:0d:46:5e:24:94:a3:8b:45:9f:18:9b:ce: + 42:c4:ae:db:83:33:bc:c2:bb:b4:30:b6:a7:37:87: + 78:7b:48:cb:25:2c:82:bb:0a:48:12:60:76:89:ec: + 8e:cc:8f:1e:52:48:e9:86:02:5a:c2:b0:8a:7c:85: + 3d:d9:ff:60:4f:33:6c:a6:a1:a0:85:e1:d7:53:f2: + ea:27:3d:65:a9:72:c1:08:83:cc:b0:25:9c:11:46: + 24:e0:3e:f4:a7:ef:ed:51:b1:65:93:42:b4:f6:e6: + 86:0a:10:79:32:36:58:b2:6b:a8:dc:d5:7a:1e:9d: + 14:ee:40:e7:b2:46:4c:bd:9a:29:c2:ec:f8:30:c1: + 62:02:2a:e2:1c:83:62:d0:85:36:1a:83:de:12:84: + 29:65:ef:d2:32:be:31:60:42:a8:cf:f8:dd:ea:d0: + 56:47:1d:bd:76:96:24:13:e7:be:d9:99:2b:fa:30: + 64:f1:8a:38:7a:a6:e1:2a:96:02:b0:9d:ba:d8:8f: + 6d:4e:7a:94:69:7d:b0:93:aa:74:e5:93:90:13:fa: + a2:99 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + E5:31:AD:BF:3A:11:96:F4:83:BC:50:3C:D4:B7:90:9B:90:EE:DE:25 + X509v3 Authority Key Identifier: + 08:76:CD:CB:07:FF:24:F6:C5:CD:ED:BB:90:BC:E2:84:37:46:75:F7 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + Full Name: + URI:http://crl.certum.pl/ctnca.crl + Authority Information Access: + OCSP - URI:http://subca.ocsp-certum.com + CA Issuers - URI:http://repository.certum.pl/ctnca.cer + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.certum.pl/CPS + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + ba:bf:f0:e1:dd:4d:2b:42:43:64:58:df:64:f3:ff:80:1a:5f: + 56:be:3b:a9:b2:76:f7:54:7a:4c:30:c1:99:24:4b:72:d2:ca: + d4:fa:08:c6:90:de:88:12:ed:f8:90:f9:fc:a9:84:fd:92:f2: + 78:e5:db:c9:22:57:ab:41:30:42:6b:0b:9f:d7:73:33:fb:01: + 67:1c:42:5c:8f:27:67:c7:6e:07:03:8d:0e:96:cb:0a:03:cc: + 3e:f8:87:3c:35:30:cd:18:8c:d5:71:dd:cd:dd:61:b0:13:a3: + 64:46:4e:fe:71:4e:6b:65:e9:14:04:f2:3f:a8:bd:0c:36:3d: + 2a:5d:9e:07:f2:c2:4f:90:c5:5e:4d:18:37:d1:27:28:80:a4: + 36:e5:ca:93:6a:65:0e:f8:93:b9:af:52:58:4b:7a:71:d8:ba: + f3:ef:d2:f3:f6:a2:97:e4:5d:14:02:9a:cb:e5:ae:b6:93:e1: + 23:9f:9b:3f:46:f7:ee:8e:a1:00:5b:66:c3:1e:68:23:86:0f: + 5d:77:ba:53:ad:f9:52:fb:70:15:c5:75:eb:cf:79:ad:49:7c: + f2:76:62:ae:44:2f:c5:5f:51:34:25:41:6a:12:0a:5f:8e:ae: + 10:c4:43:89:35:fd:ec:ff:31:e6:ec:1e:87:e9:3a:7c:29:50: + 45:41:a3:14 +-----BEGIN CERTIFICATE----- +MIIEzjCCA7agAwIBAgIQJt3SK0bJxE1aaU05gH5yrTANBgkqhkiG9w0BAQsFADB+ +MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5B +LjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIwIAYD +VQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMB4XDTE0MDkxMTEyMDAwMFoX +DTI3MDYwOTEwNDYzOVowgYUxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRv +IFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxKTAnBgNVBAMTIENlcnR1bSBEb21haW4gVmFsaWRhdGlvbiBD +QSBTSEEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoSVj343kIAfZ +VNHRBPYX4j5H+8N0JbjEvxISvOBw0TkFwhez94JwoE4H/hAq/9sNRl4klKOLRZ8Y +m85CxK7bgzO8wru0MLanN4d4e0jLJSyCuwpIEmB2ieyOzI8eUkjphgJawrCKfIU9 +2f9gTzNspqGgheHXU/LqJz1lqXLBCIPMsCWcEUYk4D70p+/tUbFlk0K09uaGChB5 +MjZYsmuo3NV6Hp0U7kDnskZMvZopwuz4MMFiAiriHINi0IU2GoPeEoQpZe/SMr4x +YEKoz/jd6tBWRx29dpYkE+e+2Zkr+jBk8Yo4eqbhKpYCsJ262I9tTnqUaX2wk6p0 +5ZOQE/qimQIDAQABo4IBPjCCATowDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +5TGtvzoRlvSDvFA81LeQm5Du3iUwHwYDVR0jBBgwFoAUCHbNywf/JPbFze27kLzi +hDdGdfcwDgYDVR0PAQH/BAQDAgEGMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9j +cmwuY2VydHVtLnBsL2N0bmNhLmNybDBrBggrBgEFBQcBAQRfMF0wKAYIKwYBBQUH +MAGGHGh0dHA6Ly9zdWJjYS5vY3NwLWNlcnR1bS5jb20wMQYIKwYBBQUHMAKGJWh0 +dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9jdG5jYS5jZXIwOQYDVR0gBDIwMDAu +BgRVHSAAMCYwJAYIKwYBBQUHAgEWGGh0dHA6Ly93d3cuY2VydHVtLnBsL0NQUzAN +BgkqhkiG9w0BAQsFAAOCAQEAur/w4d1NK0JDZFjfZPP/gBpfVr47qbJ291R6TDDB +mSRLctLK1PoIxpDeiBLt+JD5/KmE/ZLyeOXbySJXq0EwQmsLn9dzM/sBZxxCXI8n +Z8duBwONDpbLCgPMPviHPDUwzRiM1XHdzd1hsBOjZEZO/nFOa2XpFATyP6i9DDY9 +Kl2eB/LCT5DFXk0YN9EnKICkNuXKk2plDviTua9SWEt6cdi68+/S8/ail+RdFAKa +y+WutpPhI5+bP0b37o6hAFtmwx5oI4YPXXe6U635UvtwFcV16895rUl88nZirkQv +xV9RNCVBahIKX46uEMRDiTX97P8x5uweh+k6fClQRUGjFA== +-----END CERTIFICATE----- diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md index ac34c88..e9a8ff7 100644 --- a/doc/fw-addr-lists.md +++ b/doc/fw-addr-lists.md @@ -19,8 +19,8 @@ Description This script downloads, imports and updates firewall address-lists. Its main purpose is to block attacking ip addresses, spam hosts, command-and-control servers and similar malicious entities. The default configuration contains -lists from [abuse.ch](https://abuse.ch/) and -[dshield.org](https://dshield.org/), and +lists from [abuse.ch](https://abuse.ch/), [dshield.org](https://dshield.org/) +and [blocklist.de](https://www.blocklist.de/), and lists from [spamhaus.org](https://spamhaus.org/) are prepared. The address-lists are updated in place, so after initial import you will not diff --git a/global-config.rsc b/global-config.rsc index 6a37c0c..646eddb 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -101,6 +101,8 @@ cert="GlobalSign Atlas R3 DV TLS CA 2022 Q3" }; { url="https://www.dshield.org/block.txt"; cidr="/24"; cert="R3" }; + { url="https://lists.blocklist.de/lists/strongips.txt"; + cert="Certum Domain Validation CA SHA2" }; # { url="https://www.spamhaus.org/drop/drop.txt"; # cert="Cloudflare Inc ECC CA-3" }; # { url="https://www.spamhaus.org/drop/edrop.txt"; diff --git a/global-functions.rsc b/global-functions.rsc index b1833b1..f890376 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 127; +:global ExpectedConfigVersion 128; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 8ddeb91..13a358f 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -52,6 +52,7 @@ 125=("April's Fool! " . [ $SymbolForNotification "smiley-partying-face" ] . "Well, you missed it... - no charge nor fees. (Anyway... Donations are much appreciated, " . [ $SymbolForNotification "smiley-smiling-face" ] . "thanks!)"); 126="Made 'telegram-chat' capable of handling large command output. Telegram messages still limit the size, so it is truncated now."; 127="Added support for authentication to Ntfy notification module."; + 128="Added another list from blocklist.de to default configuration for 'fw-addr-lists'."; }; # Migration steps to be applied on script updates From 545fb5583aee9e8971749a7eab71b4040cf7847f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 May 2024 14:27:11 +0200 Subject: [PATCH 2213/2612] global-functions: $IsTimeSync: initialize with uptime... ... to make sure the warning is not issued too early. --- global-functions.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index f890376..3800ad5 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -685,10 +685,10 @@ :return true; } - :if ([ :typeof $IsTimeSyncResetNtp ] = "nothing") do={ - :set IsTimeSyncResetNtp 0s; - } :local Uptime [ /system/resource/get uptime ]; + :if ([ :typeof $IsTimeSyncResetNtp ] = "nothing") do={ + :set IsTimeSyncResetNtp $Uptime; + } :if ($Uptime - $IsTimeSyncResetNtp < 3m) do={ :return false; } From ca7a592dfd9f19e07bbabc32d999b604bff0d0c9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 May 2024 14:15:54 +0200 Subject: [PATCH 2214/2612] daily-psk: adopt syntax changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RouterOS 7.15beta8 came with this change: *) wifi - show inherited properties with "print" command (replaces "actual-configuration") and added "print config" for showing only configured values; While the old code is bad syntax with RouterOS 7.15, the new code is valid for older RouterOS, but produces different (and more or less unexpected) results. đŸĨ´ Let's use the new code, and add a check on the RouterOS version. With old RouterOS this now sends the notification even if the interface is disabled. --- daily-psk.capsman.rsc | 1 + daily-psk.local.rsc | 1 + daily-psk.template.rsc | 3 ++- daily-psk.wifi.rsc | 3 ++- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index 64e8ce7..985bc47 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -23,6 +23,7 @@ :global FormatLine; :global LogPrint; + :global RequiredRouterOS; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 48e2b8d..185165a 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -23,6 +23,7 @@ :global FormatLine; :global LogPrint; + :global RequiredRouterOS; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 5097b00..434410b 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -24,6 +24,7 @@ :global FormatLine; :global LogPrint; + :global RequiredRouterOS; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -85,7 +86,7 @@ /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ - :if ([ :len [ /interface/wifi/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ + :if ([ $RequiredRouterOS $ScriptName "7.15beta8" false ] = false || [ :len [ /interface/wifi/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ :if ($Seen->$Ssid = 1) do={ $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping."); diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index 9d7f285..9b938dc 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -23,6 +23,7 @@ :global FormatLine; :global LogPrint; + :global RequiredRouterOS; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -71,7 +72,7 @@ $LogPrint info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")"); /interface/wifi/access-list/set $AccList passphrase=$NewPsk; - :if ([ :len [ /interface/wifi/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ + :if ([ $RequiredRouterOS $ScriptName "7.15beta8" false ] = false || [ :len [ /interface/wifi/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ :if ($Seen->$Ssid = 1) do={ $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping."); } else={ From 169c1ab6e1fce71c50cc4eaadeaae7cc685ee7bc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 May 2024 15:51:34 +0200 Subject: [PATCH 2215/2612] daily-psk: decrease indention in notification --- daily-psk.capsman.rsc | 6 +++--- daily-psk.local.rsc | 6 +++--- daily-psk.template.rsc | 6 +++--- daily-psk.wifi.rsc | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index 985bc47..51eea36 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -81,9 +81,9 @@ $SendNotification2 ({ origin=$ScriptName; \ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - [ $FormatLine "SSID" $Ssid ] . "\n" . \ - [ $FormatLine "PSK" $NewPsk ] . "\n" . \ - [ $FormatLine "Date" $Date ] . "\n\n" . \ + [ $FormatLine "SSID" $Ssid 8 ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk 8 ] . "\n" . \ + [ $FormatLine "Date" $Date 8 ] . "\n\n" . \ "A client device specific rule must not exist!"); link=$Link }); :set ($Seen->$Ssid) 1; } diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 185165a..46d03a8 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -80,9 +80,9 @@ $SendNotification2 ({ origin=$ScriptName; \ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - [ $FormatLine "SSID" $Ssid ] . "\n" . \ - [ $FormatLine "PSK" $NewPsk ] . "\n" . \ - [ $FormatLine "Date" $Date ] . "\n\n" . \ + [ $FormatLine "SSID" $Ssid 8 ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk 8 ] . "\n" . \ + [ $FormatLine "Date" $Date 8 ] . "\n\n" . \ "A client device specific rule must not exist!"); link=$Link }); :set ($Seen->$Ssid) 1; } diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 434410b..6c67a57 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -96,9 +96,9 @@ $SendNotification2 ({ origin=$ScriptName; \ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - [ $FormatLine "SSID" $Ssid ] . "\n" . \ - [ $FormatLine "PSK" $NewPsk ] . "\n" . \ - [ $FormatLine "Date" $Date ] . "\n\n" . \ + [ $FormatLine "SSID" $Ssid 8 ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk 8 ] . "\n" . \ + [ $FormatLine "Date" $Date 8 ] . "\n\n" . \ "A client device specific rule must not exist!"); link=$Link }); :set ($Seen->$Ssid) 1; } diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index 9b938dc..9c28e9c 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -81,9 +81,9 @@ $SendNotification2 ({ origin=$ScriptName; \ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - [ $FormatLine "SSID" $Ssid ] . "\n" . \ - [ $FormatLine "PSK" $NewPsk ] . "\n" . \ - [ $FormatLine "Date" $Date ] . "\n\n" . \ + [ $FormatLine "SSID" $Ssid 8 ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk 8 ] . "\n" . \ + [ $FormatLine "Date" $Date 8 ] . "\n\n" . \ "A client device specific rule must not exist!"); link=$Link }); :set ($Seen->$Ssid) 1; } From 787ae4440ccc795e82373e80ed5e0266e529374a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 15 May 2024 15:54:12 +0200 Subject: [PATCH 2216/2612] daily-psk: quote ssid and passphrase --- daily-psk.capsman.rsc | 2 +- daily-psk.local.rsc | 2 +- daily-psk.template.rsc | 2 +- daily-psk.wifi.rsc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index 51eea36..cd5b6b0 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -69,7 +69,7 @@ :local Skip 0; :if ($NewPsk != $OldPsk) do={ - $LogPrint info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")"); + $LogPrint info $ScriptName ("Updating daily PSK for '" . $Ssid . "' to '" . $NewPsk . "' (was '" . $OldPsk . "')"); /caps-man/access-list/set $AccList private-passphrase=$NewPsk; :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 46d03a8..fbdb784 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -68,7 +68,7 @@ :local Skip 0; :if ($NewPsk != $OldPsk) do={ - $LogPrint info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")"); + $LogPrint info $ScriptName ("Updating daily PSK for '" . $Ssid . "' to '" . $NewPsk . "' (was '" . $OldPsk . "')"); /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 6c67a57..35fa82c 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -80,7 +80,7 @@ :local Skip 0; :if ($NewPsk != $OldPsk) do={ - $LogPrint info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")"); + $LogPrint info $ScriptName ("Updating daily PSK for '" . $Ssid . "' to '" . $NewPsk . "' (was '" . $OldPsk . "')"); /caps-man/access-list/set $AccList private-passphrase=$NewPsk; /interface/wifi/access-list/set $AccList passphrase=$NewPsk; /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index 9c28e9c..c1f7133 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -69,7 +69,7 @@ :local Skip 0; :if ($NewPsk != $OldPsk) do={ - $LogPrint info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")"); + $LogPrint info $ScriptName ("Updating daily PSK for '" . $Ssid . "' to '" . $NewPsk . "' (was '" . $OldPsk . "')"); /interface/wifi/access-list/set $AccList passphrase=$NewPsk; :if ([ $RequiredRouterOS $ScriptName "7.15beta8" false ] = false || [ :len [ /interface/wifi/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ From 51331ea2acd5f5563ed3641090bbb7f2104d3e96 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 May 2024 09:26:13 +0200 Subject: [PATCH 2217/2612] backup-partition: support RouterOS copy-over... ... when run interactively from CLI. --- backup-partition.rsc | 17 +++++++++++++++++ doc/backup-partition.md | 11 ++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index fc186c0..9eeb1ae 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -18,6 +18,7 @@ :global PackagesUpdateBackupFailure; :global LogPrint; + :global ScriptFromTerminal; :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -41,6 +42,22 @@ :local FallbackTo [ /partitions/get $ActiveRunning fallback-to ]; + :if ([ /partitions/get $ActiveRunning version ] != [ /partitions/get $FallbackTo version]) do={ + :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ + :put ("The partitions have different RouterOS versions. Copy over to '" . $FallbackTo . "'? [y/N]"); + :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ + :do { + /partitions/copy-to $FallbackTo; + $LogPrint info $ScriptName ("Copied RouterOS to partition '" . $FallbackTo . "'."); + } on-error={ + $LogPrint error $ScriptName ("Failed copying RouterOS to partition '" . $FallbackTo . "'!"); + :set PackagesUpdateBackupFailure true; + :error false; + } + } + } + } + :do { /system/scheduler/add start-time=startup name="running-from-backup-partition" \ on-event=(":log warning (\"Running from partition '\" . " . \ diff --git a/doc/backup-partition.md b/doc/backup-partition.md index ba20657..8996203 100644 --- a/doc/backup-partition.md +++ b/doc/backup-partition.md @@ -18,6 +18,7 @@ Description This script saves the current configuration to fallback [partition](https://wiki.mikrotik.com/wiki/Manual:Partitions). +It can also copy-over the RouterOS installation when run interactively. For this to work you need a device with sufficient flash storage that is properly partitioned. @@ -26,9 +27,10 @@ To make you aware of a possible issue a scheduler logging a warning is added in the backup partition's configuration. You may want to use [log-forward](log-forward.md) to be notified. -> âš ī¸ **Warning**: Only the configuration is saved to backup partition. -> Every now and then you should copy your installation over for a recent -> RouterOS version! +> âš ī¸ **Warning**: By default only the configuration is saved to backup +> partition. Every now and then you should copy your installation over +> for a recent RouterOS version! For that run the script from terminal +> manually. Requirements and installation ----------------------------- @@ -44,6 +46,9 @@ Just run the script: /system/script/run backup-partition; +When run interactively from terminal it supports to copy-over the RouterOS +installation when versions differ. + Creating a scheduler may be an option: /system/scheduler/add interval=1w name=backup-partition on-event="/system/script/run backup-partition;" start-time=09:30:00; From c26e44ae4673f58a89833c15faf06828e7e2dd3f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 23 May 2024 12:09:02 +0200 Subject: [PATCH 2218/2612] doc/backup-cloud: fix link for backup-partition --- doc/backup-cloud.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index be6e06d..1f9e123 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -68,7 +68,7 @@ See also -------- * [Send backup via e-mail](backup-email.md) -* [Save configuration to fallback partition](doc/backup-partition.md) +* [Save configuration to fallback partition](backup-partition.md) * [Upload backup to server](backup-upload.md) --- From 6cbe13a135fe39c097b6a7078506d99eedde2e06 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 May 2024 11:58:26 +0200 Subject: [PATCH 2219/2612] backup-partition: move code to a local function --- backup-partition.rsc | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index 9eeb1ae..a72dd0b 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -21,6 +21,22 @@ :global ScriptFromTerminal; :global ScriptLock; + :local CopyTo do={ + :local ScriptName [ :tostr $1 ]; + :local FallbackTo [ :tostr $2 ]; + + :global LogPrint; + + :do { + /partitions/copy-to $FallbackTo; + $LogPrint info $ScriptName ("Copied RouterOS to partition '" . $FallbackTo . "'."); + :return true; + } on-error={ + $LogPrint error $ScriptName ("Failed copying RouterOS to partition '" . $FallbackTo . "'!"); + :return false; + } + } + :if ([ $ScriptLock $ScriptName ] = false) do={ :set PackagesUpdateBackupFailure true; :error false; @@ -46,11 +62,7 @@ :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ :put ("The partitions have different RouterOS versions. Copy over to '" . $FallbackTo . "'? [y/N]"); :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - :do { - /partitions/copy-to $FallbackTo; - $LogPrint info $ScriptName ("Copied RouterOS to partition '" . $FallbackTo . "'."); - } on-error={ - $LogPrint error $ScriptName ("Failed copying RouterOS to partition '" . $FallbackTo . "'!"); + :if ([ $CopyTo $ScriptName $FallbackTo ] = false) do={ :set PackagesUpdateBackupFailure true; :error false; } From 16831aa1e8aa0ecb7ba95918e42aae2659530385 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 23 May 2024 12:09:28 +0200 Subject: [PATCH 2220/2612] doc/backup-email: fix link for backup-partition --- doc/backup-email.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/backup-email.md b/doc/backup-email.md index a506543..3b1dbb2 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -59,7 +59,7 @@ See also -------- * [Upload backup to Mikrotik cloud](backup-cloud.md) -* [Save configuration to fallback partition](doc/backup-partition.md) +* [Save configuration to fallback partition](backup-partition.md) * [Send notifications via e-mail](mod/notification-email.md) * [Upload backup to server](backup-upload.md) From affa11816182fa2bff454b3e82df3166c6cdd744 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 22 May 2024 12:03:53 +0200 Subject: [PATCH 2221/2612] backup-partition: support copy before feature update --- backup-partition.rsc | 13 +++++++++++++ doc/backup-partition.md | 18 +++++++++++++++--- global-config.rsc | 2 ++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index a72dd0b..3c883f7 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -15,11 +15,13 @@ :do { :local ScriptName [ :jobname ]; + :global BackupPartitionCopyBeforeFeatureUpdate; :global PackagesUpdateBackupFailure; :global LogPrint; :global ScriptFromTerminal; :global ScriptLock; + :global VersionToNum; :local CopyTo do={ :local ScriptName [ :tostr $1 ]; @@ -67,6 +69,17 @@ :error false; } } + } else={ + :local Update [ /system/package/update/get ]; + :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; + :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; + :if ($BackupPartitionCopyBeforeFeatureUpdate = true && $NumLatest > 0 && \ + ($NumInstalled & 0xffff0000) != ($NumLatest & 0xffff0000)) do={ + :if ([ $CopyTo $ScriptName $FallbackTo ] = false) do={ + :set PackagesUpdateBackupFailure true; + :error false; + } + } } } diff --git a/doc/backup-partition.md b/doc/backup-partition.md index 8996203..1cef2c9 100644 --- a/doc/backup-partition.md +++ b/doc/backup-partition.md @@ -18,7 +18,8 @@ Description This script saves the current configuration to fallback [partition](https://wiki.mikrotik.com/wiki/Manual:Partitions). -It can also copy-over the RouterOS installation when run interactively. +It can also copy-over the RouterOS installation when run interactively +or just before a feature update. For this to work you need a device with sufficient flash storage that is properly partitioned. @@ -29,8 +30,7 @@ added in the backup partition's configuration. You may want to use > âš ī¸ **Warning**: By default only the configuration is saved to backup > partition. Every now and then you should copy your installation over -> for a recent RouterOS version! For that run the script from terminal -> manually. +> for a recent RouterOS version! See below for options. Requirements and installation ----------------------------- @@ -39,6 +39,18 @@ Just install the script: $ScriptInstallUpdate backup-partition; +Configuration +------------- + +The configuration goes to `global-config-overlay`, the only parameter is: + +* `BackupPartitionCopyBeforeFeatureUpdate`: copy-over the RouterOS + installation when a feature update is pending + +> â„šī¸ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + Usage and invocation -------------------- diff --git a/global-config.rsc b/global-config.rsc index 646eddb..8a42b81 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -85,6 +85,8 @@ :global BackupUploadUrl "sftp://example.com/backup/"; :global BackupUploadUser "mikrotik"; :global BackupUploadPass "v3ry-s3cr3t"; +# Copy the RouterOS installation to backup partition before feature update. +:global BackupPartitionCopyBeforeFeatureUpdate false; # This defines the settings for firewall address-lists (fw-addr-lists). :global FwAddrLists { From 0a46fb536f929f3248085072979b7acfe119dbd5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 23 May 2024 12:09:46 +0200 Subject: [PATCH 2222/2612] doc/backup-upload: fix link for backup-partition --- doc/backup-upload.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/backup-upload.md b/doc/backup-upload.md index f524adb..c44217c 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -85,7 +85,7 @@ See also * [Upload backup to Mikrotik cloud](backup-cloud.md) * [Send backup via e-mail](backup-email.md) -* [Save configuration to fallback partition](doc/backup-partition.md) +* [Save configuration to fallback partition](backup-partition.md) --- [âŦ…ī¸ Go back to main README](../README.md) From 33a495beb76f438ba79e56ab8e4872d2df5c4da8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 23 May 2024 12:18:13 +0200 Subject: [PATCH 2223/2612] backup-partition: news on support for copy-over --- global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 3800ad5..96ed71d 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 128; +:global ExpectedConfigVersion 129; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 13a358f..b20bbaf 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -53,6 +53,7 @@ 126="Made 'telegram-chat' capable of handling large command output. Telegram messages still limit the size, so it is truncated now."; 127="Added support for authentication to Ntfy notification module."; 128="Added another list from blocklist.de to default configuration for 'fw-addr-lists'."; + 129="Extended 'backup-partition' to support RouterOS copy-over - interactively or before feature update."; }; # Migration steps to be applied on script updates From d6648563267a3c807a3b99f14881767b6e9826f0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 May 2024 20:00:03 +0200 Subject: [PATCH 2224/2612] telegram-chat: convert the message (command) to string RouterOS 7.15beta4 fixed a bug in JSON parser: *) console - do not convert string to array in ":deserialize" command; Before that change commands with a comma caused very crazy issues. Let's convert the message to a string. This does not give exactly the expected result, but mitigates telegram-chat to explode. A command like... /ip/address/print proplist=address,network; ... is converted to... /ip/address/print proplist=address;network; ... and results in: Columns: ADDRESS # ADDRESS 0 10.0.0.1/24 1 127.0.0.1/8 bad command name network (line 1 column 36) --- telegram-chat.rsc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index f8dcd42..f3efd08 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -97,6 +97,7 @@ :local Trusted false; :local Chat ($Message->"chat"); :local From ($Message->"from"); + :local Command [ :tostr ($Message->"text") ]; :foreach IdsTrusted in=($TelegramChatId, $TelegramChatIdsTrusted) do={ :if ($From->"id" = $IdsTrusted || $From->"username" = $IdsTrusted) do={ @@ -106,15 +107,15 @@ :if ($Trusted = true) do={ :local Done false; - :if ($Message->"text" = "?") do={ + :if ($Command = "?") do={ $LogPrint info $ScriptName ("Sending notice for update " . $UpdateID . "."); $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Online" . [ $IfThenElse $TelegramChatActive " (and active!)" ] . ", awaiting your commands!") }); :set Done true; } - :if ($Done = false && [ :pick ($Message->"text") 0 1 ] = "!") do={ - :if ($Message->"text" ~ ("^! *(" . [ $EscapeForRegEx $Identity ] . "|@" . $TelegramChatGroups . ")\$")) do={ + :if ($Done = false && [ :pick ($Command) 0 1 ] = "!") do={ + :if ($Command ~ ("^! *(" . [ $EscapeForRegEx $Identity ] . "|@" . $TelegramChatGroups . ")\$")) do={ :set TelegramChatActive true; } else={ :set TelegramChatActive false; @@ -123,16 +124,16 @@ " from update " . $UpdateID . "!"); :set Done true; } - :if ($Done = false && ($IsMyReply = 1 || ($IsReply = 0 && $TelegramChatActive = true)) && [ :len ($Message->"text") ] > 0) do={ - :if ([ $ValidateSyntax ($Message->"text") ] = true) do={ + :if ($Done = false && ($IsMyReply = 1 || ($IsReply = 0 && $TelegramChatActive = true)) && [ :len ($Command) ] > 0) do={ + :if ([ $ValidateSyntax ($Command) ] = true) do={ :local State ""; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); :if ([ $MkDir "tmpfs/telegram-chat" ] = false) do={ $LogPrint error $ScriptName ("Failed creating directory!"); :error false; } - $LogPrint info $ScriptName ("Running command from update " . $UpdateID . ": " . $Message->"text"); - :execute script=(":do {\n" . $Message->"text" . "\n} on-error={ /file/add name=\"" . $File . ".failed\" };" . \ + $LogPrint info $ScriptName ("Running command from update " . $UpdateID . ": " . $Command); + :execute script=(":do {\n" . $Command . "\n} on-error={ /file/add name=\"" . $File . ".failed\" };" . \ "/file/add name=\"" . $File . ".done\"") file=($File . "\00"); :if ([ $WaitForFile ($File . ".done") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ :set State ([ $SymbolForNotification "warning-sign" ] . "The command did not finish, still running in background.\n\n"); @@ -143,7 +144,7 @@ :local Content ([ /file/read chunk-size=32768 file=$File as-value ]->"data"); $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Message->"text" . "\n\n" . \ + message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Command . "\n\n" . \ $State . [ $IfThenElse ([ :len $Content ] > 0) \ ([ $SymbolForNotification "memo" ] . "Output:\n" . $Content) \ ([ $SymbolForNotification "memo" ] . "No output.") ]) }); @@ -152,7 +153,7 @@ $LogPrint info $ScriptName ("The command from update " . $UpdateID . " failed syntax validation!"); $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Message->"text" . "\n\n" . \ + message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Command . "\n\n" . \ [ $SymbolForNotification "cross-mark" ] . "The command failed syntax validation!") }); } } @@ -160,7 +161,7 @@ :local MessageText ("Received a message from untrusted contact " . \ [ $IfThenElse ([ :len ($From->"username") ] = 0) "without username" ("'" . $From->"username" . "'") ] . \ " (ID " . $From->"id" . ") in update " . $UpdateID . "!"); - :if ($Message->"text" ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ + :if ($Command ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ $LogPrint warning $ScriptName $MessageText; $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ From a97820d12a5833bce5160da674e5085b2882b53a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 25 May 2024 19:55:13 +0200 Subject: [PATCH 2225/2612] telegram-chat: drop extra parenthesis --- telegram-chat.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index f3efd08..0fd8a06 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -114,7 +114,7 @@ message=("Online" . [ $IfThenElse $TelegramChatActive " (and active!)" ] . ", awaiting your commands!") }); :set Done true; } - :if ($Done = false && [ :pick ($Command) 0 1 ] = "!") do={ + :if ($Done = false && [ :pick $Command 0 1 ] = "!") do={ :if ($Command ~ ("^! *(" . [ $EscapeForRegEx $Identity ] . "|@" . $TelegramChatGroups . ")\$")) do={ :set TelegramChatActive true; } else={ @@ -124,8 +124,8 @@ " from update " . $UpdateID . "!"); :set Done true; } - :if ($Done = false && ($IsMyReply = 1 || ($IsReply = 0 && $TelegramChatActive = true)) && [ :len ($Command) ] > 0) do={ - :if ([ $ValidateSyntax ($Command) ] = true) do={ + :if ($Done = false && ($IsMyReply = 1 || ($IsReply = 0 && $TelegramChatActive = true)) && [ :len $Command ] > 0) do={ + :if ([ $ValidateSyntax $Command ] = true) do={ :local State ""; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); :if ([ $MkDir "tmpfs/telegram-chat" ] = false) do={ From e35ba4b06ce300b698a8bf684503437961e1343a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 1 Jun 2024 23:06:24 +0200 Subject: [PATCH 2226/2612] global-functions: $CleanName: no exception for dash... ... as we still want to deduplicate it when it is inside the input string. This also unbreak certificate import for "Go Daddy Secure Certificate Authority - G2" (and more)... --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 96ed71d..447d6e9 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -229,7 +229,7 @@ :for I from=0 to=([ :len $Input ] - 1) do={ :local Char [ :pick $Input $I ]; - :if ([ :typeof [ find "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-" $Char ] ] = "nil") do={ + :if ([ :typeof [ find "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" $Char ] ] = "nil") do={ :do { :if ([ :len $Return ] = 0) do={ :error true; From cd4ac2c0881f92327ce173f2294b066ca4bc2ba2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Jun 2024 14:50:55 +0200 Subject: [PATCH 2227/2612] backup-cloud: log note on previous connection errors --- backup-cloud.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 88dd345..8f5575e 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -66,6 +66,10 @@ } while=([ $WaitForFile "tmpfs/backup-cloud/done" 200ms ] = false && $I > 0); :if ([ $WaitForFile "tmpfs/backup-cloud/done" ] = true) do={ + :if ($I < 4) do={ + :log warning ($ScriptName . ": Retry successful, please discard previous connection errors."); + } + :local Cloud [ /system/backup/cloud/get ([ find ]->0) ]; $SendNotification2 ({ origin=$ScriptName; \ From 0a085e6610aadf546b936076f6e3ae68538b1cfa Mon Sep 17 00:00:00 2001 From: netravnen <1938389+netravnen@users.noreply.github.com> Date: Mon, 10 Jun 2024 10:53:17 +0200 Subject: [PATCH 2228/2612] check-lte-firmware-upgrade: omit once Omit `once` from the `/interface/lte/firmware-upgrade` command to make sure it does acutally return a valid result. --- check-lte-firmware-upgrade.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index 3a25f83..5ea094e 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -44,7 +44,7 @@ :local Firmware; :local Info; :do { - :set Firmware [ /interface/lte/firmware-upgrade $Interface once as-value ]; + :set Firmware [ /interface/lte/firmware-upgrade $Interface as-value ]; :set Info [ /interface/lte/monitor $Interface once as-value ]; } on-error={ $LogPrint debug $ScriptName ("Could not get latest LTE firmware version for interface " . \ From c2dd9de9b1789c81f2a7db14f5dbba87d5881286 Mon Sep 17 00:00:00 2001 From: netravnen <1938389+netravnen@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:13:59 +0200 Subject: [PATCH 2229/2612] unattended-lte-firmware-upgrade: omit once Omit `once` from the `/interface/lte/firmware-upgrade` command to make sure it does acutally return a valid result. Fixes #69 --- unattended-lte-firmware-upgrade.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unattended-lte-firmware-upgrade.rsc b/unattended-lte-firmware-upgrade.rsc index 904f952..ba22c6f 100644 --- a/unattended-lte-firmware-upgrade.rsc +++ b/unattended-lte-firmware-upgrade.rsc @@ -10,7 +10,7 @@ :local Firmware; :local IntName [ /interface/lte/get $Interface name ]; :do { - :set Firmware [ /interface/lte/firmware-upgrade $Interface once as-value ]; + :set Firmware [ /interface/lte/firmware-upgrade $Interface as-value ]; } on-error={ :log debug ("Could not get latest LTE firmware version for interface " . $IntName . "."); } From 9c899f871d672d599564d94911abcabad0ea069b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 10 Jun 2024 18:10:22 +0200 Subject: [PATCH 2230/2612] backup-cloud: remove trailing spaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit How did I produce these!? đŸ˜ŗ --- backup-cloud.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 8f5575e..697ee95 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -69,7 +69,7 @@ :if ($I < 4) do={ :log warning ($ScriptName . ": Retry successful, please discard previous connection errors."); } - + :local Cloud [ /system/backup/cloud/get ([ find ]->0) ]; $SendNotification2 ({ origin=$ScriptName; \ From 2166f262c8aed8b30560e37ea01c458567892a52 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 11 Jun 2024 21:07:17 +0200 Subject: [PATCH 2231/2612] unattended-lte-firmware-upgrade: omit just another once --- unattended-lte-firmware-upgrade.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unattended-lte-firmware-upgrade.rsc b/unattended-lte-firmware-upgrade.rsc index ba22c6f..af2b6e5 100644 --- a/unattended-lte-firmware-upgrade.rsc +++ b/unattended-lte-firmware-upgrade.rsc @@ -28,7 +28,7 @@ /interface/lte/firmware-upgrade $1 upgrade=yes; :log info ("LTE firmware upgrade on '" . $1 . "' finished, waiting for reset."); :delay 240s; - :local Firmware [ /interface/lte/firmware-upgrade $1 once as-value ]; + :local Firmware [ /interface/lte/firmware-upgrade $1 as-value ]; :if (($Firmware->"installed") != ($Firmware->"latest")) do={ :log warning ("LTE firmware versions still differ. Resetting again..."); /interface/lte/at-chat $1 input="AT+RESET"; From 1e1c9be94522a6dfe24440321950c3dd0b2256a8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 11 Jun 2024 21:09:06 +0200 Subject: [PATCH 2232/2612] unattended-lte-firmware-upgrade: drop the AT reset The AT command to reset is specific to modem. So this worked for some only... Let's just drop it, and update the log message. --- unattended-lte-firmware-upgrade.rsc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/unattended-lte-firmware-upgrade.rsc b/unattended-lte-firmware-upgrade.rsc index af2b6e5..a8182e5 100644 --- a/unattended-lte-firmware-upgrade.rsc +++ b/unattended-lte-firmware-upgrade.rsc @@ -30,8 +30,7 @@ :delay 240s; :local Firmware [ /interface/lte/firmware-upgrade $1 as-value ]; :if (($Firmware->"installed") != ($Firmware->"latest")) do={ - :log warning ("LTE firmware versions still differ. Resetting again..."); - /interface/lte/at-chat $1 input="AT+RESET"; + :log warning ("LTE firmware versions still differ. Upgrade failed anyway?"); } } on-error={ :log error ("LTE firmware upgrade on '" . $1 . "' failed."); From d01362dbaa352efccf4d64a5e0404b2d43060cd5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 11 Jun 2024 21:12:46 +0200 Subject: [PATCH 2233/2612] unattended-lte-firmware-upgrade: check on valid version first --- unattended-lte-firmware-upgrade.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/unattended-lte-firmware-upgrade.rsc b/unattended-lte-firmware-upgrade.rsc index a8182e5..7ce4028 100644 --- a/unattended-lte-firmware-upgrade.rsc +++ b/unattended-lte-firmware-upgrade.rsc @@ -29,7 +29,8 @@ :log info ("LTE firmware upgrade on '" . $1 . "' finished, waiting for reset."); :delay 240s; :local Firmware [ /interface/lte/firmware-upgrade $1 as-value ]; - :if (($Firmware->"installed") != ($Firmware->"latest")) do={ + :if ([ :len ($Firmware->"latest") ] > 0 && \ + ($Firmware->"installed") != ($Firmware->"latest")) do={ :log warning ("LTE firmware versions still differ. Upgrade failed anyway?"); } } on-error={ From 76dd069fa653ad9ed8f100f71124fc5027b159df Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 19 Jun 2024 08:56:07 +0200 Subject: [PATCH 2234/2612] Let's Encrypt changed their intermediate certificates https://letsencrypt.org/2024/03/19/new-intermediate-certificates https://letsencrypt.org/certificates/ But let's keep the old ones around for now, as some sites are still using the old intermediate. --- INITIAL-COMMANDS.md | 10 +- README.d/01-download-certs.avif | Bin 4420 -> 4578 bytes README.d/03-check-certs.avif | Bin 12089 -> 12118 bytes README.md | 14 +- certs/E5.pem | 119 ++++++++++++++++ certs/R10.pem | 231 ++++++++++++++++++++++++++++++++ global-config.rsc | 6 +- global-functions.rsc | 2 +- 8 files changed, 366 insertions(+), 16 deletions(-) create mode 100644 certs/E5.pem create mode 100644 certs/R10.pem diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 4a12197..889192d 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -17,13 +17,13 @@ Initial commands Run the complete base installation: { - /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/E1.pem" dst-path="letsencrypt-E1.pem" as-value; + /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/E5.pem" dst-path="letsencrypt-E5.pem" as-value; :delay 1s; - /certificate/import file-name=letsencrypt-E1.pem passphrase=""; - :if ([ :len [ /certificate/find where fingerprint="46494e30379059df18be52124305e606fc59070e5b21076ce113954b60517cda" or fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470" ] ] != 2) do={ + /certificate/import file-name=letsencrypt-E5.pem passphrase=""; + :if ([ :len [ /certificate/find where fingerprint="e788d14b0436b5120bbee3f15c15badf08c1407fe72568a4f16f9151c380e1e3" or fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470" ] ] != 2) do={ :error "Something is wrong with your certificates!"; }; - /file/remove [ find where name="letsencrypt-E1.pem" ]; + /file/remove [ find where name="letsencrypt-E5.pem" ]; :delay 1s; /system/script/set name=("global-config-overlay-" . [ /system/clock/get date ] . "-" . [ /system/clock/get time ]) [ find where name="global-config-overlay" ]; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ @@ -34,7 +34,7 @@ Run the complete base installation: /system/scheduler/remove [ find where name="global-scripts" ]; /system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }"; :global CertificateNameByCN; - $CertificateNameByCN "E1"; + $CertificateNameByCN "E5"; $CertificateNameByCN "ISRG Root X2"; }; diff --git a/README.d/01-download-certs.avif b/README.d/01-download-certs.avif index b27b23b8ca7990d261be1e4b23349de6d493f767..b543aff2848235791b59fc0805e850a748f17a23 100644 GIT binary patch delta 3558 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 delta 3399 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 diff --git a/README.d/03-check-certs.avif b/README.d/03-check-certs.avif index 0477c398b41b439ec6eff03c8bcd2357f2637857..f24c6b567a0696bfd30899f66157ec7c23248212 100644 GIT binary patch delta 10014 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 LW+fw9Oi7tgtG9@| diff --git a/README.md b/README.md index b6e529d..1ad5aca 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ download the certificates. If you intend to download the scripts from a different location (for example from github.com) install the corresponding certificate chain. - /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/E1.pem" dst-path="letsencrypt-E1.pem"; + /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/E5.pem" dst-path="letsencrypt-E5.pem"; ![screenshot: download certs](README.d/01-download-certs.avif) @@ -78,11 +78,11 @@ want to be safe download with your workstations's browser and transfer the files to your MikroTik device. * [ISRG Root X2](https://letsencrypt.org/certs/isrg-root-x2.pem) -* Let's Encrypt [E1](https://letsencrypt.org/certs/lets-encrypt-e1.pem) +* Let's Encrypt [E5](https://letsencrypt.org/certs/2024/e5.pem) Then we import the certificates. - /certificate/import file-name=letsencrypt-E1.pem passphrase=""; + /certificate/import file-name=letsencrypt-E5.pem passphrase=""; Do not worry that the command is not shown - that happens because it contains a sensitive property, the passphrase. @@ -90,13 +90,13 @@ a sensitive property, the passphrase. ![screenshot: import certs](README.d/02-import-certs.avif) For basic verification we rename the certificates and print them by -fingerprint. Make sure exactly these two certificates ("*E1*" and +fingerprint. Make sure exactly these two certificates ("*E5*" and "*ISRG-Root-X2*") are shown. Also remove the left over file. - /certificate/set name="E1" [ find where common-name="E1" ]; + /certificate/set name="E5" [ find where common-name="E5" ]; /certificate/set name="ISRG-Root-X2" [ find where common-name="ISRG Root X2" ]; - /certificate/print proplist=name,fingerprint where fingerprint="46494e30379059df18be52124305e606fc59070e5b21076ce113954b60517cda" or fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470"; - /file/remove [ find where name="letsencrypt-E1.pem" ]; + /certificate/print proplist=name,fingerprint where fingerprint="e788d14b0436b5120bbee3f15c15badf08c1407fe72568a4f16f9151c380e1e3" or fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470"; + /file/remove [ find where name="letsencrypt-E5.pem" ]; ![screenshot: check certs](README.d/03-check-certs.avif) diff --git a/certs/E5.pem b/certs/E5.pem new file mode 100644 index 0000000..3f9e915 --- /dev/null +++ b/certs/E5.pem @@ -0,0 +1,119 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 18:6e:75:d4:ee:b0:a0:5d:fd:2d:a8:20:86:5d:1e:31 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X2 + Validity + Not Before: Mar 13 00:00:00 2024 GMT + Not After : Mar 12 23:59:59 2027 GMT + Subject: C=US, O=Let's Encrypt, CN=E5 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:0d:0b:3a:8a:6b:61:8e:b6:ef:dc:5f:58:e7:c6: + 42:45:54:ab:63:f6:66:61:48:0a:2e:59:75:b4:81: + 02:37:50:b7:3f:16:79:dc:98:ec:a1:28:97:72:20: + 1c:2c:cf:d5:7c:52:20:4e:54:78:5b:84:14:6b:c0: + 90:ae:85:ec:c0:51:41:3c:5a:87:7f:06:4d:d4:fe: + 60:d1:fa:6c:2d:e1:7d:95:10:88:a2:08:54:0f:99: + 1a:4c:e6:ea:0a:ac:d8 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + 9F:2B:5F:CF:3C:21:4F:9D:04:B7:ED:2B:2C:C4:C6:70:8B:D2:D7:0D + X509v3 Authority Key Identifier: + 7C:42:96:AE:DE:4B:48:3B:FA:92:F8:9E:8C:CF:6D:8B:A9:72:37:95 + Authority Information Access: + CA Issuers - URI:http://x2.i.lencr.org/ + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.1 + X509v3 CRL Distribution Points: + Full Name: + URI:http://x2.c.lencr.org/ + Signature Algorithm: ecdsa-with-SHA384 + Signature Value: + 30:64:02:30:1b:6d:2e:45:41:1c:45:3e:d9:5f:34:18:74:67: + 13:79:ba:ab:29:b5:b6:10:4e:83:27:4a:8b:45:4e:c7:7b:cf: + f4:40:30:1d:61:a5:e6:1c:6d:a4:90:09:92:6e:46:4b:02:30: + 46:29:18:84:34:7a:bc:fb:de:d8:1b:d8:19:a7:04:f5:cb:7e: + e7:6d:84:d9:da:8e:ea:ce:36:30:b9:a2:80:4c:2c:e6:60:12: + 4b:a9:76:aa:e8:6d:95:47:da:72:09:0c +-----BEGIN CERTIFICATE----- +MIICtDCCAjugAwIBAgIQGG511O6woF39Lagghl0eMTAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yNDAzMTMwMDAwMDBaFw0y +NzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNy +eXB0MQswCQYDVQQDEwJFNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABA0LOoprYY62 +79xfWOfGQkVUq2P2ZmFICi5ZdbSBAjdQtz8WedyY7KEol3IgHCzP1XxSIE5UeFuE +FGvAkK6F7MBRQTxah38GTdT+YNH6bC3hfZUQiKIIVA+ZGkzm6gqs2KOB+DCB9TAO +BgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIG +A1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJ8rX888IU+dBLftKyzExnCL0tcN +MB8GA1UdIwQYMBaAFHxClq7eS0g7+pL4nozPbYupcjeVMDIGCCsGAQUFBwEBBCYw +JDAiBggrBgEFBQcwAoYWaHR0cDovL3gyLmkubGVuY3Iub3JnLzATBgNVHSAEDDAK +MAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDIuYy5sZW5jci5v +cmcvMAoGCCqGSM49BAMDA2cAMGQCMBttLkVBHEU+2V80GHRnE3m6qym1thBOgydK +i0VOx3vP9EAwHWGl5hxtpJAJkm5GSwIwRikYhDR6vPve2BvYGacE9ct+522E2dqO +6s42MLmigEws5mASS6l2quhtlUfacgkM +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 41:d2:9d:d1:72:ea:ee:a7:80:c1:2c:6c:e9:2f:87:52 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X2 + Validity + Not Before: Sep 4 00:00:00 2020 GMT + Not After : Sep 17 16:00:00 2040 GMT + Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X2 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:cd:9b:d5:9f:80:83:0a:ec:09:4a:f3:16:4a:3e: + 5c:cf:77:ac:de:67:05:0d:1d:07:b6:dc:16:fb:5a: + 8b:14:db:e2:71:60:c4:ba:45:95:11:89:8e:ea:06: + df:f7:2a:16:1c:a4:b9:c5:c5:32:e0:03:e0:1e:82: + 18:38:8b:d7:45:d8:0a:6a:6e:e6:00:77:fb:02:51: + 7d:22:d8:0a:6e:9a:5b:77:df:f0:fa:41:ec:39:dc: + 75:ca:68:07:0c:1f:ea + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 7C:42:96:AE:DE:4B:48:3B:FA:92:F8:9E:8C:CF:6D:8B:A9:72:37:95 + Signature Algorithm: ecdsa-with-SHA384 + 30:65:02:30:7b:79:4e:46:50:84:c2:44:87:46:1b:45:70:ff: + 58:99:de:f4:fd:a4:d2:55:a6:20:2d:74:d6:34:bc:41:a3:50: + 5f:01:27:56:b4:be:27:75:06:af:12:2e:75:98:8d:fc:02:31: + 00:8b:f5:77:6c:d4:c8:65:aa:e0:0b:2c:ee:14:9d:27:37:a4: + f9:53:a5:51:e4:29:83:d7:f8:90:31:5b:42:9f:0a:f5:fe:ae: + 00:68:e7:8c:49:0f:b6:6f:5b:5b:15:f2:e7 +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- diff --git a/certs/R10.pem b/certs/R10.pem new file mode 100644 index 0000000..e8c1c4a --- /dev/null +++ b/certs/R10.pem @@ -0,0 +1,231 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 4b:a8:52:93:f7:9a:2f:a2:73:06:4b:a8:04:8d:75:d0 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1 + Validity + Not Before: Mar 13 00:00:00 2024 GMT + Not After : Mar 12 23:59:59 2027 GMT + Subject: C=US, O=Let's Encrypt, CN=R10 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:cf:57:e5:e6:c4:54:12:ed:b4:47:fe:c9:27:58: + 76:46:50:28:8c:1d:3e:88:df:05:9d:d5:b5:18:29: + bd:dd:b5:5a:bf:fa:f6:ce:a3:be:af:00:21:4b:62: + 5a:5a:3c:01:2f:c5:58:03:f6:89:ff:8e:11:43:eb: + c1:b5:e0:14:07:96:8f:6f:1f:d7:e7:ba:81:39:09: + 75:65:b7:c2:af:18:5b:37:26:28:e7:a3:f4:07:2b: + 6d:1a:ff:ab:58:bc:95:ae:40:ff:e9:cb:57:c4:b5: + 5b:7f:78:0d:18:61:bc:17:e7:54:c6:bb:49:91:cd: + 6e:18:d1:80:85:ee:a6:65:36:bc:74:ea:bc:50:4c: + ea:fc:21:f3:38:16:93:94:ba:b0:d3:6b:38:06:cd: + 16:12:7a:ca:52:75:c8:ad:76:b2:c2:9c:5d:98:45: + 5c:6f:61:7b:c6:2d:ee:3c:13:52:86:01:d9:57:e6: + 38:1c:df:8d:b5:1f:92:91:9a:e7:4a:1c:cc:45:a8: + 72:55:f0:b0:e6:a3:07:ec:fd:a7:1b:66:9e:3f:48: + 8b:71:84:71:58:c9:3a:fa:ef:5e:f2:5b:44:2b:3c: + 74:e7:8f:b2:47:c1:07:6a:cd:9a:b7:0d:96:f7:12: + 81:26:51:54:0a:ec:61:f6:f7:f5:e2:f2:8a:c8:95: + 0d:8d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + BB:BC:C3:47:A5:E4:BC:A9:C6:C3:A4:72:0C:10:8D:A2:35:E1:C8:E8 + X509v3 Authority Key Identifier: + 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E + Authority Information Access: + CA Issuers - URI:http://x1.i.lencr.org/ + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.1 + X509v3 CRL Distribution Points: + Full Name: + URI:http://x1.c.lencr.org/ + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 92:b1:e7:41:37:eb:79:9d:81:e6:cd:e2:25:e1:3a:20:e9:90: + 44:95:a3:81:5c:cf:c3:5d:fd:bd:a0:70:d5:b1:96:28:22:0b: + d2:f2:28:cf:0c:e7:d4:e6:43:8c:24:22:1d:c1:42:92:d1:09: + af:9f:4b:f4:c8:70:4f:20:16:b1:5a:dd:01:f6:1f:f8:1f:61: + 6b:14:27:b0:72:8d:63:ae:ee:e2:ce:4b:cf:37:dd:bb:a3:d4: + cd:e7:ad:50:ad:bd:bf:e3:ec:3e:62:36:70:99:31:a7:e8:8d: + dd:ea:62:e2:12:ae:f5:9c:d4:3d:2c:0c:aa:d0:9c:79:be:ea: + 3d:5c:44:6e:96:31:63:5a:7d:d6:7e:4f:24:a0:4b:05:7f:5e: + 6f:d2:d4:ea:5f:33:4b:13:d6:57:b6:ca:de:51:b8:5d:a3:09: + 82:74:fd:c7:78:9e:b3:b9:ac:16:da:4a:2b:96:c3:b6:8b:62: + 8f:f9:74:19:a2:9e:03:de:e9:6f:9b:b0:0f:d2:a0:5a:f6:85: + 5c:c2:04:b7:c8:d5:4e:32:c4:bf:04:5d:bc:29:f6:f7:81:8f: + 0c:5d:3c:53:c9:40:90:8b:fb:b6:08:65:b9:a4:21:d5:09:e5: + 13:84:84:37:82:ce:10:28:fc:76:c2:06:25:7a:46:52:4d:da: + 53:72:a4:27:3f:62:70:ac:be:69:48:00:fb:67:0f:db:5b:a1: + e8:d7:03:21:2d:d7:c9:f6:99:42:39:83:43:df:77:0a:12:08: + f1:25:d6:ba:94:19:54:18:88:a5:c5:8e:e1:1a:99:93:79:6b: + ec:1c:f9:31:40:b0:cc:32:00:df:9f:5e:e7:b4:92:ab:90:82: + 91:8d:0d:e0:1e:95:ba:59:3b:2e:4b:5f:c2:b7:46:35:52:39: + 06:c0:bd:aa:ac:52:c1:22:a0:44:97:99:f7:0c:a0:21:a7:a1: + 6c:71:47:16:17:01:68:c0:ca:a6:26:65:04:7c:b3:ae:c9:e7: + 94:55:c2:6f:9b:3c:1c:a9:f9:2e:c5:20:1a:f0:76:e0:be:ec: + 18:d6:4f:d8:25:fb:76:11:e8:bf:e6:21:0f:e8:e8:cc:b5:b6: + a7:d5:b8:f7:9f:41:cf:61:22:46:6a:83:b6:68:97:2e:7c:ea: + 4e:95:db:23:eb:2e:c8:2b:28:84:a4:60:e9:49:f4:44:2e:3b: + f9:ca:62:57:01:e2:5d:90:16:f9:c9:fc:7a:23:48:8e:a6:d5: + 81:72:f1:28:fa:5d:ce:fb:ed:4e:73:8f:94:2e:d2:41:94:98: + 99:db:a7:af:70:5f:f5:be:fb:02:20:bf:66:27:6c:b4:ad:fa: + 75:12:0b:2b:3e:ce:03:9e +-----BEGIN CERTIFICATE----- +MIIFBTCCAu2gAwIBAgIQS6hSk/eaL6JzBkuoBI110DANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy +Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa +Fw0yNzAzMTIyMzU5NTlaMDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF +bmNyeXB0MQwwCgYDVQQDEwNSMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQDPV+XmxFQS7bRH/sknWHZGUCiMHT6I3wWd1bUYKb3dtVq/+vbOo76vACFL +YlpaPAEvxVgD9on/jhFD68G14BQHlo9vH9fnuoE5CXVlt8KvGFs3Jijno/QHK20a +/6tYvJWuQP/py1fEtVt/eA0YYbwX51TGu0mRzW4Y0YCF7qZlNrx06rxQTOr8IfM4 +FpOUurDTazgGzRYSespSdcitdrLCnF2YRVxvYXvGLe48E1KGAdlX5jgc3421H5KR +mudKHMxFqHJV8LDmowfs/acbZp4/SItxhHFYyTr6717yW0QrPHTnj7JHwQdqzZq3 +DZb3EoEmUVQK7GH29/Xi8orIlQ2NAgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgGG +MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/ +AgEAMB0GA1UdDgQWBBS7vMNHpeS8qcbDpHIMEI2iNeHI6DAfBgNVHSMEGDAWgBR5 +tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAKG +Fmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0gBAwwCjAIBgZngQwBAgEwJwYD +VR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVuY3Iub3JnLzANBgkqhkiG9w0B +AQsFAAOCAgEAkrHnQTfreZ2B5s3iJeE6IOmQRJWjgVzPw139vaBw1bGWKCIL0vIo +zwzn1OZDjCQiHcFCktEJr59L9MhwTyAWsVrdAfYf+B9haxQnsHKNY67u4s5Lzzfd +u6PUzeetUK29v+PsPmI2cJkxp+iN3epi4hKu9ZzUPSwMqtCceb7qPVxEbpYxY1p9 +1n5PJKBLBX9eb9LU6l8zSxPWV7bK3lG4XaMJgnT9x3ies7msFtpKK5bDtotij/l0 +GaKeA97pb5uwD9KgWvaFXMIEt8jVTjLEvwRdvCn294GPDF08U8lAkIv7tghluaQh +1QnlE4SEN4LOECj8dsIGJXpGUk3aU3KkJz9icKy+aUgA+2cP21uh6NcDIS3XyfaZ +QjmDQ993ChII8SXWupQZVBiIpcWO4RqZk3lr7Bz5MUCwzDIA359e57SSq5CCkY0N +4B6Vulk7LktfwrdGNVI5BsC9qqxSwSKgRJeZ9wygIaehbHFHFhcBaMDKpiZlBHyz +rsnnlFXCb5s8HKn5LsUgGvB24L7sGNZP2CX7dhHov+YhD+jozLW2p9W4959Bz2Ei +RmqDtmiXLnzqTpXbI+suyCsohKRg6Un0RC47+cpiVwHiXZAW+cn8eiNIjqbVgXLx +KPpdzvvtTnOPlC7SQZSYmdunr3Bf9b77AiC/ZidstK36dRILKz7OA54= +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 82:10:cf:b0:d2:40:e3:59:44:63:e0:bb:63:82:8b:00 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 + Validity + Not Before: Jun 4 11:04:38 2015 GMT + Not After : Jun 4 11:04:38 2035 GMT + Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:ad:e8:24:73:f4:14:37:f3:9b:9e:2b:57:28:1c: + 87:be:dc:b7:df:38:90:8c:6e:3c:e6:57:a0:78:f7: + 75:c2:a2:fe:f5:6a:6e:f6:00:4f:28:db:de:68:86: + 6c:44:93:b6:b1:63:fd:14:12:6b:bf:1f:d2:ea:31: + 9b:21:7e:d1:33:3c:ba:48:f5:dd:79:df:b3:b8:ff: + 12:f1:21:9a:4b:c1:8a:86:71:69:4a:66:66:6c:8f: + 7e:3c:70:bf:ad:29:22:06:f3:e4:c0:e6:80:ae:e2: + 4b:8f:b7:99:7e:94:03:9f:d3:47:97:7c:99:48:23: + 53:e8:38:ae:4f:0a:6f:83:2e:d1:49:57:8c:80:74: + b6:da:2f:d0:38:8d:7b:03:70:21:1b:75:f2:30:3c: + fa:8f:ae:dd:da:63:ab:eb:16:4f:c2:8e:11:4b:7e: + cf:0b:e8:ff:b5:77:2e:f4:b2:7b:4a:e0:4c:12:25: + 0c:70:8d:03:29:a0:e1:53:24:ec:13:d9:ee:19:bf: + 10:b3:4a:8c:3f:89:a3:61:51:de:ac:87:07:94:f4: + 63:71:ec:2e:e2:6f:5b:98:81:e1:89:5c:34:79:6c: + 76:ef:3b:90:62:79:e6:db:a4:9a:2f:26:c5:d0:10: + e1:0e:de:d9:10:8e:16:fb:b7:f7:a8:f7:c7:e5:02: + 07:98:8f:36:08:95:e7:e2:37:96:0d:36:75:9e:fb: + 0e:72:b1:1d:9b:bc:03:f9:49:05:d8:81:dd:05:b4: + 2a:d6:41:e9:ac:01:76:95:0a:0f:d8:df:d5:bd:12: + 1f:35:2f:28:17:6c:d2:98:c1:a8:09:64:77:6e:47: + 37:ba:ce:ac:59:5e:68:9d:7f:72:d6:89:c5:06:41: + 29:3e:59:3e:dd:26:f5:24:c9:11:a7:5a:a3:4c:40: + 1f:46:a1:99:b5:a7:3a:51:6e:86:3b:9e:7d:72:a7: + 12:05:78:59:ed:3e:51:78:15:0b:03:8f:8d:d0:2f: + 05:b2:3e:7b:4a:1c:4b:73:05:12:fc:c6:ea:e0:50: + 13:7c:43:93:74:b3:ca:74:e7:8e:1f:01:08:d0:30: + d4:5b:71:36:b4:07:ba:c1:30:30:5c:48:b7:82:3b: + 98:a6:7d:60:8a:a2:a3:29:82:cc:ba:bd:83:04:1b: + a2:83:03:41:a1:d6:05:f1:1b:c2:b6:f0:a8:7c:86: + 3b:46:a8:48:2a:88:dc:76:9a:76:bf:1f:6a:a5:3d: + 19:8f:eb:38:f3:64:de:c8:2b:0d:0a:28:ff:f7:db: + e2:15:42:d4:22:d0:27:5d:e1:79:fe:18:e7:70:88: + ad:4e:e6:d9:8b:3a:c6:dd:27:51:6e:ff:bc:64:f5: + 33:43:4f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E + Signature Algorithm: sha256WithRSAEncryption + 55:1f:58:a9:bc:b2:a8:50:d0:0c:b1:d8:1a:69:20:27:29:08: + ac:61:75:5c:8a:6e:f8:82:e5:69:2f:d5:f6:56:4b:b9:b8:73: + 10:59:d3:21:97:7e:e7:4c:71:fb:b2:d2:60:ad:39:a8:0b:ea: + 17:21:56:85:f1:50:0e:59:eb:ce:e0:59:e9:ba:c9:15:ef:86: + 9d:8f:84:80:f6:e4:e9:91:90:dc:17:9b:62:1b:45:f0:66:95: + d2:7c:6f:c2:ea:3b:ef:1f:cf:cb:d6:ae:27:f1:a9:b0:c8:ae: + fd:7d:7e:9a:fa:22:04:eb:ff:d9:7f:ea:91:2b:22:b1:17:0e: + 8f:f2:8a:34:5b:58:d8:fc:01:c9:54:b9:b8:26:cc:8a:88:33: + 89:4c:2d:84:3c:82:df:ee:96:57:05:ba:2c:bb:f7:c4:b7:c7: + 4e:3b:82:be:31:c8:22:73:73:92:d1:c2:80:a4:39:39:10:33: + 23:82:4c:3c:9f:86:b2:55:98:1d:be:29:86:8c:22:9b:9e:e2: + 6b:3b:57:3a:82:70:4d:dc:09:c7:89:cb:0a:07:4d:6c:e8:5d: + 8e:c9:ef:ce:ab:c7:bb:b5:2b:4e:45:d6:4a:d0:26:cc:e5:72: + ca:08:6a:a5:95:e3:15:a1:f7:a4:ed:c9:2c:5f:a5:fb:ff:ac: + 28:02:2e:be:d7:7b:bb:e3:71:7b:90:16:d3:07:5e:46:53:7c: + 37:07:42:8c:d3:c4:96:9c:d5:99:b5:2a:e0:95:1a:80:48:ae: + 4c:39:07:ce:cc:47:a4:52:95:2b:ba:b8:fb:ad:d2:33:53:7d: + e5:1d:4d:6d:d5:a1:b1:c7:42:6f:e6:40:27:35:5c:a3:28:b7: + 07:8d:e7:8d:33:90:e7:23:9f:fb:50:9c:79:6c:46:d5:b4:15: + b3:96:6e:7e:9b:0c:96:3a:b8:52:2d:3f:d6:5b:e1:fb:08:c2: + 84:fe:24:a8:a3:89:da:ac:6a:e1:18:2a:b1:a8:43:61:5b:d3: + 1f:dc:3b:8d:76:f2:2d:e8:8d:75:df:17:33:6c:3d:53:fb:7b: + cb:41:5f:ff:dc:a2:d0:61:38:e1:96:b8:ac:5d:8b:37:d7:75: + d5:33:c0:99:11:ae:9d:41:c1:72:75:84:be:02:41:42:5f:67: + 24:48:94:d1:9b:27:be:07:3f:b9:b8:4f:81:74:51:e1:7a:b7: + ed:9d:23:e2:be:e0:d5:28:04:13:3c:31:03:9e:dd:7a:6c:8f: + c6:07:18:c6:7f:de:47:8e:3f:28:9e:04:06:cf:a5:54:34:77: + bd:ec:89:9b:e9:17:43:df:5b:db:5f:fe:8e:1e:57:a2:cd:40: + 9d:7e:62:22:da:de:18:27 +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- diff --git a/global-config.rsc b/global-config.rsc index 8a42b81..a0835f8 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -92,11 +92,11 @@ :global FwAddrLists { # "allow"={ # { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/allow"; -# cert="E1"; timeout=1w }; +# cert="E5"; timeout=1w }; # }; "block"={ # { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/block"; -# cert="E1" }; +# cert="E5" }; { url="https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt"; cert="GlobalSign Atlas R3 DV TLS CA 2022 Q3" }; { url="https://sslbl.abuse.ch/blacklist/sslipblacklist.txt"; @@ -112,7 +112,7 @@ }; # "mikrotik"={ # { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/mikrotik"; -# cert="E1"; timeout=1w }; +# cert="E5"; timeout=1w }; # }; }; :global FwAddrListTimeOut 1d; diff --git a/global-functions.rsc b/global-functions.rsc index 447d6e9..eb700ef 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -999,7 +999,7 @@ :global SymbolForNotification; :global ValidateSyntax; - :if ([ $CertificateAvailable "E1" ] = false) do={ + :if ([ $CertificateAvailable "E5" ] = false) do={ $LogPrint warning $0 ("Downloading certificate failed, trying without."); } From 35f4ec0b1d1d8c26ec9293efe2d9091993d7bf89 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jun 2024 10:42:36 +0200 Subject: [PATCH 2235/2612] doc/mod/notification-matrix: drop certificate hint... ... as matrix.org switched to Let's Encrypt with ISRG Root X2. --- doc/mod/notification-matrix.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index 92383be..18b6607 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -46,9 +46,6 @@ The Matrix server is connected via encrypted https, and certificate verification is applied. So make sure you have the certificate chain for your server in device's certificate store. -> â„šī¸ **Info**: The *matrix.org* server uses a Cloudflare certificate. You can -> install that with: `$CertificateAvailable "Cloudflare Inc ECC CA-3"` - ### From other device If you have setup your Matrix *notification account* before just reuse that. From d1693a241b0ec444d7ad469681e4ba81c1b398df Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jun 2024 09:50:39 +0200 Subject: [PATCH 2236/2612] certs: E1 / E5 -> ISRG Root X2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the beginning of Let's Encrypt their root certificate ISRG Root X1 was not widely trusted, at least some older and/or mobile platforms were missing that certificate in their root certificate store. At that time Let's Encrypt was using an alternative chain of trust, where a certificate was cross-signed with DST Root CA X3. To make sure a valid chain of trust is available under all circumstances a set of all certificates had to be supplied: both root vertificates ISRG Root X1 & DST Root CA X3, and an intermediate certificate. This was still true after DST Root CA X3 expired, as it could still be used as a root anchor and was shipped by Let's Encrypt when requested. đŸ¤Ē This time is finally over, and we have a clean chain for trust ending in ISRG Root X1 (or ISRG Root X2). Well, actually it is the other way round... Let's Encrypt signs with different tantamount intermediate certificates. There is not only E5, but also E6 - and we can not know beforehand which one is used on renew. So let's jetzt drop the intermediate certificates now, and rely on root certificates only. We are perfectly fine with this these days. Follow-up commits will do the same for *all* certificates. The certificate is downloaded with: curl -d '["ISRG Root X2"]' https://mkcert.org/generate/ | grep -v '^$' > certs/ISRG-Root-X2.pem --- INITIAL-COMMANDS.md | 9 ++- README.d/01-download-certs.avif | Bin 4578 -> 4596 bytes README.d/02-import-certs.avif | Bin 3606 -> 3605 bytes README.d/03-check-certs.avif | Bin 12118 -> 8932 bytes README.md | 20 +++--- certs/E1.pem | 124 -------------------------------- certs/E5.pem | 119 ------------------------------ certs/ISRG-Root-X2.pem | 21 ++++++ global-config.rsc | 6 +- global-functions.rsc | 2 +- 10 files changed, 38 insertions(+), 263 deletions(-) delete mode 100644 certs/E1.pem delete mode 100644 certs/E5.pem create mode 100644 certs/ISRG-Root-X2.pem diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 889192d..b3eff35 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -17,13 +17,13 @@ Initial commands Run the complete base installation: { - /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/E5.pem" dst-path="letsencrypt-E5.pem" as-value; + /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/ISRG-Root-X2.pem" dst-path="ISRG-Root-X2.pem" as-value; :delay 1s; - /certificate/import file-name=letsencrypt-E5.pem passphrase=""; - :if ([ :len [ /certificate/find where fingerprint="e788d14b0436b5120bbee3f15c15badf08c1407fe72568a4f16f9151c380e1e3" or fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470" ] ] != 2) do={ + /certificate/import file-name=ISRG-Root-X2.pem passphrase=""; + :if ([ :len [ /certificate/find where fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470" ] ] != 1) do={ :error "Something is wrong with your certificates!"; }; - /file/remove [ find where name="letsencrypt-E5.pem" ]; + /file/remove [ find where name="ISRG-Root-X2.pem" ]; :delay 1s; /system/script/set name=("global-config-overlay-" . [ /system/clock/get date ] . "-" . [ /system/clock/get time ]) [ find where name="global-config-overlay" ]; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ @@ -34,7 +34,6 @@ Run the complete base installation: /system/scheduler/remove [ find where name="global-scripts" ]; /system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }"; :global CertificateNameByCN; - $CertificateNameByCN "E5"; $CertificateNameByCN "ISRG Root X2"; }; diff --git a/README.d/01-download-certs.avif b/README.d/01-download-certs.avif index b543aff2848235791b59fc0805e850a748f17a23..4a074eb59dce96fbf79c0b50dfdf028f7eff9d4f 100644 GIT binary patch delta 2976 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 delta 2958 zcma))_dnDR1HkVPSrI4uQk+r9xU%<%E{-_k&dkop$clW7lyzniI%i9q%#4#0&dL`V z*_5+6<3U#PeE)&x^?F{f_xq>!ukQolMd8#iPF@g*z7IqL0)fE)f&qaT+tQMI!6_M* z;7BmMZW0_$1MFYlI?VQVg$m$$>k~}YxWC;>t&mkQX7sL{e44vLE12j_C5)^AWU&v1 z0{%~B-@VT(ihfRsmI+y@&gw#UV0wI7UM})(z`eh}ZAsB8bBLjoj-%>MK-?s)hgo`scMwFul|`+246j>0 zvh$FsiV>d_$rj@7;lES(}y zbX`?=w%}8Kav>tF&8qYM{w1JIe)M=I8RvPIUnNIeWTyE&e7*iGjqVhg3){%Pksw!h zU9tjj@)Wl-~Nfd63c5x}0m4scZuz9CII$)*|i z_qYEMw*?u;*QL*W1HxL&0wNMKx{*~L>41$j{L#nh)NTJVjo?q~y_D%jpL*a*Xu7eg zz9=hyOLsNZp37v50_tr;<7}XQMZ&Tn#ygEz>Zu%ltq)pM+7qR$3jb-|W$Huo=WAblBTbJ+2PN;H z_0-S=aoW0C`YlY-_ZA6QxHZtdd0OZ z_GMHISCXS|kTwv3#uKr{ENl;k#y?fM`9a^hdP_ZE-D{pltfuoUQFth7719YtVojs& z6M1I{-*AFz!Bn;LD)a(m|J+#tZSLDK^w`cX{n)8dNl}eQY?LcY&uz=e)AoF8^|aO7 zlk_F$(SmhM+x(DoJE#gt8!6wI8ulZsIoQq1CE1u>q8`=Fq{6S~PrhH6v3%K@cB4`t zLyOT7ptcGHu02C!*RM&g#QMDFaSmc@EsUwZQzQ8IZ7xIdr>!j?FZFNNrkGwm-sa&l zH*OwMw;CGzA;70zCXMy0(4oy`_Mkz?_|nw0)AA1OU76cdj>&t#&VrWD@`Xy~_|6sF@JGtR1U&0W!y3MOmr_M1Is@dLB|_ zW!SYD8V{Z$_8T_?45O2#dY16d%^3xTZEjqEwn_^7ldNESkG#!+EG9W8yE(;f`5hA+ z`mp$OYJUmgU8^1HD?$w3jr$o_D$_$0b=>PO!oPq zN4R0=7}cu5A-v38G#c(mc>IQbAVT(y)g^b;kH%aj{>_#0zYdhAIv~W^F$gb~n_%}~ zfS#3B>_KtoR0L|3Nv>6lZUEkaI{=uIK7anGDO+zYK`{WU%~eO4ckNp4XW4|I{f|P~CLIVduXW z8+_;V=zya{L{hKJ>>Qd}J0vPRFyB2Q^H7&2G-I0>L<5J~Tv`?314U+|iSl0hcw_x>?tlJ9=i9VZJ73;ddNB}ytMxL&lpDQUd1@4zy4tC8WOqT@JdiSXS;V$;KR zNjf|fJj0_h*PGJ=o)CTPrM-HZoW~BtJt_yvn~A(>`_`~u?8h8crx%f?s$0LG#F6SH z-o5iHYEkl!AKv$t4odOYrPmgPTsy3p#Q)59smW$SN+#SddFt)@^oOsynTM9UC1NS|6D8 zi%!TtNKLK$hmvd|5un5`Du%PhOkX2D?@ZAC!?!^FM&N%kMKt3=EY_d>kkF2Jd)Z8n zRX@6(8UqLD1|6-sxpe#E6-tib!8?4;14gP=SEI|Og4whn#g}%IJ%Fr0ByIj=2gXw3 zb@#f`#jwFy3+Xl1_#$qCexZhR1bj#zVHS%@oC@(BIKVfSxzk0~gw+w2gGcV275`$( zvbZ2IWTj5hNSP$NZC55dyS0oKFCo=F1Vj#|M{?z=0-piPFa`WckAGP2te?XU7+1z zxDxa{PKV=UII6M+ZF`)DDL>UUJV)kbsn{r-*)!znl|oWQ_);|AC)?lFf-Ly^GDyZ& z>Iz|Ag9di0SQxtf^xtkUh4)@LOTgqHS!$hH__D=X`NL#{-y+Uj5tXg)WZ!b3#E>gm zu&8{4($q1DjRNkAM8}3rAhU;lmQ5CaXl;5jn?3xb-AQD+?jd<3l15lJiMhq4X3I{I zcI#Le+uJbg#lhCaz$=2j)Bh{N1y=FPprpzt%8XWxb#$GctHCFopF}6#`-BkBc5C}9 zbaAG2wp9Dap|QV7uk$Yt7#}pw3u8_LUvsp&L8Zw@VbOMk@&;$0uogSs0cyG>;6ZW=`;yY1w;?VVr z#f&y2ciPkZ6Ioyf)A}&*>)iII1?76#@%Cd;RMWZC*t)LDv(4J8b*OiVn2l48#d2EK zWlp^|q;`~m2PdbO8)lo|NqiaJKjs@2^G89W^r@cL&4Pf$mTWC4L)cD>z~3~2lTZSZ zW-xzHO?Yjw=-?AgKReH-d7y#{ z4VsL0R5QtLy1{-ebrpUyMoBbM<=ZA`1`GF)F1*(DL3_Ju$a?LoP@4kPOK5FL5;5Wr@3X@y%9#G?3v8Y5c8cj>lQuf zh{=xYCl#GWSMQ}A>=nicJW7FQj{aC6i5e)Ve4ojE}vyApEJv0gE37G74H<&d-QVsE04}S(pz-Woa5! zyQ)mX)#Pt0vD0NcEu@@Qna`eP-aLX$Hzv}QXJRJ~NCGW|Gz9R|YS1w?qfA;Tg)I|K zwEHfAyp$fNN{3SjG3WX9kD_+nU3nG?ROi{#m-SW`rqr~bORQrgQ zbZex3`X(Rtsm&^UiWF5`8}l0;pPiU0qfFb&SN2abaU4#j^;IwIx`i* zUa3OoU@I$L7bfNz$5=<*`-v1*m`8Uw>p8=@7#H@!Kl&cV=CTnD!qB+UML4DyLUH5_4H_3Dw{$(h1 z!eZ^t^D$c;(ueo*qKNWxFidy5y2rXyj8WVk9`;LE{R8KU!7NUWzqM4}EvV)D))=12 zJ^)H~DDJ-HYZXWlTrSx-n^DR0&n0Q-y&>+N@!{}dR2GEqrUl-2opD1OZVt#f2_3T> zGx1XdK$D#19s|X@(tiu|^BNH4v+IuA_EwDq6>?(Fl-*8J99FJ>*t2QS$-2S3C0-V? zHv(H*isi{TD$?dF>xPwVF<<6BzvDga<^%?5DyOpzpHQT%5rtIApL9|@#Xvz0wQKI5 zfdvIng?bGav9EpegC1J0m6RU7hic1GB~UI2+GpDQ?49yS&rW1%VZBiJ&3zy#JoLK! zAiBbG3Drr0j~jQHeXQ%&?>#~(9T=`OI7?EWme4MVwq+kcBLHI3UtoUwH?#`sn!pKB z-k-e{$gtiHKgZ~gSJZhLHho;93FqJEheD~xCOLreLG-(v)#1{Eoi5H(R�R1WN5% zg-tJ%wPX*GuD@b+3_&3F=D-hV{b&G`{ZV;95^SikZitbU?F~VVRM&x1gelrAyjUKY zn_F8i(`<8UlU`Ix zCa~VK8~U70|EGhk9s!M@h{J?Cg2nm;3=3vgnzn0f9b?QJ4&LNcKGyRnJ3(lEmJpy_ zUTmiPV#jYTnhi^)?6Hxp44pJu$GJM4;v(y$B2}9e&yBFFYodEaJsnPBLWGY v6AxLT2LpoCn6B^KE^+4-CCMJ+U$KG$VAX*k6%!x5arK#GJ@R8$|JKfbcmJgf delta 1460 zcma*c|3A|S0LSr)YHb_>7oup<^(wsn7WgBg}wPIho;=Wl3P z2i*F_t9Y)+-un#}dM(zgKJ^TuD3M!n`Y{R-F?qn_k3aWoc^aVhqv&7-O+?6a5xt8; z9^8~Qmu@BPgT2)tmceCaC2eVyE69y1u(maJg$dV{l6kj}5a+jm=S)ySZ z)PFPQCTvg;GG&5(5H{Eo-Ua!wlS!y@m*=>D> zRkV^S{3Ug-J)hjtwqQrM8Eq=o^cp2DqSo9Vrc`PpSL9G`iu!33b_E0@2Ao$dn}gz<7Iq5P~d$jWWU^fhXs(_s`aJ`%5(7L?PUF7x24l9yzY6a=|1RXuzG6+hN8lo+wRj z2E);N5{(=?#A{tC!!TXarbx}^))Lr>SZv#xC>~To4rTU(06A#&r3mdqz)=KAWw?Ui zdX;gWwU`dh;6h}nP+#@LZkpW<%t<{D5-FAHlM_D=%=j%6w*Fy7jEvmE#FP*2TQ~H6 zst>sfVhYP$tEWdaTL~RUoBtox|B8x- zFBl3ldjq$g1rFJEv(0>^(&Q+H@O1FeWSg@t>iG#2fPN8PXPnFvk~^eV&gy)OO9HwZ zQUXvV_qe5W%kp&9&)k56J{qQ4HUkR(KoLBI#nm}c8n|cdo0TN13bhNcJ0eV)`6E;S z71t6oz*4>zAR9}I+%TThxN*uV}rv=-V;J` z`qUAS+WW?09`ywUiI7Ph^x>B<*G%1le(Q-TNVg1Nu;ALTOz3_Pv6x+$XzlQNKDq3e z?Xb&Nq=1X21wxVLKFQ}u6-#l-Lg?TORhm2+5LjH%uB*?I0g)-W33}e2__8P;Hdua2 zUo2LkReU+9XaB^Uaml*TlY`9nheKbgeM^%*VfM?`ou$Z}fZDk8SmvKuHma#UC8kkr zp(~Y3v{|cSq~)0wMyQ9BeDj>AQ#~ML+o11+Yq`gRSWH7-jm5;5|^Xs?wv)JXHotpBwBnbbTxnJ2uOizp0VhE$6M#{MC()R2qC@F z4UnLb3*y*bC#rx&ciq9aJux295$MsHZ+b5hVo4-Cwo$$5kqfam@9M$qOW1bYzxvXq AY5)KL diff --git a/README.d/03-check-certs.avif b/README.d/03-check-certs.avif index f24c6b567a0696bfd30899f66157ec7c23248212..46b7220f1df02c8379e95113aeb13bf91859de0f 100644 GIT binary patch delta 7712 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 a&VeHE+7Y9`eJGj|@?~PMWFSj}fDV{(%j#DE delta 10923 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 Date: Thu, 20 Jun 2024 09:52:17 +0200 Subject: [PATCH 2237/2612] certs: R3 / R10 -> ISRG Root X1 --- certs/ISRG-Root-X1.pem | 38 ++++++ certs/R10.pem | 231 ------------------------------------- certs/R3.pem | 237 -------------------------------------- global-config.rsc | 2 +- global-functions.rsc | 2 +- mod/notification-ntfy.rsc | 2 +- 6 files changed, 41 insertions(+), 471 deletions(-) create mode 100644 certs/ISRG-Root-X1.pem delete mode 100644 certs/R10.pem delete mode 100644 certs/R3.pem diff --git a/certs/ISRG-Root-X1.pem b/certs/ISRG-Root-X1.pem new file mode 100644 index 0000000..995c95d --- /dev/null +++ b/certs/ISRG-Root-X1.pem @@ -0,0 +1,38 @@ +# Issuer: CN=ISRG Root X1 O=Internet Security Research Group +# Subject: CN=ISRG Root X1 O=Internet Security Research Group +# Label: "ISRG Root X1" +# Serial: 172886928669790476064670243504169061120 +# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e +# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 +# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- diff --git a/certs/R10.pem b/certs/R10.pem deleted file mode 100644 index e8c1c4a..0000000 --- a/certs/R10.pem +++ /dev/null @@ -1,231 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 4b:a8:52:93:f7:9a:2f:a2:73:06:4b:a8:04:8d:75:d0 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1 - Validity - Not Before: Mar 13 00:00:00 2024 GMT - Not After : Mar 12 23:59:59 2027 GMT - Subject: C=US, O=Let's Encrypt, CN=R10 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:cf:57:e5:e6:c4:54:12:ed:b4:47:fe:c9:27:58: - 76:46:50:28:8c:1d:3e:88:df:05:9d:d5:b5:18:29: - bd:dd:b5:5a:bf:fa:f6:ce:a3:be:af:00:21:4b:62: - 5a:5a:3c:01:2f:c5:58:03:f6:89:ff:8e:11:43:eb: - c1:b5:e0:14:07:96:8f:6f:1f:d7:e7:ba:81:39:09: - 75:65:b7:c2:af:18:5b:37:26:28:e7:a3:f4:07:2b: - 6d:1a:ff:ab:58:bc:95:ae:40:ff:e9:cb:57:c4:b5: - 5b:7f:78:0d:18:61:bc:17:e7:54:c6:bb:49:91:cd: - 6e:18:d1:80:85:ee:a6:65:36:bc:74:ea:bc:50:4c: - ea:fc:21:f3:38:16:93:94:ba:b0:d3:6b:38:06:cd: - 16:12:7a:ca:52:75:c8:ad:76:b2:c2:9c:5d:98:45: - 5c:6f:61:7b:c6:2d:ee:3c:13:52:86:01:d9:57:e6: - 38:1c:df:8d:b5:1f:92:91:9a:e7:4a:1c:cc:45:a8: - 72:55:f0:b0:e6:a3:07:ec:fd:a7:1b:66:9e:3f:48: - 8b:71:84:71:58:c9:3a:fa:ef:5e:f2:5b:44:2b:3c: - 74:e7:8f:b2:47:c1:07:6a:cd:9a:b7:0d:96:f7:12: - 81:26:51:54:0a:ec:61:f6:f7:f5:e2:f2:8a:c8:95: - 0d:8d - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Client Authentication, TLS Web Server Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - BB:BC:C3:47:A5:E4:BC:A9:C6:C3:A4:72:0C:10:8D:A2:35:E1:C8:E8 - X509v3 Authority Key Identifier: - 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E - Authority Information Access: - CA Issuers - URI:http://x1.i.lencr.org/ - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - X509v3 CRL Distribution Points: - Full Name: - URI:http://x1.c.lencr.org/ - Signature Algorithm: sha256WithRSAEncryption - Signature Value: - 92:b1:e7:41:37:eb:79:9d:81:e6:cd:e2:25:e1:3a:20:e9:90: - 44:95:a3:81:5c:cf:c3:5d:fd:bd:a0:70:d5:b1:96:28:22:0b: - d2:f2:28:cf:0c:e7:d4:e6:43:8c:24:22:1d:c1:42:92:d1:09: - af:9f:4b:f4:c8:70:4f:20:16:b1:5a:dd:01:f6:1f:f8:1f:61: - 6b:14:27:b0:72:8d:63:ae:ee:e2:ce:4b:cf:37:dd:bb:a3:d4: - cd:e7:ad:50:ad:bd:bf:e3:ec:3e:62:36:70:99:31:a7:e8:8d: - dd:ea:62:e2:12:ae:f5:9c:d4:3d:2c:0c:aa:d0:9c:79:be:ea: - 3d:5c:44:6e:96:31:63:5a:7d:d6:7e:4f:24:a0:4b:05:7f:5e: - 6f:d2:d4:ea:5f:33:4b:13:d6:57:b6:ca:de:51:b8:5d:a3:09: - 82:74:fd:c7:78:9e:b3:b9:ac:16:da:4a:2b:96:c3:b6:8b:62: - 8f:f9:74:19:a2:9e:03:de:e9:6f:9b:b0:0f:d2:a0:5a:f6:85: - 5c:c2:04:b7:c8:d5:4e:32:c4:bf:04:5d:bc:29:f6:f7:81:8f: - 0c:5d:3c:53:c9:40:90:8b:fb:b6:08:65:b9:a4:21:d5:09:e5: - 13:84:84:37:82:ce:10:28:fc:76:c2:06:25:7a:46:52:4d:da: - 53:72:a4:27:3f:62:70:ac:be:69:48:00:fb:67:0f:db:5b:a1: - e8:d7:03:21:2d:d7:c9:f6:99:42:39:83:43:df:77:0a:12:08: - f1:25:d6:ba:94:19:54:18:88:a5:c5:8e:e1:1a:99:93:79:6b: - ec:1c:f9:31:40:b0:cc:32:00:df:9f:5e:e7:b4:92:ab:90:82: - 91:8d:0d:e0:1e:95:ba:59:3b:2e:4b:5f:c2:b7:46:35:52:39: - 06:c0:bd:aa:ac:52:c1:22:a0:44:97:99:f7:0c:a0:21:a7:a1: - 6c:71:47:16:17:01:68:c0:ca:a6:26:65:04:7c:b3:ae:c9:e7: - 94:55:c2:6f:9b:3c:1c:a9:f9:2e:c5:20:1a:f0:76:e0:be:ec: - 18:d6:4f:d8:25:fb:76:11:e8:bf:e6:21:0f:e8:e8:cc:b5:b6: - a7:d5:b8:f7:9f:41:cf:61:22:46:6a:83:b6:68:97:2e:7c:ea: - 4e:95:db:23:eb:2e:c8:2b:28:84:a4:60:e9:49:f4:44:2e:3b: - f9:ca:62:57:01:e2:5d:90:16:f9:c9:fc:7a:23:48:8e:a6:d5: - 81:72:f1:28:fa:5d:ce:fb:ed:4e:73:8f:94:2e:d2:41:94:98: - 99:db:a7:af:70:5f:f5:be:fb:02:20:bf:66:27:6c:b4:ad:fa: - 75:12:0b:2b:3e:ce:03:9e ------BEGIN CERTIFICATE----- -MIIFBTCCAu2gAwIBAgIQS6hSk/eaL6JzBkuoBI110DANBgkqhkiG9w0BAQsFADBP -MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy -Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa -Fw0yNzAzMTIyMzU5NTlaMDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF -bmNyeXB0MQwwCgYDVQQDEwNSMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQDPV+XmxFQS7bRH/sknWHZGUCiMHT6I3wWd1bUYKb3dtVq/+vbOo76vACFL -YlpaPAEvxVgD9on/jhFD68G14BQHlo9vH9fnuoE5CXVlt8KvGFs3Jijno/QHK20a -/6tYvJWuQP/py1fEtVt/eA0YYbwX51TGu0mRzW4Y0YCF7qZlNrx06rxQTOr8IfM4 -FpOUurDTazgGzRYSespSdcitdrLCnF2YRVxvYXvGLe48E1KGAdlX5jgc3421H5KR -mudKHMxFqHJV8LDmowfs/acbZp4/SItxhHFYyTr6717yW0QrPHTnj7JHwQdqzZq3 -DZb3EoEmUVQK7GH29/Xi8orIlQ2NAgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgGG -MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/ -AgEAMB0GA1UdDgQWBBS7vMNHpeS8qcbDpHIMEI2iNeHI6DAfBgNVHSMEGDAWgBR5 -tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAKG -Fmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0gBAwwCjAIBgZngQwBAgEwJwYD -VR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVuY3Iub3JnLzANBgkqhkiG9w0B -AQsFAAOCAgEAkrHnQTfreZ2B5s3iJeE6IOmQRJWjgVzPw139vaBw1bGWKCIL0vIo -zwzn1OZDjCQiHcFCktEJr59L9MhwTyAWsVrdAfYf+B9haxQnsHKNY67u4s5Lzzfd -u6PUzeetUK29v+PsPmI2cJkxp+iN3epi4hKu9ZzUPSwMqtCceb7qPVxEbpYxY1p9 -1n5PJKBLBX9eb9LU6l8zSxPWV7bK3lG4XaMJgnT9x3ies7msFtpKK5bDtotij/l0 -GaKeA97pb5uwD9KgWvaFXMIEt8jVTjLEvwRdvCn294GPDF08U8lAkIv7tghluaQh -1QnlE4SEN4LOECj8dsIGJXpGUk3aU3KkJz9icKy+aUgA+2cP21uh6NcDIS3XyfaZ -QjmDQ993ChII8SXWupQZVBiIpcWO4RqZk3lr7Bz5MUCwzDIA359e57SSq5CCkY0N -4B6Vulk7LktfwrdGNVI5BsC9qqxSwSKgRJeZ9wygIaehbHFHFhcBaMDKpiZlBHyz -rsnnlFXCb5s8HKn5LsUgGvB24L7sGNZP2CX7dhHov+YhD+jozLW2p9W4959Bz2Ei -RmqDtmiXLnzqTpXbI+suyCsohKRg6Un0RC47+cpiVwHiXZAW+cn8eiNIjqbVgXLx -KPpdzvvtTnOPlC7SQZSYmdunr3Bf9b77AiC/ZidstK36dRILKz7OA54= ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 82:10:cf:b0:d2:40:e3:59:44:63:e0:bb:63:82:8b:00 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 - Validity - Not Before: Jun 4 11:04:38 2015 GMT - Not After : Jun 4 11:04:38 2035 GMT - Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (4096 bit) - Modulus: - 00:ad:e8:24:73:f4:14:37:f3:9b:9e:2b:57:28:1c: - 87:be:dc:b7:df:38:90:8c:6e:3c:e6:57:a0:78:f7: - 75:c2:a2:fe:f5:6a:6e:f6:00:4f:28:db:de:68:86: - 6c:44:93:b6:b1:63:fd:14:12:6b:bf:1f:d2:ea:31: - 9b:21:7e:d1:33:3c:ba:48:f5:dd:79:df:b3:b8:ff: - 12:f1:21:9a:4b:c1:8a:86:71:69:4a:66:66:6c:8f: - 7e:3c:70:bf:ad:29:22:06:f3:e4:c0:e6:80:ae:e2: - 4b:8f:b7:99:7e:94:03:9f:d3:47:97:7c:99:48:23: - 53:e8:38:ae:4f:0a:6f:83:2e:d1:49:57:8c:80:74: - b6:da:2f:d0:38:8d:7b:03:70:21:1b:75:f2:30:3c: - fa:8f:ae:dd:da:63:ab:eb:16:4f:c2:8e:11:4b:7e: - cf:0b:e8:ff:b5:77:2e:f4:b2:7b:4a:e0:4c:12:25: - 0c:70:8d:03:29:a0:e1:53:24:ec:13:d9:ee:19:bf: - 10:b3:4a:8c:3f:89:a3:61:51:de:ac:87:07:94:f4: - 63:71:ec:2e:e2:6f:5b:98:81:e1:89:5c:34:79:6c: - 76:ef:3b:90:62:79:e6:db:a4:9a:2f:26:c5:d0:10: - e1:0e:de:d9:10:8e:16:fb:b7:f7:a8:f7:c7:e5:02: - 07:98:8f:36:08:95:e7:e2:37:96:0d:36:75:9e:fb: - 0e:72:b1:1d:9b:bc:03:f9:49:05:d8:81:dd:05:b4: - 2a:d6:41:e9:ac:01:76:95:0a:0f:d8:df:d5:bd:12: - 1f:35:2f:28:17:6c:d2:98:c1:a8:09:64:77:6e:47: - 37:ba:ce:ac:59:5e:68:9d:7f:72:d6:89:c5:06:41: - 29:3e:59:3e:dd:26:f5:24:c9:11:a7:5a:a3:4c:40: - 1f:46:a1:99:b5:a7:3a:51:6e:86:3b:9e:7d:72:a7: - 12:05:78:59:ed:3e:51:78:15:0b:03:8f:8d:d0:2f: - 05:b2:3e:7b:4a:1c:4b:73:05:12:fc:c6:ea:e0:50: - 13:7c:43:93:74:b3:ca:74:e7:8e:1f:01:08:d0:30: - d4:5b:71:36:b4:07:ba:c1:30:30:5c:48:b7:82:3b: - 98:a6:7d:60:8a:a2:a3:29:82:cc:ba:bd:83:04:1b: - a2:83:03:41:a1:d6:05:f1:1b:c2:b6:f0:a8:7c:86: - 3b:46:a8:48:2a:88:dc:76:9a:76:bf:1f:6a:a5:3d: - 19:8f:eb:38:f3:64:de:c8:2b:0d:0a:28:ff:f7:db: - e2:15:42:d4:22:d0:27:5d:e1:79:fe:18:e7:70:88: - ad:4e:e6:d9:8b:3a:c6:dd:27:51:6e:ff:bc:64:f5: - 33:43:4f - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E - Signature Algorithm: sha256WithRSAEncryption - 55:1f:58:a9:bc:b2:a8:50:d0:0c:b1:d8:1a:69:20:27:29:08: - ac:61:75:5c:8a:6e:f8:82:e5:69:2f:d5:f6:56:4b:b9:b8:73: - 10:59:d3:21:97:7e:e7:4c:71:fb:b2:d2:60:ad:39:a8:0b:ea: - 17:21:56:85:f1:50:0e:59:eb:ce:e0:59:e9:ba:c9:15:ef:86: - 9d:8f:84:80:f6:e4:e9:91:90:dc:17:9b:62:1b:45:f0:66:95: - d2:7c:6f:c2:ea:3b:ef:1f:cf:cb:d6:ae:27:f1:a9:b0:c8:ae: - fd:7d:7e:9a:fa:22:04:eb:ff:d9:7f:ea:91:2b:22:b1:17:0e: - 8f:f2:8a:34:5b:58:d8:fc:01:c9:54:b9:b8:26:cc:8a:88:33: - 89:4c:2d:84:3c:82:df:ee:96:57:05:ba:2c:bb:f7:c4:b7:c7: - 4e:3b:82:be:31:c8:22:73:73:92:d1:c2:80:a4:39:39:10:33: - 23:82:4c:3c:9f:86:b2:55:98:1d:be:29:86:8c:22:9b:9e:e2: - 6b:3b:57:3a:82:70:4d:dc:09:c7:89:cb:0a:07:4d:6c:e8:5d: - 8e:c9:ef:ce:ab:c7:bb:b5:2b:4e:45:d6:4a:d0:26:cc:e5:72: - ca:08:6a:a5:95:e3:15:a1:f7:a4:ed:c9:2c:5f:a5:fb:ff:ac: - 28:02:2e:be:d7:7b:bb:e3:71:7b:90:16:d3:07:5e:46:53:7c: - 37:07:42:8c:d3:c4:96:9c:d5:99:b5:2a:e0:95:1a:80:48:ae: - 4c:39:07:ce:cc:47:a4:52:95:2b:ba:b8:fb:ad:d2:33:53:7d: - e5:1d:4d:6d:d5:a1:b1:c7:42:6f:e6:40:27:35:5c:a3:28:b7: - 07:8d:e7:8d:33:90:e7:23:9f:fb:50:9c:79:6c:46:d5:b4:15: - b3:96:6e:7e:9b:0c:96:3a:b8:52:2d:3f:d6:5b:e1:fb:08:c2: - 84:fe:24:a8:a3:89:da:ac:6a:e1:18:2a:b1:a8:43:61:5b:d3: - 1f:dc:3b:8d:76:f2:2d:e8:8d:75:df:17:33:6c:3d:53:fb:7b: - cb:41:5f:ff:dc:a2:d0:61:38:e1:96:b8:ac:5d:8b:37:d7:75: - d5:33:c0:99:11:ae:9d:41:c1:72:75:84:be:02:41:42:5f:67: - 24:48:94:d1:9b:27:be:07:3f:b9:b8:4f:81:74:51:e1:7a:b7: - ed:9d:23:e2:be:e0:d5:28:04:13:3c:31:03:9e:dd:7a:6c:8f: - c6:07:18:c6:7f:de:47:8e:3f:28:9e:04:06:cf:a5:54:34:77: - bd:ec:89:9b:e9:17:43:df:5b:db:5f:fe:8e:1e:57:a2:cd:40: - 9d:7e:62:22:da:de:18:27 ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- diff --git a/certs/R3.pem b/certs/R3.pem deleted file mode 100644 index 837b709..0000000 --- a/certs/R3.pem +++ /dev/null @@ -1,237 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 91:2b:08:4a:cf:0c:18:a7:53:f6:d6:2e:25:a7:5f:5a - Signature Algorithm: sha256WithRSAEncryption - Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 - Validity - Not Before: Sep 4 00:00:00 2020 GMT - Not After : Sep 15 16:00:00 2025 GMT - Subject: C = US, O = Let's Encrypt, CN = R3 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:bb:02:15:28:cc:f6:a0:94:d3:0f:12:ec:8d:55: - 92:c3:f8:82:f1:99:a6:7a:42:88:a7:5d:26:aa:b5: - 2b:b9:c5:4c:b1:af:8e:6b:f9:75:c8:a3:d7:0f:47: - 94:14:55:35:57:8c:9e:a8:a2:39:19:f5:82:3c:42: - a9:4e:6e:f5:3b:c3:2e:db:8d:c0:b0:5c:f3:59:38: - e7:ed:cf:69:f0:5a:0b:1b:be:c0:94:24:25:87:fa: - 37:71:b3:13:e7:1c:ac:e1:9b:ef:db:e4:3b:45:52: - 45:96:a9:c1:53:ce:34:c8:52:ee:b5:ae:ed:8f:de: - 60:70:e2:a5:54:ab:b6:6d:0e:97:a5:40:34:6b:2b: - d3:bc:66:eb:66:34:7c:fa:6b:8b:8f:57:29:99:f8: - 30:17:5d:ba:72:6f:fb:81:c5:ad:d2:86:58:3d:17: - c7:e7:09:bb:f1:2b:f7:86:dc:c1:da:71:5d:d4:46: - e3:cc:ad:25:c1:88:bc:60:67:75:66:b3:f1:18:f7: - a2:5c:e6:53:ff:3a:88:b6:47:a5:ff:13:18:ea:98: - 09:77:3f:9d:53:f9:cf:01:e5:f5:a6:70:17:14:af: - 63:a4:ff:99:b3:93:9d:dc:53:a7:06:fe:48:85:1d: - a1:69:ae:25:75:bb:13:cc:52:03:f5:ed:51:a1:8b: - db:15 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Client Authentication, TLS Web Server Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - 14:2E:B3:17:B7:58:56:CB:AE:50:09:40:E6:1F:AF:9D:8B:14:C2:C6 - X509v3 Authority Key Identifier: - keyid:79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E - - Authority Information Access: - CA Issuers - URI:http://x1.i.lencr.org/ - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://x1.c.lencr.org/ - - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - Policy: 1.3.6.1.4.1.44947.1.1.1 - - Signature Algorithm: sha256WithRSAEncryption - 85:ca:4e:47:3e:a3:f7:85:44:85:bc:d5:67:78:b2:98:63:ad: - 75:4d:1e:96:3d:33:65:72:54:2d:81:a0:ea:c3:ed:f8:20:bf: - 5f:cc:b7:70:00:b7:6e:3b:f6:5e:94:de:e4:20:9f:a6:ef:8b: - b2:03:e7:a2:b5:16:3c:91:ce:b4:ed:39:02:e7:7c:25:8a:47: - e6:65:6e:3f:46:f4:d9:f0:ce:94:2b:ee:54:ce:12:bc:8c:27: - 4b:b8:c1:98:2f:a2:af:cd:71:91:4a:08:b7:c8:b8:23:7b:04: - 2d:08:f9:08:57:3e:83:d9:04:33:0a:47:21:78:09:82:27:c3: - 2a:c8:9b:b9:ce:5c:f2:64:c8:c0:be:79:c0:4f:8e:6d:44:0c: - 5e:92:bb:2e:f7:8b:10:e1:e8:1d:44:29:db:59:20:ed:63:b9: - 21:f8:12:26:94:93:57:a0:1d:65:04:c1:0a:22:ae:10:0d:43: - 97:a1:18:1f:7e:e0:e0:86:37:b5:5a:b1:bd:30:bf:87:6e:2b: - 2a:ff:21:4e:1b:05:c3:f5:18:97:f0:5e:ac:c3:a5:b8:6a:f0: - 2e:bc:3b:33:b9:ee:4b:de:cc:fc:e4:af:84:0b:86:3f:c0:55: - 43:36:f6:68:e1:36:17:6a:8e:99:d1:ff:a5:40:a7:34:b7:c0: - d0:63:39:35:39:75:6e:f2:ba:76:c8:93:02:e9:a9:4b:6c:17: - ce:0c:02:d9:bd:81:fb:9f:b7:68:d4:06:65:b3:82:3d:77:53: - f8:8e:79:03:ad:0a:31:07:75:2a:43:d8:55:97:72:c4:29:0e: - f7:c4:5d:4e:c8:ae:46:84:30:d7:f2:85:5f:18:a1:79:bb:e7: - 5e:70:8b:07:e1:86:93:c3:b9:8f:dc:61:71:25:2a:af:df:ed: - 25:50:52:68:8b:92:dc:e5:d6:b5:e3:da:7d:d0:87:6c:84:21: - 31:ae:82:f5:fb:b9:ab:c8:89:17:3d:e1:4c:e5:38:0e:f6:bd: - 2b:bd:96:81:14:eb:d5:db:3d:20:a7:7e:59:d3:e2:f8:58:f9: - 5b:b8:48:cd:fe:5c:4f:16:29:fe:1e:55:23:af:c8:11:b0:8d: - ea:7c:93:90:17:2f:fd:ac:a2:09:47:46:3f:f0:e9:b0:b7:ff: - 28:4d:68:32:d6:67:5e:1e:69:a3:93:b8:f5:9d:8b:2f:0b:d2: - 52:43:a6:6f:32:57:65:4d:32:81:df:38:53:85:5d:7e:5d:66: - 29:ea:b8:dd:e4:95:b5:cd:b5:56:12:42:cd:c4:4e:c6:25:38: - 44:50:6d:ec:ce:00:55:18:fe:e9:49:64:d4:4e:ca:97:9c:b4: - 5b:c0:73:a8:ab:b8:47:c2 ------BEGIN CERTIFICATE----- -MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw -WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg -RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP -R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx -sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm -NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg -Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG -/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC -AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB -Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA -FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw -AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw -Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB -gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W -PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl -ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz -CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm -lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 -avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 -yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O -yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids -hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ -HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv -MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX -nLRbwHOoq7hHwg== ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 82:10:cf:b0:d2:40:e3:59:44:63:e0:bb:63:82:8b:00 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 - Validity - Not Before: Jun 4 11:04:38 2015 GMT - Not After : Jun 4 11:04:38 2035 GMT - Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (4096 bit) - Modulus: - 00:ad:e8:24:73:f4:14:37:f3:9b:9e:2b:57:28:1c: - 87:be:dc:b7:df:38:90:8c:6e:3c:e6:57:a0:78:f7: - 75:c2:a2:fe:f5:6a:6e:f6:00:4f:28:db:de:68:86: - 6c:44:93:b6:b1:63:fd:14:12:6b:bf:1f:d2:ea:31: - 9b:21:7e:d1:33:3c:ba:48:f5:dd:79:df:b3:b8:ff: - 12:f1:21:9a:4b:c1:8a:86:71:69:4a:66:66:6c:8f: - 7e:3c:70:bf:ad:29:22:06:f3:e4:c0:e6:80:ae:e2: - 4b:8f:b7:99:7e:94:03:9f:d3:47:97:7c:99:48:23: - 53:e8:38:ae:4f:0a:6f:83:2e:d1:49:57:8c:80:74: - b6:da:2f:d0:38:8d:7b:03:70:21:1b:75:f2:30:3c: - fa:8f:ae:dd:da:63:ab:eb:16:4f:c2:8e:11:4b:7e: - cf:0b:e8:ff:b5:77:2e:f4:b2:7b:4a:e0:4c:12:25: - 0c:70:8d:03:29:a0:e1:53:24:ec:13:d9:ee:19:bf: - 10:b3:4a:8c:3f:89:a3:61:51:de:ac:87:07:94:f4: - 63:71:ec:2e:e2:6f:5b:98:81:e1:89:5c:34:79:6c: - 76:ef:3b:90:62:79:e6:db:a4:9a:2f:26:c5:d0:10: - e1:0e:de:d9:10:8e:16:fb:b7:f7:a8:f7:c7:e5:02: - 07:98:8f:36:08:95:e7:e2:37:96:0d:36:75:9e:fb: - 0e:72:b1:1d:9b:bc:03:f9:49:05:d8:81:dd:05:b4: - 2a:d6:41:e9:ac:01:76:95:0a:0f:d8:df:d5:bd:12: - 1f:35:2f:28:17:6c:d2:98:c1:a8:09:64:77:6e:47: - 37:ba:ce:ac:59:5e:68:9d:7f:72:d6:89:c5:06:41: - 29:3e:59:3e:dd:26:f5:24:c9:11:a7:5a:a3:4c:40: - 1f:46:a1:99:b5:a7:3a:51:6e:86:3b:9e:7d:72:a7: - 12:05:78:59:ed:3e:51:78:15:0b:03:8f:8d:d0:2f: - 05:b2:3e:7b:4a:1c:4b:73:05:12:fc:c6:ea:e0:50: - 13:7c:43:93:74:b3:ca:74:e7:8e:1f:01:08:d0:30: - d4:5b:71:36:b4:07:ba:c1:30:30:5c:48:b7:82:3b: - 98:a6:7d:60:8a:a2:a3:29:82:cc:ba:bd:83:04:1b: - a2:83:03:41:a1:d6:05:f1:1b:c2:b6:f0:a8:7c:86: - 3b:46:a8:48:2a:88:dc:76:9a:76:bf:1f:6a:a5:3d: - 19:8f:eb:38:f3:64:de:c8:2b:0d:0a:28:ff:f7:db: - e2:15:42:d4:22:d0:27:5d:e1:79:fe:18:e7:70:88: - ad:4e:e6:d9:8b:3a:c6:dd:27:51:6e:ff:bc:64:f5: - 33:43:4f - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E - Signature Algorithm: sha256WithRSAEncryption - 55:1f:58:a9:bc:b2:a8:50:d0:0c:b1:d8:1a:69:20:27:29:08: - ac:61:75:5c:8a:6e:f8:82:e5:69:2f:d5:f6:56:4b:b9:b8:73: - 10:59:d3:21:97:7e:e7:4c:71:fb:b2:d2:60:ad:39:a8:0b:ea: - 17:21:56:85:f1:50:0e:59:eb:ce:e0:59:e9:ba:c9:15:ef:86: - 9d:8f:84:80:f6:e4:e9:91:90:dc:17:9b:62:1b:45:f0:66:95: - d2:7c:6f:c2:ea:3b:ef:1f:cf:cb:d6:ae:27:f1:a9:b0:c8:ae: - fd:7d:7e:9a:fa:22:04:eb:ff:d9:7f:ea:91:2b:22:b1:17:0e: - 8f:f2:8a:34:5b:58:d8:fc:01:c9:54:b9:b8:26:cc:8a:88:33: - 89:4c:2d:84:3c:82:df:ee:96:57:05:ba:2c:bb:f7:c4:b7:c7: - 4e:3b:82:be:31:c8:22:73:73:92:d1:c2:80:a4:39:39:10:33: - 23:82:4c:3c:9f:86:b2:55:98:1d:be:29:86:8c:22:9b:9e:e2: - 6b:3b:57:3a:82:70:4d:dc:09:c7:89:cb:0a:07:4d:6c:e8:5d: - 8e:c9:ef:ce:ab:c7:bb:b5:2b:4e:45:d6:4a:d0:26:cc:e5:72: - ca:08:6a:a5:95:e3:15:a1:f7:a4:ed:c9:2c:5f:a5:fb:ff:ac: - 28:02:2e:be:d7:7b:bb:e3:71:7b:90:16:d3:07:5e:46:53:7c: - 37:07:42:8c:d3:c4:96:9c:d5:99:b5:2a:e0:95:1a:80:48:ae: - 4c:39:07:ce:cc:47:a4:52:95:2b:ba:b8:fb:ad:d2:33:53:7d: - e5:1d:4d:6d:d5:a1:b1:c7:42:6f:e6:40:27:35:5c:a3:28:b7: - 07:8d:e7:8d:33:90:e7:23:9f:fb:50:9c:79:6c:46:d5:b4:15: - b3:96:6e:7e:9b:0c:96:3a:b8:52:2d:3f:d6:5b:e1:fb:08:c2: - 84:fe:24:a8:a3:89:da:ac:6a:e1:18:2a:b1:a8:43:61:5b:d3: - 1f:dc:3b:8d:76:f2:2d:e8:8d:75:df:17:33:6c:3d:53:fb:7b: - cb:41:5f:ff:dc:a2:d0:61:38:e1:96:b8:ac:5d:8b:37:d7:75: - d5:33:c0:99:11:ae:9d:41:c1:72:75:84:be:02:41:42:5f:67: - 24:48:94:d1:9b:27:be:07:3f:b9:b8:4f:81:74:51:e1:7a:b7: - ed:9d:23:e2:be:e0:d5:28:04:13:3c:31:03:9e:dd:7a:6c:8f: - c6:07:18:c6:7f:de:47:8e:3f:28:9e:04:06:cf:a5:54:34:77: - bd:ec:89:9b:e9:17:43:df:5b:db:5f:fe:8e:1e:57:a2:cd:40: - 9d:7e:62:22:da:de:18:27 ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- diff --git a/global-config.rsc b/global-config.rsc index 734b51e..f99fdf1 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -102,7 +102,7 @@ { url="https://sslbl.abuse.ch/blacklist/sslipblacklist.txt"; cert="GlobalSign Atlas R3 DV TLS CA 2022 Q3" }; { url="https://www.dshield.org/block.txt"; cidr="/24"; - cert="R3" }; + cert="ISRG Root X1" }; { url="https://lists.blocklist.de/lists/strongips.txt"; cert="Certum Domain Validation CA SHA2" }; # { url="https://www.spamhaus.org/drop/drop.txt"; diff --git a/global-functions.rsc b/global-functions.rsc index 6c5ce02..567444e 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -334,7 +334,7 @@ :return true; } - :if ([ $CertificateAvailable "R3" ] = false) do={ + :if ([ $CertificateAvailable "ISRG Root X1" ] = false) do={ $LogPrint error $0 ("Downloading required certificate failed."); :return false; } diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index 4413f07..cdc10e7 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -98,7 +98,7 @@ :do { :if ($NtfyServer = "ntfy.sh") do={ - :if ([ $CertificateAvailable "R3" ] = false) do={ + :if ([ $CertificateAvailable "ISRG Root X1" ] = false) do={ $LogPrint warning $0 ("Downloading required certificate failed."); :error false; } From b875d64724a8ac3218b2e0779effe19c1729e11a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jun 2024 10:25:53 +0200 Subject: [PATCH 2238/2612] certs: GlobalSign Atlas R3 DV TLS CA 2022 Q3 -> GlobalSign --- .../GlobalSign-Atlas-R3-DV-TLS-CA-2022-Q3.pem | 177 ------------------ certs/GlobalSign.pem | 28 +++ global-config.rsc | 4 +- 3 files changed, 30 insertions(+), 179 deletions(-) delete mode 100644 certs/GlobalSign-Atlas-R3-DV-TLS-CA-2022-Q3.pem create mode 100644 certs/GlobalSign.pem diff --git a/certs/GlobalSign-Atlas-R3-DV-TLS-CA-2022-Q3.pem b/certs/GlobalSign-Atlas-R3-DV-TLS-CA-2022-Q3.pem deleted file mode 100644 index b514c11..0000000 --- a/certs/GlobalSign-Atlas-R3-DV-TLS-CA-2022-Q3.pem +++ /dev/null @@ -1,177 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 7c:2a:0c:21:3f:c6:55:53:45:c9:1f:19:1f:b8:4e:fa - Signature Algorithm: sha256WithRSAEncryption - Issuer: OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign - Validity - Not Before: Apr 20 12:00:00 2022 GMT - Not After : Apr 20 00:00:00 2025 GMT - Subject: C = BE, O = GlobalSign nv-sa, CN = GlobalSign Atlas R3 DV TLS CA 2022 Q3 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:b8:a8:7a:66:3c:4e:66:9c:ce:37:a5:54:35:4d: - 36:c7:99:d3:a8:27:36:f2:2f:c6:d5:18:3e:e9:09: - dd:05:d6:d7:2c:34:32:7c:08:63:49:d1:10:37:e5: - 78:5d:11:62:ce:6d:fb:2f:3f:37:94:db:8f:7b:30: - e9:5e:2c:d9:55:3f:b2:db:b9:a0:b5:60:37:8b:a4: - 06:32:35:50:a4:09:af:0a:45:ff:a8:1f:9b:65:8e: - dd:4a:e0:40:a1:e3:63:37:58:90:dd:75:3b:fc:0e: - 1c:82:40:98:bd:70:b1:c1:48:14:14:3c:04:4b:69: - dd:d4:9c:01:a6:e9:21:e3:82:0a:fe:e4:aa:bf:34: - a0:8c:cb:c9:79:6e:3e:5c:6a:52:9e:c4:ed:2b:c5: - 69:fe:50:3c:93:9d:b5:ff:2d:28:a8:6c:06:6c:9d: - c5:af:b2:59:fb:59:77:0d:74:7a:88:84:a4:d4:1d: - d4:ba:20:06:cc:b5:1e:48:4e:74:21:15:86:75:c0: - cc:5a:d1:05:cf:57:16:7a:13:17:ec:c2:4a:ae:d5: - 1e:72:aa:22:5a:8c:9c:82:32:c4:10:e6:42:6e:21: - 86:68:7c:80:23:30:35:d3:bd:b0:5e:0a:29:2b:f0: - 14:b1:18:37:d9:59:25:c3:e7:38:d9:e9:d4:2d:36: - 35:65 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - FA:91:39:63:9A:FB:AD:10:24:E5:BE:B5:B9:DA:AB:D9:C4:46:69:AB - X509v3 Authority Key Identifier: - 8F:F0:4B:7F:A8:2E:45:24:AE:4D:50:FA:63:9A:8B:DE:E2:DD:1B:BC - Authority Information Access: - OCSP - URI:http://ocsp2.globalsign.com/rootr3 - CA Issuers - URI:http://secure.globalsign.com/cacert/root-r3.crt - X509v3 CRL Distribution Points: - Full Name: - URI:http://crl.globalsign.com/root-r3.crl - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - Policy: 1.3.6.1.4.1.4146.10.1.3 - Signature Algorithm: sha256WithRSAEncryption - Signature Value: - 14:33:2c:79:e5:3f:82:c6:70:3f:da:59:38:a7:bb:a2:76:ac: - 61:18:05:68:57:d9:0d:fb:8a:46:bc:f1:a8:e8:0c:70:02:1d: - c6:2f:97:ed:36:3e:9e:52:86:2f:5c:62:d8:d5:47:43:9a:73: - d1:2b:25:87:9f:44:b4:14:eb:26:bc:21:47:74:20:bd:9f:a4: - bf:b3:80:1d:4d:35:7d:cd:b9:b5:da:55:f2:90:50:c8:b2:17: - 4e:0e:b4:61:88:29:5f:44:5d:03:7f:57:91:81:d0:eb:30:ae: - d5:2a:ec:82:20:ce:4e:d2:b0:8b:95:02:61:73:d8:69:34:f4: - ad:63:0e:5c:e4:20:1f:a9:7d:ed:8e:e5:1c:04:bb:22:9f:c7: - a9:22:ca:99:3d:02:a7:67:e8:06:2d:fa:04:6b:bb:49:d2:6c: - 99:57:63:6c:2d:c2:61:78:e1:20:b1:fb:f6:bf:e1:82:39:39: - 3c:7b:ef:7d:1a:95:4a:b2:72:da:55:90:ae:ed:dd:e2:70:90: - 7c:1a:ee:b5:32:5a:5d:cf:d6:fa:45:f2:9e:01:0c:31:2f:89: - 84:fe:31:60:0f:fd:ee:a6:5b:84:d5:c7:18:e6:a4:f9:40:30: - 29:18:1e:fe:fc:41:b5:b9:29:05:75:8b:62:1a:5b:22:2e:bf: - e4:59:6c:b0 ------BEGIN CERTIFICATE----- -MIIEjzCCA3egAwIBAgIQfCoMIT/GVVNFyR8ZH7hO+jANBgkqhkiG9w0BAQsFADBM -MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv -YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMjA0MjAxMjAwMDBaFw0y -NTA0MjAwMDAwMDBaMFgxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu -IG52LXNhMS4wLAYDVQQDEyVHbG9iYWxTaWduIEF0bGFzIFIzIERWIFRMUyBDQSAy -MDIyIFEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKh6ZjxOZpzO -N6VUNU02x5nTqCc28i/G1Rg+6QndBdbXLDQyfAhjSdEQN+V4XRFizm37Lz83lNuP -ezDpXizZVT+y27mgtWA3i6QGMjVQpAmvCkX/qB+bZY7dSuBAoeNjN1iQ3XU7/A4c -gkCYvXCxwUgUFDwES2nd1JwBpukh44IK/uSqvzSgjMvJeW4+XGpSnsTtK8Vp/lA8 -k521/y0oqGwGbJ3Fr7JZ+1l3DXR6iISk1B3UuiAGzLUeSE50IRWGdcDMWtEFz1cW -ehMX7MJKrtUecqoiWoycgjLEEOZCbiGGaHyAIzA1072wXgopK/AUsRg32Vklw+c4 -2enULTY1ZQIDAQABo4IBXzCCAVswDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG -CCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW -BBT6kTljmvutECTlvrW52qvZxEZpqzAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpj -move4t0bvDB7BggrBgEFBQcBAQRvMG0wLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3Nw -Mi5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1 -cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0w -K6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwIQYD -VR0gBBowGDAIBgZngQwBAgEwDAYKKwYBBAGgMgoBAzANBgkqhkiG9w0BAQsFAAOC -AQEAFDMseeU/gsZwP9pZOKe7onasYRgFaFfZDfuKRrzxqOgMcAIdxi+X7TY+nlKG -L1xi2NVHQ5pz0Sslh59EtBTrJrwhR3QgvZ+kv7OAHU01fc25tdpV8pBQyLIXTg60 -YYgpX0RdA39XkYHQ6zCu1SrsgiDOTtKwi5UCYXPYaTT0rWMOXOQgH6l97Y7lHAS7 -Ip/HqSLKmT0Cp2foBi36BGu7SdJsmVdjbC3CYXjhILH79r/hgjk5PHvvfRqVSrJy -2lWQru3d4nCQfBrutTJaXc/W+kXyngEMMS+JhP4xYA/97qZbhNXHGOak+UAwKRge -/vxBtbkpBXWLYhpbIi6/5FlssA== ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 04:00:00:00:00:01:21:58:53:08:a2 - Signature Algorithm: sha256WithRSAEncryption - Issuer: OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign - Validity - Not Before: Mar 18 10:00:00 2009 GMT - Not After : Mar 18 10:00:00 2029 GMT - Subject: OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:cc:25:76:90:79:06:78:22:16:f5:c0:83:b6:84: - ca:28:9e:fd:05:76:11:c5:ad:88:72:fc:46:02:43: - c7:b2:8a:9d:04:5f:24:cb:2e:4b:e1:60:82:46:e1: - 52:ab:0c:81:47:70:6c:dd:64:d1:eb:f5:2c:a3:0f: - 82:3d:0c:2b:ae:97:d7:b6:14:86:10:79:bb:3b:13: - 80:77:8c:08:e1:49:d2:6a:62:2f:1f:5e:fa:96:68: - df:89:27:95:38:9f:06:d7:3e:c9:cb:26:59:0d:73: - de:b0:c8:e9:26:0e:83:15:c6:ef:5b:8b:d2:04:60: - ca:49:a6:28:f6:69:3b:f6:cb:c8:28:91:e5:9d:8a: - 61:57:37:ac:74:14:dc:74:e0:3a:ee:72:2f:2e:9c: - fb:d0:bb:bf:f5:3d:00:e1:06:33:e8:82:2b:ae:53: - a6:3a:16:73:8c:dd:41:0e:20:3a:c0:b4:a7:a1:e9: - b2:4f:90:2e:32:60:e9:57:cb:b9:04:92:68:68:e5: - 38:26:60:75:b2:9f:77:ff:91:14:ef:ae:20:49:fc: - ad:40:15:48:d1:02:31:61:19:5e:b8:97:ef:ad:77: - b7:64:9a:7a:bf:5f:c1:13:ef:9b:62:fb:0d:6c:e0: - 54:69:16:a9:03:da:6e:e9:83:93:71:76:c6:69:85: - 82:17 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - 8F:F0:4B:7F:A8:2E:45:24:AE:4D:50:FA:63:9A:8B:DE:E2:DD:1B:BC - Signature Algorithm: sha256WithRSAEncryption - Signature Value: - 4b:40:db:c0:50:aa:fe:c8:0c:ef:f7:96:54:45:49:bb:96:00: - 09:41:ac:b3:13:86:86:28:07:33:ca:6b:e6:74:b9:ba:00:2d: - ae:a4:0a:d3:f5:f1:f1:0f:8a:bf:73:67:4a:83:c7:44:7b:78: - e0:af:6e:6c:6f:03:29:8e:33:39:45:c3:8e:e4:b9:57:6c:aa: - fc:12:96:ec:53:c6:2d:e4:24:6c:b9:94:63:fb:dc:53:68:67: - 56:3e:83:b8:cf:35:21:c3:c9:68:fe:ce:da:c2:53:aa:cc:90: - 8a:e9:f0:5d:46:8c:95:dd:7a:58:28:1a:2f:1d:de:cd:00:37: - 41:8f:ed:44:6d:d7:53:28:97:7e:f3:67:04:1e:15:d7:8a:96: - b4:d3:de:4c:27:a4:4c:1b:73:73:76:f4:17:99:c2:1f:7a:0e: - e3:2d:08:ad:0a:1c:2c:ff:3c:ab:55:0e:0f:91:7e:36:eb:c3: - 57:49:be:e1:2e:2d:7c:60:8b:c3:41:51:13:23:9d:ce:f7:32: - 6b:94:01:a8:99:e7:2c:33:1f:3a:3b:25:d2:86:40:ce:3b:2c: - 86:78:c9:61:2f:14:ba:ee:db:55:6f:df:84:ee:05:09:4d:bd: - 28:d8:72:ce:d3:62:50:65:1e:eb:92:97:83:31:d9:b3:b5:ca: - 47:58:3f:5f ------BEGIN CERTIFICATE----- -MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 -MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 -RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT -gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm -KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd -QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ -XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw -DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o -LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU -RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp -jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK -6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX -mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs -Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH -WD9f ------END CERTIFICATE----- diff --git a/certs/GlobalSign.pem b/certs/GlobalSign.pem new file mode 100644 index 0000000..47035e4 --- /dev/null +++ b/certs/GlobalSign.pem @@ -0,0 +1,28 @@ +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Label: "GlobalSign Root CA - R3" +# Serial: 4835703278459759426209954 +# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 +# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad +# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- diff --git a/global-config.rsc b/global-config.rsc index f99fdf1..16de721 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -98,9 +98,9 @@ # { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/block"; # cert="ISRG Root X2" }; { url="https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt"; - cert="GlobalSign Atlas R3 DV TLS CA 2022 Q3" }; + cert="GlobalSign" }; { url="https://sslbl.abuse.ch/blacklist/sslipblacklist.txt"; - cert="GlobalSign Atlas R3 DV TLS CA 2022 Q3" }; + cert="GlobalSign" }; { url="https://www.dshield.org/block.txt"; cidr="/24"; cert="ISRG Root X1" }; { url="https://lists.blocklist.de/lists/strongips.txt"; From 944e125ef9186d933609c131dfdd85178a57453b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jun 2024 10:29:40 +0200 Subject: [PATCH 2239/2612] certs: Certum Domain Validation CA SHA2 -> Certum Trusted Network CA --- certs/Certum-Domain-Validation-CA-SHA2.pem | 176 --------------------- certs/Certum-Trusted-Network-CA.pem | 29 ++++ global-config.rsc | 2 +- 3 files changed, 30 insertions(+), 177 deletions(-) delete mode 100644 certs/Certum-Domain-Validation-CA-SHA2.pem create mode 100644 certs/Certum-Trusted-Network-CA.pem diff --git a/certs/Certum-Domain-Validation-CA-SHA2.pem b/certs/Certum-Domain-Validation-CA-SHA2.pem deleted file mode 100644 index 0cc17ac..0000000 --- a/certs/Certum-Domain-Validation-CA-SHA2.pem +++ /dev/null @@ -1,176 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 279744 (0x444c0) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA - Validity - Not Before: Oct 22 12:07:37 2008 GMT - Not After : Dec 31 12:07:37 2029 GMT - Subject: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:e3:fb:7d:a3:72:ba:c2:f0:c9:14:87:f5:6b:01: - 4e:e1:6e:40:07:ba:6d:27:5d:7f:f7:5b:2d:b3:5a: - c7:51:5f:ab:a4:32:a6:61:87:b6:6e:0f:86:d2:30: - 02:97:f8:d7:69:57:a1:18:39:5d:6a:64:79:c6:01: - 59:ac:3c:31:4a:38:7c:d2:04:d2:4b:28:e8:20:5f: - 3b:07:a2:cc:4d:73:db:f3:ae:4f:c7:56:d5:5a:a7: - 96:89:fa:f3:ab:68:d4:23:86:59:27:cf:09:27:bc: - ac:6e:72:83:1c:30:72:df:e0:a2:e9:d2:e1:74:75: - 19:bd:2a:9e:7b:15:54:04:1b:d7:43:39:ad:55:28: - c5:e2:1a:bb:f4:c0:e4:ae:38:49:33:cc:76:85:9f: - 39:45:d2:a4:9e:f2:12:8c:51:f8:7c:e4:2d:7f:f5: - ac:5f:eb:16:9f:b1:2d:d1:ba:cc:91:42:77:4c:25: - c9:90:38:6f:db:f0:cc:fb:8e:1e:97:59:3e:d5:60: - 4e:e6:05:28:ed:49:79:13:4b:ba:48:db:2f:f9:72: - d3:39:ca:fe:1f:d8:34:72:f5:b4:40:cf:31:01:c3: - ec:de:11:2d:17:5d:1f:b8:50:d1:5e:19:a7:69:de: - 07:33:28:ca:50:95:f9:a7:54:cb:54:86:50:45:a9: - f9:49 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - 08:76:CD:CB:07:FF:24:F6:C5:CD:ED:BB:90:BC:E2:84:37:46:75:F7 - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - Signature Algorithm: sha1WithRSAEncryption - Signature Value: - a6:a8:ad:22:ce:01:3d:a6:a3:ff:62:d0:48:9d:8b:5e:72:b0: - 78:44:e3:dc:1c:af:09:fd:23:48:fa:bd:2a:c4:b9:55:04:b5: - 10:a3:8d:27:de:0b:82:63:d0:ee:de:0c:37:79:41:5b:22:b2: - b0:9a:41:5c:a6:70:e0:d4:d0:77:cb:23:d3:00:e0:6c:56:2f: - e1:69:0d:0d:d9:aa:bf:21:81:50:d9:06:a5:a8:ff:95:37:d0: - aa:fe:e2:b3:f5:99:2d:45:84:8a:e5:42:09:d7:74:02:2f:f7: - 89:d8:99:e9:bc:27:d4:47:8d:ba:0d:46:1c:77:cf:14:a4:1c: - b9:a4:31:c4:9c:28:74:03:34:ff:33:19:26:a5:e9:0d:74:b7: - 3e:97:c6:76:e8:27:96:a3:66:dd:e1:ae:f2:41:5b:ca:98:56: - 83:73:70:e4:86:1a:d2:31:41:ba:2f:be:2d:13:5a:76:6f:4e: - e8:4e:81:0e:3f:5b:03:22:a0:12:be:66:58:11:4a:cb:03:c4: - b4:2a:2a:2d:96:17:e0:39:54:bc:48:d3:76:27:9d:9a:2d:06: - a6:c9:ec:39:d2:ab:db:9f:9a:0b:27:02:35:29:b1:40:95:e7: - f9:e8:9c:55:88:19:46:d6:b7:34:f5:7e:ce:39:9a:d9:38:f1: - 51:f7:4f:2c ------BEGIN CERTIFICATE----- -MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM -MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D -ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU -cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 -WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg -Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw -IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH -UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM -TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU -BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM -kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x -AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV -HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y -sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL -I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 -J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY -VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI -03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 26:dd:d2:2b:46:c9:c4:4d:5a:69:4d:39:80:7e:72:ad - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA - Validity - Not Before: Sep 11 12:00:00 2014 GMT - Not After : Jun 9 10:46:39 2027 GMT - Subject: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Domain Validation CA SHA2 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:a1:25:63:df:8d:e4:20:07:d9:54:d1:d1:04:f6: - 17:e2:3e:47:fb:c3:74:25:b8:c4:bf:12:12:bc:e0: - 70:d1:39:05:c2:17:b3:f7:82:70:a0:4e:07:fe:10: - 2a:ff:db:0d:46:5e:24:94:a3:8b:45:9f:18:9b:ce: - 42:c4:ae:db:83:33:bc:c2:bb:b4:30:b6:a7:37:87: - 78:7b:48:cb:25:2c:82:bb:0a:48:12:60:76:89:ec: - 8e:cc:8f:1e:52:48:e9:86:02:5a:c2:b0:8a:7c:85: - 3d:d9:ff:60:4f:33:6c:a6:a1:a0:85:e1:d7:53:f2: - ea:27:3d:65:a9:72:c1:08:83:cc:b0:25:9c:11:46: - 24:e0:3e:f4:a7:ef:ed:51:b1:65:93:42:b4:f6:e6: - 86:0a:10:79:32:36:58:b2:6b:a8:dc:d5:7a:1e:9d: - 14:ee:40:e7:b2:46:4c:bd:9a:29:c2:ec:f8:30:c1: - 62:02:2a:e2:1c:83:62:d0:85:36:1a:83:de:12:84: - 29:65:ef:d2:32:be:31:60:42:a8:cf:f8:dd:ea:d0: - 56:47:1d:bd:76:96:24:13:e7:be:d9:99:2b:fa:30: - 64:f1:8a:38:7a:a6:e1:2a:96:02:b0:9d:ba:d8:8f: - 6d:4e:7a:94:69:7d:b0:93:aa:74:e5:93:90:13:fa: - a2:99 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - E5:31:AD:BF:3A:11:96:F4:83:BC:50:3C:D4:B7:90:9B:90:EE:DE:25 - X509v3 Authority Key Identifier: - 08:76:CD:CB:07:FF:24:F6:C5:CD:ED:BB:90:BC:E2:84:37:46:75:F7 - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 CRL Distribution Points: - Full Name: - URI:http://crl.certum.pl/ctnca.crl - Authority Information Access: - OCSP - URI:http://subca.ocsp-certum.com - CA Issuers - URI:http://repository.certum.pl/ctnca.cer - X509v3 Certificate Policies: - Policy: X509v3 Any Policy - CPS: http://www.certum.pl/CPS - Signature Algorithm: sha256WithRSAEncryption - Signature Value: - ba:bf:f0:e1:dd:4d:2b:42:43:64:58:df:64:f3:ff:80:1a:5f: - 56:be:3b:a9:b2:76:f7:54:7a:4c:30:c1:99:24:4b:72:d2:ca: - d4:fa:08:c6:90:de:88:12:ed:f8:90:f9:fc:a9:84:fd:92:f2: - 78:e5:db:c9:22:57:ab:41:30:42:6b:0b:9f:d7:73:33:fb:01: - 67:1c:42:5c:8f:27:67:c7:6e:07:03:8d:0e:96:cb:0a:03:cc: - 3e:f8:87:3c:35:30:cd:18:8c:d5:71:dd:cd:dd:61:b0:13:a3: - 64:46:4e:fe:71:4e:6b:65:e9:14:04:f2:3f:a8:bd:0c:36:3d: - 2a:5d:9e:07:f2:c2:4f:90:c5:5e:4d:18:37:d1:27:28:80:a4: - 36:e5:ca:93:6a:65:0e:f8:93:b9:af:52:58:4b:7a:71:d8:ba: - f3:ef:d2:f3:f6:a2:97:e4:5d:14:02:9a:cb:e5:ae:b6:93:e1: - 23:9f:9b:3f:46:f7:ee:8e:a1:00:5b:66:c3:1e:68:23:86:0f: - 5d:77:ba:53:ad:f9:52:fb:70:15:c5:75:eb:cf:79:ad:49:7c: - f2:76:62:ae:44:2f:c5:5f:51:34:25:41:6a:12:0a:5f:8e:ae: - 10:c4:43:89:35:fd:ec:ff:31:e6:ec:1e:87:e9:3a:7c:29:50: - 45:41:a3:14 ------BEGIN CERTIFICATE----- -MIIEzjCCA7agAwIBAgIQJt3SK0bJxE1aaU05gH5yrTANBgkqhkiG9w0BAQsFADB+ -MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5B -LjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIwIAYD -VQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMB4XDTE0MDkxMTEyMDAwMFoX -DTI3MDYwOTEwNDYzOVowgYUxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRv -IFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkxKTAnBgNVBAMTIENlcnR1bSBEb21haW4gVmFsaWRhdGlvbiBD -QSBTSEEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoSVj343kIAfZ -VNHRBPYX4j5H+8N0JbjEvxISvOBw0TkFwhez94JwoE4H/hAq/9sNRl4klKOLRZ8Y -m85CxK7bgzO8wru0MLanN4d4e0jLJSyCuwpIEmB2ieyOzI8eUkjphgJawrCKfIU9 -2f9gTzNspqGgheHXU/LqJz1lqXLBCIPMsCWcEUYk4D70p+/tUbFlk0K09uaGChB5 -MjZYsmuo3NV6Hp0U7kDnskZMvZopwuz4MMFiAiriHINi0IU2GoPeEoQpZe/SMr4x -YEKoz/jd6tBWRx29dpYkE+e+2Zkr+jBk8Yo4eqbhKpYCsJ262I9tTnqUaX2wk6p0 -5ZOQE/qimQIDAQABo4IBPjCCATowDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU -5TGtvzoRlvSDvFA81LeQm5Du3iUwHwYDVR0jBBgwFoAUCHbNywf/JPbFze27kLzi -hDdGdfcwDgYDVR0PAQH/BAQDAgEGMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9j -cmwuY2VydHVtLnBsL2N0bmNhLmNybDBrBggrBgEFBQcBAQRfMF0wKAYIKwYBBQUH -MAGGHGh0dHA6Ly9zdWJjYS5vY3NwLWNlcnR1bS5jb20wMQYIKwYBBQUHMAKGJWh0 -dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9jdG5jYS5jZXIwOQYDVR0gBDIwMDAu -BgRVHSAAMCYwJAYIKwYBBQUHAgEWGGh0dHA6Ly93d3cuY2VydHVtLnBsL0NQUzAN -BgkqhkiG9w0BAQsFAAOCAQEAur/w4d1NK0JDZFjfZPP/gBpfVr47qbJ291R6TDDB -mSRLctLK1PoIxpDeiBLt+JD5/KmE/ZLyeOXbySJXq0EwQmsLn9dzM/sBZxxCXI8n -Z8duBwONDpbLCgPMPviHPDUwzRiM1XHdzd1hsBOjZEZO/nFOa2XpFATyP6i9DDY9 -Kl2eB/LCT5DFXk0YN9EnKICkNuXKk2plDviTua9SWEt6cdi68+/S8/ail+RdFAKa -y+WutpPhI5+bP0b37o6hAFtmwx5oI4YPXXe6U635UvtwFcV16895rUl88nZirkQv -xV9RNCVBahIKX46uEMRDiTX97P8x5uweh+k6fClQRUGjFA== ------END CERTIFICATE----- diff --git a/certs/Certum-Trusted-Network-CA.pem b/certs/Certum-Trusted-Network-CA.pem new file mode 100644 index 0000000..a48e706 --- /dev/null +++ b/certs/Certum-Trusted-Network-CA.pem @@ -0,0 +1,29 @@ +# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA" +# Serial: 279744 +# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 +# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e +# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- diff --git a/global-config.rsc b/global-config.rsc index 16de721..73a9ca0 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -104,7 +104,7 @@ { url="https://www.dshield.org/block.txt"; cidr="/24"; cert="ISRG Root X1" }; { url="https://lists.blocklist.de/lists/strongips.txt"; - cert="Certum Domain Validation CA SHA2" }; + cert="Certum Trusted Network CA" }; # { url="https://www.spamhaus.org/drop/drop.txt"; # cert="Cloudflare Inc ECC CA-3" }; # { url="https://www.spamhaus.org/drop/edrop.txt"; From 7553870f2aac7182f5181273fb4a73e219fc68c7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jun 2024 10:32:01 +0200 Subject: [PATCH 2240/2612] certs: Cloudflare Inc ECC CA-3 -> Baltimore CyberTrust Root --- certs/Baltimore-CyberTrust-Root.pem | 28 +++++ certs/Cloudflare-Inc-ECC-CA-3.pem | 163 ---------------------------- global-config.rsc | 4 +- 3 files changed, 30 insertions(+), 165 deletions(-) create mode 100644 certs/Baltimore-CyberTrust-Root.pem delete mode 100644 certs/Cloudflare-Inc-ECC-CA-3.pem diff --git a/certs/Baltimore-CyberTrust-Root.pem b/certs/Baltimore-CyberTrust-Root.pem new file mode 100644 index 0000000..de8121a --- /dev/null +++ b/certs/Baltimore-CyberTrust-Root.pem @@ -0,0 +1,28 @@ +# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Label: "Baltimore CyberTrust Root" +# Serial: 33554617 +# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 +# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 +# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- diff --git a/certs/Cloudflare-Inc-ECC-CA-3.pem b/certs/Cloudflare-Inc-ECC-CA-3.pem deleted file mode 100644 index fa91603..0000000 --- a/certs/Cloudflare-Inc-ECC-CA-3.pem +++ /dev/null @@ -1,163 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 0a:37:87:64:5e:5f:b4:8c:22:4e:fd:1b:ed:14:0c:3c - Signature Algorithm: sha256WithRSAEncryption - Issuer: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root - Validity - Not Before: Jan 27 12:48:08 2020 GMT - Not After : Dec 31 23:59:59 2024 GMT - Subject: C = US, O = "Cloudflare, Inc.", CN = Cloudflare Inc ECC CA-3 - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (256 bit) - pub: - 04:b9:ad:4d:66:99:14:0b:46:ec:1f:81:d1:2a:50: - 1e:9d:03:15:2f:34:12:7d:2d:96:b8:88:38:9b:85: - 5f:8f:bf:bb:4d:ef:61:46:c4:c9:73:d4:24:4f:e0: - ee:1c:ce:6c:b3:51:71:2f:6a:ee:4c:05:09:77:d3: - 72:62:a4:9b:d7 - ASN1 OID: prime256v1 - NIST CURVE: P-256 - X509v3 extensions: - X509v3 Subject Key Identifier: - A5:CE:37:EA:EB:B0:75:0E:94:67:88:B4:45:FA:D9:24:10:87:96:1F - X509v3 Authority Key Identifier: - E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - Authority Information Access: - OCSP - URI:http://ocsp.digicert.com - X509v3 CRL Distribution Points: - Full Name: - URI:http://crl3.digicert.com/Omniroot2025.crl - X509v3 Certificate Policies: - Policy: 2.16.840.1.114412.1.1 - CPS: https://www.digicert.com/CPS - Policy: 2.16.840.1.114412.1.2 - Policy: 2.23.140.1.2.1 - Policy: 2.23.140.1.2.2 - Policy: 2.23.140.1.2.3 - Signature Algorithm: sha256WithRSAEncryption - Signature Value: - 05:24:1d:dd:1b:b0:2a:eb:98:d6:85:e3:39:4d:5e:6b:57:9d: - 82:57:fc:eb:e8:31:a2:57:90:65:05:be:16:44:38:5a:77:02: - b9:cf:10:42:c6:e1:92:a4:e3:45:27:f8:00:47:2c:68:a8:56: - 99:53:54:8f:ad:9e:40:c1:d0:0f:b6:d7:0d:0b:38:48:6c:50: - 2c:49:90:06:5b:64:1d:8b:cc:48:30:2e:de:08:e2:9b:49:22: - c0:92:0c:11:5e:96:92:94:d5:fc:20:dc:56:6c:e5:92:93:bf: - 7a:1c:c0:37:e3:85:49:15:fa:2b:e1:74:39:18:0f:b7:da:f3: - a2:57:58:60:4f:cc:8e:94:00:fc:46:7b:34:31:3e:4d:47:82: - 81:3a:cb:f4:89:5d:0e:ef:4d:0d:6e:9c:1b:82:24:dd:32:25: - 5d:11:78:51:10:3d:a0:35:23:04:2f:65:6f:9c:c1:d1:43:d7: - d0:1e:f3:31:67:59:27:dd:6b:d2:75:09:93:11:24:24:14:cf: - 29:be:e6:23:c3:b8:8f:72:3f:e9:07:c8:24:44:53:7a:b3:b9: - 61:65:a1:4c:0e:c6:48:00:c9:75:63:05:87:70:45:52:83:d3: - 95:9d:45:ea:f0:e8:31:1d:7e:09:1f:0a:fe:3e:dd:aa:3c:5e: - 74:d2:ac:b1 ------BEGIN CERTIFICATE----- -MIIDzTCCArWgAwIBAgIQCjeHZF5ftIwiTv0b7RQMPDANBgkqhkiG9w0BAQsFADBa -MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl -clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTIw -MDEyNzEyNDgwOFoXDTI0MTIzMTIzNTk1OVowSjELMAkGA1UEBhMCVVMxGTAXBgNV -BAoTEENsb3VkZmxhcmUsIEluYy4xIDAeBgNVBAMTF0Nsb3VkZmxhcmUgSW5jIEVD -QyBDQS0zMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEua1NZpkUC0bsH4HRKlAe -nQMVLzQSfS2WuIg4m4Vfj7+7Te9hRsTJc9QkT+DuHM5ss1FxL2ruTAUJd9NyYqSb -16OCAWgwggFkMB0GA1UdDgQWBBSlzjfq67B1DpRniLRF+tkkEIeWHzAfBgNVHSME -GDAWgBTlnVkwgkdYzKz6CFQ2hns6tQRN8DAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0l -BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYI -KwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j -b20wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL09t -bmlyb290MjAyNS5jcmwwbQYDVR0gBGYwZDA3BglghkgBhv1sAQEwKjAoBggrBgEF -BQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzALBglghkgBhv1sAQIw -CAYGZ4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggEB -AAUkHd0bsCrrmNaF4zlNXmtXnYJX/OvoMaJXkGUFvhZEOFp3ArnPEELG4ZKk40Un -+ABHLGioVplTVI+tnkDB0A+21w0LOEhsUCxJkAZbZB2LzEgwLt4I4ptJIsCSDBFe -lpKU1fwg3FZs5ZKTv3ocwDfjhUkV+ivhdDkYD7fa86JXWGBPzI6UAPxGezQxPk1H -goE6y/SJXQ7vTQ1unBuCJN0yJV0ReFEQPaA1IwQvZW+cwdFD19Ae8zFnWSfda9J1 -CZMRJCQUzym+5iPDuI9yP+kHyCREU3qzuWFloUwOxkgAyXVjBYdwRVKD05WdRerw -6DEdfgkfCv4+3ao8XnTSrLE= ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 33554617 (0x20000b9) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root - Validity - Not Before: May 12 18:46:00 2000 GMT - Not After : May 12 23:59:00 2025 GMT - Subject: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:a3:04:bb:22:ab:98:3d:57:e8:26:72:9a:b5:79: - d4:29:e2:e1:e8:95:80:b1:b0:e3:5b:8e:2b:29:9a: - 64:df:a1:5d:ed:b0:09:05:6d:db:28:2e:ce:62:a2: - 62:fe:b4:88:da:12:eb:38:eb:21:9d:c0:41:2b:01: - 52:7b:88:77:d3:1c:8f:c7:ba:b9:88:b5:6a:09:e7: - 73:e8:11:40:a7:d1:cc:ca:62:8d:2d:e5:8f:0b:a6: - 50:d2:a8:50:c3:28:ea:f5:ab:25:87:8a:9a:96:1c: - a9:67:b8:3f:0c:d5:f7:f9:52:13:2f:c2:1b:d5:70: - 70:f0:8f:c0:12:ca:06:cb:9a:e1:d9:ca:33:7a:77: - d6:f8:ec:b9:f1:68:44:42:48:13:d2:c0:c2:a4:ae: - 5e:60:fe:b6:a6:05:fc:b4:dd:07:59:02:d4:59:18: - 98:63:f5:a5:63:e0:90:0c:7d:5d:b2:06:7a:f3:85: - ea:eb:d4:03:ae:5e:84:3e:5f:ff:15:ed:69:bc:f9: - 39:36:72:75:cf:77:52:4d:f3:c9:90:2c:b9:3d:e5: - c9:23:53:3f:1f:24:98:21:5c:07:99:29:bd:c6:3a: - ec:e7:6e:86:3a:6b:97:74:63:33:bd:68:18:31:f0: - 78:8d:76:bf:fc:9e:8e:5d:2a:86:a7:4d:90:dc:27: - 1a:39 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Subject Key Identifier: - E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:3 - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - Signature Algorithm: sha1WithRSAEncryption - Signature Value: - 85:0c:5d:8e:e4:6f:51:68:42:05:a0:dd:bb:4f:27:25:84:03: - bd:f7:64:fd:2d:d7:30:e3:a4:10:17:eb:da:29:29:b6:79:3f: - 76:f6:19:13:23:b8:10:0a:f9:58:a4:d4:61:70:bd:04:61:6a: - 12:8a:17:d5:0a:bd:c5:bc:30:7c:d6:e9:0c:25:8d:86:40:4f: - ec:cc:a3:7e:38:c6:37:11:4f:ed:dd:68:31:8e:4c:d2:b3:01: - 74:ee:be:75:5e:07:48:1a:7f:70:ff:16:5c:84:c0:79:85:b8: - 05:fd:7f:be:65:11:a3:0f:c0:02:b4:f8:52:37:39:04:d5:a9: - 31:7a:18:bf:a0:2a:f4:12:99:f7:a3:45:82:e3:3c:5e:f5:9d: - 9e:b5:c8:9e:7c:2e:c8:a4:9e:4e:08:14:4b:6d:fd:70:6d:6b: - 1a:63:bd:64:e6:1f:b7:ce:f0:f2:9f:2e:bb:1b:b7:f2:50:88: - 73:92:c2:e2:e3:16:8d:9a:32:02:ab:8e:18:dd:e9:10:11:ee: - 7e:35:ab:90:af:3e:30:94:7a:d0:33:3d:a7:65:0f:f5:fc:8e: - 9e:62:cf:47:44:2c:01:5d:bb:1d:b5:32:d2:47:d2:38:2e:d0: - fe:81:dc:32:6a:1e:b5:ee:3c:d5:fc:e7:81:1d:19:c3:24:42: - ea:63:39:a9 ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ -RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD -VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX -DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y -ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy -VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr -mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr -IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK -mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu -XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy -dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye -jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 -BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 -DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 -9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx -jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 -Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz -ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS -R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE----- diff --git a/global-config.rsc b/global-config.rsc index 73a9ca0..cdc1d5c 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -106,9 +106,9 @@ { url="https://lists.blocklist.de/lists/strongips.txt"; cert="Certum Trusted Network CA" }; # { url="https://www.spamhaus.org/drop/drop.txt"; -# cert="Cloudflare Inc ECC CA-3" }; +# cert="Baltimore CyberTrust Root" }; # { url="https://www.spamhaus.org/drop/edrop.txt"; -# cert="Cloudflare Inc ECC CA-3" }; +# cert="Baltimore CyberTrust Root" }; }; # "mikrotik"={ # { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/mikrotik"; From a744508d4f59bb95106b454c930fbb3f9eb28066 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jun 2024 10:34:49 +0200 Subject: [PATCH 2241/2612] certs: Starfield Secure Certificate Authority - G2 -> Starfield Root Certificate Authority - G2 --- ...tarfield-Root-Certificate-Authority-G2.pem | 30 +++ ...rfield-Secure-Certificate-Authority-G2.pem | 179 ------------------ update-tunnelbroker.rsc | 2 +- 3 files changed, 31 insertions(+), 180 deletions(-) create mode 100644 certs/Starfield-Root-Certificate-Authority-G2.pem delete mode 100644 certs/Starfield-Secure-Certificate-Authority-G2.pem diff --git a/certs/Starfield-Root-Certificate-Authority-G2.pem b/certs/Starfield-Root-Certificate-Authority-G2.pem new file mode 100644 index 0000000..4e6774d --- /dev/null +++ b/certs/Starfield-Root-Certificate-Authority-G2.pem @@ -0,0 +1,30 @@ +# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 +# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e +# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- diff --git a/certs/Starfield-Secure-Certificate-Authority-G2.pem b/certs/Starfield-Secure-Certificate-Authority-G2.pem deleted file mode 100644 index 7772e6b..0000000 --- a/certs/Starfield-Secure-Certificate-Authority-G2.pem +++ /dev/null @@ -1,179 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 7 (0x7) - Signature Algorithm: sha256WithRSAEncryption - Issuer: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Root Certificate Authority - G2 - Validity - Not Before: May 3 07:00:00 2011 GMT - Not After : May 3 07:00:00 2031 GMT - Subject: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", OU = http://certs.starfieldtech.com/repository/, CN = Starfield Secure Certificate Authority - G2 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:e5:90:66:4b:ec:f9:46:71:a9:20:83:be:e9:6c: - bf:4a:c9:48:69:81:75:4e:6d:24:f6:cb:17:13:f8: - b0:71:59:84:7a:6b:2b:85:a4:34:b5:16:e5:cb:cc: - e9:41:70:2c:a4:2e:d6:fa:32:7d:e1:a8:de:94:10: - ac:31:c1:c0:d8:6a:ff:59:27:ab:76:d6:fc:0b:74: - 6b:b8:a7:ae:3f:c4:54:f4:b4:31:44:dd:93:56:8c: - a4:4c:5e:9b:89:cb:24:83:9b:e2:57:7d:b7:d8:12: - 1f:c9:85:6d:f4:d1:80:f1:50:9b:87:ae:d4:0b:10: - 05:fb:27:ba:28:6d:17:e9:0e:d6:4d:b9:39:55:06: - ff:0a:24:05:7e:2f:c6:1d:72:6c:d4:8b:29:8c:57: - 7d:da:d9:eb:66:1a:d3:4f:a7:df:7f:52:c4:30:c5: - a5:c9:0e:02:c5:53:bf:77:38:68:06:24:c3:66:c8: - 37:7e:30:1e:45:71:23:35:ff:90:d8:2a:9d:8d:e7: - b0:92:4d:3c:7f:2a:0a:93:dc:cd:16:46:65:f7:60: - 84:8b:76:4b:91:27:73:14:92:e0:ea:ee:8f:16:ea: - 8d:0e:3e:76:17:bf:7d:89:80:80:44:43:e7:2d:e0: - 43:09:75:da:36:e8:ad:db:89:3a:f5:5d:12:8e:23: - 04:83 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - 25:45:81:68:50:26:38:3D:3B:2D:2C:BE:CD:6A:D9:B6:3D:B3:66:63 - X509v3 Authority Key Identifier: - keyid:7C:0C:32:1F:A7:D9:30:7F:C4:7D:68:A3:62:A8:A1:CE:AB:07:5B:27 - - Authority Information Access: - OCSP - URI:http://ocsp.starfieldtech.com/ - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://crl.starfieldtech.com/sfroot-g2.crl - - X509v3 Certificate Policies: - Policy: X509v3 Any Policy - CPS: https://certs.starfieldtech.com/repository/ - - Signature Algorithm: sha256WithRSAEncryption - 56:65:ca:fe:f3:3f:0a:a8:93:8b:18:c7:de:43:69:13:34:20: - be:4e:5f:78:a8:6b:9c:db:6a:4d:41:db:c1:13:ec:dc:31:00: - 22:5e:f7:00:9e:0c:e0:34:65:34:f9:b1:3a:4e:48:c8:12:81: - 88:5c:5b:3e:08:53:7a:f7:1a:64:df:b8:50:61:cc:53:51:40: - 29:4b:c2:f4:ae:3a:5f:e4:ca:ad:26:cc:4e:61:43:e5:fd:57: - a6:37:70:ce:43:2b:b0:94:c3:92:e9:e1:5f:aa:10:49:b7:69: - e4:e0:d0:1f:64:a4:2b:cd:1f:6f:a0:f8:84:24:18:ce:79:3d: - a9:91:bf:54:18:13:89:99:54:11:0d:55:c5:26:0b:79:4f:5a: - 1c:6e:f9:63:db:14:80:a4:07:ab:fa:b2:a5:b9:88:dd:91:fe: - 65:3b:a4:a3:79:be:89:4d:e1:d0:b0:f4:c8:17:0c:0a:96:14: - 7c:09:b7:6c:e1:c2:d8:55:d4:18:a0:aa:41:69:70:24:a3:b9: - ef:e9:5a:dc:3e:eb:94:4a:f0:b7:de:5f:0e:76:fa:fb:fb:69: - 03:45:40:50:ee:72:0c:a4:12:86:81:cd:13:d1:4e:c4:3c:ca: - 4e:0d:d2:26:f1:00:b7:b4:a6:a2:e1:6e:7a:81:fd:30:ac:7a: - 1f:c7:59:7b ------BEGIN CERTIFICATE----- -MIIFADCCA+igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs -ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAw -MFoXDTMxMDUwMzA3MDAwMFowgcYxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 -b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj -aG5vbG9naWVzLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydHMuc3RhcmZpZWxk -dGVjaC5jb20vcmVwb3NpdG9yeS8xNDAyBgNVBAMTK1N0YXJmaWVsZCBTZWN1cmUg -Q2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQDlkGZL7PlGcakgg77pbL9KyUhpgXVObST2yxcT+LBxWYR6ayuF -pDS1FuXLzOlBcCykLtb6Mn3hqN6UEKwxwcDYav9ZJ6t21vwLdGu4p64/xFT0tDFE -3ZNWjKRMXpuJyySDm+JXfbfYEh/JhW300YDxUJuHrtQLEAX7J7oobRfpDtZNuTlV -Bv8KJAV+L8YdcmzUiymMV33a2etmGtNPp99/UsQwxaXJDgLFU793OGgGJMNmyDd+ -MB5FcSM1/5DYKp2N57CSTTx/KgqT3M0WRmX3YISLdkuRJ3MUkuDq7o8W6o0OPnYX -v32JgIBEQ+ct4EMJddo26K3biTr1XRKOIwSDAgMBAAGjggEsMIIBKDAPBgNVHRMB -Af8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUJUWBaFAmOD07LSy+ -zWrZtj2zZmMwHwYDVR0jBBgwFoAUfAwyH6fZMH/EfWijYqihzqsHWycwOgYIKwYB -BQUHAQEELjAsMCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5zdGFyZmllbGR0ZWNo -LmNvbS8wOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybC5zdGFyZmllbGR0ZWNo -LmNvbS9zZnJvb3QtZzIuY3JsMEwGA1UdIARFMEMwQQYEVR0gADA5MDcGCCsGAQUF -BwIBFitodHRwczovL2NlcnRzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkv -MA0GCSqGSIb3DQEBCwUAA4IBAQBWZcr+8z8KqJOLGMfeQ2kTNCC+Tl94qGuc22pN -QdvBE+zcMQAiXvcAngzgNGU0+bE6TkjIEoGIXFs+CFN69xpk37hQYcxTUUApS8L0 -rjpf5MqtJsxOYUPl/VemN3DOQyuwlMOS6eFfqhBJt2nk4NAfZKQrzR9voPiEJBjO -eT2pkb9UGBOJmVQRDVXFJgt5T1ocbvlj2xSApAer+rKluYjdkf5lO6Sjeb6JTeHQ -sPTIFwwKlhR8Cbds4cLYVdQYoKpBaXAko7nv6VrcPuuUSvC33l8Odvr7+2kDRUBQ -7nIMpBKGgc0T0U7EPMpODdIm8QC3tKai4W56gf0wrHofx1l7 ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 0 (0x0) - Signature Algorithm: sha256WithRSAEncryption - Issuer: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Root Certificate Authority - G2 - Validity - Not Before: Sep 1 00:00:00 2009 GMT - Not After : Dec 31 23:59:59 2037 GMT - Subject: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Root Certificate Authority - G2 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:bd:ed:c1:03:fc:f6:8f:fc:02:b1:6f:5b:9f:48: - d9:9d:79:e2:a2:b7:03:61:56:18:c3:47:b6:d7:ca: - 3d:35:2e:89:43:f7:a1:69:9b:de:8a:1a:fd:13:20: - 9c:b4:49:77:32:29:56:fd:b9:ec:8c:dd:22:fa:72: - dc:27:61:97:ee:f6:5a:84:ec:6e:19:b9:89:2c:dc: - 84:5b:d5:74:fb:6b:5f:c5:89:a5:10:52:89:46:55: - f4:b8:75:1c:e6:7f:e4:54:ae:4b:f8:55:72:57:02: - 19:f8:17:71:59:eb:1e:28:07:74:c5:9d:48:be:6c: - b4:f4:a4:b0:f3:64:37:79:92:c0:ec:46:5e:7f:e1: - 6d:53:4c:62:af:cd:1f:0b:63:bb:3a:9d:fb:fc:79: - 00:98:61:74:cf:26:82:40:63:f3:b2:72:6a:19:0d: - 99:ca:d4:0e:75:cc:37:fb:8b:89:c1:59:f1:62:7f: - 5f:b3:5f:65:30:f8:a7:b7:4d:76:5a:1e:76:5e:34: - c0:e8:96:56:99:8a:b3:f0:7f:a4:cd:bd:dc:32:31: - 7c:91:cf:e0:5f:11:f8:6b:aa:49:5c:d1:99:94:d1: - a2:e3:63:5b:09:76:b5:56:62:e1:4b:74:1d:96:d4: - 26:d4:08:04:59:d0:98:0e:0e:e6:de:fc:c3:ec:1f: - 90:f1 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - 7C:0C:32:1F:A7:D9:30:7F:C4:7D:68:A3:62:A8:A1:CE:AB:07:5B:27 - Signature Algorithm: sha256WithRSAEncryption - 11:59:fa:25:4f:03:6f:94:99:3b:9a:1f:82:85:39:d4:76:05: - 94:5e:e1:28:93:6d:62:5d:09:c2:a0:a8:d4:b0:75:38:f1:34: - 6a:9d:e4:9f:8a:86:26:51:e6:2c:d1:c6:2d:6e:95:20:4a:92: - 01:ec:b8:8a:67:7b:31:e2:67:2e:8c:95:03:26:2e:43:9d:4a: - 31:f6:0e:b5:0c:bb:b7:e2:37:7f:22:ba:00:a3:0e:7b:52:fb: - 6b:bb:3b:c4:d3:79:51:4e:cd:90:f4:67:07:19:c8:3c:46:7a: - 0d:01:7d:c5:58:e7:6d:e6:85:30:17:9a:24:c4:10:e0:04:f7: - e0:f2:7f:d4:aa:0a:ff:42:1d:37:ed:94:e5:64:59:12:20:77: - 38:d3:32:3e:38:81:75:96:73:fa:68:8f:b1:cb:ce:1f:c5:ec: - fa:9c:7e:cf:7e:b1:f1:07:2d:b6:fc:bf:ca:a4:bf:d0:97:05: - 4a:bc:ea:18:28:02:90:bd:54:78:09:21:71:d3:d1:7d:1d:d9: - 16:b0:a9:61:3d:d0:0a:00:22:fc:c7:7b:cb:09:64:45:0b:3b: - 40:81:f7:7d:7c:32:f5:98:ca:58:8e:7d:2a:ee:90:59:73:64: - f9:36:74:5e:25:a1:f5:66:05:2e:7f:39:15:a9:2a:fb:50:8b: - 8e:85:69:f4 ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs -ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw -MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 -b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj -aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp -Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg -nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 -HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N -Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN -dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 -HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G -CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU -sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 -4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg -8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K -pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 -mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 ------END CERTIFICATE----- diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index 364dc08..f9ba202 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -25,7 +25,7 @@ :error false; } - :if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ + :if ([ $CertificateAvailable "Starfield Root Certificate Authority - G2" ] = false) do={ $LogPrint error $ScriptName ("Downloading required certificate failed."); :error false; } From 0ae3d31c58d57578092e76368ebd82bdc859123d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jun 2024 10:38:35 +0200 Subject: [PATCH 2242/2612] certs: GTS CA 1C3 / GTS CA 1P5 -> GTS Root R1 --- certs/GTS-CA-1C3.pem | 242 ------------------------------------------ certs/GTS-CA-1P5.pem | 238 ----------------------------------------- certs/GTS-Root-R1.pem | 38 +++++++ doc/netwatch-dns.md | 2 +- global-functions.rsc | 2 +- 5 files changed, 40 insertions(+), 482 deletions(-) delete mode 100644 certs/GTS-CA-1C3.pem delete mode 100644 certs/GTS-CA-1P5.pem create mode 100644 certs/GTS-Root-R1.pem diff --git a/certs/GTS-CA-1C3.pem b/certs/GTS-CA-1C3.pem deleted file mode 100644 index a8432d2..0000000 --- a/certs/GTS-CA-1C3.pem +++ /dev/null @@ -1,242 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 02:03:bc:53:59:6b:34:c7:18:f5:01:50:66 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C = US, O = Google Trust Services LLC, CN = GTS Root R1 - Validity - Not Before: Aug 13 00:00:42 2020 GMT - Not After : Sep 30 00:00:42 2027 GMT - Subject: C = US, O = Google Trust Services LLC, CN = GTS CA 1C3 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:f5:88:df:e7:62:8c:1e:37:f8:37:42:90:7f:6c: - 87:d0:fb:65:82:25:fd:e8:cb:6b:a4:ff:6d:e9:5a: - 23:e2:99:f6:1c:e9:92:03:99:13:7c:09:0a:8a:fa: - 42:d6:5e:56:24:aa:7a:33:84:1f:d1:e9:69:bb:b9: - 74:ec:57:4c:66:68:93:77:37:55:53:fe:39:10:4d: - b7:34:bb:5f:25:77:37:3b:17:94:ea:3c:e5:9d:d5: - bc:c3:b4:43:eb:2e:a7:47:ef:b0:44:11:63:d8:b4: - 41:85:dd:41:30:48:93:1b:bf:b7:f6:e0:45:02:21: - e0:96:42:17:cf:d9:2b:65:56:34:07:26:04:0d:a8: - fd:7d:ca:2e:ef:ea:48:7c:37:4d:3f:00:9f:83:df: - ef:75:84:2e:79:57:5c:fc:57:6e:1a:96:ff:fc:8c: - 9a:a6:99:be:25:d9:7f:96:2c:06:f7:11:2a:02:80: - 80:eb:63:18:3c:50:49:87:e5:8a:ca:5f:19:2b:59: - 96:81:00:a0:fb:51:db:ca:77:0b:0b:c9:96:4f:ef: - 70:49:c7:5c:6d:20:fd:99:b4:b4:e2:ca:2e:77:fd: - 2d:dc:0b:b6:6b:13:0c:8c:19:2b:17:96:98:b9:f0: - 8b:f6:a0:27:bb:b6:e3:8d:51:8f:bd:ae:c7:9b:b1: - 89:9d - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - 8A:74:7F:AF:85:CD:EE:95:CD:3D:9C:D0:E2:46:14:F3:71:35:1D:27 - X509v3 Authority Key Identifier: - keyid:E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E - - Authority Information Access: - OCSP - URI:http://ocsp.pki.goog/gtsr1 - CA Issuers - URI:http://pki.goog/repo/certs/gtsr1.der - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://crl.pki.goog/gtsr1/gtsr1.crl - - X509v3 Certificate Policies: - Policy: 1.3.6.1.4.1.11129.2.5.3 - CPS: https://pki.goog/repository/ - Policy: 2.23.140.1.2.1 - Policy: 2.23.140.1.2.2 - - Signature Algorithm: sha256WithRSAEncryption - 89:7d:ac:20:5c:0c:3c:be:9a:a8:57:95:1b:b4:ae:fa:ab:a5: - 72:71:b4:36:95:fd:df:40:11:03:4c:c2:46:14:bb:14:24:ab: - f0:50:71:22:db:ad:c4:6e:7f:cf:f1:6a:6f:c8:83:1b:d8:ce: - 89:5f:87:6c:87:b8:a9:0c:a3:9b:a1:62:94:93:95:df:5b:ae: - 66:19:0b:02:96:9e:fc:b5:e7:10:69:3e:7a:cb:46:49:5f:46: - e1:41:b1:d7:98:4d:65:34:00:80:1a:3f:4f:9f:6c:7f:49:00: - 81:53:41:a4:92:21:82:82:1a:f1:a3:44:5b:2a:50:12:13:4d: - c1:53:36:f3:42:08:af:54:fa:8e:77:53:1b:64:38:27:17:09: - bd:58:c9:1b:7c:39:2d:5b:f3:ce:d4:ed:97:db:14:03:bf:09: - 53:24:1f:c2:0c:04:79:98:26:f2:61:f1:53:52:fd:42:8c:1b: - 66:2b:3f:15:a1:bb:ff:f6:9b:e3:81:9a:01:06:71:89:35:28: - 24:dd:e1:bd:eb:19:2d:e1:48:cb:3d:59:83:51:b4:74:c6:9d: - 7c:c6:b1:86:5b:af:cc:34:c4:d3:cc:d4:81:11:95:00:a1:f4: - 12:22:01:fa:b4:83:71:af:8c:b7:8c:73:24:ac:37:53:c2:00: - 90:3f:11:fe:5c:ed:36:94:10:3b:bd:29:ae:e2:c7:3a:62:3b: - 6c:63:d9:80:bf:59:71:ac:63:27:b9:4c:17:a0:da:f6:73:15: - bf:2a:de:8f:f3:a5:6c:32:81:33:03:d0:86:51:71:99:34:ba: - 93:8d:5d:b5:51:58:f7:b2:93:e8:01:f6:59:be:71:9b:fd:4d: - 28:ce:cf:6d:c7:16:dc:f7:d1:d6:46:9b:a7:ca:6b:e9:77:0f: - fd:a0:b6:1b:23:83:1d:10:1a:d9:09:00:84:e0:44:d3:a2:75: - 23:b3:34:86:f6:20:b0:a4:5e:10:1d:e0:52:46:00:9d:b1:0f: - 1f:21:70:51:f5:9a:dd:06:fc:55:f4:2b:0e:33:77:c3:4b:42: - c2:f1:77:13:fc:73:80:94:eb:1f:bb:37:3f:ce:02:2a:66:b0: - 73:1d:32:a5:32:6c:32:b0:8e:e0:c4:23:ff:5b:7d:4d:65:70: - ac:2b:9b:3d:ce:db:e0:6d:8e:32:80:be:96:9f:92:63:bc:97: - bb:5d:b9:f4:e1:71:5e:2a:e4:ef:03:22:b1:8a:65:3a:8f:c0: - 93:65:d4:85:cd:0f:0f:5b:83:59:16:47:16:2d:9c:24:3a:c8: - 80:a6:26:14:85:9b:f6:37:9b:ac:6f:f9:c5:c3:06:51:f3:e2: - 7f:c5:b1:10:ba:51:f4:dd ------BEGIN CERTIFICATE----- -MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw -MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFDMzCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAPWI3+dijB43+DdCkH9sh9D7ZYIl/ejLa6T/belaI+KZ9hzp -kgOZE3wJCor6QtZeViSqejOEH9Hpabu5dOxXTGZok3c3VVP+ORBNtzS7XyV3NzsX -lOo85Z3VvMO0Q+sup0fvsEQRY9i0QYXdQTBIkxu/t/bgRQIh4JZCF8/ZK2VWNAcm -BA2o/X3KLu/qSHw3TT8An4Pf73WELnlXXPxXbhqW//yMmqaZviXZf5YsBvcRKgKA -gOtjGDxQSYflispfGStZloEAoPtR28p3CwvJlk/vcEnHXG0g/Zm0tOLKLnf9LdwL -tmsTDIwZKxeWmLnwi/agJ7u2441Rj72ux5uxiZ0CAwEAAaOCAYAwggF8MA4GA1Ud -DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T -AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUinR/r4XN7pXNPZzQ4kYU83E1HScwHwYD -VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG -CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw -AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt -MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMFcG -A1UdIARQME4wOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br -aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcN -AQELBQADggIBAIl9rCBcDDy+mqhXlRu0rvqrpXJxtDaV/d9AEQNMwkYUuxQkq/BQ -cSLbrcRuf8/xam/IgxvYzolfh2yHuKkMo5uhYpSTld9brmYZCwKWnvy15xBpPnrL -RklfRuFBsdeYTWU0AIAaP0+fbH9JAIFTQaSSIYKCGvGjRFsqUBITTcFTNvNCCK9U -+o53UxtkOCcXCb1YyRt8OS1b887U7ZfbFAO/CVMkH8IMBHmYJvJh8VNS/UKMG2Yr -PxWhu//2m+OBmgEGcYk1KCTd4b3rGS3hSMs9WYNRtHTGnXzGsYZbr8w0xNPM1IER -lQCh9BIiAfq0g3GvjLeMcySsN1PCAJA/Ef5c7TaUEDu9Ka7ixzpiO2xj2YC/WXGs -Yye5TBeg2vZzFb8q3o/zpWwygTMD0IZRcZk0upONXbVRWPeyk+gB9lm+cZv9TSjO -z23HFtz30dZGm6fKa+l3D/2gthsjgx0QGtkJAITgRNOidSOzNIb2ILCkXhAd4FJG -AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw -juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl -1IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 6e:47:a9:c5:4b:47:0c:0d:ec:33:d0:89:b9:1c:f4:e1 - Signature Algorithm: sha384WithRSAEncryption - Issuer: C = US, O = Google Trust Services LLC, CN = GTS Root R1 - Validity - Not Before: Jun 22 00:00:00 2016 GMT - Not After : Jun 22 00:00:00 2036 GMT - Subject: C = US, O = Google Trust Services LLC, CN = GTS Root R1 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (4096 bit) - Modulus: - 00:b6:11:02:8b:1e:e3:a1:77:9b:3b:dc:bf:94:3e: - b7:95:a7:40:3c:a1:fd:82:f9:7d:32:06:82:71:f6: - f6:8c:7f:fb:e8:db:bc:6a:2e:97:97:a3:8c:4b:f9: - 2b:f6:b1:f9:ce:84:1d:b1:f9:c5:97:de:ef:b9:f2: - a3:e9:bc:12:89:5e:a7:aa:52:ab:f8:23:27:cb:a4: - b1:9c:63:db:d7:99:7e:f0:0a:5e:eb:68:a6:f4:c6: - 5a:47:0d:4d:10:33:e3:4e:b1:13:a3:c8:18:6c:4b: - ec:fc:09:90:df:9d:64:29:25:23:07:a1:b4:d2:3d: - 2e:60:e0:cf:d2:09:87:bb:cd:48:f0:4d:c2:c2:7a: - 88:8a:bb:ba:cf:59:19:d6:af:8f:b0:07:b0:9e:31: - f1:82:c1:c0:df:2e:a6:6d:6c:19:0e:b5:d8:7e:26: - 1a:45:03:3d:b0:79:a4:94:28:ad:0f:7f:26:e5:a8: - 08:fe:96:e8:3c:68:94:53:ee:83:3a:88:2b:15:96: - 09:b2:e0:7a:8c:2e:75:d6:9c:eb:a7:56:64:8f:96: - 4f:68:ae:3d:97:c2:84:8f:c0:bc:40:c0:0b:5c:bd: - f6:87:b3:35:6c:ac:18:50:7f:84:e0:4c:cd:92:d3: - 20:e9:33:bc:52:99:af:32:b5:29:b3:25:2a:b4:48: - f9:72:e1:ca:64:f7:e6:82:10:8d:e8:9d:c2:8a:88: - fa:38:66:8a:fc:63:f9:01:f9:78:fd:7b:5c:77:fa: - 76:87:fa:ec:df:b1:0e:79:95:57:b4:bd:26:ef:d6: - 01:d1:eb:16:0a:bb:8e:0b:b5:c5:c5:8a:55:ab:d3: - ac:ea:91:4b:29:cc:19:a4:32:25:4e:2a:f1:65:44: - d0:02:ce:aa:ce:49:b4:ea:9f:7c:83:b0:40:7b:e7: - 43:ab:a7:6c:a3:8f:7d:89:81:fa:4c:a5:ff:d5:8e: - c3:ce:4b:e0:b5:d8:b3:8e:45:cf:76:c0:ed:40:2b: - fd:53:0f:b0:a7:d5:3b:0d:b1:8a:a2:03:de:31:ad: - cc:77:ea:6f:7b:3e:d6:df:91:22:12:e6:be:fa:d8: - 32:fc:10:63:14:51:72:de:5d:d6:16:93:bd:29:68: - 33:ef:3a:66:ec:07:8a:26:df:13:d7:57:65:78:27: - de:5e:49:14:00:a2:00:7f:9a:a8:21:b6:a9:b1:95: - b0:a5:b9:0d:16:11:da:c7:6c:48:3c:40:e0:7e:0d: - 5a:cd:56:3c:d1:97:05:b9:cb:4b:ed:39:4b:9c:c4: - 3f:d2:55:13:6e:24:b0:d6:71:fa:f4:c1:ba:cc:ed: - 1b:f5:fe:81:41:d8:00:98:3d:3a:c8:ae:7a:98:37: - 18:05:95 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E - Signature Algorithm: sha384WithRSAEncryption - 38:96:0a:ee:3d:b4:96:1e:5f:ef:9d:9c:0b:33:9f:2b:e0:ca: - fd:d2:8e:0a:1f:41:74:a5:7c:aa:84:d4:e5:f2:1e:e6:37:52: - 32:9c:0b:d1:61:1d:bf:28:c1:b6:44:29:35:75:77:98:b2:7c: - d9:bd:74:ac:8a:68:e3:a9:31:09:29:01:60:73:e3:47:7c:53: - a8:90:4a:27:ef:4b:d7:9f:93:e7:82:36:ce:9a:68:0c:82:e7: - cf:d4:10:16:6f:5f:0e:99:5c:f6:1f:71:7d:ef:ef:7b:2f:7e: - ea:36:d6:97:70:0b:15:ee:d7:5c:56:6a:33:a5:e3:49:38:0c: - b8:7d:fb:8d:85:a4:b1:59:5e:f4:6a:e1:dd:a1:f6:64:44:ae: - e6:51:83:21:66:c6:11:3e:f3:ce:47:ee:9c:28:1f:25:da:ff: - ac:66:95:dd:35:0f:5c:ef:20:2c:62:fd:91:ba:a9:cc:fc:5a: - 9c:93:81:83:29:97:4a:7c:5a:72:b4:39:d0:b7:77:cb:79:fd: - 69:3a:92:37:ed:6e:38:65:46:7e:e9:60:bd:79:88:97:5f:38: - 12:f4:ee:af:5b:82:c8:86:d5:e1:99:6d:8c:04:f2:76:ba:49: - f6:6e:e9:6d:1e:5f:a0:ef:27:82:76:40:f8:a6:d3:58:5c:0f: - 2c:42:da:42:c6:7b:88:34:c7:c1:d8:45:9b:c1:3e:c5:61:1d: - d9:63:50:49:f6:34:85:6a:e0:18:c5:6e:47:ab:41:42:29:9b: - f6:60:0d:d2:31:d3:63:98:23:93:5a:00:81:48:b4:ef:cd:8a: - cd:c9:cf:99:ee:d9:9e:aa:36:e1:68:4b:71:49:14:36:28:3a: - 3d:1d:ce:9a:8f:25:e6:80:71:61:2b:b5:7b:cc:f9:25:16:81: - e1:31:5f:a1:a3:7e:16:a4:9c:16:6a:97:18:bd:76:72:a5:0b: - 9e:1d:36:e6:2f:a1:2f:be:70:91:0f:a8:e6:da:f8:c4:92:40: - 6c:25:7e:7b:b3:09:dc:b2:17:ad:80:44:f0:68:a5:8f:94:75: - ff:74:5a:e8:a8:02:7c:0c:09:e2:a9:4b:0b:a0:85:0b:62:b9: - ef:a1:31:92:fb:ef:f6:51:04:89:6c:e8:a9:74:a1:bb:17:b3: - b5:fd:49:0f:7c:3c:ec:83:18:20:43:4e:d5:93:ba:b4:34:b1: - 1f:16:36:1f:0c:e6:64:39:16:4c:dc:e0:fe:1d:c8:a9:62:3d: - 40:ea:ca:c5:34:02:b4:ae:89:88:33:35:dc:2c:13:73:d8:27: - f1:d0:72:ee:75:3b:22:de:98:68:66:5b:f1:c6:63:47:55:1c: - ba:a5:08:51:75:a6:48:25 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH -MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM -QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy -MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl -cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM -f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX -mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7 -zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P -fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc -vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4 -Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp -zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO -Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW -k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+ -DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF -lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW -Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 -d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z -XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR -gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3 -d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv -J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg -DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM -+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy -F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9 -SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws -E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl ------END CERTIFICATE----- diff --git a/certs/GTS-CA-1P5.pem b/certs/GTS-CA-1P5.pem deleted file mode 100644 index 5be738d..0000000 --- a/certs/GTS-CA-1P5.pem +++ /dev/null @@ -1,238 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 02:03:bc:50:a3:27:53:f0:91:80:22:ed:f1 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1 - Validity - Not Before: Aug 13 00:00:42 2020 GMT - Not After : Sep 30 00:00:42 2027 GMT - Subject: C=US, O=Google Trust Services LLC, CN=GTS CA 1P5 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:b3:82:f0:24:8c:bf:2d:87:af:b2:d9:a7:ae:fa: - ca:ba:44:d6:5b:3e:fe:b2:f7:b2:65:16:dc:de:10: - e8:4f:2d:10:58:5a:28:86:87:a1:ee:6a:b3:a0:d9: - 75:4f:7f:a1:52:01:8b:55:a8:4a:5b:06:48:c8:36: - 12:25:ab:89:f9:f2:23:5f:9d:60:65:f9:5c:da:be: - 3a:e8:5c:6d:7d:9c:d0:84:18:85:30:cd:4e:9b:ec: - 3c:d8:b3:e1:96:d4:f3:c5:0b:65:db:8f:b0:74:cb: - f6:1e:f3:78:f1:ac:95:c5:dd:73:c3:31:88:81:af: - 74:aa:6f:fd:0c:e3:05:95:f0:c5:10:4f:65:63:fa: - a0:af:c6:18:3d:c5:a1:df:97:79:d7:05:89:b3:30: - b0:74:ae:3d:92:10:6b:8c:15:77:dd:0b:04:57:fb: - 81:03:dd:ea:22:34:d5:e5:56:b2:f0:c4:8d:41:b1: - c3:02:db:62:ec:80:d0:ff:76:d4:86:e4:04:1a:b6: - b6:0c:2b:62:71:7d:d9:af:d9:f1:5e:fa:c0:1e:ca: - a0:19:5c:55:f0:80:d1:2a:0c:07:86:90:9f:35:e3: - 28:2b:5b:ef:23:c8:a3:1d:a4:a3:3a:ee:fe:83:dc: - 82:4c:25:b0:4d:c5:51:ad:9e:9b:d3:5b:84:c2:1a: - 5a:e9 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - D5:FC:9E:0D:DF:1E:CA:DD:08:97:97:6E:2B:C5:5F:C5:2B:F5:EC:B8 - X509v3 Authority Key Identifier: - E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E - Authority Information Access: - OCSP - URI:http://ocsp.pki.goog/gtsr1 - CA Issuers - URI:http://pki.goog/repo/certs/gtsr1.der - X509v3 CRL Distribution Points: - Full Name: - URI:http://crl.pki.goog/gtsr1/gtsr1.crl - X509v3 Certificate Policies: - Policy: 1.3.6.1.4.1.11129.2.5.3 - CPS: https://pki.goog/repository/ - Policy: 2.23.140.1.2.1 - Signature Algorithm: sha256WithRSAEncryption - Signature Value: - 6c:63:27:ee:23:df:e5:52:68:4d:81:66:91:85:df:7d:65:e5: - 5b:37:31:08:26:b2:07:5d:9a:be:b1:ca:01:b9:ad:bf:9d:77: - f6:51:1d:d7:98:c5:0b:49:a1:7b:a1:d7:d3:68:e5:44:0f:8b: - ba:36:dd:42:82:77:d2:8d:dd:f5:3f:fb:eb:c8:07:98:93:ee: - 5a:d0:b5:3d:de:4b:1c:2d:8c:4d:ec:7e:8c:7b:fe:4e:40:fd: - f0:b4:b3:59:02:10:51:5c:e3:c0:2b:fd:b7:06:48:51:7e:09: - 5e:3f:0f:dc:a7:fe:97:e7:79:c5:0e:44:89:78:c5:69:59:29: - a0:9a:3a:48:36:29:a6:94:93:55:2d:b8:47:b5:e9:96:b5:9f: - 07:cd:a6:ab:3e:32:8a:c0:86:83:c5:c1:41:c8:9f:2f:35:8e: - 0d:c0:07:7a:e1:ac:c9:65:b5:cb:8a:a7:dd:71:d8:61:65:39: - 84:ac:32:3e:f7:7a:36:f1:56:9f:57:a9:41:6d:5a:90:a7:db: - 3a:ea:75:80:0c:63:0b:69:74:6f:07:4c:15:f3:37:28:a5:19: - a4:6e:f5:f6:20:cd:63:b2:7e:c4:2b:09:75:89:da:d1:3c:2e: - 72:4f:36:1a:a1:9e:44:d0:cd:9b:a6:23:08:3f:97:a1:a7:9e: - 5a:a5:f7:09:94:ad:5d:76:5d:28:56:d1:1a:66:51:51:07:7b: - de:3d:b0:c8:ef:30:7a:24:2d:be:b8:b3:86:f6:4b:f7:f0:b5: - 4f:ff:ce:c6:f9:f6:3f:2a:27:08:0f:09:3e:23:5a:c7:e3:42: - 2d:7a:36:e4:3d:98:96:60:39:98:ea:d1:db:63:2a:eb:78:09: - b1:4e:21:b3:8e:b7:ce:3e:92:f1:95:5c:a4:39:d0:c0:2b:c8: - 53:15:f5:d2:2f:82:cd:06:74:67:99:90:77:37:0a:97:2d:c5: - 1c:1e:f4:d0:5b:e9:15:e3:ea:02:09:c8:13:d7:13:70:65:bf: - fb:88:9b:5a:25:be:77:09:e1:a7:6a:4e:11:75:b9:1e:4d:f1: - 00:1b:6a:66:79:8e:c3:6e:d8:6d:a2:22:a2:6d:05:fb:2c:f2: - f1:50:e5:a0:d1:d8:9f:35:7d:fc:70:ab:59:2a:02:f1:be:b0: - d3:f1:f8:cd:12:b9:6a:25:90:5b:e3:85:20:e6:f5:da:cb:40: - 1c:19:34:20:03:61:77:ba:7f:48:0f:49:0b:29:eb:e7:61:64: - c7:63:d1:47:eb:1c:e1:ee:94:46:ef:39:73:cc:ee:4f:2b:8d: - dc:fb:58:a7:b3:65:20:99:95:b9:fb:55:6f:d7:96:6e:94:3d: - f4:7a:92:8e:63:1d:df:6d ------BEGIN CERTIFICATE----- -MIIFjDCCA3SgAwIBAgINAgO8UKMnU/CRgCLt8TANBgkqhkiG9w0BAQsFADBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw -MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFQNTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBALOC8CSMvy2Hr7LZp676yrpE1ls+/rL3smUW3N4Q6E8tEFha -KIaHoe5qs6DZdU9/oVIBi1WoSlsGSMg2EiWrifnyI1+dYGX5XNq+OuhcbX2c0IQY -hTDNTpvsPNiz4ZbU88ULZduPsHTL9h7zePGslcXdc8MxiIGvdKpv/QzjBZXwxRBP -ZWP6oK/GGD3Fod+XedcFibMwsHSuPZIQa4wVd90LBFf7gQPd6iI01eVWsvDEjUGx -wwLbYuyA0P921IbkBBq2tgwrYnF92a/Z8V76wB7KoBlcVfCA0SoMB4aQnzXjKCtb -7yPIox2kozru/oPcgkwlsE3FUa2em9NbhMIaWukCAwEAAaOCAXYwggFyMA4GA1Ud -DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T -AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU1fyeDd8eyt0Il5duK8VfxSv17LgwHwYD -VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG -CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw -AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt -MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsME0G -A1UdIARGMEQwOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br -aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAgEA -bGMn7iPf5VJoTYFmkYXffWXlWzcxCCayB12avrHKAbmtv5139lEd15jFC0mhe6HX -02jlRA+LujbdQoJ30o3d9T/768gHmJPuWtC1Pd5LHC2MTex+jHv+TkD98LSzWQIQ -UVzjwCv9twZIUX4JXj8P3Kf+l+d5xQ5EiXjFaVkpoJo6SDYpppSTVS24R7XplrWf -B82mqz4yisCGg8XBQcifLzWODcAHeuGsyWW1y4qn3XHYYWU5hKwyPvd6NvFWn1ep -QW1akKfbOup1gAxjC2l0bwdMFfM3KKUZpG719iDNY7J+xCsJdYna0Twuck82GqGe -RNDNm6YjCD+XoaeeWqX3CZStXXZdKFbRGmZRUQd73j2wyO8weiQtvrizhvZL9/C1 -T//Oxvn2PyonCA8JPiNax+NCLXo25D2YlmA5mOrR22Mq63gJsU4hs463zj6S8ZVc -pDnQwCvIUxX10i+CzQZ0Z5mQdzcKly3FHB700FvpFePqAgnIE9cTcGW/+4ibWiW+ -dwnhp2pOEXW5Hk3xABtqZnmOw27YbaIiom0F+yzy8VDloNHYnzV9/HCrWSoC8b6w -0/H4zRK5aiWQW+OFIOb12stAHBk0IANhd7p/SA9JCynr52Fkx2PRR+sc4e6URu85 -c8zuTyuN3PtYp7NlIJmVuftVb9eWbpQ99HqSjmMd320= ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 02:03:e5:93:6f:31:b0:13:49:88:6b:a2:17 - Signature Algorithm: sha384WithRSAEncryption - Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1 - Validity - Not Before: Jun 22 00:00:00 2016 GMT - Not After : Jun 22 00:00:00 2036 GMT - Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R1 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (4096 bit) - Modulus: - 00:b6:11:02:8b:1e:e3:a1:77:9b:3b:dc:bf:94:3e: - b7:95:a7:40:3c:a1:fd:82:f9:7d:32:06:82:71:f6: - f6:8c:7f:fb:e8:db:bc:6a:2e:97:97:a3:8c:4b:f9: - 2b:f6:b1:f9:ce:84:1d:b1:f9:c5:97:de:ef:b9:f2: - a3:e9:bc:12:89:5e:a7:aa:52:ab:f8:23:27:cb:a4: - b1:9c:63:db:d7:99:7e:f0:0a:5e:eb:68:a6:f4:c6: - 5a:47:0d:4d:10:33:e3:4e:b1:13:a3:c8:18:6c:4b: - ec:fc:09:90:df:9d:64:29:25:23:07:a1:b4:d2:3d: - 2e:60:e0:cf:d2:09:87:bb:cd:48:f0:4d:c2:c2:7a: - 88:8a:bb:ba:cf:59:19:d6:af:8f:b0:07:b0:9e:31: - f1:82:c1:c0:df:2e:a6:6d:6c:19:0e:b5:d8:7e:26: - 1a:45:03:3d:b0:79:a4:94:28:ad:0f:7f:26:e5:a8: - 08:fe:96:e8:3c:68:94:53:ee:83:3a:88:2b:15:96: - 09:b2:e0:7a:8c:2e:75:d6:9c:eb:a7:56:64:8f:96: - 4f:68:ae:3d:97:c2:84:8f:c0:bc:40:c0:0b:5c:bd: - f6:87:b3:35:6c:ac:18:50:7f:84:e0:4c:cd:92:d3: - 20:e9:33:bc:52:99:af:32:b5:29:b3:25:2a:b4:48: - f9:72:e1:ca:64:f7:e6:82:10:8d:e8:9d:c2:8a:88: - fa:38:66:8a:fc:63:f9:01:f9:78:fd:7b:5c:77:fa: - 76:87:fa:ec:df:b1:0e:79:95:57:b4:bd:26:ef:d6: - 01:d1:eb:16:0a:bb:8e:0b:b5:c5:c5:8a:55:ab:d3: - ac:ea:91:4b:29:cc:19:a4:32:25:4e:2a:f1:65:44: - d0:02:ce:aa:ce:49:b4:ea:9f:7c:83:b0:40:7b:e7: - 43:ab:a7:6c:a3:8f:7d:89:81:fa:4c:a5:ff:d5:8e: - c3:ce:4b:e0:b5:d8:b3:8e:45:cf:76:c0:ed:40:2b: - fd:53:0f:b0:a7:d5:3b:0d:b1:8a:a2:03:de:31:ad: - cc:77:ea:6f:7b:3e:d6:df:91:22:12:e6:be:fa:d8: - 32:fc:10:63:14:51:72:de:5d:d6:16:93:bd:29:68: - 33:ef:3a:66:ec:07:8a:26:df:13:d7:57:65:78:27: - de:5e:49:14:00:a2:00:7f:9a:a8:21:b6:a9:b1:95: - b0:a5:b9:0d:16:11:da:c7:6c:48:3c:40:e0:7e:0d: - 5a:cd:56:3c:d1:97:05:b9:cb:4b:ed:39:4b:9c:c4: - 3f:d2:55:13:6e:24:b0:d6:71:fa:f4:c1:ba:cc:ed: - 1b:f5:fe:81:41:d8:00:98:3d:3a:c8:ae:7a:98:37: - 18:05:95 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E - Signature Algorithm: sha384WithRSAEncryption - Signature Value: - 9f:aa:42:26:db:0b:9b:be:ff:1e:96:92:2e:3e:a2:65:4a:6a: - 98:ba:22:cb:7d:c1:3a:d8:82:0a:06:c6:f6:a5:de:c0:4e:87: - 66:79:a1:f9:a6:58:9c:aa:f9:b5:e6:60:e7:e0:e8:b1:1e:42: - 41:33:0b:37:3d:ce:89:70:15:ca:b5:24:a8:cf:6b:b5:d2:40: - 21:98:cf:22:34:cf:3b:c5:22:84:e0:c5:0e:8a:7c:5d:88:e4: - 35:24:ce:9b:3e:1a:54:1e:6e:db:b2:87:a7:fc:f3:fa:81:55: - 14:62:0a:59:a9:22:05:31:3e:82:d6:ee:db:57:34:bc:33:95: - d3:17:1b:e8:27:a2:8b:7b:4e:26:1a:7a:5a:64:b6:d1:ac:37: - f1:fd:a0:f3:38:ec:72:f0:11:75:9d:cb:34:52:8d:e6:76:6b: - 17:c6:df:86:ab:27:8e:49:2b:75:66:81:10:21:a6:ea:3e:f4: - ae:25:ff:7c:15:de:ce:8c:25:3f:ca:62:70:0a:f7:2f:09:66: - 07:c8:3f:1c:fc:f0:db:45:30:df:62:88:c1:b5:0f:9d:c3:9f: - 4a:de:59:59:47:c5:87:22:36:e6:82:a7:ed:0a:b9:e2:07:a0: - 8d:7b:7a:4a:3c:71:d2:e2:03:a1:1f:32:07:dd:1b:e4:42:ce: - 0c:00:45:61:80:b5:0b:20:59:29:78:bd:f9:55:cb:63:c5:3c: - 4c:f4:b6:ff:db:6a:5f:31:6b:99:9e:2c:c1:6b:50:a4:d7:e6: - 18:14:bd:85:3f:67:ab:46:9f:a0:ff:42:a7:3a:7f:5c:cb:5d: - b0:70:1d:2b:34:f5:d4:76:09:0c:eb:78:4c:59:05:f3:33:42: - c3:61:15:10:1b:77:4d:ce:22:8c:d4:85:f2:45:7d:b7:53:ea: - ef:40:5a:94:0a:5c:20:5f:4e:40:5d:62:22:76:df:ff:ce:61: - bd:8c:23:78:d2:37:02:e0:8e:de:d1:11:37:89:f6:bf:ed:49: - 07:62:ae:92:ec:40:1a:af:14:09:d9:d0:4e:b2:a2:f7:be:ee: - ee:d8:ff:dc:1a:2d:de:b8:36:71:e2:fc:79:b7:94:25:d1:48: - 73:5b:a1:35:e7:b3:99:67:75:c1:19:3a:2b:47:4e:d3:42:8e: - fd:31:c8:16:66:da:d2:0c:3c:db:b3:8e:c9:a1:0d:80:0f:7b: - 16:77:14:bf:ff:db:09:94:b2:93:bc:20:58:15:e9:db:71:43: - f3:de:10:c3:00:dc:a8:2a:95:b6:c2:d6:3f:90:6b:76:db:6c: - fe:8c:bc:f2:70:35:0c:dc:99:19:35:dc:d7:c8:46:63:d5:36: - 71:ae:57:fb:b7:82:6d:dc ------BEGIN CERTIFICATE----- -MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw -MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo -27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w -Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw -TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl -qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH -szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 -Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk -MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 -wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p -aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN -VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID -AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E -FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb -C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe -QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy -h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 -7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J -ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef -MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ -Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT -6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ -0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm -2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb -bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c ------END CERTIFICATE----- diff --git a/certs/GTS-Root-R1.pem b/certs/GTS-Root-R1.pem new file mode 100644 index 0000000..a6095d2 --- /dev/null +++ b/certs/GTS-Root-R1.pem @@ -0,0 +1,38 @@ +# Issuer: CN=GTS Root R1 O=Google Trust Services LLC +# Subject: CN=GTS Root R1 O=Google Trust Services LLC +# Label: "GTS Root R1" +# Serial: 159662320309726417404178440727 +# MD5 Fingerprint: 05:fe:d0:bf:71:a8:a3:76:63:da:01:e0:d8:52:dc:40 +# SHA1 Fingerprint: e5:8c:1c:c4:91:3b:38:63:4b:e9:10:6e:e3:ad:8e:6b:9d:d9:81:4a +# SHA256 Fingerprint: d9:47:43:2a:bd:e7:b7:fa:90:fc:2e:6b:59:10:1b:12:80:e0:e1:c7:e4:e4:0f:a3:c6:88:7f:ff:57:a7:f4:cf +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo +27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w +Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw +TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl +qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH +szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 +Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk +MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p +aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN +VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb +C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy +h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 +7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J +ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef +MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ +Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT +6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ +0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm +2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb +bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c +-----END CERTIFICATE----- diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 443106f..3214368 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -64,7 +64,7 @@ the repository (see `certs` sub directory). /tool/netwatch/add comment="doh, doh-cert=DigiCert Global G2 TLS RSA SHA256 2020 CA1" host=1.1.1.1; /tool/netwatch/add comment="doh, doh-cert=DigiCert TLS Hybrid ECC SHA384 2020 CA1" host=9.9.9.9; - /tool/netwatch/add comment="doh, doh-cert=GTS CA 1C3" host=8.8.8.8; + /tool/netwatch/add comment="doh, doh-cert=GTS Root R1" host=8.8.8.8; Sometimes using just one specific (possibly internal) DNS server may be desired, with fallback in case it fails. This is possible as well: diff --git a/global-functions.rsc b/global-functions.rsc index 567444e..ca8ecb1 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -509,7 +509,7 @@ } :do { - :if ([ $CertificateAvailable "GTS CA 1P5" ] = false) do={ + :if ([ $CertificateAvailable "GTS Root R1" ] = false) do={ $LogPrint warning $0 ("Downloading required certificate failed."); :error false; } From 588dacb5af93819021b71a88f200464359dee701 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jun 2024 10:47:42 +0200 Subject: [PATCH 2243/2612] certs: Go Daddy Secure Certificate Authority - G2 -> Go Daddy Root Certificate Authority - G2 --- ...Go-Daddy-Root-Certificate-Authority-G2.pem | 30 +++ ...-Daddy-Secure-Certificate-Authority-G2.pem | 178 ------------------ mod/notification-telegram.rsc | 2 +- telegram-chat.rsc | 2 +- 4 files changed, 32 insertions(+), 180 deletions(-) create mode 100644 certs/Go-Daddy-Root-Certificate-Authority-G2.pem delete mode 100644 certs/Go-Daddy-Secure-Certificate-Authority-G2.pem diff --git a/certs/Go-Daddy-Root-Certificate-Authority-G2.pem b/certs/Go-Daddy-Root-Certificate-Authority-G2.pem new file mode 100644 index 0000000..c61f300 --- /dev/null +++ b/certs/Go-Daddy-Root-Certificate-Authority-G2.pem @@ -0,0 +1,30 @@ +# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Label: "Go Daddy Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 +# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b +# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- diff --git a/certs/Go-Daddy-Secure-Certificate-Authority-G2.pem b/certs/Go-Daddy-Secure-Certificate-Authority-G2.pem deleted file mode 100644 index 4faba90..0000000 --- a/certs/Go-Daddy-Secure-Certificate-Authority-G2.pem +++ /dev/null @@ -1,178 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 7 (0x7) - Signature Algorithm: sha256WithRSAEncryption - Issuer: C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", CN = Go Daddy Root Certificate Authority - G2 - Validity - Not Before: May 3 07:00:00 2011 GMT - Not After : May 3 07:00:00 2031 GMT - Subject: C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", OU = http://certs.godaddy.com/repository/, CN = Go Daddy Secure Certificate Authority - G2 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:b9:e0:cb:10:d4:af:76:bd:d4:93:62:eb:30:64: - b8:81:08:6c:c3:04:d9:62:17:8e:2f:ff:3e:65:cf: - 8f:ce:62:e6:3c:52:1c:da:16:45:4b:55:ab:78:6b: - 63:83:62:90:ce:0f:69:6c:99:c8:1a:14:8b:4c:cc: - 45:33:ea:88:dc:9e:a3:af:2b:fe:80:61:9d:79:57: - c4:cf:2e:f4:3f:30:3c:5d:47:fc:9a:16:bc:c3:37: - 96:41:51:8e:11:4b:54:f8:28:be:d0:8c:be:f0:30: - 38:1e:f3:b0:26:f8:66:47:63:6d:de:71:26:47:8f: - 38:47:53:d1:46:1d:b4:e3:dc:00:ea:45:ac:bd:bc: - 71:d9:aa:6f:00:db:db:cd:30:3a:79:4f:5f:4c:47: - f8:1d:ef:5b:c2:c4:9d:60:3b:b1:b2:43:91:d8:a4: - 33:4e:ea:b3:d6:27:4f:ad:25:8a:a5:c6:f4:d5:d0: - a6:ae:74:05:64:57:88:b5:44:55:d4:2d:2a:3a:3e: - f8:b8:bd:e9:32:0a:02:94:64:c4:16:3a:50:f1:4a: - ae:e7:79:33:af:0c:20:07:7f:e8:df:04:39:c2:69: - 02:6c:63:52:fa:77:c1:1b:c8:74:87:c8:b9:93:18: - 50:54:35:4b:69:4e:bc:3b:d3:49:2e:1f:dc:c1:d2: - 52:fb - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - 40:C2:BD:27:8E:CC:34:83:30:A2:33:D7:FB:6C:B3:F0:B4:2C:80:CE - X509v3 Authority Key Identifier: - keyid:3A:9A:85:07:10:67:28:B6:EF:F6:BD:05:41:6E:20:C1:94:DA:0F:DE - - Authority Information Access: - OCSP - URI:http://ocsp.godaddy.com/ - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://crl.godaddy.com/gdroot-g2.crl - - X509v3 Certificate Policies: - Policy: X509v3 Any Policy - CPS: https://certs.godaddy.com/repository/ - - Signature Algorithm: sha256WithRSAEncryption - 08:7e:6c:93:10:c8:38:b8:96:a9:90:4b:ff:a1:5f:4f:04:ef: - 6c:3e:9c:88:06:c9:50:8f:a6:73:f7:57:31:1b:be:bc:e4:2f: - db:f8:ba:d3:5b:e0:b4:e7:e6:79:62:0e:0c:a2:d7:6a:63:73: - 31:b5:f5:a8:48:a4:3b:08:2d:a2:5d:90:d7:b4:7c:25:4f:11: - 56:30:c4:b6:44:9d:7b:2c:9d:e5:5e:e6:ef:0c:61:aa:bf:e4: - 2a:1b:ee:84:9e:b8:83:7d:c1:43:ce:44:a7:13:70:0d:91:1f: - f4:c8:13:ad:83:60:d9:d8:72:a8:73:24:1e:b5:ac:22:0e:ca: - 17:89:62:58:44:1b:ab:89:25:01:00:0f:cd:c4:1b:62:db:51: - b4:d3:0f:51:2a:9b:f4:bc:73:fc:76:ce:36:a4:cd:d9:d8:2c: - ea:ae:9b:f5:2a:b2:90:d1:4d:75:18:8a:3f:8a:41:90:23:7d: - 5b:4b:fe:a4:03:58:9b:46:b2:c3:60:60:83:f8:7d:50:41:ce: - c2:a1:90:c3:bb:ef:02:2f:d2:15:54:ee:44:15:d9:0a:ae:a7: - 8a:33:ed:b1:2d:76:36:26:dc:04:eb:9f:f7:61:1f:15:dc:87: - 6f:ee:46:96:28:ad:a1:26:7d:0a:09:a7:2e:04:a3:8d:bc:f8: - bc:04:30:01 ------BEGIN CERTIFICATE----- -MIIE0DCCA7igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT -EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp -ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAwMFoXDTMxMDUwMzA3 -MDAwMFowgbQxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH -EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjEtMCsGA1UE -CxMkaHR0cDovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMTMwMQYDVQQD -EypHbyBEYWRkeSBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC54MsQ1K92vdSTYuswZLiBCGzD -BNliF44v/z5lz4/OYuY8UhzaFkVLVat4a2ODYpDOD2lsmcgaFItMzEUz6ojcnqOv -K/6AYZ15V8TPLvQ/MDxdR/yaFrzDN5ZBUY4RS1T4KL7QjL7wMDge87Am+GZHY23e -cSZHjzhHU9FGHbTj3ADqRay9vHHZqm8A29vNMDp5T19MR/gd71vCxJ1gO7GyQ5HY -pDNO6rPWJ0+tJYqlxvTV0KaudAVkV4i1RFXULSo6Pvi4vekyCgKUZMQWOlDxSq7n -eTOvDCAHf+jfBDnCaQJsY1L6d8EbyHSHyLmTGFBUNUtpTrw700kuH9zB0lL7AgMB -AAGjggEaMIIBFjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV -HQ4EFgQUQMK9J47MNIMwojPX+2yz8LQsgM4wHwYDVR0jBBgwFoAUOpqFBxBnKLbv -9r0FQW4gwZTaD94wNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v -b2NzcC5nb2RhZGR5LmNvbS8wNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL2NybC5n -b2RhZGR5LmNvbS9nZHJvb3QtZzIuY3JsMEYGA1UdIAQ/MD0wOwYEVR0gADAzMDEG -CCsGAQUFBwIBFiVodHRwczovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkv -MA0GCSqGSIb3DQEBCwUAA4IBAQAIfmyTEMg4uJapkEv/oV9PBO9sPpyIBslQj6Zz -91cxG7685C/b+LrTW+C05+Z5Yg4MotdqY3MxtfWoSKQ7CC2iXZDXtHwlTxFWMMS2 -RJ17LJ3lXubvDGGqv+QqG+6EnriDfcFDzkSnE3ANkR/0yBOtg2DZ2HKocyQetawi -DsoXiWJYRBuriSUBAA/NxBti21G00w9RKpv0vHP8ds42pM3Z2Czqrpv1KrKQ0U11 -GIo/ikGQI31bS/6kA1ibRrLDYGCD+H1QQc7CoZDDu+8CL9IVVO5EFdkKrqeKM+2x -LXY2JtwE65/3YR8V3Idv7kaWKK2hJn0KCacuBKONvPi8BDAB ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 0 (0x0) - Signature Algorithm: sha256WithRSAEncryption - Issuer: C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", CN = Go Daddy Root Certificate Authority - G2 - Validity - Not Before: Sep 1 00:00:00 2009 GMT - Not After : Dec 31 23:59:59 2037 GMT - Subject: C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", CN = Go Daddy Root Certificate Authority - G2 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:bf:71:62:08:f1:fa:59:34:f7:1b:c9:18:a3:f7: - 80:49:58:e9:22:83:13:a6:c5:20:43:01:3b:84:f1: - e6:85:49:9f:27:ea:f6:84:1b:4e:a0:b4:db:70:98: - c7:32:01:b1:05:3e:07:4e:ee:f4:fa:4f:2f:59:30: - 22:e7:ab:19:56:6b:e2:80:07:fc:f3:16:75:80:39: - 51:7b:e5:f9:35:b6:74:4e:a9:8d:82:13:e4:b6:3f: - a9:03:83:fa:a2:be:8a:15:6a:7f:de:0b:c3:b6:19: - 14:05:ca:ea:c3:a8:04:94:3b:46:7c:32:0d:f3:00: - 66:22:c8:8d:69:6d:36:8c:11:18:b7:d3:b2:1c:60: - b4:38:fa:02:8c:ce:d3:dd:46:07:de:0a:3e:eb:5d: - 7c:c8:7c:fb:b0:2b:53:a4:92:62:69:51:25:05:61: - 1a:44:81:8c:2c:a9:43:96:23:df:ac:3a:81:9a:0e: - 29:c5:1c:a9:e9:5d:1e:b6:9e:9e:30:0a:39:ce:f1: - 88:80:fb:4b:5d:cc:32:ec:85:62:43:25:34:02:56: - 27:01:91:b4:3b:70:2a:3f:6e:b1:e8:9c:88:01:7d: - 9f:d4:f9:db:53:6d:60:9d:bf:2c:e7:58:ab:b8:5f: - 46:fc:ce:c4:1b:03:3c:09:eb:49:31:5c:69:46:b3: - e0:47 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - 3A:9A:85:07:10:67:28:B6:EF:F6:BD:05:41:6E:20:C1:94:DA:0F:DE - Signature Algorithm: sha256WithRSAEncryption - 99:db:5d:79:d5:f9:97:59:67:03:61:f1:7e:3b:06:31:75:2d: - a1:20:8e:4f:65:87:b4:f7:a6:9c:bc:d8:e9:2f:d0:db:5a:ee: - cf:74:8c:73:b4:38:42:da:05:7b:f8:02:75:b8:fd:a5:b1:d7: - ae:f6:d7:de:13:cb:53:10:7e:8a:46:d1:97:fa:b7:2e:2b:11: - ab:90:b0:27:80:f9:e8:9f:5a:e9:37:9f:ab:e4:df:6c:b3:85: - 17:9d:3d:d9:24:4f:79:91:35:d6:5f:04:eb:80:83:ab:9a:02: - 2d:b5:10:f4:d8:90:c7:04:73:40:ed:72:25:a0:a9:9f:ec:9e: - ab:68:12:99:57:c6:8f:12:3a:09:a4:bd:44:fd:06:15:37:c1: - 9b:e4:32:a3:ed:38:e8:d8:64:f3:2c:7e:14:fc:02:ea:9f:cd: - ff:07:68:17:db:22:90:38:2d:7a:8d:d1:54:f1:69:e3:5f:33: - ca:7a:3d:7b:0a:e3:ca:7f:5f:39:e5:e2:75:ba:c5:76:18:33: - ce:2c:f0:2f:4c:ad:f7:b1:e7:ce:4f:a8:c4:9b:4a:54:06:c5: - 7f:7d:d5:08:0f:e2:1c:fe:7e:17:b8:ac:5e:f6:d4:16:b2:43: - 09:0c:4d:f6:a7:6b:b4:99:84:65:ca:7a:88:e2:e2:44:be:5c: - f7:ea:1c:f5 ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT -EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp -ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz -NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH -EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE -AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD -E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH -/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy -DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh -GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR -tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA -AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX -WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu -9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr -gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo -2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO -LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI -4uJEvlz36hz1 ------END CERTIFICATE----- diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 9a628ce..1890483 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -143,7 +143,7 @@ } :do { - :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ + :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={ $LogPrint warning $0 ("Downloading required certificate failed."); :error false; } diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 0fd8a06..1c274ec 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -55,7 +55,7 @@ :set TelegramRandomDelay 0; } - :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ + :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={ $LogPrint warning $ScriptName ("Downloading required certificate failed."); :error false; } From a05efdc07fa912d0d17f4994ee9e892b51030be1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jun 2024 10:55:13 +0200 Subject: [PATCH 2244/2612] certs: DigiCert Global G2 TLS RSA SHA256 2020 CA1 -> DigiCert Global Root G2 This is used by Cloudflare DNS (1.1.1.1). $CertificateAvailable "DigiCert Global Root G2"; /ip/dns/set use-doh-server=https://1.1.1.1/dns-query verify-doh-cert=yes; --- ...Cert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem | 182 ------------------ certs/DigiCert-Global-Root-G2.pem | 29 +++ doc/netwatch-dns.md | 2 +- 3 files changed, 30 insertions(+), 183 deletions(-) delete mode 100644 certs/DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem create mode 100644 certs/DigiCert-Global-Root-G2.pem diff --git a/certs/DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem b/certs/DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem deleted file mode 100644 index 12084ee..0000000 --- a/certs/DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem +++ /dev/null @@ -1,182 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 0c:f5:bd:06:2b:56:02:f4:7a:b8:50:2c:23:cc:f0:66 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2 - Validity - Not Before: Mar 30 00:00:00 2021 GMT - Not After : Mar 29 23:59:59 2031 GMT - Subject: C=US, O=DigiCert Inc, CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:cc:f7:10:62:4f:a6:bb:63:6f:ed:90:52:56:c5: - 6d:27:7b:7a:12:56:8a:f1:f4:f9:d6:e7:e1:8f:bd: - 95:ab:f2:60:41:15:70:db:12:00:fa:27:0a:b5:57: - 38:5b:7d:b2:51:93:71:95:0e:6a:41:94:5b:35:1b: - fa:7b:fa:bb:c5:be:24:30:fe:56:ef:c4:f3:7d:97: - e3:14:f5:14:4d:cb:a7:10:f2:16:ea:ab:22:f0:31: - 22:11:61:69:90:26:ba:78:d9:97:1f:e3:7d:66:ab: - 75:44:95:73:c8:ac:ff:ef:5d:0a:8a:59:43:e1:ac: - b2:3a:0f:f3:48:fc:d7:6b:37:c1:63:dc:de:46:d6: - db:45:fe:7d:23:fd:90:e8:51:07:1e:51:a3:5f:ed: - 49:46:54:7f:2c:88:c5:f4:13:9c:97:15:3c:03:e8: - a1:39:dc:69:0c:32:c1:af:16:57:4c:94:47:42:7c: - a2:c8:9c:7d:e6:d4:4d:54:af:42:99:a8:c1:04:c2: - 77:9c:d6:48:e4:ce:11:e0:2a:80:99:f0:43:70:cf: - 3f:76:6b:d1:4c:49:ab:24:5e:c2:0d:82:fd:46:a8: - ab:6c:93:cc:62:52:42:75:92:f8:9a:fa:5e:5e:b2: - b0:61:e5:1f:1f:b9:7f:09:98:e8:3d:fa:83:7f:47: - 69:a1 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - 74:85:80:C0:66:C7:DF:37:DE:CF:BD:29:37:AA:03:1D:BE:ED:CD:17 - X509v3 Authority Key Identifier: - 4E:22:54:20:18:95:E6:E3:6E:E6:0F:FA:FA:B9:12:ED:06:17:8F:39 - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - Authority Information Access: - OCSP - URI:http://ocsp.digicert.com - CA Issuers - URI:http://cacerts.digicert.com/DigiCertGlobalRootG2.crt - X509v3 CRL Distribution Points: - Full Name: - URI:http://crl3.digicert.com/DigiCertGlobalRootG2.crl - X509v3 Certificate Policies: - Policy: 2.16.840.1.114412.2.1 - Policy: 2.23.140.1.1 - Policy: 2.23.140.1.2.1 - Policy: 2.23.140.1.2.2 - Policy: 2.23.140.1.2.3 - Signature Algorithm: sha256WithRSAEncryption - Signature Value: - 90:f1:70:cb:28:97:69:97:7c:74:fd:c0:fa:26:7b:53:ab:ad: - cd:65:fd:ba:9c:06:9c:8a:d7:5a:43:87:ed:4d:4c:56:5f:ad: - c1:c5:b5:05:20:2e:59:d1:ff:4a:f5:a0:2a:d8:b0:95:ad:c9: - 2e:4a:3b:d7:a7:f6:6f:88:29:fc:30:3f:24:84:bb:c3:b7:7b: - 93:07:2c:af:87:6b:76:33:ed:00:55:52:b2:59:9e:e4:b9:d0: - f3:df:e7:0f:fe:dd:f8:c4:b9:10:72:81:09:04:5f:cf:97:9e: - 2e:32:75:8e:cf:9a:58:d2:57:31:7e:37:01:81:b2:66:6d:29: - 1a:b1:66:09:6d:d1:6e:90:f4:b9:fa:2f:01:14:c5:5c:56:64: - 01:d9:7d:87:a8:38:53:9f:8b:5d:46:6d:5c:c6:27:84:81:d4: - 7e:8c:8c:a3:9b:52:e7:c6:88:ec:37:7c:2a:fb:f0:55:5a:38: - 72:10:d8:00:13:cf:4c:73:db:aa:37:35:a8:29:81:69:9c:76: - bc:de:18:7b:90:d4:ca:cf:ef:67:03:fd:04:5a:21:16:b1:ff: - ea:3f:df:dc:82:f5:eb:f4:59:92:23:0d:24:2a:95:25:4c:ca: - a1:91:e6:d4:b7:ac:87:74:b3:f1:6d:a3:99:db:f9:d5:bd:84: - 40:9f:07:98 ------BEGIN CERTIFICATE----- -MIIEyDCCA7CgAwIBAgIQDPW9BitWAvR6uFAsI8zwZjANBgkqhkiG9w0BAQsFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH -MjAeFw0yMTAzMzAwMDAwMDBaFw0zMTAzMjkyMzU5NTlaMFkxCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMzAxBgNVBAMTKkRpZ2lDZXJ0IEdsb2Jh -bCBHMiBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAMz3EGJPprtjb+2QUlbFbSd7ehJWivH0+dbn4Y+9lavyYEEV -cNsSAPonCrVXOFt9slGTcZUOakGUWzUb+nv6u8W+JDD+Vu/E832X4xT1FE3LpxDy -FuqrIvAxIhFhaZAmunjZlx/jfWardUSVc8is/+9dCopZQ+GssjoP80j812s3wWPc -3kbW20X+fSP9kOhRBx5Ro1/tSUZUfyyIxfQTnJcVPAPooTncaQwywa8WV0yUR0J8 -osicfebUTVSvQpmowQTCd5zWSOTOEeAqgJnwQ3DPP3Zr0UxJqyRewg2C/Uaoq2yT -zGJSQnWS+Jr6Xl6ysGHlHx+5fwmY6D36g39HaaECAwEAAaOCAYIwggF+MBIGA1Ud -EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFHSFgMBmx9833s+9KTeqAx2+7c0XMB8G -A1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485MA4GA1UdDwEB/wQEAwIBhjAd -BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYIKwYBBQUHAQEEajBoMCQG -CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQAYIKwYBBQUHMAKG -NGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RH -Mi5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29t -L0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDA9BgNVHSAENjA0MAsGCWCGSAGG/WwC -ATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgGBmeBDAECAzANBgkqhkiG -9w0BAQsFAAOCAQEAkPFwyyiXaZd8dP3A+iZ7U6utzWX9upwGnIrXWkOH7U1MVl+t -wcW1BSAuWdH/SvWgKtiwla3JLko716f2b4gp/DA/JIS7w7d7kwcsr4drdjPtAFVS -slme5LnQ89/nD/7d+MS5EHKBCQRfz5eeLjJ1js+aWNJXMX43AYGyZm0pGrFmCW3R -bpD0ufovARTFXFZkAdl9h6g4U5+LXUZtXMYnhIHUfoyMo5tS58aI7Dd8KvvwVVo4 -chDYABPPTHPbqjc1qCmBaZx2vN4Ye5DUys/vZwP9BFohFrH/6j/f3IL16/RZkiMN -JCqVJUzKoZHm1Lesh3Sz8W2jmdv51b2EQJ8HmA== ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 03:3a:f1:e6:a7:11:a9:a0:bb:28:64:b1:1d:09:fa:e5 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2 - Validity - Not Before: Aug 1 12:00:00 2013 GMT - Not After : Jan 15 12:00:00 2038 GMT - Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:bb:37:cd:34:dc:7b:6b:c9:b2:68:90:ad:4a:75: - ff:46:ba:21:0a:08:8d:f5:19:54:c9:fb:88:db:f3: - ae:f2:3a:89:91:3c:7a:e6:ab:06:1a:6b:cf:ac:2d: - e8:5e:09:24:44:ba:62:9a:7e:d6:a3:a8:7e:e0:54: - 75:20:05:ac:50:b7:9c:63:1a:6c:30:dc:da:1f:19: - b1:d7:1e:de:fd:d7:e0:cb:94:83:37:ae:ec:1f:43: - 4e:dd:7b:2c:d2:bd:2e:a5:2f:e4:a9:b8:ad:3a:d4: - 99:a4:b6:25:e9:9b:6b:00:60:92:60:ff:4f:21:49: - 18:f7:67:90:ab:61:06:9c:8f:f2:ba:e9:b4:e9:92: - 32:6b:b5:f3:57:e8:5d:1b:cd:8c:1d:ab:95:04:95: - 49:f3:35:2d:96:e3:49:6d:dd:77:e3:fb:49:4b:b4: - ac:55:07:a9:8f:95:b3:b4:23:bb:4c:6d:45:f0:f6: - a9:b2:95:30:b4:fd:4c:55:8c:27:4a:57:14:7c:82: - 9d:cd:73:92:d3:16:4a:06:0c:8c:50:d1:8f:1e:09: - be:17:a1:e6:21:ca:fd:83:e5:10:bc:83:a5:0a:c4: - 67:28:f6:73:14:14:3d:46:76:c3:87:14:89:21:34: - 4d:af:0f:45:0c:a6:49:a1:ba:bb:9c:c5:b1:33:83: - 29:85 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - 4E:22:54:20:18:95:E6:E3:6E:E6:0F:FA:FA:B9:12:ED:06:17:8F:39 - Signature Algorithm: sha256WithRSAEncryption - Signature Value: - 60:67:28:94:6f:0e:48:63:eb:31:dd:ea:67:18:d5:89:7d:3c: - c5:8b:4a:7f:e9:be:db:2b:17:df:b0:5f:73:77:2a:32:13:39: - 81:67:42:84:23:f2:45:67:35:ec:88:bf:f8:8f:b0:61:0c:34: - a4:ae:20:4c:84:c6:db:f8:35:e1:76:d9:df:a6:42:bb:c7:44: - 08:86:7f:36:74:24:5a:da:6c:0d:14:59:35:bd:f2:49:dd:b6: - 1f:c9:b3:0d:47:2a:3d:99:2f:bb:5c:bb:b5:d4:20:e1:99:5f: - 53:46:15:db:68:9b:f0:f3:30:d5:3e:31:e2:8d:84:9e:e3:8a: - da:da:96:3e:35:13:a5:5f:f0:f9:70:50:70:47:41:11:57:19: - 4e:c0:8f:ae:06:c4:95:13:17:2f:1b:25:9f:75:f2:b1:8e:99: - a1:6f:13:b1:41:71:fe:88:2a:c8:4f:10:20:55:d7:f3:14:45: - e5:e0:44:f4:ea:87:95:32:93:0e:fe:53:46:fa:2c:9d:ff:8b: - 22:b9:4b:d9:09:45:a4:de:a4:b8:9a:58:dd:1b:7d:52:9f:8e: - 59:43:88:81:a4:9e:26:d5:6f:ad:dd:0d:c6:37:7d:ed:03:92: - 1b:e5:77:5f:76:ee:3c:8d:c4:5d:56:5b:a2:d9:66:6e:b3:35: - 37:e5:32:b6 ------BEGIN CERTIFICATE----- -MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH -MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI -2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx -1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ -q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz -tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ -vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP -BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV -5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY -1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 -NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG -Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 -8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe -pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl -MrY= ------END CERTIFICATE----- diff --git a/certs/DigiCert-Global-Root-G2.pem b/certs/DigiCert-Global-Root-G2.pem new file mode 100644 index 0000000..8af6c7a --- /dev/null +++ b/certs/DigiCert-Global-Root-G2.pem @@ -0,0 +1,29 @@ +# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G2" +# Serial: 4293743540046975378534879503202253541 +# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 +# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 +# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 3214368..3d2c6be 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -62,7 +62,7 @@ manually! Importing a certificate automatically is possible, at least if available in the repository (see `certs` sub directory). - /tool/netwatch/add comment="doh, doh-cert=DigiCert Global G2 TLS RSA SHA256 2020 CA1" host=1.1.1.1; + /tool/netwatch/add comment="doh, doh-cert=DigiCert Global Root G2" host=1.1.1.1; /tool/netwatch/add comment="doh, doh-cert=DigiCert TLS Hybrid ECC SHA384 2020 CA1" host=9.9.9.9; /tool/netwatch/add comment="doh, doh-cert=GTS Root R1" host=8.8.8.8; From c4e8d01de19f9c5e1d19c74c010079233c4d4df5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jun 2024 10:57:16 +0200 Subject: [PATCH 2245/2612] certs: DigiCert TLS Hybrid ECC SHA384 2020 CA1 -> DigiCert Global Root CA This is used by Cloudflare DNS Quard9 (9.9.9.9). $CertificateAvailable "DigiCert Global Root CA"; /ip/dns/set use-doh-server=https://9.9.9.9/dns-query verify-doh-cert=yes; --- certs/DigiCert-Global-Root-CA.pem | 29 +++ ...igiCert-TLS-Hybrid-ECC-SHA384-2020-CA1.pem | 174 ------------------ doc/netwatch-dns.md | 2 +- 3 files changed, 30 insertions(+), 175 deletions(-) create mode 100644 certs/DigiCert-Global-Root-CA.pem delete mode 100644 certs/DigiCert-TLS-Hybrid-ECC-SHA384-2020-CA1.pem diff --git a/certs/DigiCert-Global-Root-CA.pem b/certs/DigiCert-Global-Root-CA.pem new file mode 100644 index 0000000..b0f0013 --- /dev/null +++ b/certs/DigiCert-Global-Root-CA.pem @@ -0,0 +1,29 @@ +# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root CA" +# Serial: 10944719598952040374951832963794454346 +# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e +# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 +# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- diff --git a/certs/DigiCert-TLS-Hybrid-ECC-SHA384-2020-CA1.pem b/certs/DigiCert-TLS-Hybrid-ECC-SHA384-2020-CA1.pem deleted file mode 100644 index 446f56f..0000000 --- a/certs/DigiCert-TLS-Hybrid-ECC-SHA384-2020-CA1.pem +++ /dev/null @@ -1,174 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 07:f2:f3:5c:87:a8:77:af:7a:ef:e9:47:99:35:25:bd - Signature Algorithm: sha384WithRSAEncryption - Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA - Validity - Not Before: Apr 14 00:00:00 2021 GMT - Not After : Apr 13 23:59:59 2031 GMT - Subject: C = US, O = DigiCert Inc, CN = DigiCert TLS Hybrid ECC SHA384 2020 CA1 - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (384 bit) - pub: - 04:c1:1b:c6:9a:5b:98:d9:a4:29:a0:e9:d4:04:b5: - db:eb:a6:b2:6c:55:c0:ff:ed:98:c6:49:2f:06:27: - 51:cb:bf:70:c1:05:7a:c3:b1:9d:87:89:ba:ad:b4: - 13:17:c9:a8:b4:83:c8:b8:90:d1:cc:74:35:36:3c: - 83:72:b0:b5:d0:f7:22:69:c8:f1:80:c4:7b:40:8f: - cf:68:87:26:5c:39:89:f1:4d:91:4d:da:89:8b:e4: - 03:c3:43:e5:bf:2f:73 - ASN1 OID: secp384r1 - NIST CURVE: P-384 - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - 0A:BC:08:29:17:8C:A5:39:6D:7A:0E:CE:33:C7:2E:B3:ED:FB:C3:7A - X509v3 Authority Key Identifier: - keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 - - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Server Authentication, TLS Web Client Authentication - Authority Information Access: - OCSP - URI:http://ocsp.digicert.com - CA Issuers - URI:http://cacerts.digicert.com/DigiCertGlobalRootCA.crt - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://crl3.digicert.com/DigiCertGlobalRootCA.crl - - X509v3 Certificate Policies: - Policy: 2.16.840.1.114412.2.1 - Policy: 2.23.140.1.1 - Policy: 2.23.140.1.2.1 - Policy: 2.23.140.1.2.2 - Policy: 2.23.140.1.2.3 - - Signature Algorithm: sha384WithRSAEncryption - 47:59:81:7f:d4:1b:1f:b0:71:f6:98:5d:18:ba:98:47:98:b0: - 7e:76:2b:ea:ff:1a:8b:ac:26:b3:42:8d:31:e6:4a:e8:19:d0: - ef:da:14:e7:d7:14:92:a1:92:f2:a7:2e:2d:af:fb:1d:f6:fb: - 53:b0:8a:3f:fc:d8:16:0a:e9:b0:2e:b6:a5:0b:18:90:35:26: - a2:da:f6:a8:b7:32:fc:95:23:4b:c6:45:b9:c4:cf:e4:7c:ee: - e6:c9:f8:90:bd:72:e3:99:c3:1d:0b:05:7c:6a:97:6d:b2:ab: - 02:36:d8:c2:bc:2c:01:92:3f:04:a3:8b:75:11:c7:b9:29:bc: - 11:d0:86:ba:92:bc:26:f9:65:c8:37:cd:26:f6:86:13:0c:04: - aa:89:e5:78:b1:c1:4e:79:bc:76:a3:0b:51:e4:c5:d0:9e:6a: - fe:1a:2c:56:ae:06:36:27:a3:73:1c:08:7d:93:32:d0:c2:44: - 19:da:8d:f4:0e:7b:1d:28:03:2b:09:8a:76:ca:77:dc:87:7a: - ac:7b:52:26:55:a7:72:0f:9d:d2:88:4f:fe:b1:21:c5:1a:a1: - aa:39:f5:56:db:c2:84:c4:35:1f:70:da:bb:46:f0:86:bf:64: - 00:c4:3e:f7:9f:46:1b:9d:23:05:b9:7d:b3:4f:0f:a9:45:3a: - e3:74:30:98 ------BEGIN CERTIFICATE----- -MIIEFzCCAv+gAwIBAgIQB/LzXIeod6967+lHmTUlvTANBgkqhkiG9w0BAQwFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0yMTA0MTQwMDAwMDBaFw0zMTA0MTMyMzU5NTlaMFYxCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMDAuBgNVBAMTJ0RpZ2lDZXJ0IFRMUyBI -eWJyaWQgRUNDIFNIQTM4NCAyMDIwIENBMTB2MBAGByqGSM49AgEGBSuBBAAiA2IA -BMEbxppbmNmkKaDp1AS12+umsmxVwP/tmMZJLwYnUcu/cMEFesOxnYeJuq20ExfJ -qLSDyLiQ0cx0NTY8g3KwtdD3ImnI8YDEe0CPz2iHJlw5ifFNkU3aiYvkA8ND5b8v -c6OCAYIwggF+MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFAq8CCkXjKU5 -bXoOzjPHLrPt+8N6MB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA4G -A1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYI -KwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j -b20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp -Q2VydEdsb2JhbFJvb3RDQS5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2Ny -bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDA9BgNVHSAE -NjA0MAsGCWCGSAGG/WwCATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgG -BmeBDAECAzANBgkqhkiG9w0BAQwFAAOCAQEAR1mBf9QbH7Bx9phdGLqYR5iwfnYr -6v8ai6wms0KNMeZK6BnQ79oU59cUkqGS8qcuLa/7Hfb7U7CKP/zYFgrpsC62pQsY -kDUmotr2qLcy/JUjS8ZFucTP5Hzu5sn4kL1y45nDHQsFfGqXbbKrAjbYwrwsAZI/ -BKOLdRHHuSm8EdCGupK8JvllyDfNJvaGEwwEqonleLHBTnm8dqMLUeTF0J5q/hos -Vq4GNiejcxwIfZMy0MJEGdqN9A57HSgDKwmKdsp33Id6rHtSJlWncg+d0ohP/rEh -xRqhqjn1VtvChMQ1H3Dau0bwhr9kAMQ+959GG50jBbl9s08PqUU643QwmA== ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 08:3b:e0:56:90:42:46:b1:a1:75:6a:c9:59:91:c7:4a - Signature Algorithm: sha1WithRSAEncryption - Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA - Validity - Not Before: Nov 10 00:00:00 2006 GMT - Not After : Nov 10 00:00:00 2031 GMT - Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:e2:3b:e1:11:72:de:a8:a4:d3:a3:57:aa:50:a2: - 8f:0b:77:90:c9:a2:a5:ee:12:ce:96:5b:01:09:20: - cc:01:93:a7:4e:30:b7:53:f7:43:c4:69:00:57:9d: - e2:8d:22:dd:87:06:40:00:81:09:ce:ce:1b:83:bf: - df:cd:3b:71:46:e2:d6:66:c7:05:b3:76:27:16:8f: - 7b:9e:1e:95:7d:ee:b7:48:a3:08:da:d6:af:7a:0c: - 39:06:65:7f:4a:5d:1f:bc:17:f8:ab:be:ee:28:d7: - 74:7f:7a:78:99:59:85:68:6e:5c:23:32:4b:bf:4e: - c0:e8:5a:6d:e3:70:bf:77:10:bf:fc:01:f6:85:d9: - a8:44:10:58:32:a9:75:18:d5:d1:a2:be:47:e2:27: - 6a:f4:9a:33:f8:49:08:60:8b:d4:5f:b4:3a:84:bf: - a1:aa:4a:4c:7d:3e:cf:4f:5f:6c:76:5e:a0:4b:37: - 91:9e:dc:22:e6:6d:ce:14:1a:8e:6a:cb:fe:cd:b3: - 14:64:17:c7:5b:29:9e:32:bf:f2:ee:fa:d3:0b:42: - d4:ab:b7:41:32:da:0c:d4:ef:f8:81:d5:bb:8d:58: - 3f:b5:1b:e8:49:28:a2:70:da:31:04:dd:f7:b2:16: - f2:4c:0a:4e:07:a8:ed:4a:3d:5e:b5:7f:a3:90:c3: - af:27 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - 03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 - X509v3 Authority Key Identifier: - keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 - - Signature Algorithm: sha1WithRSAEncryption - cb:9c:37:aa:48:13:12:0a:fa:dd:44:9c:4f:52:b0:f4:df:ae: - 04:f5:79:79:08:a3:24:18:fc:4b:2b:84:c0:2d:b9:d5:c7:fe: - f4:c1:1f:58:cb:b8:6d:9c:7a:74:e7:98:29:ab:11:b5:e3:70: - a0:a1:cd:4c:88:99:93:8c:91:70:e2:ab:0f:1c:be:93:a9:ff: - 63:d5:e4:07:60:d3:a3:bf:9d:5b:09:f1:d5:8e:e3:53:f4:8e: - 63:fa:3f:a7:db:b4:66:df:62:66:d6:d1:6e:41:8d:f2:2d:b5: - ea:77:4a:9f:9d:58:e2:2b:59:c0:40:23:ed:2d:28:82:45:3e: - 79:54:92:26:98:e0:80:48:a8:37:ef:f0:d6:79:60:16:de:ac: - e8:0e:cd:6e:ac:44:17:38:2f:49:da:e1:45:3e:2a:b9:36:53: - cf:3a:50:06:f7:2e:e8:c4:57:49:6c:61:21:18:d5:04:ad:78: - 3c:2c:3a:80:6b:a7:eb:af:15:14:e9:d8:89:c1:b9:38:6c:e2: - 91:6c:8a:ff:64:b9:77:25:57:30:c0:1b:24:a3:e1:dc:e9:df: - 47:7c:b5:b4:24:08:05:30:ec:2d:bd:0b:bf:45:bf:50:b9:a9: - f3:eb:98:01:12:ad:c8:88:c6:98:34:5f:8d:0a:3c:c6:e9:d5: - 95:95:6d:de ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB -CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 -nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt -43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P -T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 -gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR -TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw -DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr -hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg -06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF -PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls -YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 3d2c6be..9fe486e 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -63,7 +63,7 @@ Importing a certificate automatically is possible, at least if available in the repository (see `certs` sub directory). /tool/netwatch/add comment="doh, doh-cert=DigiCert Global Root G2" host=1.1.1.1; - /tool/netwatch/add comment="doh, doh-cert=DigiCert TLS Hybrid ECC SHA384 2020 CA1" host=9.9.9.9; + /tool/netwatch/add comment="doh, doh-cert=DigiCert Global Root CA" host=9.9.9.9; /tool/netwatch/add comment="doh, doh-cert=GTS Root R1" host=8.8.8.8; Sometimes using just one specific (possibly internal) DNS server may be From 1a6812ef797a1683cec9678062cfaca367500ad0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jun 2024 20:51:46 +0200 Subject: [PATCH 2246/2612] notify on changes regarding certificates --- global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index ca8ecb1..eb9f638 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 129; +:global ExpectedConfigVersion 130; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index b20bbaf..cf17e7a 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -54,6 +54,7 @@ 127="Added support for authentication to Ntfy notification module."; 128="Added another list from blocklist.de to default configuration for 'fw-addr-lists'."; 129="Extended 'backup-partition' to support RouterOS copy-over - interactively or before feature update."; + 130="Dropped intermediate certificates, depending on just root certificates now."; }; # Migration steps to be applied on script updates From cdb553d39b21e82e70f427b0a7c4e95dc4f2055f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jun 2024 12:25:26 +0200 Subject: [PATCH 2247/2612] global-functions: $CertificateDownload: try fallback to mkcert.org There's a nice API that allows to download certificate by exact common name. Let's use that, as a fallback at least. https://mkcert.org/ --- global-functions.rsc | 41 ++++++++++++++++++++++++++++++----------- news-and-changes.rsc | 1 + 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index eb9f638..26472b8 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 130; +:global ExpectedConfigVersion 131; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -135,6 +135,7 @@ :global ScriptUpdatesBaseUrl; :global ScriptUpdatesUrlSuffix; + :global CertificateAvailable; :global CertificateNameByCN; :global CleanName; :global FetchUserAgentStr; @@ -143,22 +144,40 @@ $LogPrint info $0 ("Downloading and importing certificate with " . \ "CommonName '" . $CommonName . "'."); + :local FileName ([ $CleanName $CommonName ] . ".pem"); :do { - :local FileName ([ $CleanName $CommonName ] . ".pem"); /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $0 ] }) \ ($ScriptUpdatesBaseUrl . "certs/" . $FileName . $ScriptUpdatesUrlSuffix) \ dst-path=$FileName as-value; $WaitForFile $FileName; - /certificate/import file-name=$FileName passphrase="" as-value; - :delay 1s; - /file/remove [ find where name=$FileName ]; - - :foreach Cert in=[ /certificate/find where name~("^" . $FileName . "_[0-9]+\$") ] do={ - $CertificateNameByCN [ /certificate/get $Cert common-name ]; - } } on-error={ - $LogPrint warning $0 ("Failed importing certificate with CommonName '" . $CommonName . "'!"); - :return false; + $LogPrint warning $0 ("Failed downloading certificate with CommonName '" . $CommonName . \ + "' from repository! Trying fallback to mkcert.org..."); + :do { + :if ([ $CertificateAvailable "ISRG Root X1" ] = false) do={ + $LogPrint error $0 ("Downloading required certificate failed."); + :return false; + } + /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $0 ] }) \ + "https://mkcert.org/generate/" http-data=[ :serialize to=json ({ $CommonName }) ] \ + dst-path=$FileName as-value; + $WaitForFile $FileName; + :if ([ /file/get $FileName size ] = 0) do={ + /file/remove $FileName; + :error false; + } + } on-error={ + $LogPrint warning $0 ("Failed downloading certificate with CommonName '" . $CommonName . "'!"); + :return false; + } + } + + /certificate/import file-name=$FileName passphrase="" as-value; + :delay 1s; + /file/remove [ find where name=$FileName ]; + + :foreach Cert in=[ /certificate/find where name~("^" . $FileName . "_[0-9]+\$") ] do={ + $CertificateNameByCN [ /certificate/get $Cert common-name ]; } :return true; } diff --git a/news-and-changes.rsc b/news-and-changes.rsc index cf17e7a..8ddc3d6 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -55,6 +55,7 @@ 128="Added another list from blocklist.de to default configuration for 'fw-addr-lists'."; 129="Extended 'backup-partition' to support RouterOS copy-over - interactively or before feature update."; 130="Dropped intermediate certificates, depending on just root certificates now."; + 131="Enhanced certificate download to fallback to mkcert.org, so all (commonly trusted) root certificates are available now."; }; # Migration steps to be applied on script updates From f3f7d3edc0f6bd895e27019ed5d48e4afafe95fa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 25 Jun 2024 07:55:58 +0200 Subject: [PATCH 2248/2612] check-certificates: limit scope for $CertNew... ... into block where certificate is replaced. This should unbreak renewing with a certificate updated in place. --- check-certificates.rsc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index e9235f1..c9622b7 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -139,7 +139,6 @@ :foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ :local CertVal [ /certificate/get $Cert ]; - :local CertNew; :local LastName; :do { @@ -166,7 +165,7 @@ } 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]+\$") \ + :local 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 ]; @@ -190,13 +189,13 @@ /certificate/remove $Cert; /certificate/set $CertNew name=($CertVal->"name"); - :set CertNewVal; + :set Cert $CertNew; :set CertVal [ /certificate/get $CertNew ]; } $SendNotification2 ({ origin=$ScriptName; silent=true; \ subject=([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed: " . ($CertVal->"name")); \ - message=("A certificate on " . $Identity . " has been renewed.\n\n" . [ $FormatInfo $CertNew ]) }); + message=("A certificate on " . $Identity . " has been renewed.\n\n" . [ $FormatInfo $Cert ]) }); $LogPrint info $ScriptName ("The certificate '" . ($CertVal->"name") . "' has been renewed."); } on-error={ $LogPrint debug $ScriptName ("Could not renew certificate '" . ($CertVal->"name") . "'."); From ce1b635eb2d96706ef0a8b603737062338f92238 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 2 Jul 2024 21:29:14 +0200 Subject: [PATCH 2249/2612] global-functions: $GetMacVendor: cert 'GTS Root R4' --- certs/GTS-Root-R4.pem | 20 ++++++++++++++++++++ global-functions.rsc | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 certs/GTS-Root-R4.pem diff --git a/certs/GTS-Root-R4.pem b/certs/GTS-Root-R4.pem new file mode 100644 index 0000000..16a1c36 --- /dev/null +++ b/certs/GTS-Root-R4.pem @@ -0,0 +1,20 @@ +# Issuer: CN=GTS Root R4 O=Google Trust Services LLC +# Subject: CN=GTS Root R4 O=Google Trust Services LLC +# Label: "GTS Root R4" +# Serial: 159662532700760215368942768210 +# MD5 Fingerprint: 43:96:83:77:19:4d:76:b3:9d:65:52:e4:1d:22:a5:e8 +# SHA1 Fingerprint: 77:d3:03:67:b5:e0:0c:15:f6:0c:38:61:df:7c:e1:3b:92:46:4d:47 +# SHA256 Fingerprint: 34:9d:fa:40:58:c5:e2:63:12:3b:39:8a:e7:95:57:3c:4e:13:13:c8:3f:e6:8f:93:55:6c:d5:e8:03:1b:3c:7d +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi +QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR +HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D +9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 +p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD +-----END CERTIFICATE----- diff --git a/global-functions.rsc b/global-functions.rsc index 26472b8..121c5ec 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -528,7 +528,7 @@ } :do { - :if ([ $CertificateAvailable "GTS Root R1" ] = false) do={ + :if ([ $CertificateAvailable "GTS Root R4" ] = false) do={ $LogPrint warning $0 ("Downloading required certificate failed."); :error false; } From eab9b28cd28b1d12d3f0d178db22acdac5ad1758 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 4 Jul 2024 11:56:56 +0200 Subject: [PATCH 2250/2612] global-functions: $MkDir: enable tmpfs if disabled --- global-functions.rsc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 121c5ec..44b3abe 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -829,7 +829,12 @@ :global LogPrint; :global WaitForFile; - :if ([ :len [ /disk/find where slot=tmpfs type=tmpfs ] ] = 1) do={ + :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ]; + :if ([ :len $TmpFs ] = 1) do={ + :if ([ /disk/get $TmpFs disabled ] = true) do={ + $LogPrint info $0 ("The tmpfs is disabled, enabling."); + /disk/enable $TmpFs; + } :return true; } From 64bc9f73f7ed24cfb7dec9f24fb101594ae4cb79 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 3 Jul 2024 16:35:39 +0200 Subject: [PATCH 2251/2612] packages-update: run backups before package download This reduces memory pressure, especially on device with very limited RAM like mAP with its 64 MB. --- packages-update.rsc | 52 ++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index 0208b1e..97039ec 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -60,32 +60,6 @@ :error true; } - :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; - :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; - - :local DoDowngrade false; - :if ($NumInstalled > $NumLatest) do={ - :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ - :put "Latest version is older than installed one. Want to downgrade? [y/N]"; - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - :set DoDowngrade true; - } else={ - :put "Canceled..."; - } - } else={ - $LogPrint warning $ScriptName ("Not installing downgrade automatically."); - :error false; - } - } - - :foreach Package in=[ /system/package/find where !bundle ] do={ - :local PkgName [ /system/package/get $Package name ]; - :if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ - $LogPrint error $ScriptName ("Download for package " . $PkgName . " failed, update aborted."); - :error false; - } - } - :local RunOrder ({}); :foreach Script in=[ /system/script/find where source~("\n# provides: backup-script\\b") ] do={ :local ScriptVal [ /system/script/get $Script ]; @@ -120,6 +94,32 @@ } } + :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; + :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; + + :local DoDowngrade false; + :if ($NumInstalled > $NumLatest) do={ + :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ + :put "Latest version is older than installed one. Want to downgrade? [y/N]"; + :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ + :set DoDowngrade true; + } else={ + :put "Canceled..."; + } + } else={ + $LogPrint warning $ScriptName ("Not installing downgrade automatically."); + :error false; + } + } + + :foreach Package in=[ /system/package/find where !bundle ] do={ + :local PkgName [ /system/package/get $Package name ]; + :if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ + $LogPrint error $ScriptName ("Download for package " . $PkgName . " failed, update aborted."); + :error false; + } + } + :if ($DoDowngrade = true) do={ $LogPrint info $ScriptName ("Rebooting for downgrade."); :delay 1s; From 1bc6f9c45c7487c6b1fa1c26a9ceeaeadd86c90c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 5 Jul 2024 15:19:11 +0200 Subject: [PATCH 2252/2612] backup-partition: rename variable --- backup-partition.rsc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index 3c883f7..572c740 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -58,13 +58,13 @@ :error false; } - :local FallbackTo [ /partitions/get $ActiveRunning fallback-to ]; + :local FallbackToName [ /partitions/get $ActiveRunning fallback-to ]; - :if ([ /partitions/get $ActiveRunning version ] != [ /partitions/get $FallbackTo version]) do={ + :if ([ /partitions/get $ActiveRunning version ] != [ /partitions/get $FallbackToName version]) do={ :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ - :put ("The partitions have different RouterOS versions. Copy over to '" . $FallbackTo . "'? [y/N]"); + :put ("The partitions have different RouterOS versions. Copy over to '" . $FallbackToName . "'? [y/N]"); :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - :if ([ $CopyTo $ScriptName $FallbackTo ] = false) do={ + :if ([ $CopyTo $ScriptName $FallbackToName ] = false) do={ :set PackagesUpdateBackupFailure true; :error false; } @@ -75,7 +75,7 @@ :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; :if ($BackupPartitionCopyBeforeFeatureUpdate = true && $NumLatest > 0 && \ ($NumInstalled & 0xffff0000) != ($NumLatest & 0xffff0000)) do={ - :if ([ $CopyTo $ScriptName $FallbackTo ] = false) do={ + :if ([ $CopyTo $ScriptName $FallbackToName ] = false) do={ :set PackagesUpdateBackupFailure true; :error false; } @@ -87,12 +87,12 @@ /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; + /partitions/save-config-to $FallbackToName; /system/scheduler/remove "running-from-backup-partition"; - $LogPrint info $ScriptName ("Saved configuration to partition '" . $FallbackTo . "'."); + $LogPrint info $ScriptName ("Saved configuration to partition '" . $FallbackToName . "'."); } on-error={ /system/scheduler/remove [ find where name="running-from-backup-partition" ]; - $LogPrint error $ScriptName ("Failed saving configuration to partition '" . $FallbackTo . "'!"); + $LogPrint error $ScriptName ("Failed saving configuration to partition '" . $FallbackToName . "'!"); :set PackagesUpdateBackupFailure true; :error false; } From 235737c2327cf377a1208dc96af53d9c8642b305 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 5 Jul 2024 15:21:52 +0200 Subject: [PATCH 2253/2612] backup-partition: check the fallback partition actually exists... ... and use its id for actions. --- backup-partition.rsc | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index 572c740..211db0f 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -24,17 +24,18 @@ :global VersionToNum; :local CopyTo do={ - :local ScriptName [ :tostr $1 ]; - :local FallbackTo [ :tostr $2 ]; + :local ScriptName [ :tostr $1 ]; + :local FallbackTo [ :toid $2 ]; + :local FallbackToName [ :tostr $3 ]; :global LogPrint; :do { /partitions/copy-to $FallbackTo; - $LogPrint info $ScriptName ("Copied RouterOS to partition '" . $FallbackTo . "'."); + $LogPrint info $ScriptName ("Copied RouterOS to partition '" . $FallbackToName . "'."); :return true; } on-error={ - $LogPrint error $ScriptName ("Failed copying RouterOS to partition '" . $FallbackTo . "'!"); + $LogPrint error $ScriptName ("Failed copying RouterOS to partition '" . $FallbackToName . "'!"); :return false; } } @@ -59,12 +60,19 @@ } :local FallbackToName [ /partitions/get $ActiveRunning fallback-to ]; + :local FallbackTo [ /partition/find where name=$FallbackToName ]; - :if ([ /partitions/get $ActiveRunning version ] != [ /partitions/get $FallbackToName version]) do={ + :if ([ :len $FallbackTo ] < 1) do={ + $LogPrint error $ScriptName ("There is no partition with name '" . $FallbackToName . "'."); + :set PackagesUpdateBackupFailure true; + :error false; + } + + :if ([ /partitions/get $ActiveRunning version ] != [ /partitions/get $FallbackTo version]) do={ :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ :put ("The partitions have different RouterOS versions. Copy over to '" . $FallbackToName . "'? [y/N]"); :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - :if ([ $CopyTo $ScriptName $FallbackToName ] = false) do={ + :if ([ $CopyTo $ScriptName $FallbackTo $FallbackToName ] = false) do={ :set PackagesUpdateBackupFailure true; :error false; } @@ -75,7 +83,7 @@ :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; :if ($BackupPartitionCopyBeforeFeatureUpdate = true && $NumLatest > 0 && \ ($NumInstalled & 0xffff0000) != ($NumLatest & 0xffff0000)) do={ - :if ([ $CopyTo $ScriptName $FallbackToName ] = false) do={ + :if ([ $CopyTo $ScriptName $FallbackTo $FallbackToName ] = false) do={ :set PackagesUpdateBackupFailure true; :error false; } @@ -87,7 +95,7 @@ /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 $FallbackToName; + /partitions/save-config-to $FallbackTo; /system/scheduler/remove "running-from-backup-partition"; $LogPrint info $ScriptName ("Saved configuration to partition '" . $FallbackToName . "'."); } on-error={ From 25135b64e549e129914b9b5dfb74ca2011ee3d5d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 5 Jul 2024 15:32:49 +0200 Subject: [PATCH 2254/2612] backup-partition: check that target is inactive --- backup-partition.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index 211db0f..34cdc8f 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -60,10 +60,10 @@ } :local FallbackToName [ /partitions/get $ActiveRunning fallback-to ]; - :local FallbackTo [ /partition/find where name=$FallbackToName ]; + :local FallbackTo [ /partition/find where name=$FallbackToName !active ]; :if ([ :len $FallbackTo ] < 1) do={ - $LogPrint error $ScriptName ("There is no partition with name '" . $FallbackToName . "'."); + $LogPrint error $ScriptName ("There is no inactive partition named '" . $FallbackToName . "'."); :set PackagesUpdateBackupFailure true; :error false; } From 35d3c058b83388b8e187bb53ff8c1e0d85c299b5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 10 Jul 2024 11:02:53 +0200 Subject: [PATCH 2255/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 13d0508..e9bf7d1 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -47,6 +47,7 @@ Add yourself to the list, * Marek ÄŒÃĄbÃĄk * Oleksandr Yukhymchuk * Peter Holtkamp +* Peter Ponzel * Reiner Vehrenkamp * Richard Österreicher * Simon Hitzemann From 78dfc568c10332ea63cc26e39ccf165f3d384c9e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Jul 2024 08:45:53 +0200 Subject: [PATCH 2256/2612] capsman-{download-packages,rolling-upgrade}: run matching script It is possible to run old and new CAPsMAN on one system simultaneously (... since RouterOS 7.13?). Thus it may make sense to have both variants of these scripts installed, and we have to make sure to run the correct one. --- capsman-download-packages.capsman.rsc | 2 +- capsman-download-packages.template.rsc | 2 +- capsman-download-packages.wifi.rsc | 2 +- capsman-rolling-upgrade.capsman.rsc | 2 +- capsman-rolling-upgrade.template.rsc | 2 +- capsman-rolling-upgrade.wifi.rsc | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index f5695f4..84d36f7 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -73,7 +73,7 @@ } :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.capsman\n" ]->0); :if ([ :len $Script ] > 0) do={ /system/script/run $Script; } else={ diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 762dbb6..deb15a7 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -83,7 +83,7 @@ } :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%TEMPL%\n" ]->0); :if ([ :len $Script ] > 0) do={ /system/script/run $Script; } else={ diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 79aa9a7..6147d21 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -75,7 +75,7 @@ } :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.wifi\n" ]->0); :if ([ :len $Script ] > 0) do={ /system/script/run $Script; } else={ diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc index 2c9ae3d..e9ca5cc 100644 --- a/capsman-rolling-upgrade.capsman.rsc +++ b/capsman-rolling-upgrade.capsman.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: capsman-rolling-upgrade +# provides: capsman-rolling-upgrade.capsman # requires RouterOS, version=7.13 # # upgrade CAPs one after another diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index 2098bc0..a28d7f7 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: capsman-rolling-upgrade +# provides: capsman-rolling-upgrade%TEMPL% # requires RouterOS, version=7.13 # # upgrade CAPs one after another diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc index 36b8c0f..22f8818 100644 --- a/capsman-rolling-upgrade.wifi.rsc +++ b/capsman-rolling-upgrade.wifi.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# provides: capsman-rolling-upgrade +# provides: capsman-rolling-upgrade.wifi # requires RouterOS, version=7.13 # # upgrade CAPs one after another From 3fd1896ad622f8097cc14af8f37114f9fc47f5b7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Jul 2024 08:55:26 +0200 Subject: [PATCH 2257/2612] capsman-download-packages: support running several scripts... ... as it is possible to have more than just one providing the functionality. --- capsman-download-packages.capsman.rsc | 8 +++++--- capsman-download-packages.template.rsc | 8 +++++--- capsman-download-packages.wifi.rsc | 8 +++++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index 84d36f7..4f9ab9d 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -73,9 +73,11 @@ } :if ($Updated = true) do={ - :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade.capsman\n" ]->0); - :if ([ :len $Script ] > 0) do={ - /system/script/run $Script; + :local Scripts [ /system/script/find where source~"\n# provides: capsman-rolling-upgrade.capsman\n" ]; + :if ([ :len $Scripts ] > 0) do={ + :foreach Script in=$Scripts do={ + /system/script/run $Script; + } } else={ /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; } diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index deb15a7..c0e815b 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -83,9 +83,11 @@ } :if ($Updated = true) do={ - :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade%TEMPL%\n" ]->0); - :if ([ :len $Script ] > 0) do={ - /system/script/run $Script; + :local Scripts [ /system/script/find where source~"\n# provides: capsman-rolling-upgrade%TEMPL%\n" ]; + :if ([ :len $Scripts ] > 0) do={ + :foreach Script in=$Scripts do={ + /system/script/run $Script; + } } else={ /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 6147d21..64ac7cd 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -75,9 +75,11 @@ } :if ($Updated = true) do={ - :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade.wifi\n" ]->0); - :if ([ :len $Script ] > 0) do={ - /system/script/run $Script; + :local Scripts [ /system/script/find where source~"\n# provides: capsman-rolling-upgrade.wifi\n" ]; + :if ([ :len $Scripts ] > 0) do={ + :foreach Script in=$Scripts do={ + /system/script/run $Script; + } } else={ /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; } From f09fa83105ea40876e7103a118b3d6d57098cf0c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Jul 2024 13:49:02 +0200 Subject: [PATCH 2258/2612] doc/mod/ssh-keys-import: drop hint on older RouterOS --- doc/mod/ssh-keys-import.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md index db8e322..88524ab 100644 --- a/doc/mod/ssh-keys-import.md +++ b/doc/mod/ssh-keys-import.md @@ -34,12 +34,8 @@ Usage and invocation Call the function `$SSHKeysImport` with key and user as parameter to import that key: - $SSHKeysImport "ssh-rsa AAAAB3Nza...QYZk8= user" admin; - -Starting with RouterOS *7.12beta1* support for keys of type `ed25519` has -been added: - $SSHKeysImport "ssh-ed25519 AAAAC3Nza...ZVugJT user" admin; + $SSHKeysImport "ssh-rsa AAAAB3Nza...QYZk8= user" admin; The third part of the key (`user` in this example) is inherited as `key-owner` in RouterOS. Also the `MD5` fingerprint is recorded, this helps From 0101b56bff0cfad4043c4e86aa7e68325530eca3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Jul 2024 23:10:42 +0200 Subject: [PATCH 2259/2612] README: use :tocrlf to convert global-config-overlay --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6b3cd05..4fd0e3e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ RouterOS Scripts [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) @@ -155,7 +155,7 @@ This last step is required when ever you make changes to your configuration. > â„šī¸ **Info**: It is recommended to edit the configuration using the command > line interface. If using Winbox on Windows OS, the line endings may be > missing. To fix this run: -> `/system/script/set source=[ $Unix2Dos [ get global-config-overlay source ] ] global-config-overlay;` +> `/system/script/set source=[ :tocrlf [ get global-config-overlay source ] ] global-config-overlay;` Updating scripts ---------------- From 2d42fed621f5bb79a187774afe46c04e06b9c71b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Jul 2024 12:23:02 +0200 Subject: [PATCH 2260/2612] global-functions: $ScriptInstallUpdate: forcibly convert to LF... ... to make sure we do not have unintended CRLF line breaks. --- global-functions.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 44b3abe..2c7c87c 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # global functions # https://git.eworm.de/cgit/routeros-scripts/about/ @@ -1060,7 +1060,7 @@ :local Result [ /tool/fetch check-certificate=yes-without-crl \ http-header-field=({ [ $FetchUserAgentStr $0 ] }) $Url output=user as-value ]; :if ($Result->"status" = "finished") do={ - :set SourceNew ($Result->"data"); + :set SourceNew [ :tolf ($Result->"data") ]; } } on-error={ :if ($ScriptVal->"source" = "#!rsc by RouterOS\n") do={ From 68f61ae6221afeb279ea3823e42cb8da4656a2a6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Jul 2024 12:27:08 +0200 Subject: [PATCH 2261/2612] global-functions: $ScriptInstallUpdate: allow CRLF on device --- global-functions.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 2c7c87c..327443a 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1074,7 +1074,8 @@ } :if ([ :len $SourceNew ] > 0) do={ - :if ($SourceNew != $ScriptVal->"source") do={ + :local SourceCRLF [ :tocrlf $SourceNew ]; + :if ($SourceNew != $ScriptVal->"source" && $SourceCRLF != $ScriptVal->"source") do={ :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ :local Required ([ $ParseKeyValueStore [ $Grep $SourceNew ("\23 requires RouterOS, ") ] ]->"version"); :if ([ $RequiredRouterOS $0 [ $EitherOr $Required "0.0" ] false ] = true) do={ From 7cf0c5b2056bb7522f6174bd76d4b0ea19d4c647 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Jul 2024 12:38:18 +0200 Subject: [PATCH 2262/2612] capsman-download-packages: support scripts with CRLF line breaks --- capsman-download-packages.capsman.rsc | 2 +- capsman-download-packages.template.rsc | 2 +- capsman-download-packages.wifi.rsc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index 4f9ab9d..1247d9a 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -73,7 +73,7 @@ } :if ($Updated = true) do={ - :local Scripts [ /system/script/find where source~"\n# provides: capsman-rolling-upgrade.capsman\n" ]; + :local Scripts [ /system/script/find where source~"\n# provides: capsman-rolling-upgrade.capsman\r?\n" ]; :if ([ :len $Scripts ] > 0) do={ :foreach Script in=$Scripts do={ /system/script/run $Script; diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index c0e815b..8418841 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -83,7 +83,7 @@ } :if ($Updated = true) do={ - :local Scripts [ /system/script/find where source~"\n# provides: capsman-rolling-upgrade%TEMPL%\n" ]; + :local Scripts [ /system/script/find where source~"\n# provides: capsman-rolling-upgrade%TEMPL%\r?\n" ]; :if ([ :len $Scripts ] > 0) do={ :foreach Script in=$Scripts do={ /system/script/run $Script; diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 64ac7cd..c5a6999 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -75,7 +75,7 @@ } :if ($Updated = true) do={ - :local Scripts [ /system/script/find where source~"\n# provides: capsman-rolling-upgrade.wifi\n" ]; + :local Scripts [ /system/script/find where source~"\n# provides: capsman-rolling-upgrade.wifi\r?\n" ]; :if ([ :len $Scripts ] > 0) do={ :foreach Script in=$Scripts do={ /system/script/run $Script; From ee928605df642ab9f917dd1e65f85f7cb09e8192 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Jul 2024 12:41:17 +0200 Subject: [PATCH 2263/2612] news-and-changes: support scripts with CRLF line breaks --- news-and-changes.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 8ddc3d6..9ab811d 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -61,7 +61,7 @@ # Migration steps to be applied on script updates :global GlobalConfigMigration { 97=":local Rec [ /ip/dns/static/find where comment~\"^managed by dhcp-to-dns for \" ]; :if ([ :len \$Rec ] > 0) do={ /ip/dns/static/remove \$Rec; /system/script/run dhcp-to-dns; }"; - 100=":global ScriptInstallUpdate; :if ([ :len [ /system/script/find where name=\"ssh-keys-import\" source~\"^#!rsc by RouterOS\\n\" ] ] > 0) do={ /system/script/set name=\"mod/ssh-keys-import\" ssh-keys-import; \$ScriptInstallUpdate; }"; + 100=":global ScriptInstallUpdate; :if ([ :len [ /system/script/find where name=\"ssh-keys-import\" source~\"^#!rsc by RouterOS\\r?\\n\" ] ] > 0) do={ /system/script/set name=\"mod/ssh-keys-import\" ssh-keys-import; \$ScriptInstallUpdate; }"; 104=":global CharacterReplace; :global ScriptInstallUpdate; :foreach Script in={ \"capsman-download-packages\"; \"capsman-rolling-upgrade\"; \"hotspot-to-wpa\"; \"hotspot-to-wpa-cleanup\" } do={ /system/script/set name=(\$Script . \".capsman\") [ find where name=\$Script ]; :foreach Scheduler in=[ /system/scheduler/find where on-event~(\$Script . \"([^-.]|\\\$)\") ] do={ /system/scheduler/set \$Scheduler on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Script (\$Script . \".capsman\") ]; }; }; /ip/hotspot/user/profile/set on-login=\"hotspot-to-wpa.capsman\" [ find where on-login=\"hotspot-to-wpa\" ]; \$ScriptInstallUpdate;"; 111=":local Rec [ /ip/dns/static/find where comment~\"^managed by dhcp-to-dns for \" ]; :if ([ :len \$Rec ] > 0) do={ /ip/dns/static/remove \$Rec; /system/script/run dhcp-to-dns; }"; }; From a26f78329a1e941fcab969611ffbb83af4f2ea01 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Jul 2024 12:42:24 +0200 Subject: [PATCH 2264/2612] ppp-on-up: support scripts with CRLF line breaks --- ppp-on-up.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc index 4ed92c5..6484ecb 100644 --- a/ppp-on-up.rsc +++ b/ppp-on-up.rsc @@ -28,7 +28,7 @@ /ipv6/dhcp-client/release [ find where interface=$IntName !disabled ]; - :foreach Script in=[ /system/script/find where source~("\n# provides: ppp-on-up\n") ] do={ + :foreach Script in=[ /system/script/find where source~("\n# provides: ppp-on-up\r?\n") ] do={ :local ScriptName [ /system/script/get $Script name ]; :do { $LogPrint debug $ScriptName ("Running script: " . $ScriptName); From f2ca62aed0ff062b6e2dec13f8bb20e828bfdeb2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Jul 2024 12:33:47 +0200 Subject: [PATCH 2265/2612] global-functions: $ScriptInstallUpdate: support storing with CRLF Adding this in `global-config-overlay` make the scripts being stored with CRLF line breaks: :global ScriptUpdatesCRLF true; Handle with care, I do not recommend it. Thus it's just a hidden setting. --- global-functions.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 327443a..b824d62 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1008,6 +1008,7 @@ :global IDonate; :global NoNewsAndChangesNotification; :global ScriptUpdatesBaseUrl; + :global ScriptUpdatesCRLF; :global ScriptUpdatesUrlSuffix; :global CertificateAvailable; @@ -1081,7 +1082,8 @@ :if ([ $RequiredRouterOS $0 [ $EitherOr $Required "0.0" ] false ] = true) do={ :if ([ $ValidateSyntax $SourceNew ] = true) do={ $LogPrint info $0 ("Updating script: " . $ScriptVal->"name"); - /system/script/set owner=($ScriptVal->"name") source=$SourceNew $Script; + /system/script/set owner=($ScriptVal->"name") \ + source=[ $IfThenElse ($ScriptUpdatesCRLF = true) $SourceCRLF $SourceNew ] $Script; :if ($ScriptVal->"name" = "global-config") do={ :set ReloadGlobalConfig true; } From 8074305b9250d98e182f5cb968de2c8bd438f7f3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Jul 2024 23:09:32 +0200 Subject: [PATCH 2266/2612] global-functions: $Dos2Unix: use :tolf --- global-functions.rsc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index b824d62..312936b 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -313,11 +313,7 @@ # convert line endings, DOS -> UNIX :set Dos2Unix do={ - :local Input [ :tostr $1 ]; - - :global CharacterReplace; - - :return [ $CharacterReplace $Input ("\r\n") ("\n") ]; + :return [ :tolf [ :tostr $1 ] ]; } # download package from upgrade server From 8f75d542f3aa7cb3c5726412daa0ab41c6880489 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Jul 2024 23:06:57 +0200 Subject: [PATCH 2267/2612] global-functions: $PrettyPrint: use :tocrlf --- global-functions.rsc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 312936b..950ccd6 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -909,11 +909,7 @@ # print lines with trailing carriage return :set PrettyPrint do={ - :local Input [ :tostr $1 ]; - - :global Unix2Dos; - - :put [ $Unix2Dos $Input ]; + :put [ :tocrlf [ :tostr $1 ] ]; } # strip protocol from from url string From 2fd0d27447b8ce6620ec3f6d68c9d5ca62bb9f02 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Jul 2024 23:08:42 +0200 Subject: [PATCH 2268/2612] global-functions: $Unix2Dos: use :tocrlf --- global-functions.rsc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 950ccd6..54dcb68 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1433,12 +1433,7 @@ # convert line endings, UNIX -> DOS :set Unix2Dos do={ - :local Input [ :tostr $1 ]; - - :global CharacterReplace; - - :return [ $CharacterReplace [ $CharacterReplace $Input \ - ("\n") ("\r\n") ] ("\r\r\n") ("\r\n") ]; + :return [ :tocrlf [ :tostr $1 ] ]; } # url encoding From 2b758b83fd47ca765dd8c5ed15ff3d001d60a6fc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Jul 2024 23:12:50 +0200 Subject: [PATCH 2269/2612] mod/inspectvar: use :tocrlf --- doc/mod/inspectvar.md | 2 +- mod/inspectvar.rsc | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/mod/inspectvar.md b/doc/mod/inspectvar.md index d4e59b3..4e2f4c1 100644 --- a/doc/mod/inspectvar.md +++ b/doc/mod/inspectvar.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/mod/inspectvar.rsc b/mod/inspectvar.rsc index 5adca0a..73205b2 100644 --- a/mod/inspectvar.rsc +++ b/mod/inspectvar.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # inspect variables # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/inspectvar.md @@ -14,9 +14,8 @@ # inspect variable and print on terminal :set InspectVar do={ :global InspectVarReturn; - :global PrettyPrint; - $PrettyPrint [ $InspectVarReturn $1 ]; + :put [ :tocrlf [ $InspectVarReturn $1 ] ]; } # inspect variable and return formatted string From 075a9bd6c43e08efee73eb6e1ec5b0ea0391fef2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 11 Jul 2024 23:13:50 +0200 Subject: [PATCH 2270/2612] mod/ipcalc: use :tocrlf --- doc/mod/ipcalc.md | 2 +- mod/ipcalc.rsc | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/doc/mod/ipcalc.md b/doc/mod/ipcalc.md index cb655bc..9f39429 100644 --- a/doc/mod/ipcalc.md +++ b/doc/mod/ipcalc.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc index 128ca54..003bdc3 100644 --- a/mod/ipcalc.rsc +++ b/mod/ipcalc.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # ip address calculation # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ipcalc.md @@ -17,17 +17,16 @@ :global FormatLine; :global IPCalcReturn; - :global PrettyPrint; :local Values [ $IPCalcReturn $1 ]; - $PrettyPrint ( \ + :put [ :tocrlf ( \ [ $FormatLine "Address" ($Values->"address") ] . "\n" . \ [ $FormatLine "Netmask" ($Values->"netmask") ] . "\n" . \ [ $FormatLine "Network" ($Values->"network") ] . "\n" . \ [ $FormatLine "HostMin" ($Values->"hostmin") ] . "\n" . \ [ $FormatLine "HostMax" ($Values->"hostmax") ] . "\n" . \ - [ $FormatLine "Broadcast" ($Values->"broadcast") ]); + [ $FormatLine "Broadcast" ($Values->"broadcast") ]) ]; } # calculate and return netmask, network, min host, max host and broadcast From 6fbafe76ba27e35d1f3067430ba78cedfa85eb19 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Jul 2024 13:45:16 +0200 Subject: [PATCH 2271/2612] bump RouterOS requirement for all scripts and modules... ... now that global-functions requires RouterOS 7.14 anyway. --- BRANCHES.md | 2 +- CONTRIBUTIONS.md | 2 +- INITIAL-COMMANDS.md | 2 +- accesslist-duplicates.capsman.rsc | 2 +- accesslist-duplicates.local.rsc | 2 +- accesslist-duplicates.template.rsc | 2 +- accesslist-duplicates.wifi.rsc | 2 +- backup-cloud.rsc | 2 +- backup-email.rsc | 2 +- backup-partition.rsc | 2 +- backup-upload.rsc | 2 +- capsman-download-packages.capsman.rsc | 2 +- capsman-download-packages.template.rsc | 2 +- capsman-download-packages.wifi.rsc | 2 +- capsman-rolling-upgrade.capsman.rsc | 2 +- capsman-rolling-upgrade.template.rsc | 2 +- capsman-rolling-upgrade.wifi.rsc | 2 +- certificate-renew-issued.rsc | 2 +- check-certificates.rsc | 2 +- check-health.rsc | 2 +- check-lte-firmware-upgrade.rsc | 2 +- check-routeros-update.rsc | 2 +- collect-wireless-mac.capsman.rsc | 2 +- collect-wireless-mac.local.rsc | 2 +- collect-wireless-mac.template.rsc | 2 +- collect-wireless-mac.wifi.rsc | 2 +- daily-psk.capsman.rsc | 2 +- daily-psk.local.rsc | 2 +- daily-psk.template.rsc | 2 +- daily-psk.wifi.rsc | 2 +- dhcp-lease-comment.capsman.rsc | 2 +- dhcp-lease-comment.local.rsc | 2 +- dhcp-lease-comment.template.rsc | 2 +- dhcp-lease-comment.wifi.rsc | 2 +- dhcp-to-dns.rsc | 2 +- doc/accesslist-duplicates.md | 2 +- doc/backup-cloud.md | 2 +- doc/backup-email.md | 2 +- doc/backup-partition.md | 2 +- doc/backup-upload.md | 2 +- doc/capsman-download-packages.md | 2 +- doc/capsman-rolling-upgrade.md | 2 +- doc/certificate-renew-issued.md | 2 +- doc/check-certificates.md | 2 +- doc/check-health.md | 2 +- doc/check-lte-firmware-upgrade.md | 2 +- doc/check-routeros-update.md | 2 +- doc/collect-wireless-mac.md | 2 +- doc/daily-psk.md | 2 +- doc/dhcp-lease-comment.md | 2 +- doc/dhcp-to-dns.md | 2 +- doc/firmware-upgrade-reboot.md | 2 +- doc/fw-addr-lists.md | 2 +- doc/global-wait.md | 2 +- doc/gps-track.md | 2 +- doc/hotspot-to-wpa.md | 2 +- doc/ip-addr-bridge.md | 2 +- doc/ipsec-to-dns.md | 2 +- doc/ipv6-update.md | 2 +- doc/lease-script.md | 2 +- doc/leds-mode.md | 2 +- doc/log-forward.md | 2 +- doc/mod/bridge-port-to.md | 2 +- doc/mod/bridge-port-vlan.md | 2 +- doc/mod/notification-email.md | 2 +- doc/mod/notification-matrix.md | 2 +- doc/mod/notification-ntfy.md | 2 +- doc/mod/notification-telegram.md | 2 +- doc/mod/scriptrunonce.md | 2 +- doc/mod/ssh-keys-import.md | 2 +- doc/mode-button.md | 2 +- doc/netwatch-dns.md | 2 +- doc/netwatch-notify.md | 2 +- doc/ospf-to-leds.md | 2 +- doc/packages-update.md | 2 +- doc/ppp-on-up.md | 2 +- doc/sms-action.md | 2 +- doc/sms-forward.md | 2 +- doc/super-mario-theme.md | 2 +- doc/telegram-chat.md | 2 +- doc/unattended-lte-firmware-upgrade.md | 2 +- doc/update-gre-address.md | 2 +- doc/update-tunnelbroker.md | 2 +- firmware-upgrade-reboot.rsc | 2 +- fw-addr-lists.rsc | 2 +- global-wait.rsc | 2 +- gps-track.rsc | 2 +- hotspot-to-wpa-cleanup.capsman.rsc | 2 +- hotspot-to-wpa-cleanup.template.rsc | 2 +- hotspot-to-wpa-cleanup.wifi.rsc | 2 +- hotspot-to-wpa.capsman.rsc | 2 +- hotspot-to-wpa.template.rsc | 2 +- hotspot-to-wpa.wifi.rsc | 2 +- ipsec-to-dns.rsc | 2 +- ipv6-update.rsc | 2 +- lease-script.rsc | 2 +- log-forward.rsc | 2 +- mod/bridge-port-to.rsc | 2 +- mod/bridge-port-vlan.rsc | 2 +- mod/notification-email.rsc | 2 +- mod/notification-matrix.rsc | 2 +- mod/notification-ntfy.rsc | 2 +- mod/notification-telegram.rsc | 2 +- mod/scriptrunonce.rsc | 2 +- mod/ssh-keys-import.rsc | 2 +- mode-button.rsc | 2 +- netwatch-dns.rsc | 2 +- netwatch-notify.rsc | 2 +- ospf-to-leds.rsc | 2 +- packages-update.rsc | 2 +- ppp-on-up.rsc | 2 +- sms-action.rsc | 2 +- sms-forward.rsc | 2 +- telegram-chat.rsc | 2 +- update-gre-address.rsc | 2 +- update-tunnelbroker.rsc | 2 +- 116 files changed, 116 insertions(+), 116 deletions(-) diff --git a/BRANCHES.md b/BRANCHES.md index f1062bb..2bacf8e 100644 --- a/BRANCHES.md +++ b/BRANCHES.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index e9bf7d1..0b192fc 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index b3eff35..2be51c5 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index 781ae78..d6e2928 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index b79a724..e90842d 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index b8067c8..d275340 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc index c05e02c..f4dae4b 100644 --- a/accesslist-duplicates.wifi.rsc +++ b/accesslist-duplicates.wifi.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # print duplicate antries in wireless access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 697ee95..f70752e 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=40 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # upload backup to MikroTik cloud # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md diff --git a/backup-email.rsc b/backup-email.rsc index c32eb27..e507c6e 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=20 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # create and email backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md diff --git a/backup-partition.rsc b/backup-partition.rsc index 34cdc8f..23dd7ef 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=70 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # save configuration to fallback partition # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md diff --git a/backup-upload.rsc b/backup-upload.rsc index 1dc98d5..8d96eba 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=50 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # create and upload backup and config file # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index 1247d9a..f2ff024 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # download and cleanup packages for CAP installation from CAPsMAN # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 8418841..ad9b926 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # download and cleanup packages for CAP installation from CAPsMAN # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index c5a6999..056136f 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # download and cleanup packages for CAP installation from CAPsMAN # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc index e9ca5cc..f287ea3 100644 --- a/capsman-rolling-upgrade.capsman.rsc +++ b/capsman-rolling-upgrade.capsman.rsc @@ -5,7 +5,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: capsman-rolling-upgrade.capsman -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # upgrade CAPs one after another # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index a28d7f7..3d98747 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -5,7 +5,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: capsman-rolling-upgrade%TEMPL% -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # upgrade CAPs one after another # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc index 22f8818..369dccc 100644 --- a/capsman-rolling-upgrade.wifi.rsc +++ b/capsman-rolling-upgrade.wifi.rsc @@ -5,7 +5,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: capsman-rolling-upgrade.wifi -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # upgrade CAPs one after another # https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc index 7815443..f2c1dfe 100644 --- a/certificate-renew-issued.rsc +++ b/certificate-renew-issued.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # renew locally issued certificates # https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md diff --git a/check-certificates.rsc b/check-certificates.rsc index c9622b7..7aaac84 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # check for certificate validity # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md diff --git a/check-health.rsc b/check-health.rsc index a769fa8..540336d 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # check for RouterOS health state # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index 5ea094e..2e52c2a 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # check for LTE firmware upgrade, send notification # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 6dca99a..d45432a 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # check for RouterOS update, send notification and/or install # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index 74c0754..9efa9ef 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index 8a60fea..27c9d1c 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index c5cf74a..d41c17d 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc index 12c3361..0075320 100644 --- a/collect-wireless-mac.wifi.rsc +++ b/collect-wireless-mac.wifi.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # collect wireless mac adresses in access list # https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index cd5b6b0..6dafc08 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index fbdb784..4709f3a 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 35fa82c..6b7f5fd 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index c1f7133..90c6ac5 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc index b7f3589..c435ec3 100644 --- a/dhcp-lease-comment.capsman.rsc +++ b/dhcp-lease-comment.capsman.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc index e35bbe7..27e6605 100644 --- a/dhcp-lease-comment.local.rsc +++ b/dhcp-lease-comment.local.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index d4323ad..c562ca2 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc index f67ce6e..ba617d7 100644 --- a/dhcp-lease-comment.wifi.rsc +++ b/dhcp-lease-comment.wifi.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # update dhcp-server lease comment with infos from access-list # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index a3d41c9..0ab5e2a 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=20 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # check DHCP leases and add/remove/update DNS entries # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index a1f9198..a6302f5 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -4,7 +4,7 @@ Find and remove access list duplicates [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index 1f9e123..d658760 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/backup-email.md b/doc/backup-email.md index 3b1dbb2..aedae4d 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/backup-partition.md b/doc/backup-partition.md index 1cef2c9..9f62967 100644 --- a/doc/backup-partition.md +++ b/doc/backup-partition.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/backup-upload.md b/doc/backup-upload.md index c44217c..f2858b2 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index c68900e..d719934 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -4,7 +4,7 @@ Download packages for CAP upgrade from CAPsMAN [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index 27d855f..f366d40 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -4,7 +4,7 @@ Run rolling CAP upgrades from CAPsMAN [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/certificate-renew-issued.md b/doc/certificate-renew-issued.md index 91a1914..096e07b 100644 --- a/doc/certificate-renew-issued.md +++ b/doc/certificate-renew-issued.md @@ -4,7 +4,7 @@ Renew locally issued certificates [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 636f719..4188815 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -4,7 +4,7 @@ Renew certificates and notify on expiration [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/check-health.md b/doc/check-health.md index f94a0bf..578ea43 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index 59a62c7..66b2cf5 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -4,7 +4,7 @@ Notify on LTE firmware upgrade [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index f9d485c..2e9b8aa 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -4,7 +4,7 @@ Notify on RouterOS update [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 57032d8..84c111d 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -4,7 +4,7 @@ Collect MAC addresses in wireless access list [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 3894d52..2a15af5 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -4,7 +4,7 @@ Use wireless network with daily psk [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/dhcp-lease-comment.md b/doc/dhcp-lease-comment.md index f95b124..6a4c930 100644 --- a/doc/dhcp-lease-comment.md +++ b/doc/dhcp-lease-comment.md @@ -4,7 +4,7 @@ Comment DHCP leases with info from access list [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 13d5ef3..572011f 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/firmware-upgrade-reboot.md b/doc/firmware-upgrade-reboot.md index bac17a7..7ab6ac5 100644 --- a/doc/firmware-upgrade-reboot.md +++ b/doc/firmware-upgrade-reboot.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md index e9a8ff7..2008c7e 100644 --- a/doc/fw-addr-lists.md +++ b/doc/fw-addr-lists.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/global-wait.md b/doc/global-wait.md index 4b42717..6787d20 100644 --- a/doc/global-wait.md +++ b/doc/global-wait.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/gps-track.md b/doc/gps-track.md index 7006fb3..9685899 100644 --- a/doc/gps-track.md +++ b/doc/gps-track.md @@ -4,7 +4,7 @@ Send GPS position to server [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index 275fe4d..07d07dc 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/ip-addr-bridge.md b/doc/ip-addr-bridge.md index 941a8ae..ddbcc0a 100644 --- a/doc/ip-addr-bridge.md +++ b/doc/ip-addr-bridge.md @@ -4,7 +4,7 @@ Manage IP addresses with bridge status [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/ipsec-to-dns.md b/doc/ipsec-to-dns.md index 0a91960..a688e80 100644 --- a/doc/ipsec-to-dns.md +++ b/doc/ipsec-to-dns.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md index 20265fe..88600c5 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/lease-script.md b/doc/lease-script.md index 4d2f3bc..1b59ff7 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/leds-mode.md b/doc/leds-mode.md index 90ea418..c01472e 100644 --- a/doc/leds-mode.md +++ b/doc/leds-mode.md @@ -4,7 +4,7 @@ Manage LEDs dark mode [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/log-forward.md b/doc/log-forward.md index 44409dc..55b1540 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/mod/bridge-port-to.md b/doc/mod/bridge-port-to.md index 5c8bebc..2ed9dc7 100644 --- a/doc/mod/bridge-port-to.md +++ b/doc/mod/bridge-port-to.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/mod/bridge-port-vlan.md b/doc/mod/bridge-port-vlan.md index d23d5b5..ded2603 100644 --- a/doc/mod/bridge-port-vlan.md +++ b/doc/mod/bridge-port-vlan.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/mod/notification-email.md b/doc/mod/notification-email.md index 2138e31..0bef455 100644 --- a/doc/mod/notification-email.md +++ b/doc/mod/notification-email.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index 18b6607..c96a719 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/mod/notification-ntfy.md b/doc/mod/notification-ntfy.md index b2330a5..2a43e3c 100644 --- a/doc/mod/notification-ntfy.md +++ b/doc/mod/notification-ntfy.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index 159fda9..f55f936 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/mod/scriptrunonce.md b/doc/mod/scriptrunonce.md index c5fa891..0127c6d 100644 --- a/doc/mod/scriptrunonce.md +++ b/doc/mod/scriptrunonce.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md index 88524ab..dcfd95b 100644 --- a/doc/mod/ssh-keys-import.md +++ b/doc/mod/ssh-keys-import.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/mode-button.md b/doc/mode-button.md index 8734352..7feb19f 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -4,7 +4,7 @@ Mode button with multiple presses [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 9fe486e..ff6c29c 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 2db32bb..f504ed7 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/ospf-to-leds.md b/doc/ospf-to-leds.md index 121f77b..23248b5 100644 --- a/doc/ospf-to-leds.md +++ b/doc/ospf-to-leds.md @@ -4,7 +4,7 @@ Visualize OSPF state via LEDs [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/packages-update.md b/doc/packages-update.md index fae3896..8b0d4a3 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -4,7 +4,7 @@ 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/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/ppp-on-up.md b/doc/ppp-on-up.md index 21847c7..7902f3b 100644 --- a/doc/ppp-on-up.md +++ b/doc/ppp-on-up.md @@ -4,7 +4,7 @@ Run scripts on ppp connection [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/sms-action.md b/doc/sms-action.md index b4678af..5de7f0d 100644 --- a/doc/sms-action.md +++ b/doc/sms-action.md @@ -4,7 +4,7 @@ Act on received SMS [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 597410b..8e7417b 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -4,7 +4,7 @@ Forward received SMS [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/super-mario-theme.md b/doc/super-mario-theme.md index e4bae2e..2ffb25b 100644 --- a/doc/super-mario-theme.md +++ b/doc/super-mario-theme.md @@ -4,7 +4,7 @@ Play Super Mario theme [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index eb4acf5..95f8cf9 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -4,7 +4,7 @@ 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.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/unattended-lte-firmware-upgrade.md b/doc/unattended-lte-firmware-upgrade.md index 6680447..e9a888c 100644 --- a/doc/unattended-lte-firmware-upgrade.md +++ b/doc/unattended-lte-firmware-upgrade.md @@ -4,7 +4,7 @@ Install LTE firmware upgrade [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/update-gre-address.md b/doc/update-gre-address.md index 80902b9..7e101c4 100644 --- a/doc/update-gre-address.md +++ b/doc/update-gre-address.md @@ -4,7 +4,7 @@ Update GRE configuration with dynamic addresses [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/doc/update-tunnelbroker.md b/doc/update-tunnelbroker.md index 2539e2f..126d470 100644 --- a/doc/update-tunnelbroker.md +++ b/doc/update-tunnelbroker.md @@ -4,7 +4,7 @@ Update tunnelbroker configuration [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.13-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-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) diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc index 169a2e0..74847ac 100644 --- a/firmware-upgrade-reboot.rsc +++ b/firmware-upgrade-reboot.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2022-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # install firmware upgrade, and reboot # https://git.eworm.de/cgit/routeros-scripts/about/doc/firmware-upgrade-reboot.md diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 007282c..4930e86 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2023-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # download, import and update firewall address-lists # https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md diff --git a/global-wait.rsc b/global-wait.rsc index 239f575..f0631e2 100644 --- a/global-wait.rsc +++ b/global-wait.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # wait for global-functions to finish # https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md diff --git a/gps-track.rsc b/gps-track.rsc index e2a4e16..a2ea9ff 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # track gps data by sending json data to http server # https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index 8f55d71..29bd48d 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 7ac996c..06dd9f0 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index 39c9f25..7c74d10 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # manage and clean up private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index 113c95d..b85c591 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # add private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index 10f0c7e..44607cc 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # add private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index dbf50e0..25933c6 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # add private WPA passphrase after hotspot login # https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index 8894eee..bd74a8f 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2021-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # and add/remove/update DNS entries from IPSec mode-config # https://git.eworm.de/cgit/routeros-scripts/about/doc/ipsec-to-dns.md diff --git a/ipv6-update.rsc b/ipv6-update.rsc index ec9a03a..0577bdc 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # update firewall and dns settings on IPv6 prefix change # https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md diff --git a/lease-script.rsc b/lease-script.rsc index a9d4b68..f484414 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # run scripts on DHCP lease # https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md diff --git a/log-forward.rsc b/log-forward.rsc index 7abcb4d..5133e73 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # forward log messages via notification # https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md diff --git a/mod/bridge-port-to.rsc b/mod/bridge-port-to.rsc index 000532a..7dae679 100644 --- a/mod/bridge-port-to.rsc +++ b/mod/bridge-port-to.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # reset bridge ports to default bridge # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-to.md diff --git a/mod/bridge-port-vlan.rsc b/mod/bridge-port-vlan.rsc index 760e8a6..c9f55ae 100644 --- a/mod/bridge-port-vlan.rsc +++ b/mod/bridge-port-vlan.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # manage VLANs on bridge ports # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-vlan.md diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index df2e81a..3d62ddf 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # send notifications via e-mail # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-email.md diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 196633a..3adc1df 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -4,7 +4,7 @@ # Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # send notifications via Matrix # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-matrix.md diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index cdc10e7..661f69f 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # send notifications via Ntfy (ntfy.sh) # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-ntfy.md diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 1890483..671bd1c 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # send notifications via Telegram # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-telegram.md diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index c3972a0..3d5dce9 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # download script and run it once # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/scriptrunonce.md diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 6272a93..8cafa95 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # import ssh keys for public key authentication # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ssh-keys-import.md diff --git a/mode-button.rsc b/mode-button.rsc index 4994f6b..7908a7f 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # act on multiple mode and reset button presses # https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 09365ba..9635be6 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2022-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # monitor and manage dns/doh with netwatch # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-dns.md diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 17682f0..b658eae 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # monitor netwatch and send notifications # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc index 0932815..b78faa4 100644 --- a/ospf-to-leds.rsc +++ b/ospf-to-leds.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # visualize ospf instance state via leds # https://git.eworm.de/cgit/routeros-scripts/about/doc/ospf-to-leds.md diff --git a/packages-update.rsc b/packages-update.rsc index 97039ec..b08a48d 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # download packages and reboot for installation # https://git.eworm.de/cgit/routeros-scripts/about/doc/packages-update.md diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc index 6484ecb..337b32d 100644 --- a/ppp-on-up.rsc +++ b/ppp-on-up.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # run scripts on ppp up # https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md diff --git a/sms-action.rsc b/sms-action.rsc index 70bfb28..c896659 100644 --- a/sms-action.rsc +++ b/sms-action.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # run action on received SMS # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-action.md diff --git a/sms-forward.rsc b/sms-forward.rsc index 477d11e..0d493b6 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -4,7 +4,7 @@ # Anatoly Bubenkov # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # forward SMS to e-mail # https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 1c274ec..2bdc04d 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2023-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # use Telegram to chat with your Router and send commands # https://git.eworm.de/cgit/routeros-scripts/about/doc/telegram-chat.md diff --git a/update-gre-address.rsc b/update-gre-address.rsc index 76d0c81..6dd829d 100644 --- a/update-gre-address.rsc +++ b/update-gre-address.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # update gre interface remote address with dynamic address from # ipsec remote peer diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index f9ba202..67a5d30 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -5,7 +5,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: ppp-on-up -# requires RouterOS, version=7.13 +# requires RouterOS, version=7.14 # # update local address of tunnelbroker interface # https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md From 8ea780554164ef14e5fddc1ab8692eec455a0d0c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 22 Jul 2024 17:57:22 +0200 Subject: [PATCH 2272/2612] global-functions: $EitherOr: pass boolean value Note that literal "true" or "false" (even without quotes) is converted to string. So you may have to enclose it in parentheses for a boolean value: > :put [ :typeof [ $EitherOr true false ] ]; str > :put [ :typeof [ $EitherOr (true) (false) ] ]; bool --- global-functions.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 54dcb68..4f37fa5 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -382,6 +382,9 @@ :set EitherOr do={ :global IfThenElse; + :if ([ :typeof $1 ] = "bool") do={ + :return $1; + } :if ([ :typeof $1 ] = "num") do={ :return [ $IfThenElse ($1 != 0) $1 $2 ]; } From 511184a4a7bbabd6b7789defb9cc65c22bb50664 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 22 Jul 2024 21:13:02 +0200 Subject: [PATCH 2273/2612] global-functions: $EitherOr: revert... ... but leave a comment. --- global-functions.rsc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 4f37fa5..41120fd 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -382,15 +382,13 @@ :set EitherOr do={ :global IfThenElse; - :if ([ :typeof $1 ] = "bool") do={ - :return $1; - } :if ([ :typeof $1 ] = "num") do={ :return [ $IfThenElse ($1 != 0) $1 $2 ]; } :if ([ :typeof $1 ] = "time") do={ :return [ $IfThenElse ($1 > 0s) $1 $2 ]; } + # this works for boolean values, literal ones with parentheses :return [ $IfThenElse ([ :len [ :tostr $1 ] ] > 0) $1 $2 ]; } From 22d93d07081cd23954abcae66aa448794f3dda51 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 Apr 2024 10:13:33 +0200 Subject: [PATCH 2274/2612] README: drop command to remove certificate file... ... as this is done automatically with RouterOS 7.15rc1 and later. Not bumping the required RouterOS version (badge) here... Worst thing that can happen is a stale certificate file left on storage. --- README.d/03-check-certs.avif | Bin 8932 -> 8047 bytes README.md | 3 +-- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/README.d/03-check-certs.avif b/README.d/03-check-certs.avif index 46b7220f1df02c8379e95113aeb13bf91859de0f..4717b3ea9cc9436ab94be0e471263f601fcf47c8 100644 GIT binary patch delta 3868 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 m?X8>I9uN Date: Tue, 23 Apr 2024 10:14:47 +0200 Subject: [PATCH 2275/2612] INITIAL-COMMANDS: drop command to remove certificate file... ... as this is done automatically with RouterOS 7.15rc1 and later. --- INITIAL-COMMANDS.md | 1 - 1 file changed, 1 deletion(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 2be51c5..3f5f75c 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -23,7 +23,6 @@ Run the complete base installation: :if ([ :len [ /certificate/find where fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470" ] ] != 1) do={ :error "Something is wrong with your certificates!"; }; - /file/remove [ find where name="ISRG-Root-X2.pem" ]; :delay 1s; /system/script/set name=("global-config-overlay-" . [ /system/clock/get date ] . "-" . [ /system/clock/get time ]) [ find where name="global-config-overlay" ]; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ From 209c37664baddffb730dcb5d85ebc09b9bf8f3b0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Mar 2024 09:13:39 +0100 Subject: [PATCH 2276/2612] netwatch-notify: do not switch type when resolving This requires RouterOS 7.15beta4, but let's bump the required version to next stable release instead. --- doc/netwatch-notify.md | 2 +- netwatch-notify.rsc | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index f504ed7..948cbec 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index b658eae..a49d0cd 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # monitor netwatch and send notifications # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md @@ -102,7 +102,8 @@ :if ([ :typeof ($HostInfo->"resolve") ] = "str") do={ :if ([ $IsDNSResolving ] = true) do={ :do { - :local Resolve [ :resolve ($HostInfo->"resolve") ]; + :local Resolve [ :resolve type=[ $IfThenElse ([ :typeof ($HostVal->"host") ] = "ip") \ + "ipv4" "ipv6" ] ($HostInfo->"resolve") ]; :if ($Resolve != $HostVal->"host") do={ :if ([ $ResolveExpected $ScriptName ($HostInfo->"resolve") ($HostVal->"host") ] = false) do={ $LogPrint info $ScriptName ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ From a017f2422442d71bac2ae7081e089e90a1636d83 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 May 2024 20:35:06 +0200 Subject: [PATCH 2277/2612] daily-psk: drop workaround for old RouterOS --- daily-psk.capsman.rsc | 3 +-- daily-psk.local.rsc | 3 +-- daily-psk.template.rsc | 5 ++--- daily-psk.wifi.rsc | 5 ++--- doc/daily-psk.md | 2 +- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index 6dafc08..0562e39 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md @@ -23,7 +23,6 @@ :global FormatLine; :global LogPrint; - :global RequiredRouterOS; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 4709f3a..0bef0e9 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md @@ -23,7 +23,6 @@ :global FormatLine; :global LogPrint; - :global RequiredRouterOS; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 6b7f5fd..9d71958 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md @@ -24,7 +24,6 @@ :global FormatLine; :global LogPrint; - :global RequiredRouterOS; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -86,7 +85,7 @@ /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ - :if ([ $RequiredRouterOS $ScriptName "7.15beta8" false ] = false || [ :len [ /interface/wifi/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ + :if ([ :len [ /interface/wifi/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ :if ($Seen->$Ssid = 1) do={ $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping."); diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index 90c6ac5..83a896c 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # update daily PSK (pre shared key) # https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md @@ -23,7 +23,6 @@ :global FormatLine; :global LogPrint; - :global RequiredRouterOS; :global ScriptLock; :global SendNotification2; :global SymbolForNotification; @@ -72,7 +71,7 @@ $LogPrint info $ScriptName ("Updating daily PSK for '" . $Ssid . "' to '" . $NewPsk . "' (was '" . $OldPsk . "')"); /interface/wifi/access-list/set $AccList passphrase=$NewPsk; - :if ([ $RequiredRouterOS $ScriptName "7.15beta8" false ] = false || [ :len [ /interface/wifi/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ + :if ([ :len [ /interface/wifi/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ :if ($Seen->$Ssid = 1) do={ $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping."); } else={ diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 2a15af5..4a3de64 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -4,7 +4,7 @@ Use wireless network with daily psk [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) From 32474c751f9fb69e096dc7f3b9e8c1f2c1fe6f90 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 May 2024 20:37:42 +0200 Subject: [PATCH 2278/2612] telegram-chat: drop extra conversion The JSON parser was actually fixed in RouterOS 7.15beta4, but let's bump the required version to next stable release instead. --- doc/telegram-chat.md | 2 +- telegram-chat.rsc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md index 95f8cf9..1e6f70f 100644 --- a/doc/telegram-chat.md +++ b/doc/telegram-chat.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 2bdc04d..f2750f5 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2023-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # use Telegram to chat with your Router and send commands # https://git.eworm.de/cgit/routeros-scripts/about/doc/telegram-chat.md @@ -97,7 +97,7 @@ :local Trusted false; :local Chat ($Message->"chat"); :local From ($Message->"from"); - :local Command [ :tostr ($Message->"text") ]; + :local Command ($Message->"text"); :foreach IdsTrusted in=($TelegramChatId, $TelegramChatIdsTrusted) do={ :if ($From->"id" = $IdsTrusted || $From->"username" = $IdsTrusted) do={ From c28574b8f4484463e326e895fcac110d805efa01 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 19 Aug 2024 10:35:18 +0200 Subject: [PATCH 2279/2612] README: make the QR code a link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 53dcffb..ab6bd8c 100644 --- a/README.md +++ b/README.md @@ -364,7 +364,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Upstream -------- -![upstream](README.d/upstream.png) +[![upstream](README.d/upstream.png)](https://rsc.eworm.de/) URL: [GitHub.com](https://github.com/eworm-de/routeros-scripts#routeros-scripts) From 342d459436414ea94b9081474122c60b50f61569 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 19 Aug 2024 14:54:17 +0200 Subject: [PATCH 2280/2612] README: match the certificate file name from Let's Encrypt website... ... so import from manually downloaded and transferred file works out of the box as well. --- README.d/01-download-certs.avif | Bin 4596 -> 4890 bytes README.md | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.d/01-download-certs.avif b/README.d/01-download-certs.avif index 4a074eb59dce96fbf79c0b50dfdf028f7eff9d4f..d41ca0595fa2f6b2ca1eaf3a94e34244d46e017a 100644 GIT binary patch delta 3543 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 delta 3247 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 Date: Mon, 19 Aug 2024 14:55:04 +0200 Subject: [PATCH 2281/2612] INITIAL-COMMANDS: match the certificate file name from Let's Encrypt website... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... and our README. 😜 --- INITIAL-COMMANDS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 3f5f75c..84a88fe 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -17,9 +17,9 @@ Initial commands Run the complete base installation: { - /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/ISRG-Root-X2.pem" dst-path="ISRG-Root-X2.pem" as-value; + /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/ISRG-Root-X2.pem" dst-path="isrg-root-x2.pem" as-value; :delay 1s; - /certificate/import file-name=ISRG-Root-X2.pem passphrase=""; + /certificate/import file-name=isrg-root-x2.pem passphrase=""; :if ([ :len [ /certificate/find where fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470" ] ] != 1) do={ :error "Something is wrong with your certificates!"; }; From d360cc05becf4363aef07db652e39dd1315a2875 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 17 Aug 2024 21:53:10 +0200 Subject: [PATCH 2282/2612] netwatch-dns: disable DoH if time not sync... ... as it is possible that time is off, DNS via DoH fails (cert invalid), and finally syncing time fails due to failing DNS. --- netwatch-dns.rsc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 9635be6..e205081 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -16,6 +16,8 @@ :global CertificateAvailable; :global EitherOr; + :global IsDNSResolving; + :global IsTimeSync; :global LogPrint; :global ParseKeyValueStore; :global ScriptLock; @@ -67,6 +69,12 @@ :local DohCurrent [ /ip/dns/get use-doh-server ]; :local DohServers ({}); + :if ([ :len $DohCurrent ] > 0 && [ $IsDNSResolving ] = false && [ $IsTimeSync ] = false) do={ + $LogPrint info $ScriptName ("Time is not sync, disabling DoH: " . $DohCurrent); + /ip/dns/set use-doh-server=""; + :set DohCurrent ""; + } + :foreach Host in=[ /tool/netwatch/find where comment~"\\bdoh\\b" status="up" ] do={ :local HostVal [ /tool/netwatch/get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; From f17502d3d0e54173f6c843685b4e26a3c7cac89b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 18 Aug 2024 22:10:37 +0200 Subject: [PATCH 2283/2612] check-routeros-update: support switching to stable channel... ... with a feature update in testing channel. --- check-routeros-update.rsc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index d45432a..3584a94 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -125,6 +125,15 @@ } :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ + :if (($Update->"channel") = "testing" && ($NumInstalled & 0xffff0000) < ($NumLatest & 0xffff0000)) do={ + :put ("This is a feature update in testing channel. Switch to channel 'stable'? [y/N]"); + :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ + /system/package/update/set channel=stable; + $LogPrint info $ScriptName ("Switched to channel 'stable', please re-run!"); + :error true; + } + } + :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ $DoUpdate; From 3e9a7ea75a29111f4601cedf966471cbf4d9c894 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Aug 2024 09:38:13 +0200 Subject: [PATCH 2284/2612] certs: add 'DigiCert Global Root G3'... ... for quad9.net which can be used for DoH: $CertificateAvailable "DigiCert Global Root G3"; /ip/dns/set use-doh-server=https://9.9.9.9/dns-query verify-doh-cert=yes; --- certs/DigiCert-Global-Root-G3.pem | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 certs/DigiCert-Global-Root-G3.pem diff --git a/certs/DigiCert-Global-Root-G3.pem b/certs/DigiCert-Global-Root-G3.pem new file mode 100644 index 0000000..12324dc --- /dev/null +++ b/certs/DigiCert-Global-Root-G3.pem @@ -0,0 +1,22 @@ +# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G3" +# Serial: 7089244469030293291760083333884364146 +# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca +# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e +# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- From 90632f223adce7139b831fc2e6a0668431e5f26c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Aug 2024 10:59:51 +0200 Subject: [PATCH 2285/2612] doc/netwatch-dns: 'DigiCert Global Root G3' for Quad9 --- doc/netwatch-dns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index ff6c29c..54dd6c6 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -63,7 +63,7 @@ Importing a certificate automatically is possible, at least if available in the repository (see `certs` sub directory). /tool/netwatch/add comment="doh, doh-cert=DigiCert Global Root G2" host=1.1.1.1; - /tool/netwatch/add comment="doh, doh-cert=DigiCert Global Root CA" host=9.9.9.9; + /tool/netwatch/add comment="doh, doh-cert=DigiCert Global Root G3" host=9.9.9.9; /tool/netwatch/add comment="doh, doh-cert=GTS Root R1" host=8.8.8.8; Sometimes using just one specific (possibly internal) DNS server may be From 48fd281c1d048bbce9dbe0f0e6940eb8f417a9f8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Aug 2024 16:43:35 +0200 Subject: [PATCH 2286/2612] certs: drop 'DigiCert Global Root CA' --- certs/DigiCert-Global-Root-CA.pem | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 certs/DigiCert-Global-Root-CA.pem diff --git a/certs/DigiCert-Global-Root-CA.pem b/certs/DigiCert-Global-Root-CA.pem deleted file mode 100644 index b0f0013..0000000 --- a/certs/DigiCert-Global-Root-CA.pem +++ /dev/null @@ -1,29 +0,0 @@ -# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root CA" -# Serial: 10944719598952040374951832963794454346 -# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e -# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 -# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB -CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 -nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt -43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P -T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 -gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR -TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw -DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr -hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg -06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF -PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls -YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- From 917be4b42574cd66254a4559330e83bc5c2ed233 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Aug 2024 17:54:13 +0200 Subject: [PATCH 2287/2612] fw-addr-lists: spamhaus.org requires 'GTS Root R4' now Fixes: https://github.com/eworm-de/routeros-scripts/issues/78 --- global-config.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-config.rsc b/global-config.rsc index cdc1d5c..2d10a9e 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -106,9 +106,9 @@ { url="https://lists.blocklist.de/lists/strongips.txt"; cert="Certum Trusted Network CA" }; # { url="https://www.spamhaus.org/drop/drop.txt"; -# cert="Baltimore CyberTrust Root" }; +# cert="GTS Root R4" }; # { url="https://www.spamhaus.org/drop/edrop.txt"; -# cert="Baltimore CyberTrust Root" }; +# cert="GTS Root R4" }; }; # "mikrotik"={ # { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/mikrotik"; From f4c97559b337413fb91bec4927a3de2ac7e81d09 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Aug 2024 17:56:48 +0200 Subject: [PATCH 2288/2612] fw-addr-lists: drop edrop.txt, which does no longer exist --- global-config.rsc | 2 -- 1 file changed, 2 deletions(-) diff --git a/global-config.rsc b/global-config.rsc index 2d10a9e..03e5bb4 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -106,8 +106,6 @@ { url="https://lists.blocklist.de/lists/strongips.txt"; cert="Certum Trusted Network CA" }; # { url="https://www.spamhaus.org/drop/drop.txt"; -# cert="GTS Root R4" }; -# { url="https://www.spamhaus.org/drop/edrop.txt"; # cert="GTS Root R4" }; }; # "mikrotik"={ From 21fa46fdf6720cf3ec57980e29b4da9cf2e0f46d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Aug 2024 17:59:44 +0200 Subject: [PATCH 2289/2612] certs: drop 'Baltimore CyberTrust Root' --- certs/Baltimore-CyberTrust-Root.pem | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 certs/Baltimore-CyberTrust-Root.pem diff --git a/certs/Baltimore-CyberTrust-Root.pem b/certs/Baltimore-CyberTrust-Root.pem deleted file mode 100644 index de8121a..0000000 --- a/certs/Baltimore-CyberTrust-Root.pem +++ /dev/null @@ -1,28 +0,0 @@ -# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust -# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust -# Label: "Baltimore CyberTrust Root" -# Serial: 33554617 -# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 -# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 -# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ -RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD -VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX -DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y -ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy -VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr -mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr -IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK -mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu -XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy -dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye -jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 -BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 -DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 -9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx -jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 -Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz -ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS -R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE----- From 9737bfa46ad5b08f39ba0442061d08e974cb14c5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Sep 2024 22:54:41 +0200 Subject: [PATCH 2290/2612] =?UTF-8?q?certs:=20add=20poor=20man's=20check?= =?UTF-8?q?=20=F0=9F=98=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- certs/Makefile | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 certs/Makefile diff --git a/certs/Makefile b/certs/Makefile new file mode 100644 index 0000000..2e6ac9d --- /dev/null +++ b/certs/Makefile @@ -0,0 +1,31 @@ +# Makefile to check certificates + +DOMAINS = \ + 1.1.1.1/DigiCert-Global-Root-G2 \ + 8.8.8.8/GTS-Root-R1 \ + 9.9.9.9/DigiCert-Global-Root-G3 \ + api.macvendors.com/GTS-Root-R4 \ + api.mullvad.net/ISRG-Root-X1 \ + api.telegram.org/Go-Daddy-Root-Certificate-Authority-G2 \ + cloudflare-dns.com/DigiCert-Global-Root-G2 \ + dns.google/GTS-Root-R1 \ + dns.quad9.net/DigiCert-Global-Root-G3 \ + feodotracker.abuse.ch/GlobalSign \ + git.eworm.de/ISRG-Root-X2 \ + ipv4.showipv6.de/ISRG-Root-X1 \ + ipv4.tunnelbroker.net/Starfield-Root-Certificate-Authority-G2 \ + ipv6.showipv6.de/ISRG-Root-X1 \ + lists.blocklist.de/Certum-Trusted-Network-CA \ + mkcert.org/ISRG-Root-X1 \ + ntfy.sh/ISRG-Root-X1 \ + sslbl.abuse.ch/GlobalSign \ + upgrade.mikrotik.com/ISRG-Root-X1 \ + www.dshield.org/ISRG-Root-X1 \ + www.spamhaus.org/GTS-Root-R4 + +.PHONY: $(DOMAINS) + +all: $(DOMAINS) + +$(DOMAINS): + curl --output /dev/null --silent --connect-timeout 5 --cacert $(notdir $@).pem https://$(dir $@) From 09dcd51feb0d17e7c0715aa10786df169936760a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 4 Sep 2024 12:02:20 +0200 Subject: [PATCH 2291/2612] netwatch-dns: give warning on CRL use --- netwatch-dns.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index e205081..09d471d 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -19,6 +19,7 @@ :global IsDNSResolving; :global IsTimeSync; :global LogPrint; + :global LogPrintOnce; :global ParseKeyValueStore; :global ScriptLock; @@ -126,6 +127,9 @@ :if ($Data != false) do={ :if ([ :typeof [ :find $Data "doh-check-OK" ] ] = "num") do={ /ip/dns/set use-doh-server=($DohServer->"doh-url") verify-doh-cert=yes; + :if ([ /certificate/settings/get crl-use ] = true) do={ + $LogPrintOnce warning $ScriptName ("Configured to use CRL, that can cause severe issue!"); + } /ip/dns/cache/flush; $LogPrint info $ScriptName ("Setting DoH server: " . ($DohServer->"doh-url")); :error true; From d23d05f2ea3b3d0e5c11d0780ef87566641296c7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Sep 2024 22:10:11 +0200 Subject: [PATCH 2292/2612] fw-addr-lists: handle JSON format from spamhaus.org Closes: https://github.com/eworm-de/routeros-scripts/issues/79 --- fw-addr-lists.rsc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 4930e86..4675e3a 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -88,7 +88,12 @@ :while ([ :len $Data ] != 0) do={ :local Line [ :pick $Data 0 [ :find $Data "\n" ] ]; - :local Address ([ :pick $Line 0 [ $FindDelim $Line ] ] . ($List->"cidr")); + :local Address; + :if ([ :pick $Line 0 1 ] = "{") do={ + :set Address [ :tostr ([ :deserialize from=json $Line ]->"cidr") ]; + } else={ + :set Address ([ :pick $Line 0 [ $FindDelim $Line ] ] . ($List->"cidr")); + } :do { :if ($Address ~ "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(/[0-9]{1,2})?\$") do={ :set ($IPv4Addresses->$Address) $TimeOut; From fe52bd4a0a496f896439887c0943e38e8f39ce2c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 5 Sep 2024 22:58:19 +0200 Subject: [PATCH 2293/2612] fw-addr-lists: use lists in JSON format for spamhaus.org --- global-config.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-config.rsc b/global-config.rsc index 03e5bb4..2ed67f3 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -105,7 +105,9 @@ cert="ISRG Root X1" }; { url="https://lists.blocklist.de/lists/strongips.txt"; cert="Certum Trusted Network CA" }; -# { url="https://www.spamhaus.org/drop/drop.txt"; +# { url="https://www.spamhaus.org/drop/drop_v4.json"; +# cert="GTS Root R4" }; +# { url="https://www.spamhaus.org/drop/drop_v6.json"; # cert="GTS Root R4" }; }; # "mikrotik"={ From 41b19b045ad98c528ce9d8d84ab086fe7c54f265 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Sep 2024 10:16:17 +0200 Subject: [PATCH 2294/2612] global-functions: $VersionToNum: support "zero"... ... to have a clean way to generate bitmasks. [admin@mikrotik] > :put [ $VersionToNum 0.255zero0 ] 16711680 [admin@mikrotik] > :put 0x00ff0000 16711680 Once implemented everywhere the internal calculation could be changed easily. --- global-functions.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 41120fd..9ee5312 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1485,7 +1485,7 @@ :global CharacterReplace; :set Input [ $CharacterReplace $Input "." "," ]; - :foreach I in={ "alpha"; "beta"; "rc" } do={ + :foreach I in={ "zero"; "alpha"; "beta"; "rc" } do={ :set Input [ $CharacterReplace $Input $I ("," . $I . ",") ]; } @@ -1496,6 +1496,7 @@ :set Return ($Return + 0xff00); :set Multi ($Multi / 0x100); } else={ + :if ($Value = "zero") do={ } :if ($Value = "alpha") do={ :set Return ($Return + 0x3f00); } :if ($Value = "beta") do={ :set Return ($Return + 0x5f00); } :if ($Value = "rc") do={ :set Return ($Return + 0x7f00); } From 734a80ba82cfb76c34484415a5e810a1d29bdbfe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Sep 2024 10:29:06 +0200 Subject: [PATCH 2295/2612] backup-partition: use $VersionToNum to calculate bitmask --- backup-partition.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index 23dd7ef..51df454 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -81,8 +81,9 @@ :local Update [ /system/package/update/get ]; :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; + :local BitMask [ $VersionToNum "255.255zero0" ]; :if ($BackupPartitionCopyBeforeFeatureUpdate = true && $NumLatest > 0 && \ - ($NumInstalled & 0xffff0000) != ($NumLatest & 0xffff0000)) do={ + ($NumInstalled & $BitMask) != ($NumLatest & $BitMask)) do={ :if ([ $CopyTo $ScriptName $FallbackTo $FallbackToName ] = false) do={ :set PackagesUpdateBackupFailure true; :error false; From c708832b69ece50eca184b0946eebd5b3c579475 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Sep 2024 10:32:40 +0200 Subject: [PATCH 2296/2612] check-routeros-update: use $VersionToNum to calculate bitmask --- check-routeros-update.rsc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 3584a94..84849ea 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -62,6 +62,9 @@ :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; + :local BitMask [ $VersionToNum "255.255zero0" ]; + :local NumInstalledFeature ($NumInstalled & $BitMask); + :local NumLatestFeature ($NumLatest & $BitMask); :local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); :if ($NumLatest < 117505792) do={ @@ -80,7 +83,7 @@ $DoUpdate; } - :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ + :if ($SafeUpdatePatch = true && $NumInstalledFeature = $NumLatestFeature) do={ $LogPrint info $ScriptName ("Version " . $Update->"latest-version" . " is a patch release, updating..."); $SendNotification2 ({ origin=$ScriptName; \ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ @@ -125,7 +128,7 @@ } :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ - :if (($Update->"channel") = "testing" && ($NumInstalled & 0xffff0000) < ($NumLatest & 0xffff0000)) do={ + :if (($Update->"channel") = "testing" && $NumInstalledFeature < $NumLatestFeature) do={ :put ("This is a feature update in testing channel. Switch to channel 'stable'? [y/N]"); :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ /system/package/update/set channel=stable; From 60aa553219b289e9d3e4ef7f0bb7db471f45af69 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 25 Sep 2024 11:01:40 +0200 Subject: [PATCH 2297/2612] hotspot-to-wpa-cleanup: only match access-list with mac-address --- hotspot-to-wpa-cleanup.capsman.rsc | 2 +- hotspot-to-wpa-cleanup.template.rsc | 2 +- hotspot-to-wpa-cleanup.wifi.rsc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index 29bd48d..45ea72b 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -50,7 +50,7 @@ } :foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \ - !(comment~[ /system/clock/get date ]) ] do={ + !(comment~[ /system/clock/get date ]) mac-address ] do={ :local ClientVal [ /caps-man/access-list/get $Client ]; :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ mac-address=($ClientVal->"mac-address") ] ] = 0) do={ diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 06dd9f0..081f3d0 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -54,7 +54,7 @@ :foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \ :foreach Client in=[ /interface/wifi/access-list/find where comment~"^hotspot-to-wpa:" \ - !(comment~[ /system/clock/get date ]) ] do={ + !(comment~[ /system/clock/get date ]) mac-address ] do={ :local ClientVal [ /caps-man/access-list/get $Client ]; :local ClientVal [ /interface/wifi/access-list/get $Client ]; :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index 7c74d10..23f773f 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -50,7 +50,7 @@ } :foreach Client in=[ /interface/wifi/access-list/find where comment~"^hotspot-to-wpa:" \ - !(comment~[ /system/clock/get date ]) ] do={ + !(comment~[ /system/clock/get date ]) mac-address ] do={ :local ClientVal [ /interface/wifi/access-list/get $Client ]; :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ mac-address=($ClientVal->"mac-address") ] ] = 0) do={ From c2c72818de2cf35ea5b50eed3a505f86ed6be294 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 Sep 2024 15:24:05 +0200 Subject: [PATCH 2298/2612] global-functions: $CertificateDownload: add another check... ... that the certificate is really available. Turns out that mkcert.org ships certificates where OU or whatever matches - that's not what we want. --- global-functions.rsc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 9ee5312..e5471dd 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -176,6 +176,12 @@ :delay 1s; /file/remove [ find where name=$FileName ]; + :if ([ :len [ /certificate/find where common-name=$CommonName ] ] = 0) do={ + /certificate/remove [ find where name~("^" . $FileName . "_[0-9]+\$") ]; + $LogPrint warning $0 ("Certificate with CommonName '" . $CommonName . "' still unavailable!"); + :return false; + } + :foreach Cert in=[ /certificate/find where name~("^" . $FileName . "_[0-9]+\$") ] do={ $CertificateNameByCN [ /certificate/get $Cert common-name ]; } From 1776b8f50b173b49ca7ce3ab917de4493ae36ff6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Sep 2024 17:13:32 +0200 Subject: [PATCH 2299/2612] backup-partition: give warning on lock in device-mode RouterOS 7.17beta2 introduced some extra security measures, including some to prevent downgrade attacks for the installation. Thus switching partitions (which can hold quite old installations) is denied by device-mode now by default. Warn about that... https://help.mikrotik.com/docs/display/ROS/Device-mode --- backup-partition.rsc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backup-partition.rsc b/backup-partition.rsc index 51df454..56738ba 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -19,6 +19,7 @@ :global PackagesUpdateBackupFailure; :global LogPrint; + :global RequiredRouterOS; :global ScriptFromTerminal; :global ScriptLock; :global VersionToNum; @@ -59,6 +60,12 @@ :error false; } + :if ([ $RequiredRouterOS $ScriptName "7.17beta2" false ] = true && \ + ([ /system/device-mode/get ]->"partitions") != true) do={ + $LogPrint warning $ScriptName \ + ("The device mode has locked switching partitions! You will need physical access!"); + } + :local FallbackToName [ /partitions/get $ActiveRunning fallback-to ]; :local FallbackTo [ /partition/find where name=$FallbackToName !active ]; From f2576cf55892618c65fca6a1bff03b35a94acee8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 30 Sep 2024 16:10:55 +0200 Subject: [PATCH 2300/2612] packages-update: give warning on lock in device-mode RouterOS 7.17beta2 introduced some extra security measures, including some to prevent downgrade attacks for the installation. Detect early and exit with message and error. https://help.mikrotik.com/docs/display/ROS/Device-mode --- packages-update.rsc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages-update.rsc b/packages-update.rsc index b08a48d..b4fab46 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -18,6 +18,7 @@ :global Grep; :global LogPrint; :global ParseKeyValueStore; + :global RequiredRouterOS; :global ScriptFromTerminal; :global ScriptLock; :global VersionToNum; @@ -99,6 +100,13 @@ :local DoDowngrade false; :if ($NumInstalled > $NumLatest) do={ + :if ([ $RequiredRouterOS $ScriptName "7.17beta2" false ] = true && \ + ([ /system/device-mode/get ]->"downgrade") != true) do={ + $LogPrint error $ScriptName \ + ("The device mode has locked downgrades! You will need physical access!"); + :error false; + } + :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ :put "Latest version is older than installed one. Want to downgrade? [y/N]"; :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ From f75e701be3ceb89615bd29a2bce1404f1bf4117c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 30 Sep 2024 21:51:31 +0200 Subject: [PATCH 2301/2612] log-forward: get last message from log... ... not only from matched massages. --- log-forward.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/log-forward.rsc b/log-forward.rsc index 5133e73..e0d8f35 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -94,9 +94,10 @@ [ $IfThenElse ($Duplicates = true) (" Multi-repeated messages have been skipped.") ] . \ [ $IfThenElse ($LogForwardRateLimit > 30) ("\nRate limit in action, delaying forwarding.") ] . \ "\n" . $Messages) }); - - :set LogForwardLast ($MessageVal->".id"); } else={ :set LogForwardRateLimit [ $MAX 0 ($LogForwardRateLimit - 1) ]; } + + :local LogAll [ /log/find ]; + :set LogForwardLast ($LogAll->([ :len $LogAll ] - 1) ); } on-error={ } From 5135e836b82d36e49dd34ebde7ad2aedda6f8af2 Mon Sep 17 00:00:00 2001 From: Ignacio Serrano Date: Tue, 1 Oct 2024 20:32:37 +0200 Subject: [PATCH 2302/2612] mod/notification-ntfy: fix ntfy overrides --- mod/notification-ntfy.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index 661f69f..b2bb280 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -87,7 +87,7 @@ :return false; } - :local Url ("https://" . $NtfyServer . "/" . [ $UrlEncode $NtfyTopic ]); + :local Url ("https://" . $Server . "/" . [ $UrlEncode $Topic ]); :local Headers ({ [ $FetchUserAgentStr ($Notification->"origin") ]; \ ("Priority: " . [ $IfThenElse ($Notification->"silent") "low" "default" ]); \ ("Title: " . "[" . $IdentityExtra . $Identity . "] " . ($Notification->"subject")) }); @@ -97,7 +97,7 @@ } :do { - :if ($NtfyServer = "ntfy.sh") do={ + :if ($Server = "ntfy.sh") do={ :if ([ $CertificateAvailable "ISRG Root X1" ] = false) do={ $LogPrint warning $0 ("Downloading required certificate failed."); :error false; From 98e62e3eaca9d5d09b70e7ddad44c7fbe21dfbf2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 1 Oct 2024 21:42:20 +0200 Subject: [PATCH 2303/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 0b192fc..dd21fa5 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -20,6 +20,7 @@ for details! * [Anatoly Bubenkov](mailto:bubenkoff@gmail.com) (@bubenkoff) * [Ben Harris](mailto:mail@bharr.is) (@bharrisau) * [Daniel Ziegenberg](mailto:daniel@ziegenberg.at) (@ziegenberg) +* [Ignacio Serrano](mailto:ignic@ignic.com) (@ignic) * [Michael Gisbers](mailto:michael@gisbers.de) (@mgisbers) * @netravnen * [netztrip](mailto:dave-tvg@netztrip.de) (@netztrip) From c955c94098190847856c62e4e9b437200b19884c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 2 Oct 2024 14:02:29 +0200 Subject: [PATCH 2304/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index dd21fa5..ed1d6fa 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -38,6 +38,7 @@ Add yourself to the list, * Daniel Ziegenberg (@ziegenberg) * Devin Dean (@dd2594gh) * Evaldo Gardenal +* Florian Estraviz * Giorgio Bikos * Harold Schoemaker * Hugo BV From 85a7a16c1526acfc86ec313e8527fb616f142a57 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 9 Oct 2024 14:30:29 +0200 Subject: [PATCH 2305/2612] backup-partition: log the warning just once --- backup-partition.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index 56738ba..8b4be9b 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -19,6 +19,7 @@ :global PackagesUpdateBackupFailure; :global LogPrint; + :global LogPrintOnce; :global RequiredRouterOS; :global ScriptFromTerminal; :global ScriptLock; @@ -62,7 +63,7 @@ :if ([ $RequiredRouterOS $ScriptName "7.17beta2" false ] = true && \ ([ /system/device-mode/get ]->"partitions") != true) do={ - $LogPrint warning $ScriptName \ + $LogPrintOnce warning $ScriptName \ ("The device mode has locked switching partitions! You will need physical access!"); } From 82e3e7a9fce024be5b93aa6adc41d6d799c05271 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 10 Oct 2024 22:20:31 +0200 Subject: [PATCH 2306/2612] doc/netwatch-notify: always give a host... ... as that is a required property. Any ip address is fine, it is changed anyway. --- doc/netwatch-notify.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 948cbec..411a4d9 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -88,7 +88,7 @@ threshould by one. The host address can be updated dynamically. Give extra parameter `resolve` with a resolvable name: - /tool/netwatch/add comment="notify, name=example.com, resolve=example.com"; + /tool/netwatch/add comment="notify, name=example.com, resolve=example.com" host=0.0; This supports multiple A or AAAA records for a name just fine, even a CNAME to those. An update happens only if no more record with the configured host @@ -125,7 +125,7 @@ included verbatim into the notification. It is possible to add a link in notification, that is added below the formatted notification text. - /tool/netwatch/add comment="notify, name=example.com, resolve=example.com, link=https://example.com/"; + /tool/netwatch/add comment="notify, name=example.com, resolve=example.com, link=https://example.com/" host=0.0; Tips & Tricks ------------- From f7f50a9d45980e94041c9f48f017778b8a1d279c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 10 Oct 2024 22:24:56 +0200 Subject: [PATCH 2307/2612] doc/netwatch-notify: give an extra example for resolving AAAA records --- doc/netwatch-notify.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 411a4d9..9fa0e26 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -90,10 +90,15 @@ with a resolvable name: /tool/netwatch/add comment="notify, name=example.com, resolve=example.com" host=0.0; -This supports multiple A or AAAA records for a name just fine, even a CNAME +This supports multiple A records for a name just fine, even a CNAME to those. An update happens only if no more record with the configured host address is found. +The address family is preserved, so if you want AAAA records (for IPv6) +use this: + + /tool/netwatch/add comment="notify, name=example.com, resolve=example.com" host=::; + ### No notification on host down Also suppressing the notification on host down is possible with parameter From 71c58c6afb27fc66356f9d5d3d41c5af7ab2f9d7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 10 Oct 2024 22:32:46 +0200 Subject: [PATCH 2308/2612] doc/netwatch-notify: fix typo(s) --- doc/netwatch-notify.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 9fa0e26..81adfe9 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -66,9 +66,9 @@ notification is sent. Getting the escaping right may be troublesome. Please consider adding a script in `/system/script`, then running that from hook. -### Count threshould +### Count threshold -The count threshould (default is 5 checks) is configurable as well: +The count threshold (default is 5 checks) is configurable as well: /tool/netwatch/add comment="notify, name=example.com, count=10" host=104.18.144.11; @@ -81,7 +81,7 @@ suppress notification if the parent host is down: /tool/netwatch/add comment="notify, name=example.com, parent=gateway" host=93.184.216.34; Note that every configured parent in a chain increases the check count -threshould by one. +threshold by one. ### Update from DNS From 435f70999c0fc28aaf804c00552d0d54dcf10806 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Oct 2024 19:32:19 +0200 Subject: [PATCH 2309/2612] backup-partition: drop warning on lock in device-mode ... as switching partitions is possible again in RouterOS 7.17beta4. --- backup-partition.rsc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index 8b4be9b..51df454 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -19,8 +19,6 @@ :global PackagesUpdateBackupFailure; :global LogPrint; - :global LogPrintOnce; - :global RequiredRouterOS; :global ScriptFromTerminal; :global ScriptLock; :global VersionToNum; @@ -61,12 +59,6 @@ :error false; } - :if ([ $RequiredRouterOS $ScriptName "7.17beta2" false ] = true && \ - ([ /system/device-mode/get ]->"partitions") != true) do={ - $LogPrintOnce warning $ScriptName \ - ("The device mode has locked switching partitions! You will need physical access!"); - } - :local FallbackToName [ /partitions/get $ActiveRunning fallback-to ]; :local FallbackTo [ /partition/find where name=$FallbackToName !active ]; From 07c95763775cb5fdef056ef6ba7ff3ac1399dbaf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Oct 2024 19:38:20 +0200 Subject: [PATCH 2310/2612] packages-update: check for explicit state... ... as all device-mode properties are given since RouterOS 7.14beta4. Let's assume we do not have to care about RouterOS 7.14beta2 any more... As older versions will not match the check we can now merge right away. --- packages-update.rsc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index b4fab46..c2f0ba6 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -18,7 +18,6 @@ :global Grep; :global LogPrint; :global ParseKeyValueStore; - :global RequiredRouterOS; :global ScriptFromTerminal; :global ScriptLock; :global VersionToNum; @@ -100,8 +99,7 @@ :local DoDowngrade false; :if ($NumInstalled > $NumLatest) do={ - :if ([ $RequiredRouterOS $ScriptName "7.17beta2" false ] = true && \ - ([ /system/device-mode/get ]->"downgrade") != true) do={ + :if (([ /system/device-mode/get ]->"downgrade") = false) do={ $LogPrint error $ScriptName \ ("The device mode has locked downgrades! You will need physical access!"); :error false; From 7229c756af86df3a670ca79138e6e35342951461 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Oct 2024 23:19:16 +0200 Subject: [PATCH 2311/2612] fw-addr-lists: spamhaus.org requires 'ISRG Root X1' now --- certs/Makefile | 2 +- global-config.rsc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/certs/Makefile b/certs/Makefile index 2e6ac9d..09e7a20 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -21,7 +21,7 @@ DOMAINS = \ sslbl.abuse.ch/GlobalSign \ upgrade.mikrotik.com/ISRG-Root-X1 \ www.dshield.org/ISRG-Root-X1 \ - www.spamhaus.org/GTS-Root-R4 + www.spamhaus.org/ISRG-Root-X1 .PHONY: $(DOMAINS) diff --git a/global-config.rsc b/global-config.rsc index 2ed67f3..c4e04b5 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -106,9 +106,9 @@ { url="https://lists.blocklist.de/lists/strongips.txt"; cert="Certum Trusted Network CA" }; # { url="https://www.spamhaus.org/drop/drop_v4.json"; -# cert="GTS Root R4" }; +# cert="ISRG Root X1" }; # { url="https://www.spamhaus.org/drop/drop_v6.json"; -# cert="GTS Root R4" }; +# cert="ISRG Root X1" }; }; # "mikrotik"={ # { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/mikrotik"; From d022c876514107bd345a17a0c01896947a83b45f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Oct 2024 21:38:38 +0200 Subject: [PATCH 2312/2612] ipv6-update: ignore if address was acquired https://github.com/eworm-de/routeros-scripts/issues/85 --- ipv6-update.rsc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ipv6-update.rsc b/ipv6-update.rsc index 0577bdc..47bf3de 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -18,12 +18,18 @@ :global ParseKeyValueStore; :global ScriptLock; + :local NaAddress $"na-address"; :local PdPrefix $"pd-prefix"; :if ([ $ScriptLock $ScriptName ] = false) do={ :error false; } + :if ([ :typeof $NaAddress ] = "str") do={ + $LogPrint info $ScriptName ("An address (" . $NaAddress . ") was acquired, not a prefix. Ignoring."); + :error false; + } + :if ([ :typeof $PdPrefix ] = "nothing") do={ $LogPrint error $ScriptName ("This script is supposed to run from ipv6 dhcp-client."); :error false; From e803f8b3c0956e8b9f3992433d0a3caf9cb4c899 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Oct 2024 22:35:14 +0200 Subject: [PATCH 2313/2612] ipv6-update: create a dynamic address-list entry only This should make sure that the script runs once after reboot, even if the prefix does not change. An existing static entry needs to be removed to make this work! https://github.com/eworm-de/routeros-scripts/issues/85 --- doc/ipv6-update.md | 12 ++++++++---- ipv6-update.rsc | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md index 88600c5..42f0fe4 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -45,13 +45,17 @@ Installing [ppp-on-up](ppp-on-up.md) may solve this. Configuration ------------- -An address list entry is updated with current prefix and can be used in -firewall rules, comment has to be "`ipv6-pool-`" and actual pool name: +As an address-list entry is mandatory a dynamic one is created automatically. +It is updated with current prefix and can be used in firewall rules. + +Alternatively a static address-list entry can be used, where comment has to +be "`ipv6-pool-`" and actual pool name. Use what ever list is desired, and +create it with: /ipv6/firewall/address-list/add address=2003:cf:2f0f:de00::/56 comment=ipv6-pool-isp list=extern; -As this entry is mandatory it is created automatically if it does not exist, -with the comment also set for list. +If the dynamic entry exists already you need to remove it before creating +the static one.. Address list entries for specific interfaces can be updated as well. The interface needs to get its address from pool `isp` and the address list entry diff --git a/ipv6-update.rsc b/ipv6-update.rsc index 47bf3de..ccc0eb9 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -37,8 +37,8 @@ :local Pool [ /ipv6/pool/get [ find where prefix=$PdPrefix ] name ]; :if ([ :len [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={ - /ipv6/firewall/address-list/add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool); - $LogPrint warning $ScriptName ("Added ipv6 address list entry for ipv6-pool-" . $Pool); + /ipv6/firewall/address-list/add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool) dynamic=yes; + $LogPrint warning $ScriptName ("Added dynamic ipv6 address list entry for ipv6-pool-" . $Pool); } :local AddrList [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ]; :local OldPrefix [ /ipv6/firewall/address-list/get ($AddrList->0) address ]; From 3169270dbda239b860ee7b2989d2bfdf7b5b78c7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Oct 2024 22:31:58 +0100 Subject: [PATCH 2314/2612] doc/mod/notification-matrix: better document certificate import --- doc/mod/notification-matrix.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index c96a719..dd46404 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -46,6 +46,13 @@ The Matrix server is connected via encrypted https, and certificate verification is applied. So make sure you have the certificate chain for your server in device's certificate store. +The example below is for `matrix.org`, which uses a trust chain from *Google +Trust Services*. Run this to import the required certificate: + + $CertificateAvailable "GTS Root R4"; + +Replace the CA certificate name with what ever is needed for your server. + ### From other device If you have setup your Matrix *notification account* before just reuse that. From a6584170c31dc9773840adbc1c7b9721544c764e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Oct 2024 22:33:46 +0100 Subject: [PATCH 2315/2612] certs: check cert for matrix.org --- certs/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/certs/Makefile b/certs/Makefile index 09e7a20..9ce8dd4 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -16,6 +16,7 @@ DOMAINS = \ ipv4.tunnelbroker.net/Starfield-Root-Certificate-Authority-G2 \ ipv6.showipv6.de/ISRG-Root-X1 \ lists.blocklist.de/Certum-Trusted-Network-CA \ + matrix.org/GTS-Root-R4 \ mkcert.org/ISRG-Root-X1 \ ntfy.sh/ISRG-Root-X1 \ sslbl.abuse.ch/GlobalSign \ From 3506f710710332186caecfcd64d9a6d8f57f3180 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 30 Oct 2024 21:52:50 +0100 Subject: [PATCH 2316/2612] global-functions: $CertificateAvailable: fail without CommonName --- global-functions.rsc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index e5471dd..47a69c4 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -107,6 +107,11 @@ "is configured to download certificate CRLs to system!"); } + :if ([ :len $CommonName ] = 0) do={ + $LogPrint warning $0 ("No CommonName given!"); + :return false; + } + :if ([ :len [ /certificate/find where common-name=$CommonName ] ] = 0) do={ $LogPrint info $0 ("Certificate with CommonName '" . $CommonName . "' not available."); :if ([ $CertificateDownload $CommonName ] = false) do={ From 3c0852d6b829d8babc3a57002991e35f7bd31d0a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 30 Oct 2024 17:46:03 +0100 Subject: [PATCH 2317/2612] introduce CERTIFICATES, guide to find root certificate --- CERTIFICATES.d/01-dialog-A.avif | Bin 0 -> 29972 bytes CERTIFICATES.d/02-dialog-B.avif | Bin 0 -> 28821 bytes CERTIFICATES.d/03-window.avif | Bin 0 -> 48111 bytes CERTIFICATES.d/04-certificate.avif | Bin 0 -> 22386 bytes CERTIFICATES.md | 74 +++++++++++++++++++++++++++++ 5 files changed, 74 insertions(+) create mode 100644 CERTIFICATES.d/01-dialog-A.avif create mode 100644 CERTIFICATES.d/02-dialog-B.avif create mode 100644 CERTIFICATES.d/03-window.avif create mode 100644 CERTIFICATES.d/04-certificate.avif create mode 100644 CERTIFICATES.md diff --git a/CERTIFICATES.d/01-dialog-A.avif b/CERTIFICATES.d/01-dialog-A.avif new file mode 100644 index 0000000000000000000000000000000000000000..2fc3c9bdd9e2e846b90814f7d1cb6fc130c498f4 GIT binary patch literal 29972 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 X(5VeJS+20d`+(Mw9f)=(A|Jb;MOUpz literal 0 HcmV?d00001 diff --git a/CERTIFICATES.d/02-dialog-B.avif b/CERTIFICATES.d/02-dialog-B.avif new file mode 100644 index 0000000000000000000000000000000000000000..5e408abedc1a94d8d0988382312d3f34715aef9e GIT binary patch literal 28821 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 literal 0 HcmV?d00001 diff --git a/CERTIFICATES.d/03-window.avif b/CERTIFICATES.d/03-window.avif new file mode 100644 index 0000000000000000000000000000000000000000..96039a3bbab865a20c017636205ab56dc3c0f099 GIT binary patch literal 48111 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 BgM9!1 literal 0 HcmV?d00001 diff --git a/CERTIFICATES.d/04-certificate.avif b/CERTIFICATES.d/04-certificate.avif new file mode 100644 index 0000000000000000000000000000000000000000..e6663146d6f4ec8f70a068751ed96f7f9b90ad75 GIT binary patch literal 22386 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

    ~Yh_~P@|>z=u7`j{mT7_W>n)j6m8kZ+2GJP- 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 V(D}T0{ai`;EVN36d*R2n;;^5yT!{bx literal 0 HcmV?d00001 diff --git a/CERTIFICATES.md b/CERTIFICATES.md new file mode 100644 index 0000000..dfd8639 --- /dev/null +++ b/CERTIFICATES.md @@ -0,0 +1,74 @@ +Certificate name from browser +============================= + +[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) +[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) +[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) +[![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) + +[âŦ…ī¸ Go back to main README](README.md) + +All well known desktop, mobile and server operating systems come with a +certificate store that is populated with a set of well known and trusted +certificates, acting as *trust anchors*. + +However RouterOS does not, still sometimes a specific certificate is +required to properly verify a chain of trust. One example is downloading +the scripts from this repository with `fetch` command, thus the very +first step of [installation](README.md#the-long-way-in-detail) is importing +the certificate. + +The scripts can install additional certificates when required. This happens +from this repository if available, or from [mkcert.org](https://mkcert.org) +as a fallback. + +Get the certificate's CommonName +-------------------------------- + +But how to determine what certificate may be required? Often easiest way +is to use a desktop browser to get that information. This demonstration uses +[Mozilla Firefox](https://www.mozilla.org/firefox/). + +Let's assume we want to make sure the certificate for +[git.eworm.de](https://git.eworm.de/) is available. Open that page in the +browser, then click the *lock* icon in addressbar, followed by "*Connection +secure*". + +![screenshot: dialog A](CERTIFICATES.d/01-dialog-A.avif) + +The dialog will change, click "*More information*". + +![screenshot: dialog B](CERTIFICATES.d/02-dialog-B.avif) + +A new window opens, click the button "*View Certificate*". (That window +can be closed now.) + +![screenshot: window](CERTIFICATES.d/03-window.avif) + +A new tab opens, showing information on the server certificate and its +chain of trust. The leftmost certificate is what we are interested in. + +![screenshot: certificate](CERTIFICATES.d/04-certificate.avif) + +Now we know that "`ISRG Root X2`" is required, some scripts need just +that information. + +Import a certificate by CommonName +---------------------------------- + +Running the function `$CertificateAvailable` with that name as parameter +makes sure the certificate is available in the device's store: + + $CertificateAvailable "ISRG Root X2"; + +If the certificate is actually available already nothing happens, and there +is no output. Otherwise the certificate is downloaded and imported. + +If importing a certificate with that exact name fails a warning is given +and nothing is actually imported. + +--- +[âŦ…ī¸ Go back to main README](README.md) +[âŦ†ī¸ Go back to top](#top) From af942d90d3eae961cc5616118800ec1727e14004 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 31 Oct 2024 14:31:20 +0100 Subject: [PATCH 2318/2612] doc/mod/notification-matrix: link to 'certificate name from browser' --- CERTIFICATES.md | 5 +++++ doc/mod/notification-matrix.md | 3 +++ 2 files changed, 8 insertions(+) diff --git a/CERTIFICATES.md b/CERTIFICATES.md index dfd8639..92a124b 100644 --- a/CERTIFICATES.md +++ b/CERTIFICATES.md @@ -69,6 +69,11 @@ is no output. Otherwise the certificate is downloaded and imported. If importing a certificate with that exact name fails a warning is given and nothing is actually imported. +See also +-------- + +* [Send notifications via Matrix](doc/mod/notification-matrix.md) + --- [âŦ…ī¸ Go back to main README](README.md) [âŦ†ī¸ Go back to top](#top) diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index dd46404..fbc9b91 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -52,6 +52,8 @@ Trust Services*. Run this to import the required certificate: $CertificateAvailable "GTS Root R4"; Replace the CA certificate name with what ever is needed for your server. +You may want to find the +[certificate name from browser](../../CERTIFICATES.md). ### From other device @@ -127,6 +129,7 @@ function available: See also -------- +* [Certificate name from browser](../../CERTIFICATES.md) * [Send notifications via e-mail](notification-email.md) * [Send notifications via Ntfy](notification-ntfy.md) * [Send notifications via Telegram](notification-telegram.md) From c5740c2328c4d468766686717fd14b9860e0494c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 31 Oct 2024 14:43:39 +0100 Subject: [PATCH 2319/2612] doc/mod/notification-ntfy: link to 'certificate name from browser' --- CERTIFICATES.md | 1 + doc/mod/notification-ntfy.md | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CERTIFICATES.md b/CERTIFICATES.md index 92a124b..819c32c 100644 --- a/CERTIFICATES.md +++ b/CERTIFICATES.md @@ -73,6 +73,7 @@ See also -------- * [Send notifications via Matrix](doc/mod/notification-matrix.md) +* [Send notifications via Ntfy](doc/mod/notification-ntfy.md) --- [âŦ…ī¸ Go back to main README](README.md) diff --git a/doc/mod/notification-ntfy.md b/doc/mod/notification-ntfy.md index 2a43e3c..5393d44 100644 --- a/doc/mod/notification-ntfy.md +++ b/doc/mod/notification-ntfy.md @@ -52,6 +52,10 @@ basic authentication. Configure `NtfyServerUser` and `NtfyServerPass` for this. Even authentication via access token is possible, adding it as password with a blank username. +For a custom service installing an additional certificate may be required. +You may want to install that certificate manually, after finding the +[certificate name from browser](../../CERTIFICATES.md). + Usage and invocation -------------------- @@ -82,6 +86,7 @@ function available: See also -------- +* [Certificate name from browser](../../CERTIFICATES.md) * [Send notifications via e-mail](notification-email.md) * [Send notifications via Matrix](notification-matrix.md) * [Send notifications via Telegram](notification-telegram.md) From d213369e73da042014ca68af17831c5bc3eb4310 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 31 Oct 2024 14:34:17 +0100 Subject: [PATCH 2320/2612] doc/fw-addr-lists: link to 'certificate name from browser' --- CERTIFICATES.md | 1 + doc/fw-addr-lists.md | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CERTIFICATES.md b/CERTIFICATES.md index 819c32c..2543299 100644 --- a/CERTIFICATES.md +++ b/CERTIFICATES.md @@ -72,6 +72,7 @@ and nothing is actually imported. See also -------- +* [Download, import and update firewall address-lists](doc/fw-addr-lists.md) * [Send notifications via Matrix](doc/mod/notification-matrix.md) * [Send notifications via Ntfy](doc/mod/notification-ntfy.md) diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md index 2008c7e..3d9e771 100644 --- a/doc/fw-addr-lists.md +++ b/doc/fw-addr-lists.md @@ -62,9 +62,8 @@ The configuration goes to `global-config-overlay`, these are the parameters: > your local `global-config-overlay` and modify it to your specific needs. Naming a certificate for a list makes the script verify the server -certificate, so you should add that if possible. Some certificates are -available in my repository and downloaded automatically. Import it manually -(menu `/certificate/`) if missing. +certificate, so you should add that if possible. You may want to find the +[certificate name from browser](../CERTIFICATES.md). Create firewall rules to process the packets that are related to addresses from address-lists. @@ -127,6 +126,11 @@ Drop packets in firewall's raw section: > âš ī¸ **Warning**: Just again... The order of firewall rules is important. Make > sure they actually take effect as expected! +See also +-------- + +* [Certificate name from browser](../CERTIFICATES.md) + --- [âŦ…ī¸ Go back to main README](../README.md) [âŦ†ī¸ Go back to top](#top) From 31dfdf7e6243527d77af6b4ae93e753cd45c8cbb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 31 Oct 2024 15:17:31 +0100 Subject: [PATCH 2321/2612] doc/netwatch-dns: link to 'certificate name from browser' --- CERTIFICATES.md | 1 + doc/netwatch-dns.md | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CERTIFICATES.md b/CERTIFICATES.md index 2543299..589d480 100644 --- a/CERTIFICATES.md +++ b/CERTIFICATES.md @@ -73,6 +73,7 @@ See also -------- * [Download, import and update firewall address-lists](doc/fw-addr-lists.md) +* [Manage DNS and DoH servers from netwatch](doc/netwatch-dns.md) * [Send notifications via Matrix](doc/mod/notification-matrix.md) * [Send notifications via Ntfy](doc/mod/notification-ntfy.md) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 54dd6c6..cdfbd97 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -59,8 +59,8 @@ resolves to the same address. Be aware that you have to keep the ip address in sync with real world manually! -Importing a certificate automatically is possible, at least if available in -the repository (see `certs` sub directory). +Importing a certificate automatically is possible. You may want to find the +[certificate name from browser](../CERTIFICATES.md). /tool/netwatch/add comment="doh, doh-cert=DigiCert Global Root G2" host=1.1.1.1; /tool/netwatch/add comment="doh, doh-cert=DigiCert Global Root G3" host=9.9.9.9; @@ -87,6 +87,7 @@ Also this allows to update host address, see option `resolve`. See also -------- +* [Certificate name from browser](../CERTIFICATES.md) * [Notify on host up and down](netwatch-notify.md) --- From 084c246ef0cab329fe981732089277fa8398800b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 5 Nov 2024 17:49:28 +0100 Subject: [PATCH 2322/2612] fw-addr-lists: simplify looping lines With `:deserialize` the **record** separator is always a new line. The property `delimiter=` is a **field** reparator, so you can parse a lines into an array. We do not want (or need) that, so use new line as field separator. This will result in an array with just one element, and we use that. Also convert the data to line feed explicitly, just to be sure. --- fw-addr-lists.rsc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 4675e3a..a9513d8 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -65,7 +65,7 @@ :for I from=1 to=5 do={ :if ($Data = false) do={ - :set Data [ $FetchHuge $ScriptName ($List->"url") $CheckCertificate ]; + :set Data [ :tolf [ $FetchHuge $ScriptName ($List->"url") $CheckCertificate ] ]; :if ($Data = false) do={ :if ($I < 5) do={ $LogPrint debug $ScriptName ("Failed downloading for list '" . $FwListName . \ @@ -86,8 +86,8 @@ "B for list '" . $FwListName . "' from: " . $List->"url"); } - :while ([ :len $Data ] != 0) do={ - :local Line [ :pick $Data 0 [ :find $Data "\n" ] ]; + :foreach Line in=[ :deserialize $Data delimiter="\n" from=dsv options=dsv.plain ] do={ + :set Line ($Line->0); :local Address; :if ([ :pick $Line 0 1 ] = "{") do={ :set Address [ :tostr ([ :deserialize from=json $Line ]->"cidr") ]; @@ -109,7 +109,6 @@ :error true; } } on-error={ } - :set Data [ :pick $Data ([ :len $Line ] + 1) [ :len $Data ] ]; } } From 9c945b1a3283bb352707c69630c579cf82484dcb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Nov 2024 10:03:19 +0100 Subject: [PATCH 2323/2612] mod/ssh-keys-import: $SSHKeysImportFile: simplify looping lines --- mod/ssh-keys-import.rsc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 8cafa95..00f443a 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -88,12 +88,11 @@ $LogPrint warning $0 ("File '" . $FileName . "' does not exist."); :return false; } - :local Keys ([ /file/get $FileName contents ] . "\n"); + :local Keys [ :tolf [ /file/get $FileName contents ] ]; - :do { + :foreach Line in=[ :deserialize $Keys delimiter="\n" from=dsv options=dsv.plain ] do={ + :set Line ($Line->0); :local Continue false; - :local Line [ :pick $Keys 0 [ :find $Keys "\n" ] ]; - :set Keys [ :pick $Keys ([ :find $Keys "\n" ] + 1) [ :len $Keys ] ]; :local KeyVal [ :toarray [ $CharacterReplace $Line " " "," ] ]; :if ($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa") do={ :do { @@ -110,5 +109,5 @@ :if ($Continue = false && [ :len ($KeyVal->0) ] > 0) do={ $LogPrint warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported."); } - } while=([ :len $Keys ] > 0); + } } From 0837391c38987462c3a1787143d631b92e0a0551 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Nov 2024 08:30:07 +0100 Subject: [PATCH 2324/2612] mod/ssh-keys-import: $SSHKeysImportFile: let `:deserialize` split the fields --- mod/ssh-keys-import.rsc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 00f443a..f67c0fc 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -72,7 +72,6 @@ :local FileName [ :tostr $1 ]; :local User [ :tostr $2 ]; - :global CharacterReplace; :global EitherOr; :global LogPrint; :global ParseKeyValueStore; @@ -90,20 +89,18 @@ } :local Keys [ :tolf [ /file/get $FileName contents ] ]; - :foreach Line in=[ :deserialize $Keys delimiter="\n" from=dsv options=dsv.plain ] do={ - :set Line ($Line->0); + :foreach KeyVal in=[ :deserialize $Keys delimiter=" " from=dsv options=dsv.plain ] do={ :local Continue false; - :local KeyVal [ :toarray [ $CharacterReplace $Line " " "," ] ]; :if ($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa") do={ :do { - $SSHKeysImport $Line $User; + $SSHKeysImport ($KeyVal->0 . " " . $KeyVal->1 . " " . $KeyVal->2) $User; } on-error={ $LogPrint warning $0 ("Failed importing key for user '" . $User . "'."); } :set Continue true; } :if ($Continue = false && $KeyVal->0 = "#") do={ - :set User [ $EitherOr ([ $ParseKeyValueStore [ :pick $Line 2 [ :len $Line ] ] ]->"user") $User ]; + :set User [ $EitherOr ([ $ParseKeyValueStore ($KeyVal->1) ]->"user") $User ]; :set Continue true; } :if ($Continue = false && [ :len ($KeyVal->0) ] > 0) do={ From 1f526b356121749991fee69cee5a6c728855c8f2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 8 Nov 2024 08:50:12 +0100 Subject: [PATCH 2325/2612] mod/ssh-keys-import: $SSHKeysImport: split with `:deserialize` --- mod/ssh-keys-import.rsc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index f67c0fc..d6b3b3f 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -16,7 +16,6 @@ :local Key [ :tostr $1 ]; :local User [ :tostr $2 ]; - :global CharacterReplace; :global GetRandom20CharAlNum; :global LogPrint; :global MkDir; @@ -32,7 +31,7 @@ :return false; } - :local KeyVal [ :toarray [ $CharacterReplace $Key " " "," ] ]; + :local KeyVal ([ :deserialize $Key delimiter=" " from=dsv options=dsv.plain ]->0); :if (!($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa")) do={ $LogPrint warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported."); :return false; From 6c8fa8e639318b72c2102dfff884aa039d09a0f0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 12 Nov 2024 17:40:05 +0100 Subject: [PATCH 2326/2612] check-routeros-update: replace hard-coded version --- check-routeros-update.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 84849ea..c7a5702 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -67,7 +67,7 @@ :local NumLatestFeature ($NumLatest & $BitMask); :local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); - :if ($NumLatest < 117505792) do={ + :if ($NumLatest < [ $VersionToNum "7.0" ]) do={ $LogPrint info $ScriptName ("The version '" . ($Update->"latest-version") . "' is not a valid version."); :error false; } From d97f63fa5a9e4649338e2a70e83516fbd6a61abc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 12 Nov 2024 17:41:54 +0100 Subject: [PATCH 2327/2612] check-routeros-update: add specific message for empty version string --- check-routeros-update.rsc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index c7a5702..7ff9ccb 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -60,6 +60,11 @@ :error true; } + :if ([ :len ($Update->"latest-version") ] = 0) do={ + $LogPrint info $ScriptName ("Received an empty version string from server."); + :error false; + } + :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; :local BitMask [ $VersionToNum "255.255zero0" ]; From 04172f0438411dd803705f372c7e85bd879d4d6b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 12 Nov 2024 17:42:54 +0100 Subject: [PATCH 2328/2612] check-routeros-update: make invalid version string a warning --- check-routeros-update.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 7ff9ccb..d489351 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -73,7 +73,7 @@ :local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); :if ($NumLatest < [ $VersionToNum "7.0" ]) do={ - $LogPrint info $ScriptName ("The version '" . ($Update->"latest-version") . "' is not a valid version."); + $LogPrint warning $ScriptName ("The version '" . ($Update->"latest-version") . "' is not a valid version."); :error false; } From a545d0d39e21b4fdf0b68153f7b4b175e2ea2bdf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 12 Nov 2024 17:46:02 +0100 Subject: [PATCH 2329/2612] check-routeros-update: always exit early if up to date... ... and just make the output and log dependent on terminal. --- check-routeros-update.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index d489351..0624808 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -55,8 +55,10 @@ /system/package/update/check-for-updates without-paging as-value; :local Update [ /system/package/update/get ]; - :if ([ $ScriptFromTerminal $ScriptName ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={ - $LogPrint info $ScriptName ("System is already up to date."); + :if (($Update->"installed-version") = ($Update->"latest-version")) do={ + :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ + $LogPrint info $ScriptName ("System is already up to date."); + } :error true; } From f1533b8962bc67d17e9f6b5666ae51ee4d1e1ff4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 12 Nov 2024 17:53:30 +0100 Subject: [PATCH 2330/2612] hotspot-to-wpa-cleanup: use the timeout in message... ... not the actual value. --- hotspot-to-wpa-cleanup.capsman.rsc | 2 +- hotspot-to-wpa-cleanup.template.rsc | 2 +- hotspot-to-wpa-cleanup.wifi.rsc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index 45ea72b..e305170 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -65,7 +65,7 @@ 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."); + " was not seen for " . $Timeout . ", removing."); /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ mac-address=($LeaseVal->"mac-address") ]; /ip/dhcp-server/lease/remove $Lease; diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 081f3d0..70bee42 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -71,7 +71,7 @@ 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."); + " was not seen for " . $Timeout . ", removing."); /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ mac-address=($LeaseVal->"mac-address") ]; diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index 23f773f..c814705 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -65,7 +65,7 @@ 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."); + " was not seen for " . $Timeout . ", removing."); /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ mac-address=($LeaseVal->"mac-address") ]; /ip/dhcp-server/lease/remove $Lease; From ae655646ba21cdf4638e6001a49c9d3cf849bc08 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 12 Nov 2024 18:02:26 +0100 Subject: [PATCH 2331/2612] hotspot-to-wpa-cleanup: clean up daily only --- hotspot-to-wpa-cleanup.capsman.rsc | 3 ++- hotspot-to-wpa-cleanup.template.rsc | 3 ++- hotspot-to-wpa-cleanup.wifi.rsc | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index e305170..674a480 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -62,7 +62,8 @@ :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={ + server=$Server last-seen>($Timeout + [ /system/clock/get time ]) \ + 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 " . $Timeout . ", removing."); diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 70bee42..88c307b 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -68,7 +68,8 @@ :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={ + server=$Server last-seen>($Timeout + [ /system/clock/get time ]) \ + 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 " . $Timeout . ", removing."); diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index c814705..b73f1a9 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -62,7 +62,8 @@ :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={ + server=$Server last-seen>($Timeout + [ /system/clock/get time ]) \ + 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 " . $Timeout . ", removing."); From e5c3aeb5cd314119dd7b062e43d65fdff7371051 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Nov 2024 08:57:05 +0100 Subject: [PATCH 2332/2612] hotspot-to-wpa-cleanup: prepare real timeout value in variable... ... to make sure it is not re-calculated for every single lease. --- hotspot-to-wpa-cleanup.capsman.rsc | 4 ++-- hotspot-to-wpa-cleanup.template.rsc | 4 ++-- hotspot-to-wpa-cleanup.wifi.rsc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index 674a480..d429904 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -61,9 +61,9 @@ } :foreach Server,Timeout in=$DHCPServers do={ + :local TimeoutExtra ($Timeout + [ /system/clock/get time ]); :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ - server=$Server last-seen>($Timeout + [ /system/clock/get time ]) \ - comment~"^hotspot-to-wpa:" ] do={ + server=$Server last-seen>$TimeoutExtra comment~"^hotspot-to-wpa:" ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; $LogPrint info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ " was not seen for " . $Timeout . ", removing."); diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 88c307b..726bc74 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -67,9 +67,9 @@ } :foreach Server,Timeout in=$DHCPServers do={ + :local TimeoutExtra ($Timeout + [ /system/clock/get time ]); :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ - server=$Server last-seen>($Timeout + [ /system/clock/get time ]) \ - comment~"^hotspot-to-wpa:" ] do={ + server=$Server last-seen>$TimeoutExtra comment~"^hotspot-to-wpa:" ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; $LogPrint info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ " was not seen for " . $Timeout . ", removing."); diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index b73f1a9..32ae565 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -61,9 +61,9 @@ } :foreach Server,Timeout in=$DHCPServers do={ + :local TimeoutExtra ($Timeout + [ /system/clock/get time ]); :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ - server=$Server last-seen>($Timeout + [ /system/clock/get time ]) \ - comment~"^hotspot-to-wpa:" ] do={ + server=$Server last-seen>$TimeoutExtra comment~"^hotspot-to-wpa:" ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; $LogPrint info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ " was not seen for " . $Timeout . ", removing."); From a224fbc42457550fcb7f6daa81c2cb14b7075799 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 13 Nov 2024 08:59:30 +0100 Subject: [PATCH 2333/2612] hotspot-to-wpa-cleanup: revert display of timeout value... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... as the timeout is a time value, and showing "4w00:00:00" (with lots of zeros) is not any better. 😜 This reverts commit f1533b8962bc67d17e9f6b5666ae51ee4d1e1ff4. --- hotspot-to-wpa-cleanup.capsman.rsc | 2 +- hotspot-to-wpa-cleanup.template.rsc | 2 +- hotspot-to-wpa-cleanup.wifi.rsc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index d429904..e935850 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -66,7 +66,7 @@ server=$Server last-seen>$TimeoutExtra comment~"^hotspot-to-wpa:" ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; $LogPrint info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . $Timeout . ", removing."); + " 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; diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 726bc74..fa99b5d 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -72,7 +72,7 @@ server=$Server last-seen>$TimeoutExtra comment~"^hotspot-to-wpa:" ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; $LogPrint info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . $Timeout . ", removing."); + " was not seen for " . ($LeaseVal->"last-seen") . ", removing."); /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ mac-address=($LeaseVal->"mac-address") ]; diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index 32ae565..d3f859e 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -66,7 +66,7 @@ server=$Server last-seen>$TimeoutExtra comment~"^hotspot-to-wpa:" ] do={ :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; $LogPrint info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . $Timeout . ", removing."); + " was not seen for " . ($LeaseVal->"last-seen") . ", removing."); /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ mac-address=($LeaseVal->"mac-address") ]; /ip/dhcp-server/lease/remove $Lease; From 5b09469cc6c707b473b74687951b2d1e6468928a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 14 Nov 2024 21:03:07 +0100 Subject: [PATCH 2334/2612] packages-update: drop check for device-mode downgrade... ... as things have been revised and this specific setting was removed. --- packages-update.rsc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index c2f0ba6..b08a48d 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -99,12 +99,6 @@ :local DoDowngrade false; :if ($NumInstalled > $NumLatest) do={ - :if (([ /system/device-mode/get ]->"downgrade") = false) do={ - $LogPrint error $ScriptName \ - ("The device mode has locked downgrades! You will need physical access!"); - :error false; - } - :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ :put "Latest version is older than installed one. Want to downgrade? [y/N]"; :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ From 1beda3aa7c08cbe0e06aff164fabfa86e8b6353d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 Nov 2024 23:01:22 +0100 Subject: [PATCH 2335/2612] mode-button: fix the caller parameter to $LogPrint This is inside a function, so use just $0 here. --- mode-button.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mode-button.rsc b/mode-button.rsc index 7908a7f..84eb8ea 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -52,7 +52,7 @@ :if ([ :len $Code ] > 0) do={ :if ([ $ValidateSyntax $Code ] = true) do={ - $LogPrint info $ScriptName ("Acting on " . $Count . " mode-button presses: " . $Code); + $LogPrint info $0 ("Acting on " . $Count . " mode-button presses: " . $Code); :for I from=1 to=$Count do={ $LEDInvert; @@ -66,10 +66,10 @@ [ :parse $Code ]; } else={ - $LogPrint warning $ScriptName ("The code for " . $Count . " mode-button presses failed syntax validation!"); + $LogPrint warning $0 ("The code for " . $Count . " mode-button presses failed syntax validation!"); } } else={ - $LogPrint info $ScriptName ("No action defined for " . $Count . " mode-button presses."); + $LogPrint info $0 ("No action defined for " . $Count . " mode-button presses."); } } /system/scheduler/add name="_ModeButtonScheduler" \ From 53b6f7720ec33146581ceb878447d35d462c8697 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 Nov 2024 23:02:43 +0100 Subject: [PATCH 2336/2612] mode-button: catch runtime errors in executed code --- mode-button.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mode-button.rsc b/mode-button.rsc index 84eb8ea..ac1fb4f 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -64,7 +64,11 @@ :delay 200ms; } - [ :parse $Code ]; + :do { + [ :parse $Code ]; + } on-error={ + $LogPrint warning $0 ("The code for " . $Count . " mode-button presses failed with runtime error!"); + } } else={ $LogPrint warning $0 ("The code for " . $Count . " mode-button presses failed syntax validation!"); } From 08ad4e519410c91d61e172f4ea97046dffc2db31 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 Nov 2024 23:07:26 +0100 Subject: [PATCH 2337/2612] mode-button: do not act on disabled LED --- mode-button.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mode-button.rsc b/mode-button.rsc index ac1fb4f..3bd922b 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -36,7 +36,8 @@ :global IfThenElse; - :local LED [ /system/leds/find where leds=$ModeButtonLED type~"^(on|off)\$" interface=[] ]; + :local LED [ /system/leds/find where leds=$ModeButtonLED \ + !disabled type~"^(on|off)\$" interface=[] ]; :if ([ :len $LED ] = 0) do={ :return false; } From 4d8dce97691ad090091574a790449a7bd564023c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 22 Nov 2024 14:06:22 +0100 Subject: [PATCH 2338/2612] fw-addr-lists: spamhaus.org returned to 'GTS Root R4' --- certs/Makefile | 2 +- global-config.rsc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/certs/Makefile b/certs/Makefile index 9ce8dd4..870cb54 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -22,7 +22,7 @@ DOMAINS = \ sslbl.abuse.ch/GlobalSign \ upgrade.mikrotik.com/ISRG-Root-X1 \ www.dshield.org/ISRG-Root-X1 \ - www.spamhaus.org/ISRG-Root-X1 + www.spamhaus.org/GTS-Root-R4 .PHONY: $(DOMAINS) diff --git a/global-config.rsc b/global-config.rsc index c4e04b5..2ed67f3 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -106,9 +106,9 @@ { url="https://lists.blocklist.de/lists/strongips.txt"; cert="Certum Trusted Network CA" }; # { url="https://www.spamhaus.org/drop/drop_v4.json"; -# cert="ISRG Root X1" }; +# cert="GTS Root R4" }; # { url="https://www.spamhaus.org/drop/drop_v6.json"; -# cert="ISRG Root X1" }; +# cert="GTS Root R4" }; }; # "mikrotik"={ # { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/mikrotik"; From 794525b706827682c3525eeeb0797567c757b7de Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 27 Nov 2024 09:54:19 +0100 Subject: [PATCH 2339/2612] fw-addr-lists: require RouterOS 7.16 Actually the requirement bumped with the change in commit: * 084c246ef0cab329fe981732089277fa8398800b fw-addr-lists: simplify looping lines --- doc/fw-addr-lists.md | 2 +- fw-addr-lists.rsc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md index 3d9e771..f581fd2 100644 --- a/doc/fw-addr-lists.md +++ b/doc/fw-addr-lists.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.16-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index a9513d8..34b2fcc 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2023-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.16 # # download, import and update firewall address-lists # https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md From e851cd5ad0ccb38667ec88a52fdc123cc5a16aee Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 27 Nov 2024 09:57:11 +0100 Subject: [PATCH 2340/2612] mod/ssh-keys-import: require RouterOS 7.16 Actually the requirement bumped with the change in commits: * 9c945b1a3283bb352707c69630c579cf82484dcb mod/ssh-keys-import: $SSHKeysImportFile: simplify looping lines * 1f526b356121749991fee69cee5a6c728855c8f2 mod/ssh-keys-import: $SSHKeysImport: split with `:deserialize` --- doc/mod/ssh-keys-import.md | 2 +- mod/ssh-keys-import.rsc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md index dcfd95b..344f4bc 100644 --- a/doc/mod/ssh-keys-import.md +++ b/doc/mod/ssh-keys-import.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.16-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index d6b3b3f..c7b2788 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.16 # # import ssh keys for public key authentication # https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ssh-keys-import.md From 6548f83ef4f60efadc3574876680801ee09ef638 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 8 Aug 2024 21:30:46 +0200 Subject: [PATCH 2341/2612] dhcp-to-dns: explicitly expect type=A... ... which is provided since 7.16beta7 (but require next stable release 7.16 as that is available meanwhile). I had this on my wishlist for a long time, and opened an issue in March 2023 about it (SUP-111312). Back then I changed the code to support both, see commit 779b3b8872b23b784c331d7a454c86439046f5d3. --- dhcp-to-dns.rsc | 8 ++++---- doc/dhcp-to-dns.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 0ab5e2a..9bf506f 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -4,7 +4,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=20 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.16 # # check DHCP leases and add/remove/update DNS entries # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md @@ -40,7 +40,7 @@ } :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={ + :foreach DnsRecord in=[ /ip/dns/static/find where comment~("^" . $CommentPrefix . "\\b") type=A ] do={ :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; :local DnsRecordInfo [ $ParseKeyValueStore ($DnsRecordVal->"comment") ]; :local MacInServer ($DnsRecordInfo->"macaddress" . " in " . $DnsRecordInfo->"server"); @@ -83,7 +83,7 @@ :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) ]; + :local DnsRecord [ /ip/dns/static/find where comment=$Comment type=A ]; :if ([ :len $DnsRecord ] > 0) do={ :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; @@ -116,7 +116,7 @@ } } - :if ([ :len [ /ip/dns/static/find where name=$FullA (!type or type=A) ] ] > 1) do={ + :if ([ :len [ /ip/dns/static/find where name=$FullA type=A ] ] > 1) do={ $LogPrintOnce warning $ScriptName ("The name '" . $FullA . "' appeared in more than one A record!"); } } else={ diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 572011f..4211d85 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.16-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) From 09e8b1d21953ad8ba5185b3cb02bbd4b35269963 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Aug 2024 08:53:20 +0200 Subject: [PATCH 2342/2612] netwatch-dns: explicitly expect type=A... ... which is provided since 7.16beta7 (but require next stable release 7.16 as that is available meanwhile). --- doc/netwatch-dns.md | 2 +- netwatch-dns.rsc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index cdfbd97..6d2c865 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.16-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 09d471d..6fbfc89 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2022-2024 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.16 # # monitor and manage dns/doh with netwatch # https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-dns.md @@ -80,7 +80,7 @@ :local HostVal [ /tool/netwatch/get $Host ]; :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; :local HostName [ /ip/dns/static/find where name address=($HostVal->"host") \ - (!type or type="A" or type="AAAA") !disabled !dynamic ]; + (type="A" or type="AAAA") !disabled !dynamic ]; :if ([ :len $HostName ] > 0) do={ :set HostName [ /ip/dns/static/get ($HostName->0) name ]; } From 0d69f8952c25f3bfecd9e33c1520e74eebe42314 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:06:56 +0100 Subject: [PATCH 2343/2612] global-functions: introduce $ExitError... ... as a simple macro to print error message on unintentional error. --- global-functions.rsc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 6fec6dd..26ccc2a 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -32,6 +32,7 @@ :global DownloadPackage; :global EitherOr; :global EscapeForRegEx; +:global ExitError; :global FetchHuge; :global FetchUserAgentStr; :global FormatLine; @@ -425,6 +426,18 @@ :return $Return; } +# simple macro to print error message on unintentional error +:set ExitError do={ + :local ExitOK [ :tostr $1 ]; + :local ScriptName [ :tostr $2 ]; + + :global LogPrint; + + :if ($ExitOK = "false") do={ + $LogPrint error $ScriptName ("Script exited with error."); + } +} + # fetch huge data to file, read in chunks :set FetchHuge do={ :local ScriptName [ :tostr $1 ]; From ed6739b8bcb93f8e1025401e22db4244c70ac8c6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 8 Dec 2024 22:02:52 +0100 Subject: [PATCH 2344/2612] global-functions: $ExitError: give script name in message --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 26ccc2a..8941994 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -434,7 +434,7 @@ :global LogPrint; :if ($ExitOK = "false") do={ - $LogPrint error $ScriptName ("Script exited with error."); + $LogPrint error $ScriptName ("Script '" . $ScriptName . "' exited with error."); } } From 36b81fab9474aa0ddc6acdb88f51ef211a1c5563 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:19:54 +0100 Subject: [PATCH 2345/2612] backup-cloud: use $ExitError to indicate unintentional error --- backup-cloud.rsc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index f70752e..4cc7a58 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -12,6 +12,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -34,6 +35,7 @@ :if ([ $ScriptLock $ScriptName ] = false) do={ :set PackagesUpdateBackupFailure true; + :set ExitOK true; :error false; } $WaitFullyConnected; @@ -44,6 +46,7 @@ :if ([ $MkDir ("tmpfs/backup-cloud") ] = false) do={ $LogPrint error $ScriptName ("Failed creating directory!"); + :set ExitOK true; :error false; } @@ -87,4 +90,6 @@ :set PackagesUpdateBackupFailure true; } /file/remove "tmpfs/backup-cloud"; -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 52b5490babc9005fbbb8e0cb1e2ae323a2bd2f70 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:22:11 +0100 Subject: [PATCH 2346/2612] backup-email: use $ExitError to indicate unintentional error --- backup-email.rsc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/backup-email.rsc b/backup-email.rsc index e507c6e..e1d44ea 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -12,6 +12,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -39,17 +40,20 @@ :if ([ :typeof $SendEMail2 ] = "nothing") do={ $LogPrint error $ScriptName ("The module for sending notifications via e-mail is not installed."); + :set ExitOK true; :error false; } :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ $LogPrint error $ScriptName ("Configured to send neither backup nor config export."); + :set ExitOK true; :error false; } :if ([ $ScriptLock $ScriptName ] = false) do={ :set PackagesUpdateBackupFailure true; + :set ExitOK true; :error false; } $WaitFullyConnected; @@ -69,6 +73,7 @@ :if ([ $MkDir $DirName ] = false) do={ $LogPrint error $ScriptName ("Failed creating directory!"); + :set ExitOK true; :error false; } @@ -116,9 +121,12 @@ :if ($I >= 120) do={ $LogPrint warning $ScriptName ("Files are still available, sending e-mail failed."); :set PackagesUpdateBackupFailure true; + :set ExitOK true; :error false; } :delay 1s; :set I ($I + 1); } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 2c4053cff55a7d0a90f364f7aded280422dc1d65 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:26:34 +0100 Subject: [PATCH 2347/2612] accesslist-duplicates: use $ExitError to indicate unintentional error --- accesslist-duplicates.capsman.rsc | 5 ++++- accesslist-duplicates.local.rsc | 5 ++++- accesslist-duplicates.template.rsc | 5 ++++- accesslist-duplicates.wifi.rsc | 5 ++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index d6e2928..ce0ce11 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -13,6 +13,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -31,4 +32,6 @@ } :set ($Seen->$Mac) 1; } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index e90842d..aa78fe8 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -13,6 +13,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -31,4 +32,6 @@ } :set ($Seen->$Mac) 1; } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index d275340..d0c282d 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -40,4 +41,6 @@ } :set ($Seen->$Mac) 1; } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc index f4dae4b..b1444e3 100644 --- a/accesslist-duplicates.wifi.rsc +++ b/accesslist-duplicates.wifi.rsc @@ -13,6 +13,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -31,4 +32,6 @@ } :set ($Seen->$Mac) 1; } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 95030b9b74db03cf67c4702c82bb1d1224c9690e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:28:30 +0100 Subject: [PATCH 2348/2612] backup-partition: use $ExitError to indicate unintentional error --- backup-partition.rsc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index 51df454..f1e1c17 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -12,6 +12,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -42,12 +43,14 @@ :if ([ $ScriptLock $ScriptName ] = false) do={ :set PackagesUpdateBackupFailure true; + :set ExitOK true; :error false; } :if ([ :len [ /partitions/find ] ] < 2) do={ $LogPrint error $ScriptName ("Device does not have a fallback partition."); :set PackagesUpdateBackupFailure true; + :set ExitOK true; :error false; } @@ -56,6 +59,7 @@ :if ([ :len $ActiveRunning ] < 1) do={ $LogPrint error $ScriptName ("Device is not running from active partition."); :set PackagesUpdateBackupFailure true; + :set ExitOK true; :error false; } @@ -65,6 +69,7 @@ :if ([ :len $FallbackTo ] < 1) do={ $LogPrint error $ScriptName ("There is no inactive partition named '" . $FallbackToName . "'."); :set PackagesUpdateBackupFailure true; + :set ExitOK true; :error false; } @@ -74,6 +79,7 @@ :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ :if ([ $CopyTo $ScriptName $FallbackTo $FallbackToName ] = false) do={ :set PackagesUpdateBackupFailure true; + :set ExitOK true; :error false; } } @@ -86,6 +92,7 @@ ($NumInstalled & $BitMask) != ($NumLatest & $BitMask)) do={ :if ([ $CopyTo $ScriptName $FallbackTo $FallbackToName ] = false) do={ :set PackagesUpdateBackupFailure true; + :set ExitOK true; :error false; } } @@ -103,6 +110,9 @@ /system/scheduler/remove [ find where name="running-from-backup-partition" ]; $LogPrint error $ScriptName ("Failed saving configuration to partition '" . $FallbackToName . "'!"); :set PackagesUpdateBackupFailure true; + :set ExitOK true; :error false; } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 268743ef6be5c400ec9fcb044e4961c5d8d9b531 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:29:02 +0100 Subject: [PATCH 2349/2612] backup-upload: use $ExitError to indicate unintentional error --- backup-upload.rsc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 8d96eba..12698e9 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -12,6 +12,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -43,11 +44,13 @@ :if ($BackupSendBinary != true && \ $BackupSendExport != true) do={ $LogPrint error $ScriptName ("Configured to send neither backup nor config export."); + :set ExitOK true; :error false; } :if ([ $ScriptLock $ScriptName ] = false) do={ :set PackagesUpdateBackupFailure true; + :set ExitOK true; :error false; } $WaitFullyConnected; @@ -67,6 +70,7 @@ :if ([ $MkDir $DirName ] = false) do={ $LogPrint error $ScriptName ("Failed creating directory!"); + :set ExitOK true; :error false; } @@ -158,4 +162,6 @@ :set PackagesUpdateBackupFailure true; } /file/remove $DirName; -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From c909bef613884bf67d239a1e6c0bed4e3d7a112e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:51 +0100 Subject: [PATCH 2350/2612] capsman-download-packages: use $ExitError to indicate unintentional error --- capsman-download-packages.capsman.rsc | 8 +++++++- capsman-download-packages.template.rsc | 8 +++++++- capsman-download-packages.wifi.rsc | 8 +++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index f2ff024..1802884 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -25,6 +26,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } $WaitFullyConnected; @@ -35,6 +37,7 @@ :if ([ :len $PackagePath ] = 0) do={ $LogPrint warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages."); + :set ExitOK true; :error false; } @@ -42,6 +45,7 @@ :if ([ $MkDir $PackagePath ] = false) do={ $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ $PackagePath . ") failed!"); + :set ExitOK true; :error false; } $LogPrint info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ @@ -82,4 +86,6 @@ /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index ad9b926..72edaa9 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -15,6 +15,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -26,6 +27,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } $WaitFullyConnected; @@ -37,6 +39,7 @@ :if ([ :len $PackagePath ] = 0) do={ $LogPrint warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages."); + :set ExitOK true; :error false; } @@ -44,6 +47,7 @@ :if ([ $MkDir $PackagePath ] = false) do={ $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ $PackagePath . ") failed!"); + :set ExitOK true; :error false; } $LogPrint info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ @@ -93,4 +97,6 @@ /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 056136f..74a5d9d 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -25,6 +26,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } $WaitFullyConnected; @@ -35,6 +37,7 @@ :if ([ :len $PackagePath ] = 0) do={ $LogPrint warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages."); + :set ExitOK true; :error false; } @@ -42,6 +45,7 @@ :if ([ $MkDir $PackagePath ] = false) do={ $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ $PackagePath . ") failed!"); + :set ExitOK true; :error false; } $LogPrint info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ @@ -84,4 +88,6 @@ /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 172d43288e2117f2a687df6168d2d461e780a8c3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:51 +0100 Subject: [PATCH 2351/2612] capsman-rolling-upgrade: use $ExitError to indicate unintentional error --- capsman-rolling-upgrade.capsman.rsc | 6 +++++- capsman-rolling-upgrade.template.rsc | 6 +++++- capsman-rolling-upgrade.wifi.rsc | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc index f287ea3..d0f9fb8 100644 --- a/capsman-rolling-upgrade.capsman.rsc +++ b/capsman-rolling-upgrade.capsman.rsc @@ -15,6 +15,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -22,6 +23,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -43,4 +45,6 @@ :delay ($Delay . "s"); } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index 3d98747..1bd5f2a 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -16,6 +16,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -23,6 +24,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -51,4 +53,6 @@ :delay ($Delay . "s"); } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc index 369dccc..c9e6622 100644 --- a/capsman-rolling-upgrade.wifi.rsc +++ b/capsman-rolling-upgrade.wifi.rsc @@ -15,6 +15,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -22,6 +23,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -44,4 +46,6 @@ :delay ($Delay . "s"); } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From dc7642c1fd3c3029e3993d9ff73b7743ec8e0ea8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:51 +0100 Subject: [PATCH 2352/2612] certificate-renew-issued: use $ExitError to indicate unintentional error --- certificate-renew-issued.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc index f2c1dfe..ce61f7d 100644 --- a/certificate-renew-issued.rsc +++ b/certificate-renew-issued.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -21,6 +22,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -45,4 +47,6 @@ $LogPrint info $ScriptName ("Issued a new certificate for '" . $CertVal->"common-name" . "'."); } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 00487f93d48e5e7547281808225d108eeeae586f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:51 +0100 Subject: [PATCH 2353/2612] check-certificates: use $ExitError to indicate unintentional error --- check-certificates.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 7aaac84..52cfc5e 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -133,6 +134,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } $WaitFullyConnected; @@ -218,4 +220,6 @@ ", it is invalid after " . ($CertVal->"invalid-after") . "."); } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 451df78dd8371288413fd45064141b6063e36187 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:51 +0100 Subject: [PATCH 2354/2612] check-health: use $ExitError to indicate unintentional error --- check-health.rsc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/check-health.rsc b/check-health.rsc index 540336d..495b450 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -40,6 +41,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -78,6 +80,7 @@ :if ([ :len [ /system/health/find ] ] = 0) do={ $LogPrint debug $ScriptName ("Your device does not provide any health values."); + :set ExitOK true; :error true; } @@ -175,4 +178,6 @@ } :set ($CheckHealthLast->$Name) $Value; } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 91c8d306558c056792ff8132caa77fdf0bda059a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:51 +0100 Subject: [PATCH 2355/2612] check-lte-firmware-upgrade: use $ExitError to indicate unintentional error --- check-lte-firmware-upgrade.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index 2e52c2a..898d6f1 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -19,6 +20,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -100,4 +102,6 @@ :foreach Interface in=[ /interface/lte/find ] do={ $CheckInterface $ScriptName $Interface; } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 9d17beef03ace2d75c9e2f9f98fa297707c9e0e3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:51 +0100 Subject: [PATCH 2356/2612] check-routeros-update: use $ExitError to indicate unintentional error --- check-routeros-update.rsc | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 0624808..510acd9 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -34,20 +35,24 @@ :global WaitFullyConnected; :local DoUpdate do={ + :global LogPrint; + :if ([ :len [ /system/script/find where name="packages-update" ] ] > 0) do={ /system/script/run packages-update; } else={ /system/package/update/install without-paging; } - :error "Waiting for system to reboot."; + $LogPrint info $0 ("Waiting for system to reboot."); } :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } $WaitFullyConnected; :if ([ :len [ /system/scheduler/find where name="_RebootForUpdate" ] ] > 0) do={ + :set ExitOK true; :error "A reboot for update is already scheduled."; } @@ -59,11 +64,13 @@ :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ $LogPrint info $ScriptName ("System is already up to date."); } + :set ExitOK true; :error true; } :if ([ :len ($Update->"latest-version") ] = 0) do={ $LogPrint info $ScriptName ("Received an empty version string from server."); + :set ExitOK true; :error false; } @@ -76,6 +83,7 @@ :if ($NumLatest < [ $VersionToNum "7.0" ]) do={ $LogPrint warning $ScriptName ("The version '" . ($Update->"latest-version") . "' is not a valid version."); + :set ExitOK true; :error false; } @@ -88,6 +96,8 @@ message=("Installing ALL versions automatically, including " . $Update->"latest-version" . \ "... Updating on " . $Identity . "..."); link=$Link; silent=true }); $DoUpdate; + :set ExitOK true; + :error true; } :if ($SafeUpdatePatch = true && $NumInstalledFeature = $NumLatestFeature) do={ @@ -97,6 +107,8 @@ message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ ", updating on " . $Identity . "..."); link=$Link; silent=true }); $DoUpdate; + :set ExitOK true; + :error true; } :if ($SafeUpdateNeighbor = true) do={ @@ -111,6 +123,8 @@ message=("Seen a neighbor (" . $Neighbor . ") running version " . $Update->"latest-version" . \ " from " . $Update->"channel" . ", updating on " . $Identity . "..."); link=$Link; silent=true }); $DoUpdate; + :set ExitOK true; + :error true; } } @@ -131,6 +145,8 @@ message=("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ ", updating on " . $Identity . "..."); link=$Link; silent=true }); $DoUpdate; + :set ExitOK true; + :error true; } } @@ -140,6 +156,7 @@ :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ /system/package/update/set channel=stable; $LogPrint info $ScriptName ("Switched to channel 'stable', please re-run!"); + :set ExitOK true; :error true; } } @@ -147,6 +164,8 @@ :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ $DoUpdate; + :set ExitOK true; + :error true; } else={ :put "Canceled..."; } @@ -155,6 +174,7 @@ :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ $LogPrint info $ScriptName ("Already sent the RouterOS update notification for version " . \ $Update->"latest-version" . "."); + :set ExitOK true; :error true; } @@ -170,6 +190,7 @@ :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ $LogPrint info $ScriptName ("Already sent the RouterOS downgrade notification for version " . \ $Update->"latest-version" . "."); + :set ExitOK true; :error true; } @@ -182,4 +203,6 @@ " is available for downgrade."); :set SentRouterosUpdateNotification ($Update->"latest-version"); } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From bf322781d17629c3254520766ae540fb3ae846be Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:51 +0100 Subject: [PATCH 2357/2612] collect-wireless-mac: use $ExitError to indicate unintentional error --- collect-wireless-mac.capsman.rsc | 6 +++++- collect-wireless-mac.local.rsc | 6 +++++- collect-wireless-mac.template.rsc | 6 +++++- collect-wireless-mac.wifi.rsc | 6 +++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index 9efa9ef..77fd6e3 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -29,6 +30,7 @@ :global SymbolForNotification; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :set ExitOK true; :error false; } @@ -93,4 +95,6 @@ $LogPrint debug $ScriptName ("No mac address available... Ignoring."); } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index 27c9d1c..dc7be19 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -29,6 +30,7 @@ :global SymbolForNotification; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :set ExitOK true; :error false; } @@ -94,4 +96,6 @@ $LogPrint debug $ScriptName ("No mac address available... Ignoring."); } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index d41c17d..34b1695 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -15,6 +15,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -30,6 +31,7 @@ :global SymbolForNotification; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :set ExitOK true; :error false; } @@ -111,4 +113,6 @@ $LogPrint debug $ScriptName ("No mac address available... Ignoring."); } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc index 0075320..23c93b0 100644 --- a/collect-wireless-mac.wifi.rsc +++ b/collect-wireless-mac.wifi.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -29,6 +30,7 @@ :global SymbolForNotification; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :set ExitOK true; :error false; } @@ -93,4 +95,6 @@ $LogPrint debug $ScriptName ("No mac address available... Ignoring."); } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From f9a6916827b3954637f52ac726d937e04a471e3e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:51 +0100 Subject: [PATCH 2358/2612] daily-psk.capsman: use $ExitError to indicate unintentional error --- daily-psk.capsman.rsc | 6 +++++- daily-psk.local.rsc | 6 +++++- daily-psk.template.rsc | 6 +++++- daily-psk.wifi.rsc | 6 +++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index 0562e39..263f6e5 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -31,6 +32,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } $WaitFullyConnected; @@ -89,4 +91,6 @@ } } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 0bef0e9..f0757e1 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -31,6 +32,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } $WaitFullyConnected; @@ -88,4 +90,6 @@ } } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 9d71958..7e36b5a 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -15,6 +15,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -32,6 +33,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } $WaitFullyConnected; @@ -104,4 +106,6 @@ } } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index 83a896c..293f0e4 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -31,6 +32,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } $WaitFullyConnected; @@ -89,4 +91,6 @@ } } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 87cde2cc2fe8604457f9fd4826abac1409d88a0d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2359/2612] dhcp-lease-comment: use $ExitError to indicate unintentional error --- dhcp-lease-comment.capsman.rsc | 6 +++++- dhcp-lease-comment.local.rsc | 6 +++++- dhcp-lease-comment.template.rsc | 6 +++++- dhcp-lease-comment.wifi.rsc | 6 +++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc index c435ec3..5ac0009 100644 --- a/dhcp-lease-comment.capsman.rsc +++ b/dhcp-lease-comment.capsman.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -21,6 +22,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -36,4 +38,6 @@ /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc index 27e6605..1b74d93 100644 --- a/dhcp-lease-comment.local.rsc +++ b/dhcp-lease-comment.local.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -21,6 +22,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -36,4 +38,6 @@ /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index c562ca2..8f1ad47 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -15,6 +15,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -22,6 +23,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -41,4 +43,6 @@ /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc index ba617d7..d3741c5 100644 --- a/dhcp-lease-comment.wifi.rsc +++ b/dhcp-lease-comment.wifi.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -21,6 +22,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -36,4 +38,6 @@ /ip/dhcp-server/lease/set comment=$NewComment $Lease; } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From c8d423c7d59a9051914d5dd676bcd997d7e9854b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2360/2612] dhcp-to-dns: use $ExitError to indicate unintentional error --- dhcp-to-dns.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 9bf506f..ad55c4d 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -12,6 +12,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -27,6 +28,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :set ExitOK true; :error false; } @@ -123,4 +125,6 @@ $LogPrint debug $ScriptName ("No address available... Ignoring."); } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 590030d391d523bc555c192c5f84f9cdb6504abd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2361/2612] firmware-upgrade-reboot: use $ExitError to indicate unintentional error --- firmware-upgrade-reboot.rsc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc index 74847ac..9655903 100644 --- a/firmware-upgrade-reboot.rsc +++ b/firmware-upgrade-reboot.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -19,6 +20,7 @@ :global VersionToNum; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -26,10 +28,12 @@ :if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ $LogPrint info $ScriptName ("Current and upgrade firmware match with version " . \ $RouterBoard->"current-firmware" . "."); + :set ExitOK true; :error true; } :if ([ $VersionToNum ($RouterBoard->"current-firmware") ] > [ $VersionToNum ($RouterBoard->"upgrade-firmware") ]) do={ $LogPrint info $ScriptName ("Different firmware version is available, but it is a downgrade. Ignoring."); + :set ExitOK true; :error true; } @@ -51,4 +55,6 @@ $LogPrint info $ScriptName ("Firmware upgrade successful, rebooting."); /system/reboot; -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 923a6385bf8fcb770a70650318d96f0571d7297e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2362/2612] fw-addr-lists: use $ExitError to indicate unintentional error --- fw-addr-lists.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 34b2fcc..6682f4a 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -36,6 +37,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } $WaitFullyConnected; @@ -184,4 +186,6 @@ " - renewed: " . [ $HumanReadableNum $CntRenew 1000 ] . \ " - removed: " . [ $HumanReadableNum $CntRemove 1000 ]); } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 90cfa83d95baf440544a331fd60f9903afa1fead Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2363/2612] gps-track: use $ExitError to indicate unintentional error --- gps-track.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gps-track.rsc b/gps-track.rsc index a2ea9ff..c0ecac4 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -23,6 +24,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } $WaitFullyConnected; @@ -45,4 +47,6 @@ } else={ $LogPrint debug $ScriptName ("GPS data not valid."); } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From f7b96aa3e93f98b7a8dd076e34b7c302fe436f50 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2364/2612] hotspot-to-wpa-cleanup: use $ExitError to indicate unintentional error --- hotspot-to-wpa-cleanup.capsman.rsc | 6 +++++- hotspot-to-wpa-cleanup.template.rsc | 6 +++++- hotspot-to-wpa-cleanup.wifi.rsc | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index e935850..8a38213 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -23,6 +24,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :set ExitOK true; :error false; } @@ -72,4 +74,6 @@ /ip/dhcp-server/lease/remove $Lease; } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index fa99b5d..e8d2dfb 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -15,6 +15,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -24,6 +25,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :set ExitOK true; :error false; } @@ -79,4 +81,6 @@ /ip/dhcp-server/lease/remove $Lease; } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index d3f859e..e2ef1fd 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -23,6 +24,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :set ExitOK true; :error false; } @@ -72,4 +74,6 @@ /ip/dhcp-server/lease/remove $Lease; } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From ff00c27f990b851b9d14f708aecae6087fedc011 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 09:55:12 +0100 Subject: [PATCH 2365/2612] global-functions: $ExitError: give matching message for functions --- global-functions.rsc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 8941994..6c74c2f 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -428,13 +428,15 @@ # simple macro to print error message on unintentional error :set ExitError do={ - :local ExitOK [ :tostr $1 ]; - :local ScriptName [ :tostr $2 ]; + :local ExitOK [ :tostr $1 ]; + :local Name [ :tostr $2 ]; + :global IfThenElse; :global LogPrint; :if ($ExitOK = "false") do={ - $LogPrint error $ScriptName ("Script '" . $ScriptName . "' exited with error."); + $LogPrint error $Name ([ $IfThenElse ([ :pick $Name 0 1 ] = "\$") \ + "Function" "Script" ] . " '" . $Name . "' exited with error."); } } From 8e12453058ae848a6d61c104ab6aa22902205d98 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2366/2612] hotspot-to-wpa: use $ExitError to indicate unintentional error --- hotspot-to-wpa.capsman.rsc | 8 +++++++- hotspot-to-wpa.template.rsc | 8 +++++++- hotspot-to-wpa.wifi.rsc | 8 +++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index b85c591..e57d327 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -13,6 +13,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -25,11 +26,13 @@ :local UserName $username; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); + :set ExitOK true; :error false; } @@ -57,6 +60,7 @@ :if ($Template->"action" = "reject") do={ $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); + :set ExitOK true; :error true; } @@ -95,4 +99,6 @@ :delay 2s; /caps-man/access-list/set $Entry action=accept; -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index 44607cc..efe37d0 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -14,6 +14,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -26,11 +27,13 @@ :local UserName $username; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); + :set ExitOK true; :error false; } @@ -64,6 +67,7 @@ :if ($Template->"action" = "reject") do={ $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); + :set ExitOK true; :error true; } @@ -115,4 +119,6 @@ :delay 2s; /caps-man/access-list/set $Entry action=accept; /interface/wifi/access-list/set $Entry action=accept; -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index 25933c6..6242d04 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -13,6 +13,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -25,11 +26,13 @@ :local UserName $username; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); + :set ExitOK true; :error false; } @@ -57,6 +60,7 @@ :if ($Template->"action" = "reject") do={ $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); + :set ExitOK true; :error true; } @@ -92,4 +96,6 @@ :delay 2s; /interface/wifi/access-list/set $Entry action=accept; -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 8c5bd8f5e2a5943e720e6086c1aec74ddb81eaf1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 09:02:04 +0100 Subject: [PATCH 2367/2612] global-functions: $ScriptInstallUpdate: use $ExitError to indicate unintentional error --- global-functions.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 6c74c2f..743c50e 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1018,7 +1018,7 @@ } # install new scripts, update existing scripts -:set ScriptInstallUpdate do={ +:set ScriptInstallUpdate do={ :do { :local Scripts [ :toarray $1 ]; :local NewComment [ :tostr $2 ]; @@ -1237,7 +1237,9 @@ :set GlobalConfigChanges; :set GlobalConfigMigration; } -} +} on-error={ + :global ExitError; $ExitError false $0; +} } # lock script against multiple invocation :set ScriptLock do={ From a6fd6bd80cf827a417549c5d433630efcbf1b8b6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2368/2612] ipsec-to-dns: use $ExitError to indicate unintentional error --- ipsec-to-dns.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index bd74a8f..47676ca 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -26,6 +27,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -76,4 +78,6 @@ /ip/dns/static/add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 5b9031ccca75e7e1ba8479af1ae180ae8422ac74 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 11:06:38 +0100 Subject: [PATCH 2369/2612] global-functions: $SendNotification: use $ExitError to indicate unintentional error --- global-functions.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 743c50e..625f8cd 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1374,11 +1374,13 @@ } # send notification via NotificationFunctions - expects at least two string arguments -:set SendNotification do={ +:set SendNotification do={ :do { :global SendNotification2; $SendNotification2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 }); -} +} on-error={ + :global ExitError; $ExitError false $0; +} } # send notification via NotificationFunctions - expects one array argument :set SendNotification2 do={ From 82de8bd935c5a2ccdaf3bfb9db732bdec0ce7d96 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2370/2612] ipv6-update: use $ExitError to indicate unintentional error --- ipv6-update.rsc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ipv6-update.rsc b/ipv6-update.rsc index ccc0eb9..ea1d444 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -22,16 +23,19 @@ :local PdPrefix $"pd-prefix"; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } :if ([ :typeof $NaAddress ] = "str") do={ $LogPrint info $ScriptName ("An address (" . $NaAddress . ") was acquired, not a prefix. Ignoring."); + :set ExitOK true; :error false; } :if ([ :typeof $PdPrefix ] = "nothing") do={ $LogPrint error $ScriptName ("This script is supposed to run from ipv6 dhcp-client."); + :set ExitOK true; :error false; } @@ -90,4 +94,6 @@ } } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 1fe90a6e9aeaba7350f13f52cc9a196a0bc8ca1c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 09:03:41 +0100 Subject: [PATCH 2371/2612] mode-button: $ModeButtonScheduler: use $ExitError to indicate unintentional error --- mode-button.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mode-button.rsc b/mode-button.rsc index 2d428ed..90fe80e 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -25,7 +25,7 @@ :if ([ :len $Scheduler ] = 0) do={ $LogPrint info $ScriptName ("Creating scheduler _ModeButtonScheduler, counting presses..."); - :global ModeButtonScheduler do={ + :global ModeButtonScheduler do={ :do { :local FuncName $0; :global ModeButton; @@ -81,7 +81,9 @@ } else={ $LogPrint info $FuncName ("No action defined for " . $Count . " mode-button presses."); } - } + } on-error={ + :global ExitError; $ExitError false $0; + } } /system/scheduler/add name="_ModeButtonScheduler" \ on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s; } else={ From 177a1e798a09115ecc9241f5f39065a2583bcfac Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2372/2612] lease-script: use $ExitError to indicate unintentional error --- lease-script.rsc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lease-script.rsc b/lease-script.rsc index f484414..995c7e4 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -25,6 +26,7 @@ [ :typeof $leaseServerName ] = "nothing" || \ [ :typeof $leaseBound ] = "nothing") do={ $LogPrint error $ScriptName ("This script is supposed to run from ip dhcp-server."); + :set ExitOK true; :error false; } @@ -32,11 +34,13 @@ "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC); :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :set ExitOK true; :error false; } :if ([ :len [ /system/script/job/find where script=$ScriptName ] ] > 1) do={ $LogPrint debug $ScriptName ("More invocations are waiting, exiting early."); + :set ExitOK true; :error true; } @@ -56,4 +60,6 @@ $LogPrint warning $ScriptName ("Running script '" . $Script . "' failed!"); } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 5db686a15ccd21ed3a190cd4c9eea0bcc6e56abd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 09:09:05 +0100 Subject: [PATCH 2373/2612] mod/bridge-port-to: $BridgePortTo: use $ExitError to indicate unintentional error --- mod/bridge-port-to.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/bridge-port-to.rsc b/mod/bridge-port-to.rsc index 7dae679..9e7b911 100644 --- a/mod/bridge-port-to.rsc +++ b/mod/bridge-port-to.rsc @@ -10,7 +10,7 @@ :global BridgePortTo; -:set BridgePortTo do={ +:set BridgePortTo do={ :do { :local BridgePortTo [ :tostr $1 ]; :global IfThenElse; @@ -65,4 +65,6 @@ $LogPrint info $0 ("Re-enabling interfaces..."); /interface/ethernet/enable $InterfaceReEnable; } -} +} on-error={ + :global ExitError; $ExitError false $0; +} } From da7a031081bcbb4c563bb8b56f7ee150c32b54c0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2374/2612] log-forward: use $ExitError to indicate unintentional error --- log-forward.rsc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/log-forward.rsc b/log-forward.rsc index e0d8f35..8e660fc 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -33,6 +34,7 @@ :global SymbolForNotification; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -43,6 +45,7 @@ :if ($LogForwardRateLimit > 30) do={ :set LogForwardRateLimit ($LogForwardRateLimit - 1); $LogPrint info $ScriptName ("Rate limit in action, not forwarding logs, if any!"); + :set ExitOK true; :error false; } @@ -100,4 +103,6 @@ :local LogAll [ /log/find ]; :set LogForwardLast ($LogAll->([ :len $LogAll ] - 1) ); -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 495232b299bafadc4d21551f094c3c42fa090f57 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 09:09:48 +0100 Subject: [PATCH 2375/2612] mod/bridge-port-vlan: $BridgePortVlan: use $ExitError to indicate unintentional error --- mod/bridge-port-vlan.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/bridge-port-vlan.rsc b/mod/bridge-port-vlan.rsc index c9f55ae..18fa2db 100644 --- a/mod/bridge-port-vlan.rsc +++ b/mod/bridge-port-vlan.rsc @@ -10,7 +10,7 @@ :global BridgePortVlan; -:global BridgePortVlan do={ +:global BridgePortVlan do={ :do { :local ConfigTo [ :tostr $1 ]; :global IfThenElse; @@ -74,4 +74,6 @@ $LogPrint info $0 ("Re-enabling interfaces..."); /interface/ethernet/enable $InterfaceReEnable; } -} +} on-error={ + :global ExitError; $ExitError false $0; +} } From b7ce6aee71733a1e84b911a21c8868b8d2279c10 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2376/2612] mode-button: use $ExitError to indicate unintentional error --- mode-button.rsc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mode-button.rsc b/mode-button.rsc index 3bd922b..24de453 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -83,4 +84,6 @@ $LogPrint debug $ScriptName ("Updating scheduler _ModeButtonScheduler..."); /system/scheduler/set $Scheduler start-time=[ /system/clock/get time ]; } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 05cb87f475ffc3f9fdc1fa6988925e79a3dacd38 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 09:10:08 +0100 Subject: [PATCH 2377/2612] mod/inspectvar: $InspectVar: use $ExitError to indicate unintentional error --- mod/inspectvar.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/inspectvar.rsc b/mod/inspectvar.rsc index 73205b2..0209214 100644 --- a/mod/inspectvar.rsc +++ b/mod/inspectvar.rsc @@ -12,11 +12,13 @@ :global InspectVarReturn; # inspect variable and print on terminal -:set InspectVar do={ +:set InspectVar do={ :do { :global InspectVarReturn; :put [ :tocrlf [ $InspectVarReturn $1 ] ]; -} +} on-error={ + :global ExitError; $ExitError false $0; +} } # inspect variable and return formatted string :set InspectVarReturn do={ From d89a3694850a76e487b139eebf24572344a5502e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:08:36 +0100 Subject: [PATCH 2378/2612] netwatch-dns: use $ExitError to indicate unintentional error --- netwatch-dns.rsc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 6fbfc89..a704c84 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -24,12 +25,14 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } :local SettleTime (5m30s - [ /system/resource/get uptime ]); :if ($SettleTime > 0s) do={ $LogPrint info $ScriptName ("System just booted, giving netwatch " . $SettleTime . " to settle."); + :set ExitOK true; :error true; } @@ -92,6 +95,7 @@ :if ($DohCurrent = $HostInfo->"doh-url") do={ $LogPrint debug $ScriptName ("Current DoH server is still up: " . $DohCurrent); + :set ExitOK true; :error true; } @@ -132,6 +136,7 @@ } /ip/dns/cache/flush; $LogPrint info $ScriptName ("Setting DoH server: " . ($DohServer->"doh-url")); + :set ExitOK true; :error true; } else={ $LogPrint warning $ScriptName ("Received unexpected response from DoH server: " . \ @@ -139,4 +144,6 @@ } } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 34172e4c78cc5a6d0fe99df279e42a8794f84c94 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 09:10:27 +0100 Subject: [PATCH 2379/2612] mod/ipcalc: $IPCalc: use $ExitError to indicate unintentional error --- mod/ipcalc.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc index 003bdc3..021cd30 100644 --- a/mod/ipcalc.rsc +++ b/mod/ipcalc.rsc @@ -12,7 +12,7 @@ :global IPCalcReturn; # print netmask, network, min host, max host and broadcast -:set IPCalc do={ +:set IPCalc do={ :do { :local Input [ :tostr $1 ]; :global FormatLine; @@ -27,7 +27,9 @@ [ $FormatLine "HostMin" ($Values->"hostmin") ] . "\n" . \ [ $FormatLine "HostMax" ($Values->"hostmax") ] . "\n" . \ [ $FormatLine "Broadcast" ($Values->"broadcast") ]) ]; -} +} on-error={ + :global ExitError; $ExitError false $0; +} } # calculate and return netmask, network, min host, max host and broadcast :set IPCalcReturn do={ From bdc15eaefb51b40b3d414f0e94bfa22233b0f2a4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2380/2612] netwatch-notify: use $ExitError to indicate unintentional error --- netwatch-notify.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index a49d0cd..f1e87bd 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -75,6 +76,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -218,4 +220,6 @@ "since"=($Metric->"since") }; } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 5450618723dabf9d42857047ea906c9fc87886dd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 08:51:50 +0100 Subject: [PATCH 2381/2612] mod/notification-email: $FlushEmailQueue: use $ExitError to indicate unintentional error --- mod/notification-email.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 3d62ddf..ff4188c 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -34,7 +34,7 @@ } # flush e-mail queue -:set FlushEmailQueue do={ +:set FlushEmailQueue do={ :do { :global EmailQueue; :global EitherOr; @@ -113,7 +113,9 @@ } else={ /system/scheduler/set interval=1m comment="Waiting for retry..." $Scheduler; } -} +} on-error={ + :global ExitError; $ExitError false $0; +} } # generate filter for log-forward :set LogForwardFilterLogForwarding do={ From eeb76c227cbc04c410e7062daef4cda9cb3d5bf3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2382/2612] ospf-to-leds: use $ExitError to indicate unintentional error --- ospf-to-leds.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc index b78faa4..d96e763 100644 --- a/ospf-to-leds.rsc +++ b/ospf-to-leds.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -19,6 +20,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -42,4 +44,6 @@ /system/leds/set type=off [ find where leds=$LED ]; } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 1927dc505a88ef5ecb86d1d925cf44a5225b4b7c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 11:09:44 +0100 Subject: [PATCH 2383/2612] mod/notification-email: $SendEMail: use $ExitError to indicate unintentional error --- mod/notification-email.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index ff4188c..e51779b 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -226,11 +226,13 @@ } # send notification via e-mail - expects at least two string arguments -:set SendEMail do={ +:set SendEMail do={ :do { :global SendEMail2; $SendEMail2 ({ origin=$0; subject=$1; message=$2; link=$3 }); -} +} on-error={ + :global ExitError; $ExitError false $0; +} } # send notification via e-mail - expects one array argument :set SendEMail2 do={ From 81f59f9894cfd9b29a2366e8a13e124b358dadde Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2384/2612] packages-update: use $ExitError to indicate unintentional error --- packages-update.rsc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages-update.rsc b/packages-update.rsc index b08a48d..924a5d9 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -45,6 +46,7 @@ } :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -52,11 +54,13 @@ :if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ $LogPrint warning $ScriptName ("Latest version is not known."); + :set ExitOK true; :error false; } :if ($Update->"installed-version" = $Update->"latest-version") do={ $LogPrint info $ScriptName ("Version " . $Update->"latest-version" . " is already installed."); + :set ExitOK true; :error true; } @@ -85,10 +89,12 @@ $LogPrint info $ScriptName ("User requested to continue anyway."); } else={ $LogPrint info $ScriptName ("Canceled update..."); + :set ExitOK true; :error false; } } else={ $LogPrint warning $ScriptName ("Canceled non-interactive update."); + :set ExitOK true; :error false; } } @@ -108,6 +114,7 @@ } } else={ $LogPrint warning $ScriptName ("Not installing downgrade automatically."); + :set ExitOK true; :error false; } } @@ -116,6 +123,7 @@ :local PkgName [ /system/package/get $Package name ]; :if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ $LogPrint error $ScriptName ("Download for package " . $PkgName . " failed, update aborted."); + :set ExitOK true; :error false; } } @@ -130,11 +138,13 @@ :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; :if (([ /terminal/inkey timeout=60 ] % 32) = 19) do={ $Schedule $ScriptName; + :set ExitOK true; :error true; } } else={ :if ($PackagesUpdateDeferReboot = true) do={ $Schedule $ScriptName; + :set ExitOK true; :error true; } } @@ -142,4 +152,6 @@ $LogPrint info $ScriptName ("Rebooting for update."); :delay 1s; /system/reboot; -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 1994b23e462c02ee71d5cb9db21d0e6075010c3c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 08:56:35 +0100 Subject: [PATCH 2385/2612] mod/notification-matrix: $FlushMatrixQueue: use $ExitError to indicate unintentional error --- mod/notification-matrix.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 3adc1df..751967c 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -18,7 +18,7 @@ :global SetupMatrixJoinRoom; # flush Matrix queue -:set FlushMatrixQueue do={ +:set FlushMatrixQueue do={ :do { :global MatrixQueue; :global IsFullyConnected; @@ -57,7 +57,9 @@ /system/scheduler/remove [ find where name="_FlushMatrixQueue" ]; :set MatrixQueue; } -} +} on-error={ + :global ExitError; $ExitError false $0; +} } # send notification via Matrix - expects one array argument :set ($NotificationFunctions->"matrix") do={ From be0548007184bae80dd40b4a6390ababeeb39617 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2386/2612] ppp-on-up: use $ExitError to indicate unintentional error --- ppp-on-up.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc index 337b32d..13b42c7 100644 --- a/ppp-on-up.rsc +++ b/ppp-on-up.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -20,6 +21,7 @@ :if ([ :typeof $Interface ] = "nothing") do={ $LogPrint error $ScriptName ("This script is supposed to run from ppp on-up script hook."); + :set ExitOK true; :error false; } @@ -37,4 +39,6 @@ $LogPrint warning $ScriptName ("Running script '" . $ScriptName . "' failed!"); } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From de9dee83bea855a893594e0d58ca609872f75072 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 11:10:03 +0100 Subject: [PATCH 2387/2612] mod/notification-matrix: $SendMatrix: use $ExitError to indicate unintentional error --- mod/notification-matrix.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 751967c..14f369d 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -166,11 +166,13 @@ } # send notification via Matrix - expects at least two string arguments -:set SendMatrix do={ +:set SendMatrix do={ :do { :global SendMatrix2; $SendMatrix2 ({ origin=$0; subject=$1; message=$2; link=$3 }); -} +} on-error={ + :global ExitError; $ExitError false $0; +} } # send notification via Matrix - expects one array argument :set SendMatrix2 do={ From ede351f47e8311fe00bada723e69ab90dc1332d0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2388/2612] sms-action: use $ExitError to indicate unintentional error --- sms-action.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sms-action.rsc b/sms-action.rsc index c896659..fd3096c 100644 --- a/sms-action.rsc +++ b/sms-action.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -23,6 +24,7 @@ :if ([ :typeof $Action ] = "nothing") do={ $LogPrint error $ScriptName ("This script is supposed to run from SMS hook with action=..."); + :set ExitOK true; :error false; } @@ -34,4 +36,6 @@ } else={ $LogPrint warning $ScriptName ("The code for action '" . $Action . "' failed syntax validation!"); } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From aac723e2a1eede3649c5f3b4bbe67af0e951063a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 08:57:01 +0100 Subject: [PATCH 2389/2612] mod/notification-ntfy: $FlushNtfyQueue: use $ExitError to indicate unintentional error --- mod/notification-ntfy.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index b2bb280..5fdeedf 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -15,7 +15,7 @@ :global SendNtfy2; # flush ntfy queue -:set FlushNtfyQueue do={ +:set FlushNtfyQueue do={ :do { :global NtfyQueue; :global NtfyMessageIDs; @@ -52,7 +52,9 @@ /system/scheduler/remove [ find where name="_FlushNtfyQueue" ]; :set NtfyQueue; } -} +} on-error={ + :global ExitError; $ExitError false $0; +} } # send notification via ntfy - expects one array argument :set ($NotificationFunctions->"ntfy") do={ From a78fe98fd0746dd88429413d9c81123866d880bd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2390/2612] sms-forward: use $ExitError to indicate unintentional error --- sms-forward.rsc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sms-forward.rsc b/sms-forward.rsc index 0d493b6..8334d5f 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -12,6 +12,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -28,11 +29,13 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } :if ([ /tool/sms/get receive-enabled ] = false) do={ $LogPrintOnce warning $ScriptName ("Receiving of SMS is not enabled."); + :set ExitOK true; :error false; } @@ -42,6 +45,7 @@ :if ([ /interface/lte/get ($Settings->"port") running ] != true) do={ $LogPrint info $ScriptName ("The LTE interface is not in running state, skipping."); + :set ExitOK true; :error true; } @@ -92,4 +96,6 @@ } } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From e76ae11b029169e971f7313b17d5c43589fa8170 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 11:10:24 +0100 Subject: [PATCH 2391/2612] mod/notification-ntfy: $SendNtfy: use $ExitError to indicate unintentional error --- mod/notification-ntfy.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index 5fdeedf..7e0234b 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -134,11 +134,13 @@ } # send notification via ntfy - expects at least two string arguments -:set SendNtfy do={ +:set SendNtfy do={ :do { :global SendNtfy2; $SendNtfy2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 }); -} +} on-error={ + :global ExitError; $ExitError false $0; +} } # send notification via ntfy - expects one array argument :set SendNtfy2 do={ From adbefca0e48bda15d90cc53c52c3982230f8864c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2392/2612] telegram-chat: use $ExitError to indicate unintentional error --- telegram-chat.rsc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index f2750f5..8589aab 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -11,6 +11,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -43,6 +44,7 @@ :global WaitFullyConnected; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -57,6 +59,7 @@ :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={ $LogPrint warning $ScriptName ("Downloading required certificate failed."); + :set ExitOK true; :error false; } @@ -82,6 +85,7 @@ :if ($Data = false) do={ $LogPrint warning $ScriptName ("Failed getting updates."); + :set ExitOK true; :error false; } @@ -130,6 +134,7 @@ :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); :if ([ $MkDir "tmpfs/telegram-chat" ] = false) do={ $LogPrint error $ScriptName ("Failed creating directory!"); + :set ExitOK true; :error false; } $LogPrint info $ScriptName ("Running command from update " . $UpdateID . ": " . $Command); @@ -176,4 +181,6 @@ } :set TelegramChatOffset ([ :pick $TelegramChatOffset 1 3 ], \ [ $IfThenElse ($UpdateID >= $TelegramChatOffset->2) ($UpdateID + 1) ($TelegramChatOffset->2) ]); -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From e89867be1533cd561bf61b65f3019946e2ceeee1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 08:57:20 +0100 Subject: [PATCH 2393/2612] mod/notification-telegram: $FlushTelegramQueue: use $ExitError to indicate unintentional error --- mod/notification-telegram.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 671bd1c..993782d 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -15,7 +15,7 @@ :global SendTelegram2; # flush telegram queue -:set FlushTelegramQueue do={ +:set FlushTelegramQueue do={ :do { :global TelegramQueue; :global TelegramMessageIDs; @@ -56,7 +56,9 @@ /system/scheduler/remove [ find where name="_FlushTelegramQueue" ]; :set TelegramQueue; } -} +} on-error={ + :global ExitError; $ExitError false $0; +} } # send notification via telegram - expects one array argument :set ($NotificationFunctions->"telegram") do={ From d4ea0e18a710c5a68c7dabaa5c1c5a40568c965b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2394/2612] update-gre-address: use $ExitError to indicate unintentional error --- update-gre-address.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/update-gre-address.rsc b/update-gre-address.rsc index 6dd829d..87762d6 100644 --- a/update-gre-address.rsc +++ b/update-gre-address.rsc @@ -12,6 +12,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -20,6 +21,7 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } @@ -39,4 +41,6 @@ } } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 4968b79fc1142c9bfdbfe93c8f917cfdd7f51790 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 11:10:43 +0100 Subject: [PATCH 2395/2612] mod/notification-telegram: $SendTelegram: use $ExitError to indicate unintentional error --- mod/notification-telegram.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 993782d..7d75b8b 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -182,11 +182,13 @@ } # send notification via telegram - expects at least two string arguments -:set SendTelegram do={ +:set SendTelegram do={ :do { :global SendTelegram2; $SendTelegram2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 }); -} +} on-error={ + :global ExitError; $ExitError false $0; +} } # send notification via telegram - expects one array argument :set SendTelegram2 do={ From ee030740cba5bd0c8b0c9c3e77551dd460abe48b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 Dec 2024 10:31:52 +0100 Subject: [PATCH 2396/2612] update-tunnelbroker: use $ExitError to indicate unintentional error --- update-tunnelbroker.rsc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index 67a5d30..dd43c64 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -13,6 +13,7 @@ :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } +:local ExitOK false; :do { :local ScriptName [ :jobname ]; @@ -22,11 +23,13 @@ :global ScriptLock; :if ([ $ScriptLock $ScriptName ] = false) do={ + :set ExitOK true; :error false; } :if ([ $CertificateAvailable "Starfield Root Certificate Authority - G2" ] = false) do={ $LogPrint error $ScriptName ("Downloading required certificate failed."); + :set ExitOK true; :error false; } @@ -50,6 +53,7 @@ :if (!($Data ~ "^(good|nochg) ")) do={ $LogPrint error $ScriptName ("Failed sending the local address to tunnelbroker or unexpected response!"); + :set ExitOK true; :error false; } @@ -64,4 +68,6 @@ /interface/6to4/set $Interface local-address=$PublicAddress; } } -} on-error={ } +} on-error={ + :global ExitError; $ExitError $ExitOK [ :jobname ]; +} From 48bcf8ee6e92445b01f792f1c52af012ba05b7b4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 09:45:30 +0100 Subject: [PATCH 2397/2612] =?UTF-8?q?global-functions:=20$FetchHuge:=20pas?= =?UTF-8?q?sing=20boolean=20to=20function=20is=20still=20broken...=20?= =?UTF-8?q?=F0=9F=A4=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- global-functions.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 47a69c4..6fec6dd 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -427,9 +427,9 @@ # fetch huge data to file, read in chunks :set FetchHuge do={ - :local ScriptName [ :tostr $1 ]; - :local Url [ :tostr $2 ]; - :local CheckCert [ :tobool $3 ]; + :local ScriptName [ :tostr $1 ]; + :local Url [ :tostr $2 ]; + :local CheckCert [ :tostr $3 ]; :global CleanName; :global FetchUserAgentStr; @@ -439,7 +439,7 @@ :global MkDir; :global WaitForFile; - :set CheckCert [ $IfThenElse ($CheckCert = false) "no" "yes-without-crl" ]; + :set CheckCert [ $IfThenElse ($CheckCert = "false") "no" "yes-without-crl" ]; :local DirName ("tmpfs/" . [ $CleanName $ScriptName ]); :if ([ $MkDir $DirName ] = false) do={ From 73e0ac75f10019794a2692371ca08a46bea69eb9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 09:10:44 +0100 Subject: [PATCH 2398/2612] mod/scriptrunonce: $ScriptRunOnce: use $ExitError to indicate unintentional error --- mod/scriptrunonce.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index 3d5dce9..c8dcf26 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -11,7 +11,7 @@ :global ScriptRunOnce; # fetch and run script(s) once -:set ScriptRunOnce do={ +:set ScriptRunOnce do={ :do { :local Scripts [ :toarray $1 ]; :global ScriptRunOnceBaseUrl; @@ -49,4 +49,6 @@ } } } -} +} on-error={ + :global ExitError; $ExitError false $0; +} } From 1788c0599865ee9cb7e5015e260d7e4a49abf581 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 09:11:39 +0100 Subject: [PATCH 2399/2612] mod/ssh-keys-import: $SSHKeysImport: use $ExitError to indicate unintentional error --- mod/ssh-keys-import.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index c7b2788..b2f1d20 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -12,7 +12,7 @@ :global SSHKeysImportFile; # import single key passed as string -:set SSHKeysImport do={ +:set SSHKeysImport do={ :do { :local Key [ :tostr $1 ]; :local User [ :tostr $2 ]; @@ -64,7 +64,9 @@ /file/remove "tmpfs/ssh-keys-import"; :return false; } -} +} on-error={ + :global ExitError; $ExitError false $0; +} } # import keys from a file :set SSHKeysImportFile do={ From f8a55860afaf8817e52cb89add227fa9a84435f0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 8 Dec 2024 22:19:01 +0100 Subject: [PATCH 2400/2612] check-routeros-update: pass script name to local function --- check-routeros-update.rsc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 510acd9..a2e39b6 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -35,6 +35,8 @@ :global WaitFullyConnected; :local DoUpdate do={ + :local ScriptName [ :tostr $1 ]; + :global LogPrint; :if ([ :len [ /system/script/find where name="packages-update" ] ] > 0) do={ @@ -42,7 +44,7 @@ } else={ /system/package/update/install without-paging; } - $LogPrint info $0 ("Waiting for system to reboot."); + $LogPrint info $ScriptName ("Waiting for system to reboot."); } :if ([ $ScriptLock $ScriptName ] = false) do={ @@ -95,7 +97,7 @@ 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; + $DoUpdate $ScriptName; :set ExitOK true; :error true; } @@ -106,7 +108,7 @@ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ ", updating on " . $Identity . "..."); link=$Link; silent=true }); - $DoUpdate; + $DoUpdate $ScriptName; :set ExitOK true; :error true; } @@ -122,7 +124,7 @@ 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; + $DoUpdate $ScriptName; :set ExitOK true; :error true; } @@ -144,7 +146,7 @@ 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; + $DoUpdate $ScriptName; :set ExitOK true; :error true; } @@ -163,7 +165,7 @@ :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - $DoUpdate; + $DoUpdate $ScriptName; :set ExitOK true; :error true; } else={ From 210ef26b93364f4b69cde9ff34139d51572357ee Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 9 Dec 2024 09:11:56 +0100 Subject: [PATCH 2401/2612] mod/ssh-keys-import: $SSHKeysImportFile: use $ExitError to indicate unintentional error --- mod/ssh-keys-import.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index b2f1d20..583e827 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -69,7 +69,7 @@ } } # import keys from a file -:set SSHKeysImportFile do={ +:set SSHKeysImportFile do={ :do { :local FileName [ :tostr $1 ]; :local User [ :tostr $2 ]; @@ -108,4 +108,6 @@ $LogPrint warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported."); } } -} +} on-error={ + :global ExitError; $ExitError false $0; +} } From e51191035b21c529efb4387dfe59976c3112f561 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 8 Dec 2024 22:22:18 +0100 Subject: [PATCH 2402/2612] mode-button: $ModeButtonScheduler: explicitly name the variable --- mode-button.rsc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/mode-button.rsc b/mode-button.rsc index 24de453..2d428ed 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -26,6 +26,8 @@ :if ([ :len $Scheduler ] = 0) do={ $LogPrint info $ScriptName ("Creating scheduler _ModeButtonScheduler, counting presses..."); :global ModeButtonScheduler do={ + :local FuncName $0; + :global ModeButton; :global LogPrint; @@ -54,7 +56,7 @@ :if ([ :len $Code ] > 0) do={ :if ([ $ValidateSyntax $Code ] = true) do={ - $LogPrint info $0 ("Acting on " . $Count . " mode-button presses: " . $Code); + $LogPrint info $FuncName ("Acting on " . $Count . " mode-button presses: " . $Code); :for I from=1 to=$Count do={ $LEDInvert; @@ -69,13 +71,15 @@ :do { [ :parse $Code ]; } on-error={ - $LogPrint warning $0 ("The code for " . $Count . " mode-button presses failed with runtime error!"); + $LogPrint warning $FuncName \ + ("The code for " . $Count . " mode-button presses failed with runtime error!"); } } else={ - $LogPrint warning $0 ("The code for " . $Count . " mode-button presses failed syntax validation!"); + $LogPrint warning $FuncName \ + ("The code for " . $Count . " mode-button presses failed syntax validation!"); } } else={ - $LogPrint info $0 ("No action defined for " . $Count . " mode-button presses."); + $LogPrint info $FuncName ("No action defined for " . $Count . " mode-button presses."); } } /system/scheduler/add name="_ModeButtonScheduler" \ From bceabebf9c6c30e2b1057448d74a5de006ef5d1e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Dec 2024 17:05:12 +0100 Subject: [PATCH 2403/2612] mod/notification-email: drop useless safeguard Guess it was useful back in the day. Now the function exits early if the queue is empty... So this can never be zero. --- mod/notification-email.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index e51779b..dd90923 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -71,7 +71,7 @@ $LogPrint warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty."); } - /system/scheduler/set interval=([ $EitherOr $QueueLen 1 ] . "m") comment="Sending..." $Scheduler; + /system/scheduler/set interval=($QueueLen . "m") comment="Sending..." $Scheduler; :foreach Id,Message in=$EmailQueue do={ :if ([ :typeof $Message ] = "array" ) do={ From 42bcc63d29c85a7fcdb175b3ea725654d2db7039 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Dec 2024 17:12:24 +0100 Subject: [PATCH 2404/2612] mod/notification-email: increase retry interval on failure --- mod/notification-email.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index dd90923..b109bf4 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -46,8 +46,9 @@ :local AllDone true; :local QueueLen [ :len $EmailQueue ]; :local Scheduler [ /system/scheduler/find where name="_FlushEmailQueue" ]; + :local SchedVal [ /system/scheduler/get $Scheduler ]; - :if ([ :len $Scheduler ] > 0 && [ /system/scheduler/get $Scheduler interval ] < 1m) do={ + :if ([ :len $Scheduler ] > 0 && ($SchedVal->"interval") < 1m) do={ /system/scheduler/set interval=1m comment="Doing initial checks..." $Scheduler; } @@ -111,7 +112,8 @@ /system/scheduler/remove $Scheduler; :set EmailQueue; } else={ - /system/scheduler/set interval=1m comment="Waiting for retry..." $Scheduler; + /system/scheduler/set interval=(($SchedVal->"run-count") . "m") \ + comment="Waiting for retry..." $Scheduler; } } on-error={ :global ExitError; $ExitError false $0; From c311e58d998fabc7568acd77f0a8bd42468f50b0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Dec 2024 20:23:26 +0100 Subject: [PATCH 2405/2612] leds-toggle-mode: toggle in one call... ... and drop the condition. --- leds-toggle-mode.rsc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/leds-toggle-mode.rsc b/leds-toggle-mode.rsc index 136c9d1..07e12ae 100644 --- a/leds-toggle-mode.rsc +++ b/leds-toggle-mode.rsc @@ -6,8 +6,4 @@ # toggle LEDs mode # https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md -:if ([ /system/leds/settings/get all-leds-off ] = "never") do={ - /system/leds/settings/set all-leds-off=immediate; -} else={ - /system/leds/settings/set all-leds-off=never; -} +/system/leds/settings/set all-leds-off=(({ "never"="immediate"; "immediate"="never" })->[ get all-leds-off ]); From d70efe910ae3a9bef3ee6b62c0fd6d591bab89e3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 10 Dec 2024 20:32:50 +0100 Subject: [PATCH 2406/2612] mode-button: support led toggle without extra script --- global-config.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-config.rsc b/global-config.rsc index 2ed67f3..5292853 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -186,7 +186,7 @@ # Run different commands with multiple mode-button presses. :global ModeButton { - 1="/system/script/run leds-toggle-mode;"; + 1="/system/leds/settings/set all-leds-off=(({ \"never\"=\"immediate\"; \"immediate\"=\"never\" })->[ get all-leds-off ]);"; 2=":global Identity; :global SendNotification; :global SymbolForNotification; \$SendNotification ([ \$SymbolForNotification \"earth\" ] . \"Hello...\") (\"Hello world, \" . \$Identity . \" calling!\");"; 3="/system/shutdown;"; 4="/system/reboot;"; From 8231c3e833ee83a118f4d8395c097e6a9f312c2f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Dec 2024 10:40:06 +0100 Subject: [PATCH 2407/2612] global-functions: $WaitForFile: delay until "complete"... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Well, turns out that waiting for existence of a file is not sufficient. Chances are that a file is available just partly, so wait until the size no longer changes... Let's hope that works as expected. 🤞 --- global-functions.rsc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 625f8cd..e5e5d50 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1577,6 +1577,16 @@ :delay $Delay; :set I ($I + 1); } + + :local File [ /file/find where name=$FileName ]; + :local SizeA 0; + :local SizeB 1; + :while ($SizeA < $SizeB) do={ + :set SizeA $SizeB; + :delay $Delay; + :set SizeB [ /file/get $File size ]; + } + :return true; } From 009a6bd76204083f4b1971b285d90e916c0fbc29 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Dec 2024 10:55:23 +0100 Subject: [PATCH 2408/2612] mod/notification-email: $FlushEmailQueue: return on success --- mod/notification-email.rsc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index b109bf4..1d9a0a1 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -111,10 +111,11 @@ :if ($AllDone = true && $QueueLen = [ :len $EmailQueue ]) do={ /system/scheduler/remove $Scheduler; :set EmailQueue; - } else={ - /system/scheduler/set interval=(($SchedVal->"run-count") . "m") \ - comment="Waiting for retry..." $Scheduler; + :return true; } + + /system/scheduler/set interval=(($SchedVal->"run-count") . "m") \ + comment="Waiting for retry..." $Scheduler; } on-error={ :global ExitError; $ExitError false $0; } } From 53106731528adc607ee40336b79c516fac594a17 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Dec 2024 10:59:37 +0100 Subject: [PATCH 2409/2612] mod/notification-email: $FlushEmailQueue: return on purge --- mod/notification-email.rsc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 1d9a0a1..60c1e9b 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -114,6 +114,12 @@ :return true; } + :if ([ :len [ /system/scheduler/find where name="_FlushEmailQueue" ] ] = 0 && \ + [ :typeof $EmailQueue ] = "nothing") do={ + $LogPrint info $0 ("Queue was purged? Exiting."); + :return false; + } + /system/scheduler/set interval=(($SchedVal->"run-count") . "m") \ comment="Waiting for retry..." $Scheduler; } on-error={ From 1e2ca3d21441ac7881b7c556c8d73c70bb92edc6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Dec 2024 11:28:12 +0100 Subject: [PATCH 2410/2612] mod/notification-email: $FlushEmailQueue: create scheduler if missing... ... as it is required to be modified several times below. --- mod/notification-email.rsc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 60c1e9b..c474750 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -46,9 +46,15 @@ :local AllDone true; :local QueueLen [ :len $EmailQueue ]; :local Scheduler [ /system/scheduler/find where name="_FlushEmailQueue" ]; - :local SchedVal [ /system/scheduler/get $Scheduler ]; - :if ([ :len $Scheduler ] > 0 && ($SchedVal->"interval") < 1m) do={ + :if ([ :len $Scheduler ] < 0) do={ + /system/scheduler/add name="_FlushEmailQueue" interval=1m start-time=startup \ + comment="Doing initial checks..." on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); + :set Scheduler [ /system/scheduler/find where name="_FlushEmailQueue" ]; + } + + :local SchedVal [ /system/scheduler/get $Scheduler ]; + :if (($SchedVal->"interval") < 1m) do={ /system/scheduler/set interval=1m comment="Doing initial checks..." $Scheduler; } From 8c8c75ca66d59d9368fe3f4fe7f1124a425f41b3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Dec 2024 11:51:17 +0100 Subject: [PATCH 2411/2612] mod/notification-email: $FlushEmailQueue: move the check up... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... as this needs to be done before creating a scheduler. 😜 Also remove the scheduler and return. --- mod/notification-email.rsc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index c474750..bbce6d0 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -47,6 +47,12 @@ :local QueueLen [ :len $EmailQueue ]; :local Scheduler [ /system/scheduler/find where name="_FlushEmailQueue" ]; + :if ([ :len $Scheduler ] > 0 && $QueueLen = 0) do={ + $LogPrint warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty."); + /system/scheduler/remove $Scheduler; + :return false; + } + :if ([ :len $Scheduler ] < 0) do={ /system/scheduler/add name="_FlushEmailQueue" interval=1m start-time=startup \ comment="Doing initial checks..." on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); @@ -74,10 +80,6 @@ :return false; } - :if ([ :len $Scheduler ] > 0 && $QueueLen = 0) do={ - $LogPrint warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty."); - } - /system/scheduler/set interval=($QueueLen . "m") comment="Sending..." $Scheduler; :foreach Id,Message in=$EmailQueue do={ From b66332eb464884d69eef56aa5ecb7ae74d1914cc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Dec 2024 11:58:41 +0100 Subject: [PATCH 2412/2612] mod/notification-email: $FlushEmailQueue: just return on empty queue --- mod/notification-email.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index bbce6d0..a3291d9 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -53,6 +53,10 @@ :return false; } + :if ($QueueLen = 0) do={ + :return true; + } + :if ([ :len $Scheduler ] < 0) do={ /system/scheduler/add name="_FlushEmailQueue" interval=1m start-time=startup \ comment="Doing initial checks..." on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); From a7878d664f51ed77a574a5d360c9c53863d0d488 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 Dec 2024 12:11:15 +0100 Subject: [PATCH 2413/2612] fw-addr-lists: do not fail on invalid json data --- fw-addr-lists.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 6682f4a..a195c89 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -92,7 +92,9 @@ :set Line ($Line->0); :local Address; :if ([ :pick $Line 0 1 ] = "{") do={ - :set Address [ :tostr ([ :deserialize from=json $Line ]->"cidr") ]; + :do { + :set Address [ :tostr ([ :deserialize from=json $Line ]->"cidr") ]; + } on-error={ } } else={ :set Address ([ :pick $Line 0 [ $FindDelim $Line ] ] . ($List->"cidr")); } From d1b9b1b410933e0510845c245f742a7df172dc61 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Dec 2024 17:40:49 +0100 Subject: [PATCH 2414/2612] mod/notification-ntfy: support authentication with bearer token Closes: https://github.com/eworm-de/routeros-scripts/issues/86 --- doc/mod/notification-ntfy.md | 2 ++ global-config.rsc | 1 + mod/notification-ntfy.rsc | 6 ++++++ 3 files changed, 9 insertions(+) diff --git a/doc/mod/notification-ntfy.md b/doc/mod/notification-ntfy.md index 5393d44..04dee35 100644 --- a/doc/mod/notification-ntfy.md +++ b/doc/mod/notification-ntfy.md @@ -52,6 +52,8 @@ basic authentication. Configure `NtfyServerUser` and `NtfyServerPass` for this. Even authentication via access token is possible, adding it as password with a blank username. +Also available is `NtfyServerToken` to add a bearer token for authentication. + For a custom service installing an additional certificate may be required. You may want to install that certificate manually, after finding the [certificate name from browser](../../CERTIFICATES.md). diff --git a/global-config.rsc b/global-config.rsc index 5292853..0c8f738 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -58,6 +58,7 @@ :global NtfyServer "ntfy.sh"; :global NtfyServerUser []; :global NtfyServerPass []; +:global NtfyServerToken []; :global NtfyTopic ""; # It is possible to override e-mail, Telegram, Matrix and Ntfy setting diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index 7e0234b..7e4eaf0 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -67,6 +67,8 @@ :global NtfyServerOverride; :global NtfyServerPass; :global NtfyServerPassOverride; + :global NtfyServerToken; + :global NtfyServerTokenOverride; :global NtfyServerUser; :global NtfyServerUserOverride; :global NtfyTopic; @@ -83,6 +85,7 @@ :local Server [ $EitherOr ($NtfyServerOverride->($Notification->"origin")) $NtfyServer ]; :local User [ $EitherOr ($NtfyServerUserOverride->($Notification->"origin")) $NtfyServerUser ]; :local Pass [ $EitherOr ($NtfyServerPassOverride->($Notification->"origin")) $NtfyServerPass ]; + :local Token [ $EitherOr ($NtfyServerTokenOverride->($Notification->"origin")) $NtfyServerToken ]; :local Topic [ $EitherOr ($NtfyTopicOverride->($Notification->"origin")) $NtfyTopic ]; :if ([ :len $Topic ] = 0) do={ @@ -93,6 +96,9 @@ :local Headers ({ [ $FetchUserAgentStr ($Notification->"origin") ]; \ ("Priority: " . [ $IfThenElse ($Notification->"silent") "low" "default" ]); \ ("Title: " . "[" . $IdentityExtra . $Identity . "] " . ($Notification->"subject")) }); + :if ([ :len $Token ] > 0) do={ + :set Headers ($Headers, ("Authorization: Bearer " . $Token)); + } :local Text (($Notification->"message") . "\n"); :if ([ :len ($Notification->"link") ] > 0) do={ :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . ($Notification->"link")); From 6bee4675509e874d2f2ed8ee960f251b5667a451 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 13 Dec 2024 17:48:49 +0100 Subject: [PATCH 2415/2612] mod/notification-ntfy: add basic authentication in headers This makes it a bit easier and straight forward as we pass the headers anyway. --- mod/notification-ntfy.rsc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index 7e4eaf0..f8351fd 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -39,7 +39,7 @@ :do { /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ http-header-field=($Message->"headers") http-data=($Message->"text") \ - ($Message->"url") user=($Message->"user") password=($Message->"pass") as-value; + ($Message->"url") as-value; :set ($NtfyQueue->$Id); } on-error={ $LogPrint debug $0 ("Sending queued Ntfy message failed."); @@ -96,6 +96,9 @@ :local Headers ({ [ $FetchUserAgentStr ($Notification->"origin") ]; \ ("Priority: " . [ $IfThenElse ($Notification->"silent") "low" "default" ]); \ ("Title: " . "[" . $IdentityExtra . $Identity . "] " . ($Notification->"subject")) }); + :if ([ :len $User ] > 0 || [ :len $Pass ] > 0) do={ + :set Headers ($Headers, ("Authorization: Basic " . [ :convert to=base64 ($User . ":" . $Pass) ])); + } :if ([ :len $Token ] > 0) do={ :set Headers ($Headers, ("Authorization: Bearer " . $Token)); } @@ -112,7 +115,7 @@ } } /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ - http-header-field=$Headers http-data=$Text $Url user=$User password=$Pass as-value; + http-header-field=$Headers http-data=$Text $Url as-value; } on-error={ $LogPrint info $0 ("Failed sending ntfy notification! Queuing..."); @@ -123,7 +126,7 @@ "This message was queued since " . [ /system/clock/get date ] . " " . \ [ /system/clock/get time ] . " and may be obsolete."); :set ($NtfyQueue->[ :len $NtfyQueue ]) \ - { url=$Url; user=$User; pass=$Pass; headers=$Headers; text=$Text }; + { url=$Url; headers=$Headers; text=$Text }; :if ([ :len [ /system/scheduler/find where name="_FlushNtfyQueue" ] ] = 0) do={ /system/scheduler/add name="_FlushNtfyQueue" interval=1m start-time=startup \ on-event=(":global FlushNtfyQueue; \$FlushNtfyQueue;"); From ba39c29648282159082dfa999ec40c7fc84b0e3c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 25 Dec 2024 21:47:23 +0100 Subject: [PATCH 2416/2612] global-functions: $ParseKeyValueStore: split key and value... ... into separate variables. --- global-functions.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index e5e5d50..b212d3a 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -925,8 +925,9 @@ :local Result ({}); :foreach KeyValue in=[ :toarray $Source ] do={ :if ([ :find $KeyValue "=" ]) do={ - :set ($Result->[ :pick $KeyValue 0 [ :find $KeyValue "=" ] ]) \ - [ :pick $KeyValue ([ :find $KeyValue "=" ] + 1) [ :len $KeyValue ] ]; + :local Key [ :pick $KeyValue 0 [ :find $KeyValue "=" ] ]; + :local Value [ :pick $KeyValue ([ :find $KeyValue "=" ] + 1) [ :len $KeyValue ] ]; + :set ($Result->$Key) $Value; } else={ :set ($Result->$KeyValue) true; } From 8212bd6c95935f02335d7d774bd3115a2c071fb1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 25 Dec 2024 21:56:45 +0100 Subject: [PATCH 2417/2612] global-functions: $ParseKeyValueStore: properly return boolean values --- global-functions.rsc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index b212d3a..766e8a2 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -927,6 +927,8 @@ :if ([ :find $KeyValue "=" ]) do={ :local Key [ :pick $KeyValue 0 [ :find $KeyValue "=" ] ]; :local Value [ :pick $KeyValue ([ :find $KeyValue "=" ] + 1) [ :len $KeyValue ] ]; + :if ($Value="true") do={ :set Value true; } + :if ($Value="false") do={ :set Value false; } :set ($Result->$Key) $Value; } else={ :set ($Result->$KeyValue) true; From ef3ce7cc6c43b28e6a80345d9861775767ba86f4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 25 Dec 2024 22:22:30 +0100 Subject: [PATCH 2418/2612] global-functions: $ParseKeyValueStore: support JSON as input This used to require a key=value store, separated with commas. An example for `netwatch-notify` is: /tool/netwatch/add comment="notify, name=example.com" host=93.184.215.14; Now JSON is supported as well, so you could use: /tool/netwatch/add comment="{\"notify\":true,\"name\":\"example.com\"}" host=93.184.215.14; Looks more clumsy here, but may be of help in more complex setups... --- global-functions.rsc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 766e8a2..85818b4 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -919,6 +919,13 @@ # parse key value store :set ParseKeyValueStore do={ :local Source $1; + + :if ([ :pick $Source 0 1 ] = "{") do={ + :do { + :return [ :deserialize from=json $Source ]; + } on-error={ } + } + :if ([ :typeof $Source ] != "array") do={ :set Source [ :tostr $1 ]; } From 3ada3055fff08e655864f4e8e07f060b73077394 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 30 Dec 2024 19:51:42 +0100 Subject: [PATCH 2419/2612] fw-addr-lists: spamhaus.org returned to 'ISRG Root X1' This reverts commit 4d8dce97691ad090091574a790449a7bd564023c. --- certs/Makefile | 2 +- global-config.rsc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/certs/Makefile b/certs/Makefile index 870cb54..9ce8dd4 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -22,7 +22,7 @@ DOMAINS = \ sslbl.abuse.ch/GlobalSign \ upgrade.mikrotik.com/ISRG-Root-X1 \ www.dshield.org/ISRG-Root-X1 \ - www.spamhaus.org/GTS-Root-R4 + www.spamhaus.org/ISRG-Root-X1 .PHONY: $(DOMAINS) diff --git a/global-config.rsc b/global-config.rsc index 0c8f738..cd41a9c 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -107,9 +107,9 @@ { url="https://lists.blocklist.de/lists/strongips.txt"; cert="Certum Trusted Network CA" }; # { url="https://www.spamhaus.org/drop/drop_v4.json"; -# cert="GTS Root R4" }; +# cert="ISRG Root X1" }; # { url="https://www.spamhaus.org/drop/drop_v6.json"; -# cert="GTS Root R4" }; +# cert="ISRG Root X1" }; }; # "mikrotik"={ # { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/mikrotik"; From 191cc1b952b469c474b0181ebdee0ccfd47ae75b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 30 Dec 2024 20:09:46 +0100 Subject: [PATCH 2420/2612] global-functions: $FetchHuge: another workaround for complete file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turns out the workaround in $WaitForFile (commit 8231c3e833ee83a118f4d8395c097e6a9f312c2f) is not sufficient. It helps sometimes, but not always. Possibly depends on CPU speed and bandwidth of internet connection... Who knows!? đŸ¤Ē But! Reading the file goes beyond the known file size. That's suspicious and indicates this exact issue. So add a delay, and keep reading until sizes are equal. --- global-functions.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 85818b4..a59eca1 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -479,9 +479,13 @@ :local FileSize [ /file/get $FileName size ]; :local Return ""; :local VarSize 0; - :while ($VarSize < $FileSize) do={ + :while ($VarSize != $FileSize) do={ :set Return ($Return . ([ /file/read offset=$VarSize chunk-size=32768 file=$FileName as-value ]->"data")); + :set FileSize [ /file/get $FileName size ]; :set VarSize [ :len $Return ]; + :if ($VarSize > $FileSize) do={ + :delay 100ms; + } } /file/remove $DirName; :return $Return; From b98b2457140701261b299af0a2d742bf6aa2b9bc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 30 Dec 2024 20:22:51 +0100 Subject: [PATCH 2421/2612] global-functions: $WaitForFile: drop the first workaround This reverts commit 8231c3e833ee83a118f4d8395c097e6a9f312c2f. Truned out this workaround was not sufficient, see the follow-up in commit 191cc1b952b469c474b0181ebdee0ccfd47ae75b for details. But possibly the second one does it on its own? Reverting this for a test run. --- global-functions.rsc | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index a59eca1..d5df5e7 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1591,16 +1591,6 @@ :delay $Delay; :set I ($I + 1); } - - :local File [ /file/find where name=$FileName ]; - :local SizeA 0; - :local SizeB 1; - :while ($SizeA < $SizeB) do={ - :set SizeA $SizeB; - :delay $Delay; - :set SizeB [ /file/get $File size ]; - } - :return true; } From 9e3729c27990a7ecbdc73694319b924ee00ba867 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Jan 2025 00:04:06 +0100 Subject: [PATCH 2422/2612] update copyright for 2025 --- accesslist-duplicates.capsman.rsc | 2 +- accesslist-duplicates.local.rsc | 2 +- accesslist-duplicates.template.rsc | 2 +- accesslist-duplicates.wifi.rsc | 2 +- backup-cloud.rsc | 2 +- backup-email.rsc | 2 +- backup-partition.rsc | 2 +- backup-upload.rsc | 2 +- capsman-download-packages.capsman.rsc | 2 +- capsman-download-packages.template.rsc | 2 +- capsman-download-packages.wifi.rsc | 2 +- capsman-rolling-upgrade.capsman.rsc | 2 +- capsman-rolling-upgrade.template.rsc | 2 +- capsman-rolling-upgrade.wifi.rsc | 2 +- certificate-renew-issued.rsc | 2 +- check-certificates.rsc | 2 +- check-health.rsc | 2 +- check-lte-firmware-upgrade.rsc | 2 +- check-routeros-update.rsc | 2 +- collect-wireless-mac.capsman.rsc | 2 +- collect-wireless-mac.local.rsc | 2 +- collect-wireless-mac.template.rsc | 2 +- collect-wireless-mac.wifi.rsc | 2 +- daily-psk.capsman.rsc | 2 +- daily-psk.local.rsc | 2 +- daily-psk.template.rsc | 2 +- daily-psk.wifi.rsc | 2 +- dhcp-lease-comment.capsman.rsc | 2 +- dhcp-lease-comment.local.rsc | 2 +- dhcp-lease-comment.template.rsc | 2 +- dhcp-lease-comment.wifi.rsc | 2 +- dhcp-to-dns.rsc | 2 +- firmware-upgrade-reboot.rsc | 2 +- fw-addr-lists.rsc | 2 +- global-config-overlay.rsc | 2 +- global-config.rsc | 2 +- global-functions.rsc | 2 +- global-wait.rsc | 2 +- gps-track.rsc | 2 +- hotspot-to-wpa-cleanup.capsman.rsc | 2 +- hotspot-to-wpa-cleanup.template.rsc | 2 +- hotspot-to-wpa-cleanup.wifi.rsc | 2 +- hotspot-to-wpa.capsman.rsc | 2 +- hotspot-to-wpa.template.rsc | 2 +- hotspot-to-wpa.wifi.rsc | 2 +- ip-addr-bridge.rsc | 2 +- ipsec-to-dns.rsc | 2 +- ipv6-update.rsc | 2 +- lease-script.rsc | 2 +- leds-day-mode.rsc | 2 +- leds-night-mode.rsc | 2 +- leds-toggle-mode.rsc | 2 +- log-forward.rsc | 2 +- mod/bridge-port-to.rsc | 2 +- mod/bridge-port-vlan.rsc | 2 +- mod/inspectvar.rsc | 2 +- mod/ipcalc.rsc | 2 +- mod/notification-email.rsc | 2 +- mod/notification-matrix.rsc | 2 +- mod/notification-ntfy.rsc | 2 +- mod/notification-telegram.rsc | 2 +- mod/scriptrunonce.rsc | 2 +- mod/ssh-keys-import.rsc | 2 +- mode-button.rsc | 2 +- netwatch-dns.rsc | 2 +- netwatch-notify.rsc | 2 +- news-and-changes.rsc | 2 +- ospf-to-leds.rsc | 2 +- packages-update.rsc | 2 +- ppp-on-up.rsc | 2 +- sms-action.rsc | 2 +- sms-forward.rsc | 2 +- super-mario-theme.rsc | 2 +- telegram-chat.rsc | 2 +- unattended-lte-firmware-upgrade.rsc | 2 +- update-gre-address.rsc | 2 +- update-tunnelbroker.rsc | 2 +- 77 files changed, 77 insertions(+), 77 deletions(-) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index ce0ce11..b611917 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.capsman -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index aa78fe8..ef0cf32 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.local -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index d0c282d..ab5b671 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates%TEMPL% -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc index b1444e3..0205598 100644 --- a/accesslist-duplicates.wifi.rsc +++ b/accesslist-duplicates.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.wifi -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 4cc7a58..37ca92f 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: backup-cloud -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=40 diff --git a/backup-email.rsc b/backup-email.rsc index e1d44ea..489927b 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: backup-email -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=20 diff --git a/backup-partition.rsc b/backup-partition.rsc index f1e1c17..b2b75ac 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: backup-partition -# Copyright (c) 2022-2024 Christian Hesse +# Copyright (c) 2022-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=70 diff --git a/backup-upload.rsc b/backup-upload.rsc index 12698e9..e050140 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: backup-upload -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: backup-script, order=50 diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index 1802884..4609498 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-download-packages.capsman -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 72edaa9..642a068 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-download-packages%TEMPL% -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 74a5d9d..1ea9b79 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-download-packages.wifi -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc index d0f9fb8..7a5ed81 100644 --- a/capsman-rolling-upgrade.capsman.rsc +++ b/capsman-rolling-upgrade.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-rolling-upgrade.capsman -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index 1bd5f2a..fd7e31f 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-rolling-upgrade%TEMPL% -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc index c9e6622..3fb99b8 100644 --- a/capsman-rolling-upgrade.wifi.rsc +++ b/capsman-rolling-upgrade.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: capsman-rolling-upgrade.wifi -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc index ce61f7d..32c3267 100644 --- a/certificate-renew-issued.rsc +++ b/certificate-renew-issued.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: certificate-renew-issued -# Copyright (c) 2019-2024 Christian Hesse +# Copyright (c) 2019-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/check-certificates.rsc b/check-certificates.rsc index 52cfc5e..226364b 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-certificates -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/check-health.rsc b/check-health.rsc index 495b450..d3586db 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-health -# Copyright (c) 2019-2024 Christian Hesse +# Copyright (c) 2019-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index 898d6f1..cd9f979 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-lte-firmware-upgrade -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index a2e39b6..c3d2625 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: check-routeros-update -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index 77fd6e3..05e4b89 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.capsman -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index dc7be19..67c1a98 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.local -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index 34b1695..84a9667 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac%TEMPL% -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc index 23c93b0..fa4953b 100644 --- a/collect-wireless-mac.wifi.rsc +++ b/collect-wireless-mac.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.wifi -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=40 diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index 263f6e5..f41da29 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk.capsman -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index f0757e1..2920cb5 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk.local -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 7e36b5a..05c376e 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk%TEMPL% -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index 293f0e4..4182ab8 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: daily-psk.wifi -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc index 5ac0009..947181b 100644 --- a/dhcp-lease-comment.capsman.rsc +++ b/dhcp-lease-comment.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.capsman -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc index 1b74d93..27306dd 100644 --- a/dhcp-lease-comment.local.rsc +++ b/dhcp-lease-comment.local.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.local -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index 8f1ad47..8552b26 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment%TEMPL% -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc index d3741c5..bf67bd0 100644 --- a/dhcp-lease-comment.wifi.rsc +++ b/dhcp-lease-comment.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.wifi -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=60 diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index ad55c4d..1eb832a 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: dhcp-to-dns -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=20 diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc index 9655903..f9e557c 100644 --- a/firmware-upgrade-reboot.rsc +++ b/firmware-upgrade-reboot.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: firmware-upgrade-reboot -# Copyright (c) 2022-2024 Christian Hesse +# Copyright (c) 2022-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index a195c89..e98a610 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: fw-addr-lists -# Copyright (c) 2023-2024 Christian Hesse +# Copyright (c) 2023-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.16 diff --git a/global-config-overlay.rsc b/global-config-overlay.rsc index 9ffd90c..227ae5a 100644 --- a/global-config-overlay.rsc +++ b/global-config-overlay.rsc @@ -1,5 +1,5 @@ # Overlay for global configuration by RouterOS Scripts -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global configuration, custom overlay diff --git a/global-config.rsc b/global-config.rsc index cd41a9c..1f4e9ca 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-config -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global configuration diff --git a/global-functions.rsc b/global-functions.rsc index d5df5e7..a2dd279 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-functions -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/global-wait.rsc b/global-wait.rsc index f0631e2..529dbd7 100644 --- a/global-wait.rsc +++ b/global-wait.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-wait -# Copyright (c) 2020-2024 Christian Hesse +# Copyright (c) 2020-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/gps-track.rsc b/gps-track.rsc index c0ecac4..1bd976a 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: gps-track -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index 8a38213..1d27faf 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa-cleanup.capsman -# Copyright (c) 2021-2024 Christian Hesse +# Copyright (c) 2021-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index e8d2dfb..f92dbe5 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa-cleanup%TEMPL% -# Copyright (c) 2021-2024 Christian Hesse +# Copyright (c) 2021-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index e2ef1fd..cd21593 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa-cleanup.wifi -# Copyright (c) 2021-2024 Christian Hesse +# Copyright (c) 2021-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # provides: lease-script, order=80 diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index e57d327..d962ba7 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa.capsman -# Copyright (c) 2019-2024 Christian Hesse +# Copyright (c) 2019-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index efe37d0..3438be7 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa%TEMPL% -# Copyright (c) 2019-2024 Christian Hesse +# Copyright (c) 2019-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index 6242d04..a2bb3ca 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa.wifi -# Copyright (c) 2019-2024 Christian Hesse +# Copyright (c) 2019-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/ip-addr-bridge.rsc b/ip-addr-bridge.rsc index 758cd46..00b45a3 100644 --- a/ip-addr-bridge.rsc +++ b/ip-addr-bridge.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ip-addr-bridge -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # enable or disable ip addresses based on bridge port state diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index 47676ca..39b21d5 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ipsec-to-dns -# Copyright (c) 2021-2024 Christian Hesse +# Copyright (c) 2021-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/ipv6-update.rsc b/ipv6-update.rsc index ea1d444..a2fb831 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ipv6-update -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/lease-script.rsc b/lease-script.rsc index 995c7e4..3d0fc72 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: lease-script -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/leds-day-mode.rsc b/leds-day-mode.rsc index b7c6b5b..e0f08d6 100644 --- a/leds-day-mode.rsc +++ b/leds-day-mode.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-day-mode -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # enable LEDs diff --git a/leds-night-mode.rsc b/leds-night-mode.rsc index fb7c7a2..1f50dfd 100644 --- a/leds-night-mode.rsc +++ b/leds-night-mode.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-night-mode -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # disable LEDs diff --git a/leds-toggle-mode.rsc b/leds-toggle-mode.rsc index 07e12ae..55d5b82 100644 --- a/leds-toggle-mode.rsc +++ b/leds-toggle-mode.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-toggle-mode -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # toggle LEDs mode diff --git a/log-forward.rsc b/log-forward.rsc index 8e660fc..8c2ebc0 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: log-forward -# Copyright (c) 2020-2024 Christian Hesse +# Copyright (c) 2020-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/mod/bridge-port-to.rsc b/mod/bridge-port-to.rsc index 9e7b911..ec6f612 100644 --- a/mod/bridge-port-to.rsc +++ b/mod/bridge-port-to.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/bridge-port-to -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/mod/bridge-port-vlan.rsc b/mod/bridge-port-vlan.rsc index 18fa2db..6221646 100644 --- a/mod/bridge-port-vlan.rsc +++ b/mod/bridge-port-vlan.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/bridge-port-vlan -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/mod/inspectvar.rsc b/mod/inspectvar.rsc index 0209214..01724bb 100644 --- a/mod/inspectvar.rsc +++ b/mod/inspectvar.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/inspectvar -# Copyright (c) 2020-2024 Christian Hesse +# Copyright (c) 2020-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc index 021cd30..69dec8b 100644 --- a/mod/ipcalc.rsc +++ b/mod/ipcalc.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/ipcalc -# Copyright (c) 2020-2024 Christian Hesse +# Copyright (c) 2020-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index a3291d9..6d700f5 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/notification-email -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 14f369d..aad8b42 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/notification-matrix -# Copyright (c) 2013-2024 Michael Gisbers +# Copyright (c) 2013-2025 Michael Gisbers # Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index f8351fd..53ba9b4 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/notification-ntfy -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 7d75b8b..f9700cf 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/notification-telegram -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index c8dcf26..7e01e72 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/scriptrunonece -# Copyright (c) 2020-2024 Christian Hesse +# Copyright (c) 2020-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 583e827..ad3a81e 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/ssh-keys-import -# Copyright (c) 2020-2024 Christian Hesse +# Copyright (c) 2020-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.16 diff --git a/mode-button.rsc b/mode-button.rsc index 90fe80e..f8bd7b8 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mode-button -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index a704c84..81f9d95 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: netwatch-dns -# Copyright (c) 2022-2024 Christian Hesse +# Copyright (c) 2022-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.16 diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index f1e87bd..e79977e 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: netwatch-notify -# Copyright (c) 2020-2024 Christian Hesse +# Copyright (c) 2020-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.15 diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 9ab811d..545a0c9 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -1,5 +1,5 @@ # News, changes and migration by RouterOS Scripts -# Copyright (c) 2019-2024 Christian Hesse +# Copyright (c) 2019-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md :global IDonate; diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc index d96e763..3400e7f 100644 --- a/ospf-to-leds.rsc +++ b/ospf-to-leds.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ospf-to-leds -# Copyright (c) 2020-2024 Christian Hesse +# Copyright (c) 2020-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/packages-update.rsc b/packages-update.rsc index 924a5d9..a79946d 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: packages-update -# Copyright (c) 2019-2024 Christian Hesse +# Copyright (c) 2019-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc index 13b42c7..a776ce2 100644 --- a/ppp-on-up.rsc +++ b/ppp-on-up.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ppp-on-up -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/sms-action.rsc b/sms-action.rsc index fd3096c..f22a0bb 100644 --- a/sms-action.rsc +++ b/sms-action.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: sms-action -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/sms-forward.rsc b/sms-forward.rsc index 8334d5f..efebb75 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: sms-forward -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # Anatoly Bubenkov # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # diff --git a/super-mario-theme.rsc b/super-mario-theme.rsc index 63308b0..fc868c8 100644 --- a/super-mario-theme.rsc +++ b/super-mario-theme.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: super-mario-theme -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # play Super Mario theme diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 8589aab..eebb617 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: telegram-chat -# Copyright (c) 2023-2024 Christian Hesse +# Copyright (c) 2023-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.15 diff --git a/unattended-lte-firmware-upgrade.rsc b/unattended-lte-firmware-upgrade.rsc index 7ce4028..f1bc552 100644 --- a/unattended-lte-firmware-upgrade.rsc +++ b/unattended-lte-firmware-upgrade.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: unattended-lte-firmware-upgrade -# Copyright (c) 2018-2024 Christian Hesse +# Copyright (c) 2018-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # schedule unattended lte firmware upgrade diff --git a/update-gre-address.rsc b/update-gre-address.rsc index 87762d6..4ac311a 100644 --- a/update-gre-address.rsc +++ b/update-gre-address.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: update-gre-address -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # requires RouterOS, version=7.14 diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index dd43c64..589544c 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: update-tunnelbroker -# Copyright (c) 2013-2024 Christian Hesse +# Copyright (c) 2013-2025 Christian Hesse # Michael Gisbers # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # From db508ddcd1a4bb78af95e5d96a4f626173d29557 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Jan 2025 09:30:05 +0100 Subject: [PATCH 2423/2612] backup-cloud: refuse when running from backup partition --- backup-cloud.rsc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 37ca92f..f32a04d 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -38,6 +38,14 @@ :set ExitOK true; :error false; } + + :if ([ :len [ /system/scheduler/find where name="running-from-backup-partition" ] ] > 0) do={ + $LogPrint warning $ScriptName ("Running from backup partition, refusing to act."); + :set PackagesUpdateBackupFailure true; + :set ExitOK true; + :error false; + } + $WaitFullyConnected; :if ([ $ScriptFromTerminal $ScriptName ] = false && $BackupRandomDelay > 0) do={ From 303c39390068ebf0ab5cba3bbb967d6079fbdeb2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Jan 2025 09:30:20 +0100 Subject: [PATCH 2424/2612] backup-email: refuse when running from backup partition --- backup-email.rsc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backup-email.rsc b/backup-email.rsc index 489927b..731fb95 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -56,6 +56,14 @@ :set ExitOK true; :error false; } + + :if ([ :len [ /system/scheduler/find where name="running-from-backup-partition" ] ] > 0) do={ + $LogPrint warning $ScriptName ("Running from backup partition, refusing to act."); + :set PackagesUpdateBackupFailure true; + :set ExitOK true; + :error false; + } + $WaitFullyConnected; :if ([ $ScriptFromTerminal $ScriptName ] = false && $BackupRandomDelay > 0) do={ From 6c990079a6c6f92c748f98a5128e7438e05caefb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Jan 2025 09:26:44 +0100 Subject: [PATCH 2425/2612] backup-partition: refuse when running from backup partition --- backup-partition.rsc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backup-partition.rsc b/backup-partition.rsc index b2b75ac..2298225 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -47,6 +47,13 @@ :error false; } + :if ([ :len [ /system/scheduler/find where name="running-from-backup-partition" ] ] > 0) do={ + $LogPrint warning $ScriptName ("Running from backup partition, refusing to act."); + :set PackagesUpdateBackupFailure true; + :set ExitOK true; + :error false; + } + :if ([ :len [ /partitions/find ] ] < 2) do={ $LogPrint error $ScriptName ("Device does not have a fallback partition."); :set PackagesUpdateBackupFailure true; From d9693f4d5f783935cd2e47479889cc035b294934 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Jan 2025 09:30:38 +0100 Subject: [PATCH 2426/2612] backup-upload: refuse when running from backup partition --- backup-upload.rsc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backup-upload.rsc b/backup-upload.rsc index e050140..e035415 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -53,6 +53,14 @@ :set ExitOK true; :error false; } + + :if ([ :len [ /system/scheduler/find where name="running-from-backup-partition" ] ] > 0) do={ + $LogPrint warning $ScriptName ("Running from backup partition, refusing to act."); + :set PackagesUpdateBackupFailure true; + :set ExitOK true; + :error false; + } + $WaitFullyConnected; :if ([ $ScriptFromTerminal $ScriptName ] = false && $BackupRandomDelay > 0) do={ From 665516b33de8d4d58d18274e05a0180cf6978af0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Jan 2025 09:30:59 +0100 Subject: [PATCH 2427/2612] check-routeros-update: refuse when running from backup partition --- check-routeros-update.rsc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index c3d2625..19abebf 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -51,6 +51,13 @@ :set ExitOK true; :error false; } + + :if ([ :len [ /system/scheduler/find where name="running-from-backup-partition" ] ] > 0) do={ + $LogPrint warning $ScriptName ("Running from backup partition, refusing to act."); + :set ExitOK true; + :error false; + } + $WaitFullyConnected; :if ([ :len [ /system/scheduler/find where name="_RebootForUpdate" ] ] > 0) do={ From ce2d090e998d51b92376f3470b829f598f3ce5bd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 6 Jan 2025 09:31:13 +0100 Subject: [PATCH 2428/2612] packages-update: refuse when running from backup partition --- packages-update.rsc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages-update.rsc b/packages-update.rsc index a79946d..7644219 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -50,6 +50,12 @@ :error false; } + :if ([ :len [ /system/scheduler/find where name="running-from-backup-partition" ] ] > 0) do={ + $LogPrint warning $ScriptName ("Running from backup partition, refusing to act."); + :set ExitOK true; + :error false; + } + :local Update [ /system/package/update/get ]; :if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ From 98791f48fdb684f946fb94e8735b1073942cd731 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 9 Jan 2025 13:20:45 +0100 Subject: [PATCH 2429/2612] ppp-on-up: release only bound ipv6 dhcp clients --- ppp-on-up.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc index a776ce2..ba9d0aa 100644 --- a/ppp-on-up.rsc +++ b/ppp-on-up.rsc @@ -28,7 +28,7 @@ :local IntName [ /interface/get $Interface name ]; $LogPrint info $ScriptName ("PPP interface " . $IntName . " is up."); - /ipv6/dhcp-client/release [ find where interface=$IntName !disabled ]; + /ipv6/dhcp-client/release [ find where interface=$IntName !disabled bound ]; :foreach Script in=[ /system/script/find where source~("\n# provides: ppp-on-up\r?\n") ] do={ :local ScriptName [ /system/script/get $Script name ]; From e8b1e19b284af74032e1edcbb08665752dbe508a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 22 Nov 2024 14:06:22 +0100 Subject: [PATCH 2430/2612] fw-addr-lists: spamhaus.org returned to 'GTS Root R4' --- certs/Makefile | 2 +- global-config.rsc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/certs/Makefile b/certs/Makefile index 9ce8dd4..870cb54 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -22,7 +22,7 @@ DOMAINS = \ sslbl.abuse.ch/GlobalSign \ upgrade.mikrotik.com/ISRG-Root-X1 \ www.dshield.org/ISRG-Root-X1 \ - www.spamhaus.org/ISRG-Root-X1 + www.spamhaus.org/GTS-Root-R4 .PHONY: $(DOMAINS) diff --git a/global-config.rsc b/global-config.rsc index 1f4e9ca..c63283d 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -107,9 +107,9 @@ { url="https://lists.blocklist.de/lists/strongips.txt"; cert="Certum Trusted Network CA" }; # { url="https://www.spamhaus.org/drop/drop_v4.json"; -# cert="ISRG Root X1" }; +# cert="GTS Root R4" }; # { url="https://www.spamhaus.org/drop/drop_v6.json"; -# cert="ISRG Root X1" }; +# cert="GTS Root R4" }; }; # "mikrotik"={ # { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/mikrotik"; From ccf17a438cd10f77f0f0c0cd83f6f6729b6479c7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 23 Jan 2025 23:07:38 +0100 Subject: [PATCH 2431/2612] global-config: download scripts from rsc.eworm.de MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently AI bots are crawling website all around the world. For a website hosting git content this adds a lot of extra load and traffic: The site has lots of sections, repositories have a lot of files, branches, tags, commit ids, etc... Multiply that and you have a nearly unlimited number of unique urls. The bots try to get each and every of these. To speed up the learing process on their side a swarm of hundreds, thousands or more ip addresses is active at the same time, ultimately DDOS'ing the websites, making it inaccessible. đŸ˜ŗđŸ¤Ŧ Well, there is one single file all of these AI bots are not interested in: robots.txt đŸ¤ŦđŸ¤Ŧ On top some use random user agent strings, making filtering impossible. đŸ¤ŦđŸ¤ŦđŸ¤Ŧ For a short term sulution I deploy the repository content as static files, hopefully making these accessible at least. We will see. --- global-config.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/global-config.rsc b/global-config.rsc index c63283d..3e17320 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -217,14 +217,16 @@ :global GpsTrackUrl "https://example.com/index.php"; # This is the base url to fetch scripts from. -:global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/"; +:global ScriptUpdatesBaseUrl "https://rsc.eworm.de/main/"; # alternative urls - main: stable code - next: currently in development +#:global ScriptUpdatesBaseUrl "https://rsc.eworm.de/next/"; +#:global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/"; #:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/main/"; #:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/next/"; #:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/main/"; #:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/next/"; :global ScriptUpdatesUrlSuffix ""; -# use next branch with default url (git.eworm.de) +# use next branch with my git url (git.eworm.de) #:global ScriptUpdatesUrlSuffix "?h=next"; # Use this for defaults with $ScriptRunOnce From d4acc5aa59e30c5e430b553fb2142c7e7e004822 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 11:03:50 +0100 Subject: [PATCH 2432/2612] BRANCHES: adopt new default url --- BRANCHES.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BRANCHES.md b/BRANCHES.md index 2bacf8e..5d94077 100644 --- a/BRANCHES.md +++ b/BRANCHES.md @@ -22,13 +22,13 @@ for testing. To install a single script from `next` branch: - $ScriptInstallUpdate script-name "url-suffix=?h=next"; + $ScriptInstallUpdate script-name "base-url=https://rsc.eworm.de/next/"; ## Switch existing script Alternatively switch an existing script to update from `next` branch: - /system/script/set comment="url-suffix=?h=next" script-name; + /system/script/set comment="base-url=https://rsc.eworm.de/next/" script-name; $ScriptInstallUpdate; ## Switch installation @@ -36,7 +36,7 @@ Alternatively switch an existing script to update from `next` branch: Last but not least - to switch the complete installation to the `next` branch edit `global-config-overlay` and add: - :global ScriptUpdatesUrlSuffix "?h=next"; + :global ScriptUpdatesBaseUrl "https://rsc.eworm.de/next/"; ... then reload the configuration and update: From a446f31262118d59d6ec938a022b2f7d99fb5a70 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 23 Jan 2025 23:56:18 +0100 Subject: [PATCH 2433/2612] fw-addr-lists: use my static mirror --- global-config.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/global-config.rsc b/global-config.rsc index 3e17320..c8b2c2e 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -92,11 +92,11 @@ # This defines the settings for firewall address-lists (fw-addr-lists). :global FwAddrLists { # "allow"={ -# { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/allow"; +# { url="https://rsc.eworm.de/main/fw-addr-lists.d/allow"; # cert="ISRG Root X2"; timeout=1w }; # }; "block"={ -# { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/block"; +# { url="https://rsc.eworm.de/main/fw-addr-lists.d/block"; # cert="ISRG Root X2" }; { url="https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt"; cert="GlobalSign" }; @@ -112,7 +112,7 @@ # cert="GTS Root R4" }; }; # "mikrotik"={ -# { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/mikrotik"; +# { url="https://rsc.eworm.de/main/fw-addr-lists.d/mikrotik"; # cert="ISRG Root X2"; timeout=1w }; # }; }; From 500054535c44f7682bf82712dc37e299299b09dd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:30:01 +0100 Subject: [PATCH 2434/2612] unattended-lte-firmware-upgrade: require RouterOS --- unattended-lte-firmware-upgrade.rsc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unattended-lte-firmware-upgrade.rsc b/unattended-lte-firmware-upgrade.rsc index f1bc552..ea18edf 100644 --- a/unattended-lte-firmware-upgrade.rsc +++ b/unattended-lte-firmware-upgrade.rsc @@ -3,6 +3,8 @@ # Copyright (c) 2018-2025 Christian Hesse # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.14 +# # schedule unattended lte firmware upgrade # https://git.eworm.de/cgit/routeros-scripts/about/doc/unattended-lte-firmware-upgrade.md From 1dda59034e366c6cb6e2b78fa820ece1407f93e5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2435/2612] accesslist-duplicates: use short url rsc.eworm.de --- accesslist-duplicates.capsman.rsc | 4 ++-- accesslist-duplicates.local.rsc | 4 ++-- accesslist-duplicates.template.rsc | 4 ++-- accesslist-duplicates.wifi.rsc | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index b611917..0c4eaaf 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.capsman # Copyright (c) 2018-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # print duplicate antries in wireless access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md +# https://rsc.eworm.de/doc/accesslist-duplicates.md # # !! Do not edit this file, it is generated from template! diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index ef0cf32..353fe1f 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.local # Copyright (c) 2018-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # print duplicate antries in wireless access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md +# https://rsc.eworm.de/doc/accesslist-duplicates.md # # !! Do not edit this file, it is generated from template! diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index ab5b671..4219014 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates%TEMPL% # Copyright (c) 2018-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # print duplicate antries in wireless access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md +# https://rsc.eworm.de/doc/accesslist-duplicates.md # # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc index 0205598..3ee53d8 100644 --- a/accesslist-duplicates.wifi.rsc +++ b/accesslist-duplicates.wifi.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: accesslist-duplicates.wifi # Copyright (c) 2018-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # print duplicate antries in wireless access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md +# https://rsc.eworm.de/doc/accesslist-duplicates.md # # !! Do not edit this file, it is generated from template! From 5281b4ba02a721af189ad70244c95cb175c6af06 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2436/2612] backup-cloud: use short url rsc.eworm.de --- backup-cloud.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index f32a04d..efae055 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: backup-cloud # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: backup-script, order=40 # requires RouterOS, version=7.14 # # upload backup to MikroTik cloud -# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md +# https://rsc.eworm.de/doc/backup-cloud.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 08ff07d037d88e7aba7356ba0f744a4e92d597ea Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2437/2612] backup-email: use short url rsc.eworm.de --- backup-email.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backup-email.rsc b/backup-email.rsc index 731fb95..f6ebad0 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: backup-email # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: backup-script, order=20 # requires RouterOS, version=7.14 # # create and email backup and config file -# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md +# https://rsc.eworm.de/doc/backup-email.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From c70b6a8eb304641df205c1d18f12670d183a9385 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2438/2612] backup-partition: use short url rsc.eworm.de --- backup-partition.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backup-partition.rsc b/backup-partition.rsc index 2298225..b8bf7b1 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: backup-partition # Copyright (c) 2022-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: backup-script, order=70 # requires RouterOS, version=7.14 # # save configuration to fallback partition -# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md +# https://rsc.eworm.de/doc/backup-partition.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 38b5fbab9cdc9fd755c04a2f7debd2d62ae05aab Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2439/2612] backup-upload: use short url rsc.eworm.de --- backup-upload.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index e035415..011c502 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: backup-upload # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: backup-script, order=50 # requires RouterOS, version=7.14 # # create and upload backup and config file -# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md +# https://rsc.eworm.de/doc/backup-upload.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From b938847030e90c8c3b8decb55e6625aa2e537798 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2440/2612] capsman-download-packages: use short url rsc.eworm.de --- capsman-download-packages.capsman.rsc | 4 ++-- capsman-download-packages.template.rsc | 4 ++-- capsman-download-packages.wifi.rsc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index 4609498..fa76ff5 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -2,12 +2,12 @@ # RouterOS script: capsman-download-packages.capsman # Copyright (c) 2018-2025 Christian Hesse # Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # download and cleanup packages for CAP installation from CAPsMAN -# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md +# https://rsc.eworm.de/doc/capsman-download-packages.md # # !! Do not edit this file, it is generated from template! diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 642a068..912e279 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -2,12 +2,12 @@ # RouterOS script: capsman-download-packages%TEMPL% # Copyright (c) 2018-2025 Christian Hesse # Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # download and cleanup packages for CAP installation from CAPsMAN -# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md +# https://rsc.eworm.de/doc/capsman-download-packages.md # # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 1ea9b79..3a5e7d1 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -2,12 +2,12 @@ # RouterOS script: capsman-download-packages.wifi # Copyright (c) 2018-2025 Christian Hesse # Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # download and cleanup packages for CAP installation from CAPsMAN -# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md +# https://rsc.eworm.de/doc/capsman-download-packages.md # # !! Do not edit this file, it is generated from template! From 26dbf5805a83a2670e678ec93d02796f7c3233cd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2441/2612] capsman-rolling-upgrade: use short url rsc.eworm.de --- capsman-rolling-upgrade.capsman.rsc | 4 ++-- capsman-rolling-upgrade.template.rsc | 4 ++-- capsman-rolling-upgrade.wifi.rsc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc index 7a5ed81..abe066e 100644 --- a/capsman-rolling-upgrade.capsman.rsc +++ b/capsman-rolling-upgrade.capsman.rsc @@ -2,13 +2,13 @@ # RouterOS script: capsman-rolling-upgrade.capsman # Copyright (c) 2018-2025 Christian Hesse # Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: capsman-rolling-upgrade.capsman # requires RouterOS, version=7.14 # # upgrade CAPs one after another -# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md +# https://rsc.eworm.de/doc/capsman-rolling-upgrade.md # # !! Do not edit this file, it is generated from template! diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index fd7e31f..c1c7ff1 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -2,13 +2,13 @@ # RouterOS script: capsman-rolling-upgrade%TEMPL% # Copyright (c) 2018-2025 Christian Hesse # Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: capsman-rolling-upgrade%TEMPL% # requires RouterOS, version=7.14 # # upgrade CAPs one after another -# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md +# https://rsc.eworm.de/doc/capsman-rolling-upgrade.md # # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc index 3fb99b8..44c99db 100644 --- a/capsman-rolling-upgrade.wifi.rsc +++ b/capsman-rolling-upgrade.wifi.rsc @@ -2,13 +2,13 @@ # RouterOS script: capsman-rolling-upgrade.wifi # Copyright (c) 2018-2025 Christian Hesse # Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: capsman-rolling-upgrade.wifi # requires RouterOS, version=7.14 # # upgrade CAPs one after another -# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md +# https://rsc.eworm.de/doc/capsman-rolling-upgrade.md # # !! Do not edit this file, it is generated from template! From 1b7458ac955dc32ea12f19a779c985f27e0c6a28 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2442/2612] certificate-renew-issued: use short url rsc.eworm.de --- certificate-renew-issued.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc index 32c3267..5a4043d 100644 --- a/certificate-renew-issued.rsc +++ b/certificate-renew-issued.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: certificate-renew-issued # Copyright (c) 2019-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # renew locally issued certificates -# https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md +# https://rsc.eworm.de/doc/certificate-renew-issued.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 1239ac31044270036a8204cd7856776d8faee06e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2443/2612] check-certificates: use short url rsc.eworm.de --- check-certificates.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 226364b..02e3e52 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: check-certificates # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # check for certificate validity -# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md +# https://rsc.eworm.de/doc/check-certificates.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 231be730aea0bad7a914c387a719d7c46ecbb468 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2444/2612] check-health: use short url rsc.eworm.de --- check-health.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-health.rsc b/check-health.rsc index d3586db..31bd6c2 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: check-health # Copyright (c) 2019-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # check for RouterOS health state -# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md +# https://rsc.eworm.de/doc/check-health.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 7484663b92062ae6c120227de22d387df93123ad Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2445/2612] check-lte-firmware-upgrade: use short url rsc.eworm.de --- check-lte-firmware-upgrade.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index cd9f979..562b8fe 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: check-lte-firmware-upgrade # Copyright (c) 2018-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # check for LTE firmware upgrade, send notification -# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md +# https://rsc.eworm.de/doc/check-lte-firmware-upgrade.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 36c87c91ea9b4bc5ef1153733d38e52ad0e3e291 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2446/2612] check-routeros-update: use short url rsc.eworm.de --- check-routeros-update.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 19abebf..9486d6c 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: check-routeros-update # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # check for RouterOS update, send notification and/or install -# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md +# https://rsc.eworm.de/doc/check-routeros-update.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From f8058eaf71c54fb722fb65c5e87c9f448927a36e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2447/2612] collect-wireless-mac: use short url rsc.eworm.de --- collect-wireless-mac.capsman.rsc | 4 ++-- collect-wireless-mac.local.rsc | 4 ++-- collect-wireless-mac.template.rsc | 4 ++-- collect-wireless-mac.wifi.rsc | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index 05e4b89..f718e0b 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.capsman # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=40 # requires RouterOS, version=7.14 # # collect wireless mac adresses in access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md +# https://rsc.eworm.de/doc/collect-wireless-mac.md # # !! Do not edit this file, it is generated from template! diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index 67c1a98..0017875 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.local # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=40 # requires RouterOS, version=7.14 # # collect wireless mac adresses in access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md +# https://rsc.eworm.de/doc/collect-wireless-mac.md # # !! Do not edit this file, it is generated from template! diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index 84a9667..527e985 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac%TEMPL% # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=40 # requires RouterOS, version=7.14 # # collect wireless mac adresses in access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md +# https://rsc.eworm.de/doc/collect-wireless-mac.md # # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc index fa4953b..5f9de7d 100644 --- a/collect-wireless-mac.wifi.rsc +++ b/collect-wireless-mac.wifi.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: collect-wireless-mac.wifi # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=40 # requires RouterOS, version=7.14 # # collect wireless mac adresses in access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md +# https://rsc.eworm.de/doc/collect-wireless-mac.md # # !! Do not edit this file, it is generated from template! From 96fa76f07dfe86d31f32c90e969cb824d727280a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2448/2612] daily-psk.template: use short url rsc.eworm.de --- daily-psk.capsman.rsc | 4 ++-- daily-psk.local.rsc | 4 ++-- daily-psk.template.rsc | 4 ++-- daily-psk.wifi.rsc | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc index f41da29..5672931 100644 --- a/daily-psk.capsman.rsc +++ b/daily-psk.capsman.rsc @@ -2,12 +2,12 @@ # RouterOS script: daily-psk.capsman # Copyright (c) 2013-2025 Christian Hesse # Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.15 # # update daily PSK (pre shared key) -# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md +# https://rsc.eworm.de/doc/daily-psk.md # # !! Do not edit this file, it is generated from template! diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc index 2920cb5..9dea469 100644 --- a/daily-psk.local.rsc +++ b/daily-psk.local.rsc @@ -2,12 +2,12 @@ # RouterOS script: daily-psk.local # Copyright (c) 2013-2025 Christian Hesse # Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.15 # # update daily PSK (pre shared key) -# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md +# https://rsc.eworm.de/doc/daily-psk.md # # !! Do not edit this file, it is generated from template! diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc index 05c376e..8202eeb 100644 --- a/daily-psk.template.rsc +++ b/daily-psk.template.rsc @@ -2,12 +2,12 @@ # RouterOS script: daily-psk%TEMPL% # Copyright (c) 2013-2025 Christian Hesse # Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.15 # # update daily PSK (pre shared key) -# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md +# https://rsc.eworm.de/doc/daily-psk.md # # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc index 4182ab8..3de3c5b 100644 --- a/daily-psk.wifi.rsc +++ b/daily-psk.wifi.rsc @@ -2,12 +2,12 @@ # RouterOS script: daily-psk.wifi # Copyright (c) 2013-2025 Christian Hesse # Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.15 # # update daily PSK (pre shared key) -# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md +# https://rsc.eworm.de/doc/daily-psk.md # # !! Do not edit this file, it is generated from template! From 61dee2177634b6e464aab4b644eb686f914cb365 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2449/2612] dhcp-lease-comment: use short url rsc.eworm.de --- dhcp-lease-comment.capsman.rsc | 4 ++-- dhcp-lease-comment.local.rsc | 4 ++-- dhcp-lease-comment.template.rsc | 4 ++-- dhcp-lease-comment.wifi.rsc | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc index 947181b..3803963 100644 --- a/dhcp-lease-comment.capsman.rsc +++ b/dhcp-lease-comment.capsman.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.capsman # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=60 # requires RouterOS, version=7.14 # # update dhcp-server lease comment with infos from access-list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md +# https://rsc.eworm.de/doc/dhcp-lease-comment.md # # !! Do not edit this file, it is generated from template! diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc index 27306dd..d5f1461 100644 --- a/dhcp-lease-comment.local.rsc +++ b/dhcp-lease-comment.local.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.local # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=60 # requires RouterOS, version=7.14 # # update dhcp-server lease comment with infos from access-list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md +# https://rsc.eworm.de/doc/dhcp-lease-comment.md # # !! Do not edit this file, it is generated from template! diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index 8552b26..2bddc26 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment%TEMPL% # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=60 # requires RouterOS, version=7.14 # # update dhcp-server lease comment with infos from access-list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md +# https://rsc.eworm.de/doc/dhcp-lease-comment.md # # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc index bf67bd0..515b438 100644 --- a/dhcp-lease-comment.wifi.rsc +++ b/dhcp-lease-comment.wifi.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: dhcp-lease-comment.wifi # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=60 # requires RouterOS, version=7.14 # # update dhcp-server lease comment with infos from access-list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md +# https://rsc.eworm.de/doc/dhcp-lease-comment.md # # !! Do not edit this file, it is generated from template! From 632d294a988188eb9ea182316d28411b8c281ed2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2450/2612] dhcp-to-dns: use short url rsc.eworm.de --- dhcp-to-dns.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc index 1eb832a..9b94098 100644 --- a/dhcp-to-dns.rsc +++ b/dhcp-to-dns.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: dhcp-to-dns # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=20 # requires RouterOS, version=7.16 # # check DHCP leases and add/remove/update DNS entries -# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md +# https://rsc.eworm.de/doc/dhcp-to-dns.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 7b760d9fa408b12ef00328266c77707f835f0600 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2451/2612] firmware-upgrade-reboot: use short url rsc.eworm.de --- firmware-upgrade-reboot.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc index f9e557c..e3d62de 100644 --- a/firmware-upgrade-reboot.rsc +++ b/firmware-upgrade-reboot.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: firmware-upgrade-reboot # Copyright (c) 2022-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # install firmware upgrade, and reboot -# https://git.eworm.de/cgit/routeros-scripts/about/doc/firmware-upgrade-reboot.md +# https://rsc.eworm.de/doc/firmware-upgrade-reboot.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 39c5aeda13e107f1dd91fc632cab536befeca6eb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2452/2612] fw-addr-lists: use short url rsc.eworm.de --- fw-addr-lists.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index e98a610..d41dc04 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: fw-addr-lists # Copyright (c) 2023-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.16 # # download, import and update firewall address-lists -# https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md +# https://rsc.eworm.de/doc/fw-addr-lists.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From ac62b8f24fc72aefbb9994abac3baa07bd3cfa93 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2453/2612] global-config-overlay: use short url rsc.eworm.de --- global-config-overlay.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/global-config-overlay.rsc b/global-config-overlay.rsc index 227ae5a..9afaceb 100644 --- a/global-config-overlay.rsc +++ b/global-config-overlay.rsc @@ -1,12 +1,12 @@ # Overlay for global configuration by RouterOS Scripts # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # global configuration, custom overlay -# https://git.eworm.de/cgit/routeros-scripts/about/#editing-configuration +# https://rsc.eworm.de/#editing-configuration # Copy relevant configuration from global-config, paste and modify it here. -# https://git.eworm.de/cgit/routeros-scripts/about/global-config.rsc +# https://rsc.eworm.de/global-config.rsc # End of global-config-overlay From b7923485bdac90458321989eda261517afc4986e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2454/2612] global-config: use short url rsc.eworm.de --- global-config.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/global-config.rsc b/global-config.rsc index c8b2c2e..df26ef9 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -1,10 +1,10 @@ #!rsc by RouterOS # RouterOS script: global-config # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # global configuration -# https://git.eworm.de/cgit/routeros-scripts/about/ +# https://rsc.eworm.de/ # Set this to 'true' to disable news and change notifications. :global NoNewsAndChangesNotification false; @@ -238,7 +238,7 @@ # This project is developed in private spare time and usage is free of charge # for you. If you like the scripts and think this is of value for you or your # business please consider a donation: -# https://git.eworm.de/cgit/routeros-scripts/about/#donate +# https://rsc.eworm.de/#donate # Enable this to silence donation hint. :global IDonate false; From 7be415d0ed8238564608c47b251f21f25e6f1d43 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2455/2612] global-functions: use short url rsc.eworm.de --- global-functions.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index a2dd279..d5ac31c 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -2,12 +2,12 @@ # RouterOS script: global-functions # Copyright (c) 2013-2025 Christian Hesse # Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # global functions -# https://git.eworm.de/cgit/routeros-scripts/about/ +# https://rsc.eworm.de/ :local ScriptName [ :jobname ]; From 0431b02324877ae8585eb31effd789747f2aaf96 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2456/2612] global-wait: use short url rsc.eworm.de --- global-wait.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-wait.rsc b/global-wait.rsc index 529dbd7..bc98462 100644 --- a/global-wait.rsc +++ b/global-wait.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: global-wait # Copyright (c) 2020-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # wait for global-functions to finish -# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md +# https://rsc.eworm.de/doc/global-wait.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 72db13c0ab7bc2ba71400bb74976391d7a78e925 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2457/2612] gps-track: use short url rsc.eworm.de --- gps-track.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gps-track.rsc b/gps-track.rsc index 1bd976a..08873de 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: gps-track # Copyright (c) 2018-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # track gps data by sending json data to http server -# https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md +# https://rsc.eworm.de/doc/gps-track.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 996602bfe9f0363edae13c51604c23f46546ac49 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2458/2612] hotspot-to-wpa-cleanup: use short url rsc.eworm.de --- hotspot-to-wpa-cleanup.capsman.rsc | 4 ++-- hotspot-to-wpa-cleanup.template.rsc | 4 ++-- hotspot-to-wpa-cleanup.wifi.rsc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index 1d27faf..fde36f9 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa-cleanup.capsman # Copyright (c) 2021-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=80 # requires RouterOS, version=7.14 # # manage and clean up private WPA passphrase after hotspot login -# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# https://rsc.eworm.de/doc/hotspot-to-wpa.md # # !! Do not edit this file, it is generated from template! diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index f92dbe5..3ddcbe0 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa-cleanup%TEMPL% # Copyright (c) 2021-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=80 # requires RouterOS, version=7.14 # # manage and clean up private WPA passphrase after hotspot login -# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# https://rsc.eworm.de/doc/hotspot-to-wpa.md # # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index cd21593..034530b 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa-cleanup.wifi # Copyright (c) 2021-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=80 # requires RouterOS, version=7.14 # # manage and clean up private WPA passphrase after hotspot login -# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# https://rsc.eworm.de/doc/hotspot-to-wpa.md # # !! Do not edit this file, it is generated from template! From 9474102c62b4e9d36f908e40e14031da5a6fc116 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2459/2612] hotspot-to-wpa: use short url rsc.eworm.de --- hotspot-to-wpa.capsman.rsc | 4 ++-- hotspot-to-wpa.template.rsc | 4 ++-- hotspot-to-wpa.wifi.rsc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index d962ba7..1c77de9 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa.capsman # Copyright (c) 2019-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # add private WPA passphrase after hotspot login -# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# https://rsc.eworm.de/doc/hotspot-to-wpa.md # # !! Do not edit this file, it is generated from template! diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index 3438be7..d8cd261 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa%TEMPL% # Copyright (c) 2019-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # add private WPA passphrase after hotspot login -# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# https://rsc.eworm.de/doc/hotspot-to-wpa.md # # !! This is just a template to generate the real script! # !! Pattern '%TEMPL%' is replaced, paths are filtered. diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index a2bb3ca..345087d 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: hotspot-to-wpa.wifi # Copyright (c) 2019-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # add private WPA passphrase after hotspot login -# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# https://rsc.eworm.de/doc/hotspot-to-wpa.md # # !! Do not edit this file, it is generated from template! From 453d80a121f7e92602466490b77b7d47ba3ef251 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2460/2612] ip-addr-bridge: use short url rsc.eworm.de --- ip-addr-bridge.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ip-addr-bridge.rsc b/ip-addr-bridge.rsc index 00b45a3..68ff4a4 100644 --- a/ip-addr-bridge.rsc +++ b/ip-addr-bridge.rsc @@ -1,10 +1,10 @@ #!rsc by RouterOS # RouterOS script: ip-addr-bridge # Copyright (c) 2018-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # enable or disable ip addresses based on bridge port state -# https://git.eworm.de/cgit/routeros-scripts/about/doc/ip-addr-bridge.md +# https://rsc.eworm.de/doc/ip-addr-bridge.md :foreach Bridge in=[ /interface/bridge/find ] do={ :local BrName [ /interface/bridge/get $Bridge name ]; From 02cc581aff6c6a4191620450e5607c74aeaca203 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2461/2612] ipsec-to-dns: use short url rsc.eworm.de --- ipsec-to-dns.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index 39b21d5..1af5809 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: ipsec-to-dns # Copyright (c) 2021-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # and add/remove/update DNS entries from IPSec mode-config -# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipsec-to-dns.md +# https://rsc.eworm.de/doc/ipsec-to-dns.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 71316f7377987124858d74a9f5f741a133047dec Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2462/2612] ipv6-update: use short url rsc.eworm.de --- ipv6-update.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipv6-update.rsc b/ipv6-update.rsc index a2fb831..7eb625b 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: ipv6-update # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # update firewall and dns settings on IPv6 prefix change -# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md +# https://rsc.eworm.de/doc/ipv6-update.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 5ead61cb6269ab5f2e6c145a4736765d938f6305 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2463/2612] lease-script: use short url rsc.eworm.de --- lease-script.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lease-script.rsc b/lease-script.rsc index 3d0fc72..b6ceac9 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: lease-script # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # run scripts on DHCP lease -# https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md +# https://rsc.eworm.de/doc/lease-script.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 5e60d2e1b7d1973a18737042e94d3e0ba262db14 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2464/2612] leds-day-mode: use short url rsc.eworm.de --- leds-day-mode.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/leds-day-mode.rsc b/leds-day-mode.rsc index e0f08d6..7344fde 100644 --- a/leds-day-mode.rsc +++ b/leds-day-mode.rsc @@ -1,9 +1,9 @@ #!rsc by RouterOS # RouterOS script: leds-day-mode # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # enable LEDs -# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md +# https://rsc.eworm.de/doc/leds-mode.md /system/leds/settings/set all-leds-off=never; From bf11489d11058562a1a10b883dbdb1d06f8c1a8e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2465/2612] leds-night-mode: use short url rsc.eworm.de --- leds-night-mode.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/leds-night-mode.rsc b/leds-night-mode.rsc index 1f50dfd..8bd028e 100644 --- a/leds-night-mode.rsc +++ b/leds-night-mode.rsc @@ -1,9 +1,9 @@ #!rsc by RouterOS # RouterOS script: leds-night-mode # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # disable LEDs -# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md +# https://rsc.eworm.de/doc/leds-mode.md /system/leds/settings/set all-leds-off=immediate; From b75a35417a4dc0793515275bdee8443248f5762c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2466/2612] leds-toggle-mode: use short url rsc.eworm.de --- leds-toggle-mode.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/leds-toggle-mode.rsc b/leds-toggle-mode.rsc index 55d5b82..b55e351 100644 --- a/leds-toggle-mode.rsc +++ b/leds-toggle-mode.rsc @@ -1,9 +1,9 @@ #!rsc by RouterOS # RouterOS script: leds-toggle-mode # Copyright (c) 2018-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # toggle LEDs mode -# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md +# https://rsc.eworm.de/doc/leds-mode.md /system/leds/settings/set all-leds-off=(({ "never"="immediate"; "immediate"="never" })->[ get all-leds-off ]); From b8841a71356c6e25870913183d10ef9a8732a42d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2467/2612] log-forward: use short url rsc.eworm.de --- log-forward.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/log-forward.rsc b/log-forward.rsc index 8c2ebc0..379fa54 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: log-forward # Copyright (c) 2020-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # forward log messages via notification -# https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md +# https://rsc.eworm.de/doc/log-forward.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 6920842d1584a7c8b3a7208c1230a373d2932a8d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2468/2612] mod/bridge-port-to: use short url rsc.eworm.de --- mod/bridge-port-to.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/bridge-port-to.rsc b/mod/bridge-port-to.rsc index ec6f612..f00e10b 100644 --- a/mod/bridge-port-to.rsc +++ b/mod/bridge-port-to.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: mod/bridge-port-to # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # reset bridge ports to default bridge -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-to.md +# https://rsc.eworm.de/doc/mod/bridge-port-to.md :global BridgePortTo; From d5a50d824f0343a70e1945127b42dde719d761d2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2469/2612] mod/bridge-port-vlan: use short url rsc.eworm.de --- mod/bridge-port-vlan.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/bridge-port-vlan.rsc b/mod/bridge-port-vlan.rsc index 6221646..62e71e3 100644 --- a/mod/bridge-port-vlan.rsc +++ b/mod/bridge-port-vlan.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: mod/bridge-port-vlan # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # manage VLANs on bridge ports -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-vlan.md +# https://rsc.eworm.de/doc/mod/bridge-port-vlan.md :global BridgePortVlan; From 18fcecd21126b72c9ba1aef4375450bb8751feb3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2470/2612] mode-button: use short url rsc.eworm.de --- mode-button.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode-button.rsc b/mode-button.rsc index f8bd7b8..9339f1c 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: mode-button # Copyright (c) 2018-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # act on multiple mode and reset button presses -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md +# https://rsc.eworm.de/doc/mode-button.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 078d5368fbfa195d1e6584b3789cfb3078babad7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2471/2612] mod/inspectvar: use short url rsc.eworm.de --- mod/inspectvar.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/inspectvar.rsc b/mod/inspectvar.rsc index 01724bb..0f05da7 100644 --- a/mod/inspectvar.rsc +++ b/mod/inspectvar.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: mod/inspectvar # Copyright (c) 2020-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # inspect variables -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/inspectvar.md +# https://rsc.eworm.de/doc/mod/inspectvar.md :global InspectVar; :global InspectVarReturn; From 828f68be3c85a43e28884546f74dab3aca403eb9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2472/2612] mod/ipcalc: use short url rsc.eworm.de --- mod/ipcalc.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc index 69dec8b..fbed74b 100644 --- a/mod/ipcalc.rsc +++ b/mod/ipcalc.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: mod/ipcalc # Copyright (c) 2020-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # ip address calculation -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ipcalc.md +# https://rsc.eworm.de/doc/mod/ipcalc.md :global IPCalc; :global IPCalcReturn; From 631f63836b6b758c4ff3816ffdd5c76d95d31961 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2473/2612] mod/notification-email: use short url rsc.eworm.de --- mod/notification-email.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 6d700f5..ca23550 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: mod/notification-email # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # send notifications via e-mail -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-email.md +# https://rsc.eworm.de/doc/mod/notification-email.md :global EMailGenerateFrom; :global FlushEmailQueue; From 6567a94a4f4e263308a0b01663448179e6554821 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2474/2612] mod/notification-matrix: use short url rsc.eworm.de --- mod/notification-matrix.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index aad8b42..aee231d 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -2,12 +2,12 @@ # RouterOS script: mod/notification-matrix # Copyright (c) 2013-2025 Michael Gisbers # Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # send notifications via Matrix -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-matrix.md +# https://rsc.eworm.de/doc/mod/notification-matrix.md :global FlushMatrixQueue; :global NotificationFunctions; From 6e7f311269a1694dbc243eb60a363f1db4d89cd8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2475/2612] mod/notification-ntfy: use short url rsc.eworm.de --- mod/notification-ntfy.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index 53ba9b4..df252bb 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: mod/notification-ntfy # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # send notifications via Ntfy (ntfy.sh) -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-ntfy.md +# https://rsc.eworm.de/doc/mod/notification-ntfy.md :global FlushNtfyQueue; :global NotificationFunctions; From 27144a428a03241a7e67859bfa6acfc37e62f6dc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2476/2612] mod/notification-telegram: use short url rsc.eworm.de --- mod/notification-telegram.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index f9700cf..a20367c 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: mod/notification-telegram # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # send notifications via Telegram -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-telegram.md +# https://rsc.eworm.de/doc/mod/notification-telegram.md :global FlushTelegramQueue; :global NotificationFunctions; From 66ab2a85114165ca2b5f4f5a6e221eed4c560b45 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2477/2612] mod/scriptrunonce: use short url rsc.eworm.de --- mod/scriptrunonce.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index 7e01e72..cae2b05 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: mod/scriptrunonece # Copyright (c) 2020-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # download script and run it once -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/scriptrunonce.md +# https://rsc.eworm.de/doc/mod/scriptrunonce.md :global ScriptRunOnce; From ed184445783921343498f4f3589df858b2754cbd Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2478/2612] mod/ssh-keys-import: use short url rsc.eworm.de --- mod/ssh-keys-import.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index ad3a81e..35aa7ec 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: mod/ssh-keys-import # Copyright (c) 2020-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.16 # # import ssh keys for public key authentication -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ssh-keys-import.md +# https://rsc.eworm.de/doc/mod/ssh-keys-import.md :global SSHKeysImport; :global SSHKeysImportFile; From 299b34883ff508291dfa4acf04118695223c0cd3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2479/2612] netwatch-dns: use short url rsc.eworm.de --- netwatch-dns.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index 81f9d95..e05c3ac 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: netwatch-dns # Copyright (c) 2022-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.16 # # monitor and manage dns/doh with netwatch -# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-dns.md +# https://rsc.eworm.de/doc/netwatch-dns.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 563aeb8f71da109060961a16541f56c7dc019e2b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2480/2612] netwatch-notify: use short url rsc.eworm.de --- netwatch-notify.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index e79977e..8b05c5e 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: netwatch-notify # Copyright (c) 2020-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.15 # # monitor netwatch and send notifications -# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md +# https://rsc.eworm.de/doc/netwatch-notify.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 719079c5c1298a4800ac482247ee9ac5a9502740 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2481/2612] news-and-changes: use short url rsc.eworm.de --- news-and-changes.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 545a0c9..7508b43 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -1,6 +1,6 @@ # News, changes and migration by RouterOS Scripts # Copyright (c) 2019-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md :global IDonate; From 3b0ea3a2388c69914fa76204c6e940b60f6aee83 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2482/2612] ospf-to-leds: use short url rsc.eworm.de --- ospf-to-leds.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc index 3400e7f..9d822c1 100644 --- a/ospf-to-leds.rsc +++ b/ospf-to-leds.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: ospf-to-leds # Copyright (c) 2020-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # visualize ospf instance state via leds -# https://git.eworm.de/cgit/routeros-scripts/about/doc/ospf-to-leds.md +# https://rsc.eworm.de/doc/ospf-to-leds.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 90a148a9d86f069048974399feca29a7911e833d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2483/2612] packages-update: use short url rsc.eworm.de --- packages-update.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index 7644219..9971e47 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: packages-update # Copyright (c) 2019-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # download packages and reboot for installation -# https://git.eworm.de/cgit/routeros-scripts/about/doc/packages-update.md +# https://rsc.eworm.de/doc/packages-update.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 867e504c94faf9d87b8caa6e4d77cd5426af9f73 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2484/2612] ppp-on-up: use short url rsc.eworm.de --- ppp-on-up.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc index ba9d0aa..85e9689 100644 --- a/ppp-on-up.rsc +++ b/ppp-on-up.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: ppp-on-up # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # run scripts on ppp up -# https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md +# https://rsc.eworm.de/doc/ppp-on-up.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 1f5aea9fca6ecd5706cb29c8226109281333510d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2485/2612] sms-action: use short url rsc.eworm.de --- sms-action.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sms-action.rsc b/sms-action.rsc index f22a0bb..34d2127 100644 --- a/sms-action.rsc +++ b/sms-action.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: sms-action # Copyright (c) 2018-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # run action on received SMS -# https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-action.md +# https://rsc.eworm.de/doc/sms-action.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 7addf2e53a73e230aeac962c9b86a1f1f7e2ddd4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2486/2612] sms-forward: use short url rsc.eworm.de --- sms-forward.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sms-forward.rsc b/sms-forward.rsc index efebb75..654fd56 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -2,12 +2,12 @@ # RouterOS script: sms-forward # Copyright (c) 2013-2025 Christian Hesse # Anatoly Bubenkov -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # forward SMS to e-mail -# https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md +# https://rsc.eworm.de/doc/sms-forward.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From dd2854e983685ae39465c4375bbdb7b4d27956e8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2487/2612] super-mario-theme: use short url rsc.eworm.de --- super-mario-theme.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/super-mario-theme.rsc b/super-mario-theme.rsc index fc868c8..726c526 100644 --- a/super-mario-theme.rsc +++ b/super-mario-theme.rsc @@ -1,10 +1,10 @@ #!rsc by RouterOS # RouterOS script: super-mario-theme # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # play Super Mario theme -# https://git.eworm.de/cgit/routeros-scripts/about/doc/super-mario-theme.md +# https://rsc.eworm.de/doc/super-mario-theme.md :local Beeps { { 660; 100 }; 150; { 660; 100 }; 300; { 660; 100 }; 300; From e3ca37ad9a6f49ae5990e0fb4630d40e77153439 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:12 +0100 Subject: [PATCH 2488/2612] telegram-chat: use short url rsc.eworm.de --- telegram-chat.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index eebb617..dcdbefa 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: telegram-chat # Copyright (c) 2023-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.15 # # use Telegram to chat with your Router and send commands -# https://git.eworm.de/cgit/routeros-scripts/about/doc/telegram-chat.md +# https://rsc.eworm.de/doc/telegram-chat.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 32ac10e6efcd8967b998aef066220a75d4819e0c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2489/2612] unattended-lte-firmware-upgrade: use short url rsc.eworm.de --- unattended-lte-firmware-upgrade.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unattended-lte-firmware-upgrade.rsc b/unattended-lte-firmware-upgrade.rsc index ea18edf..c7df92f 100644 --- a/unattended-lte-firmware-upgrade.rsc +++ b/unattended-lte-firmware-upgrade.rsc @@ -1,12 +1,12 @@ #!rsc by RouterOS # RouterOS script: unattended-lte-firmware-upgrade # Copyright (c) 2018-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # schedule unattended lte firmware upgrade -# https://git.eworm.de/cgit/routeros-scripts/about/doc/unattended-lte-firmware-upgrade.md +# https://rsc.eworm.de/doc/unattended-lte-firmware-upgrade.md :foreach Interface in=[ /interface/lte/find where running ] do={ :local Firmware; From 49aef0606bb36ee1b0d2ed93e7ce6b63d38338da Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2490/2612] update-gre-address: use short url rsc.eworm.de --- update-gre-address.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/update-gre-address.rsc b/update-gre-address.rsc index 4ac311a..6b169a0 100644 --- a/update-gre-address.rsc +++ b/update-gre-address.rsc @@ -1,13 +1,13 @@ #!rsc by RouterOS # RouterOS script: update-gre-address # Copyright (c) 2013-2025 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 # # update gre interface remote address with dynamic address from # ipsec remote peer -# https://git.eworm.de/cgit/routeros-scripts/about/doc/update-gre-address.md +# https://rsc.eworm.de/doc/update-gre-address.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From c04ee5aadf4880bcea019f1cdcc1bfca918cce2c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Jan 2025 20:46:11 +0100 Subject: [PATCH 2491/2612] update-tunnelbroker: use short url rsc.eworm.de --- update-tunnelbroker.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index 589544c..c47a45f 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -2,13 +2,13 @@ # RouterOS script: update-tunnelbroker # Copyright (c) 2013-2025 Christian Hesse # Michael Gisbers -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# https://rsc.eworm.de/COPYING.md # # provides: ppp-on-up # requires RouterOS, version=7.14 # # update local address of tunnelbroker interface -# https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md +# https://rsc.eworm.de/doc/update-tunnelbroker.md :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } From 106a9bddefd7577b4baf7ae1d78e1bbde09b281e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 09:18:48 +0100 Subject: [PATCH 2492/2612] README: give hint on device mode --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 98209bd..8594f58 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,12 @@ Specific scripts may require even newer RouterOS version. > â„šī¸ **Info**: The `main` branch is now RouterOS v7 only. If you are still > running RouterOS v6 switch to `routeros-v6` branch! +Starting with RouterOS 7.17 the +[device-mode](https://help.mikrotik.com/docs/spaces/ROS/pages/93749258/Device-mode) +has been extended to give more fine-grained control over what features are +available. You need to enable `scheduler` and `fetch` at least, specific +scripts may require additional features. + ### Hardware RouterOS packages increase in size with each release. This becomes a From b177e298d7b447c41854d840eed6f687b6cec8b6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 09:45:25 +0100 Subject: [PATCH 2493/2612] global-functions: $ScriptInstallUpdate: support checking for device-mode features --- global-functions.rsc | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index d5ac31c..7d65f45 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -5,6 +5,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, fetch, scheduler # # global functions # https://rsc.eworm.de/ @@ -1071,6 +1072,7 @@ :local ExpectedConfigVersionBefore $ExpectedConfigVersion; :local ReloadGlobalFunctions false; :local ReloadGlobalConfig false; + :local DeviceMode [ /system/device-mode/get ]; :foreach Script in=[ /system/script/find where source~"^#!rsc by RouterOS\r?\n" ] do={ :local ScriptVal [ /system/script/get $Script ]; @@ -1113,19 +1115,31 @@ :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ :local Required ([ $ParseKeyValueStore [ $Grep $SourceNew ("\23 requires RouterOS, ") ] ]->"version"); :if ([ $RequiredRouterOS $0 [ $EitherOr $Required "0.0" ] false ] = true) do={ - :if ([ $ValidateSyntax $SourceNew ] = true) do={ - $LogPrint info $0 ("Updating script: " . $ScriptVal->"name"); - /system/script/set owner=($ScriptVal->"name") \ - source=[ $IfThenElse ($ScriptUpdatesCRLF = true) $SourceCRLF $SourceNew ] $Script; - :if ($ScriptVal->"name" = "global-config") do={ - :set ReloadGlobalConfig true; + :local RequiredDM [ $ParseKeyValueStore [ $Grep $SourceNew ("\23 requires device-mode, ") ] ]; + :local MissingDM ({}); + :foreach Feature,Value in=$RequiredDM do={ + :if ([ :typeof ($DeviceMode->$Feature) ] = "bool" && ($DeviceMode->$Feature) = false) do={ + :set MissingDM ($MissingDM, $Feature); } - :if ($ScriptVal->"name" = "global-functions" || $ScriptVal->"name" ~ ("^mod/.")) do={ - :set ReloadGlobalFunctions true; + } + :if ([ :len $MissingDM ] = 0) do={ + :if ([ $ValidateSyntax $SourceNew ] = true) do={ + $LogPrint info $0 ("Updating script: " . $ScriptVal->"name"); + /system/script/set owner=($ScriptVal->"name") \ + source=[ $IfThenElse ($ScriptUpdatesCRLF = true) $SourceCRLF $SourceNew ] $Script; + :if ($ScriptVal->"name" = "global-config") do={ + :set ReloadGlobalConfig true; + } + :if ($ScriptVal->"name" = "global-functions" || $ScriptVal->"name" ~ ("^mod/.")) do={ + :set ReloadGlobalFunctions true; + } + } else={ + $LogPrint warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . \ + "' failed! Ignoring!"); } } else={ - $LogPrint warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . \ - "' failed! Ignoring!"); + $LogPrintOnce warning $0 ("The script '" . $ScriptVal->"name" . "' requires disabled " . \ + "device-mode features (" . [ :tostr $MissingDM ] . "). Ignoring!"); } } else={ $LogPrintOnce warning $0 ("The script '" . $ScriptVal->"name" . "' requires RouterOS " . \ From aebc4e37da1a8e9ed1b343a83c7d60ac50fab9d5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:26:22 +0100 Subject: [PATCH 2494/2612] backup-partition: add dependencies on device-mode --- backup-partition.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/backup-partition.rsc b/backup-partition.rsc index b8bf7b1..bfa7765 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -5,6 +5,7 @@ # # provides: backup-script, order=70 # requires RouterOS, version=7.14 +# requires device-mode, scheduler # # save configuration to fallback partition # https://rsc.eworm.de/doc/backup-partition.md From d81a786e8288fea463c7188f1939c59713add31a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:20:26 +0100 Subject: [PATCH 2495/2612] backup-upload: add dependencies on device-mode --- backup-upload.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/backup-upload.rsc b/backup-upload.rsc index 011c502..dc5120f 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -5,6 +5,7 @@ # # provides: backup-script, order=50 # requires RouterOS, version=7.14 +# requires device-mode, fetch # # create and upload backup and config file # https://rsc.eworm.de/doc/backup-upload.md From 95b675f67ec9d7c5a9df01a54c1754834b02beee Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:21:12 +0100 Subject: [PATCH 2496/2612] check-certificates: add dependencies on device-mode --- check-certificates.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/check-certificates.rsc b/check-certificates.rsc index 02e3e52..4271e00 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, fetch # # check for certificate validity # https://rsc.eworm.de/doc/check-certificates.md From 43f6c0b975bb4db73131f78014ca3d59123bd4a6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:21:26 +0100 Subject: [PATCH 2497/2612] check-routeros-update: add dependencies on device-mode --- check-routeros-update.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 9486d6c..5c9b392 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, fetch, scheduler # # check for RouterOS update, send notification and/or install # https://rsc.eworm.de/doc/check-routeros-update.md From bc0227c49b99372ff46516e55175cf6ae1da31d3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:21:40 +0100 Subject: [PATCH 2498/2612] gps-track: add dependencies on device-mode --- gps-track.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/gps-track.rsc b/gps-track.rsc index 08873de..5e35f8d 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, fetch # # track gps data by sending json data to http server # https://rsc.eworm.de/doc/gps-track.md From e29ef31eb85e9b9001536ed1bb63a0b479cf4cad Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:35:31 +0100 Subject: [PATCH 2499/2612] hotspot-to-wpa: add dependencies on device-mode --- hotspot-to-wpa.capsman.rsc | 1 + hotspot-to-wpa.template.rsc | 1 + hotspot-to-wpa.wifi.rsc | 1 + 3 files changed, 3 insertions(+) diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index 1c77de9..de9f9d9 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, hotspot # # add private WPA passphrase after hotspot login # https://rsc.eworm.de/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index d8cd261..003b12e 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, hotspot # # add private WPA passphrase after hotspot login # https://rsc.eworm.de/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index 345087d..0d6a7b9 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, hotspot # # add private WPA passphrase after hotspot login # https://rsc.eworm.de/doc/hotspot-to-wpa.md From 1ad4d05be8a69490902308baa515b8c87095bb2d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:35:23 +0100 Subject: [PATCH 2500/2612] hotspot-to-wpa-cleanup: add dependencies on device-mode --- hotspot-to-wpa-cleanup.capsman.rsc | 1 + hotspot-to-wpa-cleanup.template.rsc | 1 + hotspot-to-wpa-cleanup.wifi.rsc | 1 + 3 files changed, 3 insertions(+) diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index fde36f9..c21ec3e 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -5,6 +5,7 @@ # # provides: lease-script, order=80 # requires RouterOS, version=7.14 +# requires device-mode, hotspot # # manage and clean up private WPA passphrase after hotspot login # https://rsc.eworm.de/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 3ddcbe0..1bd877e 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -5,6 +5,7 @@ # # provides: lease-script, order=80 # requires RouterOS, version=7.14 +# requires device-mode, hotspot # # manage and clean up private WPA passphrase after hotspot login # https://rsc.eworm.de/doc/hotspot-to-wpa.md diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index 034530b..8e36204 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -5,6 +5,7 @@ # # provides: lease-script, order=80 # requires RouterOS, version=7.14 +# requires device-mode, hotspot # # manage and clean up private WPA passphrase after hotspot login # https://rsc.eworm.de/doc/hotspot-to-wpa.md From 5f1cbe6de5466ccaaf1b5eb29f7087f04cf342c3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:25:15 +0100 Subject: [PATCH 2501/2612] ipsec-to-dns: add dependencies on device-mode --- ipsec-to-dns.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index 1af5809..91f6b45 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, ipsec # # and add/remove/update DNS entries from IPSec mode-config # https://rsc.eworm.de/doc/ipsec-to-dns.md From 56e74268b079fba7bda8803c0d88eeb67d0f4397 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:31:30 +0100 Subject: [PATCH 2502/2612] mode-button: add dependencies on device-mode --- mode-button.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/mode-button.rsc b/mode-button.rsc index 9339f1c..4cf5e75 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, scheduler # # act on multiple mode and reset button presses # https://rsc.eworm.de/doc/mode-button.md From 370e81321fe485a94560b4debe2ce7044c99e86f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:15:49 +0100 Subject: [PATCH 2503/2612] mod/notification-email: add dependencies on device-mode --- mod/notification-email.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index ca23550..404e74d 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, email, scheduler # # send notifications via e-mail # https://rsc.eworm.de/doc/mod/notification-email.md From 9a12934202c1bf8f46b326b37e7b06d84609c4ce Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:21:57 +0100 Subject: [PATCH 2504/2612] mod/notification-matrix: add dependencies on device-mode --- mod/notification-matrix.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index aee231d..9b2b641 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -5,6 +5,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, fetch, scheduler # # send notifications via Matrix # https://rsc.eworm.de/doc/mod/notification-matrix.md From 9f2f54b4790659189c60e72918cc200625c22d25 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:22:08 +0100 Subject: [PATCH 2505/2612] mod/notification-ntfy: add dependencies on device-mode --- mod/notification-ntfy.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index df252bb..212fde2 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, fetch, scheduler # # send notifications via Ntfy (ntfy.sh) # https://rsc.eworm.de/doc/mod/notification-ntfy.md From 378a8978dfb86f1f690732cc0e513330282bcd98 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:22:22 +0100 Subject: [PATCH 2506/2612] mod/notification-telegram: add dependencies on device-mode --- mod/notification-telegram.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index a20367c..c3ef2dd 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, fetch, scheduler # # send notifications via Telegram # https://rsc.eworm.de/doc/mod/notification-telegram.md From 59c9d0ce4bf97407a5f35d8556ecc9f4f03ca752 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:22:43 +0100 Subject: [PATCH 2507/2612] mod/scriptrunonce: add dependencies on device-mode --- mod/scriptrunonce.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index cae2b05..e5368c4 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, fetch # # download script and run it once # https://rsc.eworm.de/doc/mod/scriptrunonce.md From 3ef458860153ab858eec70e0899efa91a84236d4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:22:55 +0100 Subject: [PATCH 2508/2612] netwatch-dns: add dependencies on device-mode --- netwatch-dns.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc index e05c3ac..467d636 100644 --- a/netwatch-dns.rsc +++ b/netwatch-dns.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.16 +# requires device-mode, fetch # # monitor and manage dns/doh with netwatch # https://rsc.eworm.de/doc/netwatch-dns.md From 8dc1e1ea6bdb815de28823dfa43d1cfeda67379f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:32:17 +0100 Subject: [PATCH 2509/2612] packages-update: add dependencies on device-mode --- packages-update.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/packages-update.rsc b/packages-update.rsc index 9971e47..ff47b2a 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, scheduler # # download packages and reboot for installation # https://rsc.eworm.de/doc/packages-update.md From ef48b8d39ebacf2bd1c560c6dea33399a9a47b47 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:23:58 +0100 Subject: [PATCH 2510/2612] telegram-chat: add dependencies on device-mode --- telegram-chat.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index dcdbefa..8f29d8c 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.15 +# requires device-mode, fetch # # use Telegram to chat with your Router and send commands # https://rsc.eworm.de/doc/telegram-chat.md From 9421566352041654e1f2ded815739b040eec1df4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:28:40 +0100 Subject: [PATCH 2511/2612] unattended-lte-firmware-upgrade: add dependencies on device-mode --- unattended-lte-firmware-upgrade.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/unattended-lte-firmware-upgrade.rsc b/unattended-lte-firmware-upgrade.rsc index c7df92f..74495d1 100644 --- a/unattended-lte-firmware-upgrade.rsc +++ b/unattended-lte-firmware-upgrade.rsc @@ -4,6 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.14 +# requires device-mode, scheduler # # schedule unattended lte firmware upgrade # https://rsc.eworm.de/doc/unattended-lte-firmware-upgrade.md From d921af9a6bda54da74f6b7520db1a8e5697c8c3e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 10:23:06 +0100 Subject: [PATCH 2512/2612] update-tunnelbroker: add dependencies on device-mode --- update-tunnelbroker.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index c47a45f..a58589b 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -6,6 +6,7 @@ # # provides: ppp-on-up # requires RouterOS, version=7.14 +# requires device-mode, fetch # # update local address of tunnelbroker interface # https://rsc.eworm.de/doc/update-tunnelbroker.md From 8b19e74736693483faf533fd22fce458ae4fac9e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 21:58:47 +0100 Subject: [PATCH 2513/2612] global-functions: $ScriptInstallUpdate: resolve nested conditions... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... and check one after another in a do-block. This uses `:error` as poor man's continue. đŸ¤Ē --- global-functions.rsc | 97 ++++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 45 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 7d65f45..befe8f0 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1109,52 +1109,59 @@ } } - :if ([ :len $SourceNew ] > 0) do={ - :local SourceCRLF [ :tocrlf $SourceNew ]; - :if ($SourceNew != $ScriptVal->"source" && $SourceCRLF != $ScriptVal->"source") do={ - :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ - :local Required ([ $ParseKeyValueStore [ $Grep $SourceNew ("\23 requires RouterOS, ") ] ]->"version"); - :if ([ $RequiredRouterOS $0 [ $EitherOr $Required "0.0" ] false ] = true) do={ - :local RequiredDM [ $ParseKeyValueStore [ $Grep $SourceNew ("\23 requires device-mode, ") ] ]; - :local MissingDM ({}); - :foreach Feature,Value in=$RequiredDM do={ - :if ([ :typeof ($DeviceMode->$Feature) ] = "bool" && ($DeviceMode->$Feature) = false) do={ - :set MissingDM ($MissingDM, $Feature); - } - } - :if ([ :len $MissingDM ] = 0) do={ - :if ([ $ValidateSyntax $SourceNew ] = true) do={ - $LogPrint info $0 ("Updating script: " . $ScriptVal->"name"); - /system/script/set owner=($ScriptVal->"name") \ - source=[ $IfThenElse ($ScriptUpdatesCRLF = true) $SourceCRLF $SourceNew ] $Script; - :if ($ScriptVal->"name" = "global-config") do={ - :set ReloadGlobalConfig true; - } - :if ($ScriptVal->"name" = "global-functions" || $ScriptVal->"name" ~ ("^mod/.")) do={ - :set ReloadGlobalFunctions true; - } - } else={ - $LogPrint warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . \ - "' failed! Ignoring!"); - } - } else={ - $LogPrintOnce warning $0 ("The script '" . $ScriptVal->"name" . "' requires disabled " . \ - "device-mode features (" . [ :tostr $MissingDM ] . "). Ignoring!"); - } - } else={ - $LogPrintOnce warning $0 ("The script '" . $ScriptVal->"name" . "' requires RouterOS " . \ - $Required . ", which is not met by your installation. Ignoring!"); - } - } else={ - $LogPrint warning $0 ("Looks like new script '" . $ScriptVal->"name" . \ - "' is not valid (missing shebang). Ignoring!"); - } - } else={ - $LogPrint debug $0 ("Script '" . $ScriptVal->"name" . "' did not change."); + :do { + :if ([ :len $SourceNew ] = 0) do={ + $LogPrint debug $0 ("No update for script '" . $ScriptVal->"name" . "'."); + :error false; } - } else={ - $LogPrint debug $0 ("No update for script '" . $ScriptVal->"name" . "'."); - } + + :local SourceCRLF [ :tocrlf $SourceNew ]; + :if ($SourceNew = $ScriptVal->"source" || $SourceCRLF = $ScriptVal->"source") do={ + $LogPrint debug $0 ("Script '" . $ScriptVal->"name" . "' did not change."); + :error false; + } + + :if ([ :pick $SourceNew 0 18 ] != "#!rsc by RouterOS\n") do={ + $LogPrint warning $0 ("Looks like new script '" . $ScriptVal->"name" . \ + "' is not valid (missing shebang). Ignoring!"); + :error false; + } + + :local RequiredROS ([ $ParseKeyValueStore [ $Grep $SourceNew ("\23 requires RouterOS, ") ] ]->"version"); + :if ([ $RequiredRouterOS $0 [ $EitherOr $RequiredROS "0.0" ] false ] = false) do={ + $LogPrintOnce warning $0 ("The script '" . $ScriptVal->"name" . "' requires RouterOS " . \ + $RequiredROS . ", which is not met by your installation. Ignoring!"); + :error false; + } + + :local RequiredDM [ $ParseKeyValueStore [ $Grep $SourceNew ("\23 requires device-mode, ") ] ]; + :local MissingDM ({}); + :foreach Feature,Value in=$RequiredDM do={ + :if ([ :typeof ($DeviceMode->$Feature) ] = "bool" && ($DeviceMode->$Feature) = false) do={ + :set MissingDM ($MissingDM, $Feature); + } + } + :if ([ :len $MissingDM ] > 0) do={ + $LogPrintOnce warning $0 ("The script '" . $ScriptVal->"name" . "' requires disabled " . \ + "device-mode features (" . [ :tostr $MissingDM ] . "). Ignoring!"); + :error false; + } + + :if ([ $ValidateSyntax $SourceNew ] = false) do={ + $LogPrint warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . "' failed! Ignoring!"); + :error false; + } + + $LogPrint info $0 ("Updating script: " . $ScriptVal->"name"); + /system/script/set owner=($ScriptVal->"name") \ + source=[ $IfThenElse ($ScriptUpdatesCRLF = true) $SourceCRLF $SourceNew ] $Script; + :if ($ScriptVal->"name" = "global-config") do={ + :set ReloadGlobalConfig true; + } + :if ($ScriptVal->"name" = "global-functions" || $ScriptVal->"name" ~ ("^mod/.")) do={ + :set ReloadGlobalFunctions true; + } + } on-error={ } } :if ($ReloadGlobalFunctions = true) do={ From 414c83ef814af82d53f5b4de3a8d6b5a004704c1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 29 Jan 2025 22:07:06 +0100 Subject: [PATCH 2514/2612] global-functions: $ScriptInstallUpdate: resolve more nested conditions Just like the previous one. --- global-functions.rsc | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index befe8f0..a2ec833 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1221,18 +1221,24 @@ :if ([ :len $GlobalConfigMigration ] > 0) do={ :for I from=($ExpectedConfigVersionBefore + 1) to=$ExpectedConfigVersion do={ :local Migration ($GlobalConfigMigration->[ :tostr $I ]); - :if ([ :typeof $Migration ] = "str") do={ - :if ([ $ValidateSyntax $Migration ] = true) do={ - $LogPrint info $0 ("Applying migration for change " . $I . ": " . $Migration); - :do { - [ :parse $Migration ]; - } on-error={ - $LogPrint warning $0 ("Migration code for change " . $I . " failed to run!"); - } - } else={ - $LogPrint warning $0 ("Migration code for change " . $I . " failed syntax validation!"); + :do { + :if ([ :typeof $Migration ] != "str") do={ + $LogPrint debug $0 ("Migration code for change " . $I . " is not available."); + :error false; } - } + + :if ([ $ValidateSyntax $Migration ] = false) do={ + $LogPrint warning $0 ("Migration code for change " . $I . " failed syntax validation!"); + :error false; + } + + $LogPrint info $0 ("Applying migration for change " . $I . ": " . $Migration); + :do { + [ :parse $Migration ]; + } on-error={ + $LogPrint warning $0 ("Migration code for change " . $I . " failed to run!"); + } + } on-error={ } } } From aa294b4c67d038eae1b4e785dfd934176a1fb704 Mon Sep 17 00:00:00 2001 From: Miquel Bonastre Date: Thu, 30 Jan 2025 20:27:14 +0100 Subject: [PATCH 2515/2612] certs: fix curl false positives... ... when default capath contains system certs If curl has a default capath (debian 12 capath=/etc/ssl/certs) it will add those certs and return ok to any valid https url, defeating the intended use of the cacert option in the Makefile that validates sites and certs. To avoid that, adding option "--capath /dev/null" overrides the default value, if any. Closes: https://github.com/eworm-de/routeros-scripts/pull/88 --- certs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certs/Makefile b/certs/Makefile index 870cb54..b5f6a92 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -29,4 +29,4 @@ DOMAINS = \ all: $(DOMAINS) $(DOMAINS): - curl --output /dev/null --silent --connect-timeout 5 --cacert $(notdir $@).pem https://$(dir $@) + curl --output /dev/null --silent --connect-timeout 5 --capath /dev/null --cacert $(notdir $@).pem https://$(dir $@) From fcb5347e3398dd8c77c44904a4bf0cefc57f3174 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 30 Jan 2025 22:16:49 +0100 Subject: [PATCH 2516/2612] certs: split checks for dual, ipv4 & ipv6... ... and check both if available. --- certs/Makefile | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/certs/Makefile b/certs/Makefile index b5f6a92..87b4feb 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -1,32 +1,52 @@ # Makefile to check certificates -DOMAINS = \ - 1.1.1.1/DigiCert-Global-Root-G2 \ - 8.8.8.8/GTS-Root-R1 \ - 9.9.9.9/DigiCert-Global-Root-G3 \ +CURL = curl \ + --capath /dev/null \ + --connect-timeout 5 \ + --output /dev/null \ + --silent + +DOMAINS_DUAL = \ api.macvendors.com/GTS-Root-R4 \ - api.mullvad.net/ISRG-Root-X1 \ api.telegram.org/Go-Daddy-Root-Certificate-Authority-G2 \ cloudflare-dns.com/DigiCert-Global-Root-G2 \ dns.google/GTS-Root-R1 \ dns.quad9.net/DigiCert-Global-Root-G3 \ - feodotracker.abuse.ch/GlobalSign \ git.eworm.de/ISRG-Root-X2 \ - ipv4.showipv6.de/ISRG-Root-X1 \ - ipv4.tunnelbroker.net/Starfield-Root-Certificate-Authority-G2 \ - ipv6.showipv6.de/ISRG-Root-X1 \ lists.blocklist.de/Certum-Trusted-Network-CA \ matrix.org/GTS-Root-R4 \ + raw.githubusercontent.com/DigiCert-Global-Root-G2 \ + rsc.eworm.de/ISRG-Root-X2 \ + upgrade.mikrotik.com/ISRG-Root-X1 +DOMAINS_IPV4 = \ + 1.1.1.1/DigiCert-Global-Root-G2 \ + 8.8.8.8/GTS-Root-R1 \ + 9.9.9.9/DigiCert-Global-Root-G3 \ + api.mullvad.net/ISRG-Root-X1 \ + feodotracker.abuse.ch/GlobalSign \ + ipv4.showipv6.de/ISRG-Root-X1 \ + ipv4.tunnelbroker.net/Starfield-Root-Certificate-Authority-G2 \ mkcert.org/ISRG-Root-X1 \ ntfy.sh/ISRG-Root-X1 \ sslbl.abuse.ch/GlobalSign \ - upgrade.mikrotik.com/ISRG-Root-X1 \ www.dshield.org/ISRG-Root-X1 \ www.spamhaus.org/GTS-Root-R4 +DOMAINS_IPV6 = \ + [2606\:4700\:4700\:\:1111]/DigiCert-Global-Root-G2 \ + [2001\:4860\:4860\:\:8888]/GTS-Root-R1 \ + [2620\:fe\:\:9]/DigiCert-Global-Root-G3 \ + ipv6.showipv6.de/ISRG-Root-X1 -.PHONY: $(DOMAINS) +.PHONY: $(DOMAINS_DUAL) $(DOMAINS_IPV4) $(DOMAINS_IPV6) -all: $(DOMAINS) +all: $(DOMAINS_DUAL) $(DOMAINS_IPV4) $(DOMAINS_IPV6) -$(DOMAINS): - curl --output /dev/null --silent --connect-timeout 5 --capath /dev/null --cacert $(notdir $@).pem https://$(dir $@) +$(DOMAINS_DUAL): + $(CURL) -4 --cacert $(notdir $@).pem https://$(dir $@) + $(CURL) -6 --cacert $(notdir $@).pem https://$(dir $@) + +$(DOMAINS_IPV4): + $(CURL) -4 --cacert $(notdir $@).pem https://$(dir $@) + +$(DOMAINS_IPV6): + $(CURL) -6 --cacert $(notdir $@).pem https://$(dir $@) From 87fb70534f8d86509505185f787118c64b3924ba Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 30 Jan 2025 22:25:55 +0100 Subject: [PATCH 2517/2612] certs: support checking ipv4 or ipv6 only Just run for IPv4 only: make NOIPV6=1 ... or for IPv6 only: make NOIPV4=1 --- certs/Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/certs/Makefile b/certs/Makefile index 87b4feb..5dfb0d1 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -42,11 +42,19 @@ DOMAINS_IPV6 = \ all: $(DOMAINS_DUAL) $(DOMAINS_IPV4) $(DOMAINS_IPV6) $(DOMAINS_DUAL): +ifndef NOIPV4 $(CURL) -4 --cacert $(notdir $@).pem https://$(dir $@) +endif +ifndef NOIPV6 $(CURL) -6 --cacert $(notdir $@).pem https://$(dir $@) +endif $(DOMAINS_IPV4): +ifndef NOIPV4 $(CURL) -4 --cacert $(notdir $@).pem https://$(dir $@) +endif $(DOMAINS_IPV6): +ifndef NOIPV6 $(CURL) -6 --cacert $(notdir $@).pem https://$(dir $@) +endif From 0eb91b6bfa8e22f24f0be8052ae2b93c0114ae59 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 30 Jan 2025 22:30:57 +0100 Subject: [PATCH 2518/2612] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index ed1d6fa..ef1bd8b 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -22,6 +22,7 @@ for details! * [Daniel Ziegenberg](mailto:daniel@ziegenberg.at) (@ziegenberg) * [Ignacio Serrano](mailto:ignic@ignic.com) (@ignic) * [Michael Gisbers](mailto:michael@gisbers.de) (@mgisbers) +* [Miquel Bonastre](mailto:mbonastre@yahoo.com) (@mbonastre) * @netravnen * [netztrip](mailto:dave-tvg@netztrip.de) (@netztrip) * [Stefan MÃŧller](mailto:stefan.mueller.83@gmail.com) (@PackElend) From 44d0c852f11cce04139a25613822f103e39e06b1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 31 Jan 2025 11:39:51 +0100 Subject: [PATCH 2519/2612] check-certificates: try with "star." for renewal with wildcards --- check-certificates.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/check-certificates.rsc b/check-certificates.rsc index 4271e00..a61cf81 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -158,6 +158,10 @@ :if ($ImportSuccess = false) do={ :set LastName [ :pick $SAN ([ :find $SAN ":" ] + 1) [ :len $SAN ] ]; :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName ]; + :if ($ImportSuccess = false && [ :pick $LastName 0 ] = "*") do={ + :set LastName ("star." . [ :pick $LastName 2 [ :len $LastName ] ]); + :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName ]; + } } } :if ($ImportSuccess = false) do={ :error false; } From 75e5ddec527ac505540306ca5b26b7c40cdb1b5d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 31 Jan 2025 13:09:22 +0100 Subject: [PATCH 2520/2612] check-certificates: do not rename the wrong certificate --- check-certificates.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index a61cf81..2900a83 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -68,8 +68,10 @@ $LogPrint warning $ScriptName ("Decryption failed for certificate file '" . $CertFileName . "'."); } - :foreach CertInChain in=[ /certificate/find where name~("^" . [ $EscapeForRegEx $CertFileName ] . "_[0-9]+\$") \ - common-name!=$Name !(subject-alt-name~("(^|\\W)(DNS|IP):" . [ $EscapeForRegEx $Name ] . "(\\W|\$)")) !(common-name=[]) ] do={ + :foreach CertInChain in=[ /certificate/find where common-name!=$Name !private-key \ + name~("^" . [ $EscapeForRegEx $CertFileName ] . "_[0-9]+\$") \ + !(subject-alt-name~("(^|\\W)(DNS|IP):" . [ $EscapeForRegEx $Name ] . "(\\W|\$)")) \ + !(common-name=[]) ] do={ $CertificateNameByCN [ /certificate/get $CertInChain common-name ]; } From eabe3f6e951010ff9c112d82ee27bc39e3786960 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 31 Jan 2025 21:33:57 +0100 Subject: [PATCH 2521/2612] check-certificates: pass real and modified name into function --- check-certificates.rsc | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 2900a83..b986179 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -34,7 +34,8 @@ :local CheckCertificatesDownloadImport do={ :local ScriptName [ :tostr $1 ]; - :local Name [ :tostr $2 ]; + :local CertName [ :tostr $2 ]; + :local FetchName [ :tostr $3 ]; :global CertRenewUrl; :global CertRenewPass; @@ -49,7 +50,7 @@ :local Return false; :foreach Type in={ ".pem"; ".p12" } do={ - :local CertFileName ([ $UrlEncode $Name ] . $Type); + :local CertFileName ([ $UrlEncode $FetchName ] . $Type); :do { /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) \ ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; @@ -68,9 +69,9 @@ $LogPrint warning $ScriptName ("Decryption failed for certificate file '" . $CertFileName . "'."); } - :foreach CertInChain in=[ /certificate/find where common-name!=$Name !private-key \ + :foreach CertInChain in=[ /certificate/find where common-name!=$CertName !private-key \ name~("^" . [ $EscapeForRegEx $CertFileName ] . "_[0-9]+\$") \ - !(subject-alt-name~("(^|\\W)(DNS|IP):" . [ $EscapeForRegEx $Name ] . "(\\W|\$)")) \ + !(subject-alt-name~("(^|\\W)(DNS|IP):" . [ $EscapeForRegEx $CertName ] . "(\\W|\$)")) \ !(common-name=[]) ] do={ $CertificateNameByCN [ /certificate/get $CertInChain common-name ]; } @@ -145,6 +146,7 @@ :foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ :local CertVal [ /certificate/get $Cert ]; :local LastName; + :local FetchName; :do { :if ([ :len $CertRenewUrl ] = 0) do={ @@ -155,14 +157,16 @@ :local ImportSuccess false; :set LastName ($CertVal->"common-name"); - :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName ]; + :set FetchName $LastName; + :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName $FetchName ]; :foreach SAN in=($CertVal->"subject-alt-name") do={ :if ($ImportSuccess = false) do={ :set LastName [ :pick $SAN ([ :find $SAN ":" ] + 1) [ :len $SAN ] ]; - :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName ]; + :set FetchName $LastName; + :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName $FetchName ]; :if ($ImportSuccess = false && [ :pick $LastName 0 ] = "*") do={ - :set LastName ("star." . [ :pick $LastName 2 [ :len $LastName ] ]); - :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName ]; + :set FetchName ("star." . [ :pick $LastName 2 [ :len $LastName ] ]); + :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName $FetchName ]; } } } @@ -174,7 +178,7 @@ } else={ $LogPrint debug $ScriptName ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced."); - :local CertNew [ /certificate/find where name~("^" . [ $EscapeForRegEx [ $UrlEncode $LastName ] ] . "\\.(p12|pem)_[0-9]+\$") \ + :local CertNew [ /certificate/find where name~("^" . [ $EscapeForRegEx [ $UrlEncode $FetchName ] ] . "\\.(p12|pem)_[0-9]+\$") \ (common-name=($CertVal->"common-name") or subject-alt-name~("(^|\\W)(DNS|IP):" . [ $EscapeForRegEx $LastName ] . "(\\W|\$)")) \ fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ]; :local CertNewVal [ /certificate/get $CertNew ]; From 3ad7ccd3d6c443bf64156ffcd980a418584c35d1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 3 Feb 2025 10:05:35 +0100 Subject: [PATCH 2522/2612] check-certificates: check to characters for star-dot --- check-certificates.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index b986179..34e7537 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -164,7 +164,7 @@ :set LastName [ :pick $SAN ([ :find $SAN ":" ] + 1) [ :len $SAN ] ]; :set FetchName $LastName; :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName $FetchName ]; - :if ($ImportSuccess = false && [ :pick $LastName 0 ] = "*") do={ + :if ($ImportSuccess = false && [ :pick $LastName 0 2 ] = "*.") do={ :set FetchName ("star." . [ :pick $LastName 2 [ :len $LastName ] ]); :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName $FetchName ]; } From 61f3c26199b4c22ae312a09f6c82f8e9cc403dd0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 3 Feb 2025 14:35:47 +0100 Subject: [PATCH 2523/2612] doc/check-health: highligh note on bad initial state --- doc/check-health.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/check-health.md b/doc/check-health.md index 578ea43..a945371 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -26,14 +26,16 @@ health related events: * power supply failed or recovered * temperature is above or below threshold -Note that bad initial state will not trigger an event. - Monitoring CPU and RAM utilization (available processing and memory resources) works on all devices. Other than that only sensors available in hardware can be checked. See what your hardware supports: /system/health/print; +> âš ī¸ **Warning**: Note that bad initial state will not trigger an event! For +> example rebooting a device that is already too hot will not trigger an +> alert on high temperature. + ### Sample notifications #### CPU utilization From 3024b246b58fa106592c7f6f949e421e15edcdb3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 4 Feb 2025 12:02:31 +0100 Subject: [PATCH 2524/2612] check-health: remove extra line break --- check-health.rsc | 1 - 1 file changed, 1 deletion(-) diff --git a/check-health.rsc b/check-health.rsc index 31bd6c2..76de4cb 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -91,7 +91,6 @@ :set CheckHealthTemperatureNotified ({}); } - :foreach Voltage in=[ /system/health/find where type="V" ] do={ :local Name [ /system/health/get $Voltage name ]; :local Value [ /system/health/get $Voltage value ]; From bfe5f20920a90fc54b7b25a238a1763fa6f2d5e7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 4 Feb 2025 15:08:37 +0100 Subject: [PATCH 2525/2612] check-health: remove trailing whitespaces --- check-health.rsc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/check-health.rsc b/check-health.rsc index 76de4cb..34c508c 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -107,16 +107,16 @@ message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ [ $FormatLine "old value" ($CheckHealthLast->$Name . " V") 12 ] . "\n" . \ [ $FormatLine "new value" ($Value . " V") 12 ]) }); - } else={ - :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \ - message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") }); - } - :if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ - message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") }); + } else={ + :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \ + message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") }); + } + :if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ + message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") }); } } } From 6501c98c822af958588512c374474f16bac61493 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Feb 2025 09:36:15 +0100 Subject: [PATCH 2526/2612] certs: dns.google switched to 'GTS Root R4' Note that 8.8.8.8 is still at 'GTS Root R1'... --- certs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certs/Makefile b/certs/Makefile index 5dfb0d1..ba25303 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -10,7 +10,7 @@ DOMAINS_DUAL = \ api.macvendors.com/GTS-Root-R4 \ api.telegram.org/Go-Daddy-Root-Certificate-Authority-G2 \ cloudflare-dns.com/DigiCert-Global-Root-G2 \ - dns.google/GTS-Root-R1 \ + dns.google/GTS-Root-R4 \ dns.quad9.net/DigiCert-Global-Root-G3 \ git.eworm.de/ISRG-Root-X2 \ lists.blocklist.de/Certum-Trusted-Network-CA \ From 27c92b4382f961ad427313f6a0bfc01716e805d1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Feb 2025 09:51:42 +0100 Subject: [PATCH 2527/2612] doc/netwatch-dns: switch exmample to cloudflare-dns.com --- doc/netwatch-dns.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index 6d2c865..aa4e91f 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -53,8 +53,8 @@ Note that using a name in DoH url may introduce a chicken-and-egg issue! Adding a static DNS record has the same result for the url, but always resolves to the same address. - /ip/dns/static/add name="dns.nextdns.io" address=199.247.16.158; - /tool/netwatch/add comment="doh" host=199.247.16.158; + /ip/dns/static/add name="cloudflare-dns.com" address=1.1.1.1; + /tool/netwatch/add comment="doh" host=1.1.1.1; Be aware that you have to keep the ip address in sync with real world manually! From 84ba3a463a46876f3e728326034d404d02aefb67 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Feb 2025 09:55:41 +0100 Subject: [PATCH 2528/2612] doc/netwatch-dns: warn on different certificate... ... based on indicated server name. Currently this is true for 8.8.8.8 (GTS Root R1) and dns.google (GTS Root R4). --- doc/netwatch-dns.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md index aa4e91f..0d94918 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -66,6 +66,10 @@ Importing a certificate automatically is possible. You may want to find the /tool/netwatch/add comment="doh, doh-cert=DigiCert Global Root G3" host=9.9.9.9; /tool/netwatch/add comment="doh, doh-cert=GTS Root R1" host=8.8.8.8; +> âš ī¸ **Warning**: Combining these techniques can cause some confusion and +> troubles! Chances are that a service uses different certificates based +> on indicated server name. + Sometimes using just one specific (possibly internal) DNS server may be desired, with fallback in case it fails. This is possible as well: From 23d38927bcd553229d1cd80bff0d3506ab40f6fa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 4 Feb 2025 12:27:35 +0100 Subject: [PATCH 2529/2612] check-health: split off plugins... ... from 'check-health', so the script works on all devices to monitor CPU and RAM. The supported plugins for sensors in hardware are installed automatically. --- check-health.d/state.rsc | 48 ++++++++ check-health.d/temperature.rsc | 74 ++++++++++++ check-health.d/voltage.rsc | 63 ++++++++++ check-health.rsc | 108 +++--------------- ...l.avif => notification-08-state-fail.avif} | Bin ...-ok.avif => notification-09-state-ok.avif} | Bin doc/check-health.md | 42 +++++-- global-functions.rsc | 2 +- news-and-changes.rsc | 2 + 9 files changed, 239 insertions(+), 100 deletions(-) create mode 100644 check-health.d/state.rsc create mode 100644 check-health.d/temperature.rsc create mode 100644 check-health.d/voltage.rsc rename doc/check-health.d/{notification-08-psu-fail.avif => notification-08-state-fail.avif} (100%) rename doc/check-health.d/{notification-09-psu-ok.avif => notification-09-state-ok.avif} (100%) diff --git a/check-health.d/state.rsc b/check-health.d/state.rsc new file mode 100644 index 0000000..bcc1fbc --- /dev/null +++ b/check-health.d/state.rsc @@ -0,0 +1,48 @@ +#!rsc by RouterOS +# RouterOS script: check-health.d/state +# Copyright (c) 2019-2025 Christian Hesse +# https://rsc.eworm.de/COPYING.md +# +# requires RouterOS, version=7.14 +# +# check for RouterOS health state - state plugin +# https://rsc.eworm.de/doc/check-health.md + +:global CheckHealthPlugins; + +:set ($CheckHealthPlugins->[ :jobname ]) do={ + :local FuncName [ :tostr $0 ]; + + :global CheckHealthLast; + :global Identity; + + :global LogPrint; + :global SendNotification2; + :global SymbolForNotification; + + :if ([ :len [ /system/health/find where type="" name~"-state\$"] ] = 0) do={ + $LogPrint debug $FuncName ("Your device does not provide any state health values."); + :return false; + } + + :foreach State in=[ /system/health/find where type="" name~"-state\$" ] do={ + :local Name [ /system/health/get $State name ]; + :local Value [ /system/health/get $State value ]; + + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ + :if ($CheckHealthLast->$Name = "ok" && \ + $Value != "ok") do={ + $SendNotification2 ({ origin=$FuncName; \ + subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ + message=("The device '" . $Name . "' on " . $Identity . " failed!") }); + } + :if ($CheckHealthLast->$Name != "ok" && \ + $Value = "ok") do={ + $SendNotification2 ({ origin=$FuncName; \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ + message=("The device '" . $Name . "' on " . $Identity . " recovered!") }); + } + } + :set ($CheckHealthLast->$Name) $Value; + } +} diff --git a/check-health.d/temperature.rsc b/check-health.d/temperature.rsc new file mode 100644 index 0000000..9b84782 --- /dev/null +++ b/check-health.d/temperature.rsc @@ -0,0 +1,74 @@ +#!rsc by RouterOS +# RouterOS script: check-health.d/temperature +# Copyright (c) 2019-2025 Christian Hesse +# https://rsc.eworm.de/COPYING.md +# +# requires RouterOS, version=7.14 +# +# check for RouterOS health state - temperature plugin +# https://rsc.eworm.de/doc/check-health.md + +:global CheckHealthPlugins; + +:set ($CheckHealthPlugins->[ :jobname ]) do={ + :local FuncName [ :tostr $0 ]; + + :global CheckHealthLast; + :global CheckHealthTemperature; + :global CheckHealthTemperatureDeviation; + :global CheckHealthTemperatureNotified; + :global Identity; + + :global LogPrint; + :global SendNotification2; + :global SymbolForNotification; + + :if ([ :len [ /system/health/find where type="C" ] ] = 0) do={ + $LogPrint debug $FuncName ("Your device does not provide any voltage health values."); + :return false; + } + + :local TempToNum do={ + :global CharacterReplace; + :local T [ :toarray [ $CharacterReplace $1 "." "," ] ]; + :return ($T->0 * 10 + $T->1); + } + + :if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ + :set CheckHealthTemperatureNotified ({}); + } + + :foreach Temperature in=[ /system/health/find where type="C" ] do={ + :local Name [ /system/health/get $Temperature name ]; + :local Value [ /system/health/get $Temperature value ]; + + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ + :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ + $LogPrint info $FuncName ("No threshold given for " . $Name . ", assuming 50C."); + :set ($CheckHealthTemperature->$Name) 50; + } + :local Validate [ /system/health/get [ find where name=$Name ] value ]; + :while ($Value != $Validate) do={ + :set Value $Validate; + :set Validate [ /system/health/get [ find where name=$Name ] value ]; + } + :if ($Value > $CheckHealthTemperature->$Name && \ + $CheckHealthTemperatureNotified->$Name != true) do={ + $SendNotification2 ({ origin=$FuncName; \ + subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ + message=("The " . $Name . " on " . $Identity . " is above threshold: " . \ + $Value . "\C2\B0" . "C") }); + :set ($CheckHealthTemperatureNotified->$Name) true; + } + :if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ + $CheckHealthTemperatureNotified->$Name = true) do={ + $SendNotification2 ({ origin=$FuncName; \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ + message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ + $Value . "\C2\B0" . "C") }); + :set ($CheckHealthTemperatureNotified->$Name) false; + } + } + :set ($CheckHealthLast->$Name) $Value; + } +} diff --git a/check-health.d/voltage.rsc b/check-health.d/voltage.rsc new file mode 100644 index 0000000..6394795 --- /dev/null +++ b/check-health.d/voltage.rsc @@ -0,0 +1,63 @@ +#!rsc by RouterOS +# RouterOS script: check-health.d/voltage +# Copyright (c) 2019-2025 Christian Hesse +# https://rsc.eworm.de/COPYING.md +# +# requires RouterOS, version=7.14 +# +# check for RouterOS health state - voltage plugin +# https://rsc.eworm.de/doc/check-health.md + +:global CheckHealthPlugins; + +:set ($CheckHealthPlugins->[ :jobname ]) do={ + :local FuncName [ :tostr $0 ]; + + :global CheckHealthLast; + :global CheckHealthVoltageLow; + :global CheckHealthVoltagePercent; + :global Identity; + + :global FormatLine; + :global IfThenElse; + :global LogPrint; + :global SendNotification2; + :global SymbolForNotification; + + :if ([ :len [ /system/health/find where type="V" ] ] = 0) do={ + $LogPrint debug $FuncName ("Your device does not provide any voltage health values."); + :return false; + } + + :foreach Voltage in=[ /system/health/find where type="V" ] do={ + :local Name [ /system/health/get $Voltage name ]; + :local Value [ /system/health/get $Voltage value ]; + + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ + :local NumCurr [ $TempToNum $Value ]; + :local NumLast [ $TempToNum ($CheckHealthLast->$Name) ]; + + :if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \ + $NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={ + $SendNotification2 ({ origin=$FuncName; \ + subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \ + $NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ + message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ + [ $FormatLine "old value" ($CheckHealthLast->$Name . " V") 12 ] . "\n" . \ + [ $FormatLine "new value" ($Value . " V") 12 ]) }); + } else={ + :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ + $SendNotification2 ({ origin=$FuncName; \ + subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \ + message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") }); + } + :if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={ + $SendNotification2 ({ origin=$FuncName; \ + subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ + message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") }); + } + } + } + :set ($CheckHealthLast->$Name) $Value; + } +} diff --git a/check-health.rsc b/check-health.rsc index 34c508c..827f597 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -19,11 +19,6 @@ :global CheckHealthCPUUtilizationNotified; :global CheckHealthLast; :global CheckHealthRAMUtilizationNotified; - :global CheckHealthTemperature; - :global CheckHealthTemperatureDeviation; - :global CheckHealthTemperatureNotified; - :global CheckHealthVoltageLow; - :global CheckHealthVoltagePercent; :global Identity; :global FormatLine; @@ -33,6 +28,7 @@ :global ScriptLock; :global SendNotification2; :global SymbolForNotification; + :global ValidateSyntax; :local TempToNum do={ :global CharacterReplace; @@ -78,105 +74,37 @@ :set CheckHealthRAMUtilizationNotified false; } - :if ([ :len [ /system/health/find ] ] = 0) do={ - $LogPrint debug $ScriptName ("Your device does not provide any health values."); + :local Plugins [ /system/script/find where name~"^check-health.d/." ]; + :if ([ :len $Plugins ] = 0) do={ + $LogPrint debug $ScriptName ("No plugins installed."); :set ExitOK true; :error true; } + :global CheckHealthPlugins ({}); :if ([ :typeof $CheckHealthLast ] != "array") do={ :set CheckHealthLast ({}); } - :if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ - :set CheckHealthTemperatureNotified ({}); - } - :foreach Voltage in=[ /system/health/find where type="V" ] do={ - :local Name [ /system/health/get $Voltage name ]; - :local Value [ /system/health/get $Voltage value ]; - - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :local NumCurr [ $TempToNum $Value ]; - :local NumLast [ $TempToNum ($CheckHealthLast->$Name) ]; - - :if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \ - $NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \ - $NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ - [ $FormatLine "old value" ($CheckHealthLast->$Name . " V") 12 ] . "\n" . \ - [ $FormatLine "new value" ($Value . " V") 12 ]) }); - } else={ - :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \ - message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") }); - } - :if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ - message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") }); - } + :foreach Plugin in=$Plugins do={ + :local PluginVal [ /system/script/get $Plugin ]; + :if ([ $ValidateSyntax ($PluginVal->"source") ] = true) do={ + :do { + /system/script/run $Plugin; + } on-error={ + $LogPrint error $ScriptName ("Plugin '" . $ScriptVal->"name" . "' failed to run."); } + } else={ + $LogPrint error $ScriptName ("Plugin '" . $ScriptVal->"name" . "' failed syntax validation, skipping."); } - :set ($CheckHealthLast->$Name) $Value; } - :foreach PSU in=[ /system/health/find where name~"^psu.*-state\$" ] do={ - :local Name [ /system/health/get $PSU name ]; - :local Value [ /system/health/get $PSU value ]; - - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :if ($CheckHealthLast->$Name = "ok" && \ - $Value != "ok") do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ - message=("The power supply unit '" . $Name . "' on " . $Identity . " failed!") }); - } - :if ($CheckHealthLast->$Name != "ok" && \ - $Value = "ok") do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ - message=("The power supply unit '" . $Name . "' on " . $Identity . " recovered!") }); - } - } - :set ($CheckHealthLast->$Name) $Value; + :foreach PluginName,Discard in=$CheckHealthPlugins do={ + ($CheckHealthPlugins->$PluginName) \ + ("\$CheckHealthPlugins->\"" . $PluginName . "\""); } - :foreach Temperature in=[ /system/health/find where type="C" ] do={ - :local Name [ /system/health/get $Temperature name ]; - :local Value [ /system/health/get $Temperature value ]; - - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ - $LogPrint info $ScriptName ("No threshold given for " . $Name . ", assuming 50C."); - :set ($CheckHealthTemperature->$Name) 50; - } - :local Validate [ /system/health/get [ find where name=$Name ] value ]; - :while ($Value != $Validate) do={ - :set Value $Validate; - :set Validate [ /system/health/get [ find where name=$Name ] value ]; - } - :if ($Value > $CheckHealthTemperature->$Name && \ - $CheckHealthTemperatureNotified->$Name != true) do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " is above threshold: " . \ - $Value . "\C2\B0" . "C") }); - :set ($CheckHealthTemperatureNotified->$Name) true; - } - :if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ - $CheckHealthTemperatureNotified->$Name = true) do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ - $Value . "\C2\B0" . "C") }); - :set ($CheckHealthTemperatureNotified->$Name) false; - } - } - :set ($CheckHealthLast->$Name) $Value; - } + :set CheckHealthPlugins; } on-error={ :global ExitError; $ExitError $ExitOK [ :jobname ]; } diff --git a/doc/check-health.d/notification-08-psu-fail.avif b/doc/check-health.d/notification-08-state-fail.avif similarity index 100% rename from doc/check-health.d/notification-08-psu-fail.avif rename to doc/check-health.d/notification-08-state-fail.avif diff --git a/doc/check-health.d/notification-09-psu-ok.avif b/doc/check-health.d/notification-09-state-ok.avif similarity index 100% rename from doc/check-health.d/notification-09-psu-ok.avif rename to doc/check-health.d/notification-09-state-ok.avif diff --git a/doc/check-health.md b/doc/check-health.md index a945371..51e71bc 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -17,21 +17,21 @@ Description ----------- This script is run from scheduler periodically, sending notification on -health related events: +health related events. Monitoring CPU and RAM utilization (available +processing and memory resources) works on all devices: * high CPU utilization * high RAM utilization (low available RAM) + +With additional plugins functionality can be extended, depending on +sensors available in hardware: + * voltage jumps up or down more than configured threshold * voltage drops below hard lower limit +* fan failed or recovered * power supply failed or recovered * temperature is above or below threshold -Monitoring CPU and RAM utilization (available processing and memory -resources) works on all devices. Other than that only sensors available -in hardware can be checked. See what your hardware supports: - - /system/health/print; - > âš ī¸ **Warning**: Note that bad initial state will not trigger an event! For > example rebooting a device that is already too hot will not trigger an > alert on high temperature. @@ -59,8 +59,8 @@ in hardware can be checked. See what your hardware supports: #### PSU state -![check-health notification psu fail](check-health.d/notification-08-psu-fail.avif) -![check-health notification psu ok](check-health.d/notification-09-psu-ok.avif) +![check-health notification state fail](check-health.d/notification-08-state-fail.avif) +![check-health notification state ok](check-health.d/notification-09-state-ok.avif) Requirements and installation ----------------------------- @@ -74,6 +74,30 @@ Just install the script and create a scheduler: > precision of cpu utilization, escpecially on devices with limited > resources. Thus an unusual interval is used here. +### Plugins + +Additional plugins are available for sensors available in hardware. First +check what your hardware supports: + + /system/health/print; + +Then install the plugin for *fan* and *power supply unit* *state*: + + $ScriptInstallUpdate check-health,check-health.d/state; + +... or *temperature*: + + $ScriptInstallUpdate check-health,check-health.d/temperature; + +... or *voltage*: + + $ScriptInstallUpdate check-health,check-health.d/voltage; + +You can also combine the commands and install all or a subset of plugins +in one go: + + $ScriptInstallUpdate check-health,check-health.d/state,check-health.d/temperature,check-health.d/voltage; + Configuration ------------- diff --git a/global-functions.rsc b/global-functions.rsc index a2ec833..8eb6712 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -13,7 +13,7 @@ :local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 131; +:global ExpectedConfigVersion 132; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 7508b43..c7e566f 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -56,6 +56,7 @@ 129="Extended 'backup-partition' to support RouterOS copy-over - interactively or before feature update."; 130="Dropped intermediate certificates, depending on just root certificates now."; 131="Enhanced certificate download to fallback to mkcert.org, so all (commonly trusted) root certificates are available now."; + 132="Split off plugins from 'check-health', so the script works on all devices to monitor CPU and RAM. The supported plugins for sensors in hardware are installed automatically."; }; # Migration steps to be applied on script updates @@ -64,4 +65,5 @@ 100=":global ScriptInstallUpdate; :if ([ :len [ /system/script/find where name=\"ssh-keys-import\" source~\"^#!rsc by RouterOS\\r?\\n\" ] ] > 0) do={ /system/script/set name=\"mod/ssh-keys-import\" ssh-keys-import; \$ScriptInstallUpdate; }"; 104=":global CharacterReplace; :global ScriptInstallUpdate; :foreach Script in={ \"capsman-download-packages\"; \"capsman-rolling-upgrade\"; \"hotspot-to-wpa\"; \"hotspot-to-wpa-cleanup\" } do={ /system/script/set name=(\$Script . \".capsman\") [ find where name=\$Script ]; :foreach Scheduler in=[ /system/scheduler/find where on-event~(\$Script . \"([^-.]|\\\$)\") ] do={ /system/scheduler/set \$Scheduler on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Script (\$Script . \".capsman\") ]; }; }; /ip/hotspot/user/profile/set on-login=\"hotspot-to-wpa.capsman\" [ find where on-login=\"hotspot-to-wpa\" ]; \$ScriptInstallUpdate;"; 111=":local Rec [ /ip/dns/static/find where comment~\"^managed by dhcp-to-dns for \" ]; :if ([ :len \$Rec ] > 0) do={ /ip/dns/static/remove \$Rec; /system/script/run dhcp-to-dns; }"; + 132=":if ([ :len [ /system/script/find where name=\"check-health\" ] ] > 0) do={ :local Code \":local Install \\\"check-health\\\"; :if ([ :len [ /system/health/find where type=\\\"\\\" name~\\\"-state\\\\\\\$\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/state\\\"); }; :if ([ :len [ /system/health/find where type=\\\"C\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/temperature\\\"); }; :if ([ :len [ /system/health/find where type=\\\"V\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/voltage\\\"); }; :global ScriptInstallUpdate; \\\$ScriptInstallUpdate \\\$Install;\"; :global ValidateSyntax; :if ([ \$ValidateSyntax \$Code ] = true) do={ :do { [ :parse \$Code ]; } on-error={ }; }; }"; }; From 7b660d095293e24bd3fedf2a00815eedec84ccf5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Feb 2025 21:24:20 +0100 Subject: [PATCH 2530/2612] packages-update: move configuration variables up --- packages-update.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages-update.rsc b/packages-update.rsc index ff47b2a..ba6d4f7 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -16,6 +16,9 @@ :do { :local ScriptName [ :jobname ]; + :global PackagesUpdateDeferReboot; + :global PackagesUpdateBackupFailure; + :global DownloadPackage; :global Grep; :global LogPrint; @@ -24,9 +27,6 @@ :global ScriptLock; :global VersionToNum; - :global PackagesUpdateDeferReboot; - :global PackagesUpdateBackupFailure; - :local Schedule do={ :local ScriptName [ :tostr $1 ]; From dafd95d44a18088771e6e0fd9b2ef115ddbcbc18 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Feb 2025 21:26:39 +0100 Subject: [PATCH 2531/2612] packages-update: disable random delay for backup --- packages-update.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages-update.rsc b/packages-update.rsc index ba6d4f7..788edd4 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -16,6 +16,7 @@ :do { :local ScriptName [ :jobname ]; + :global BackupRandomDelay; :global PackagesUpdateDeferReboot; :global PackagesUpdateBackupFailure; @@ -79,7 +80,9 @@ :set ($RunOrder->($Store->"order" . "-" . $ScriptVal->"name")) ($ScriptVal->"name"); } + :local BackupRandomDelayBefore $BackupRandomDelay; :foreach Order,Script in=$RunOrder do={ + :set BackupRandomDelay 0; :set PackagesUpdateBackupFailure false; :do { $LogPrint info $ScriptName ("Running backup script " . $Script . " before update."); @@ -87,6 +90,7 @@ } on-error={ :set PackagesUpdateBackupFailure true; } + :set BackupRandomDelay $BackupRandomDelayBefore; :if ($PackagesUpdateBackupFailure = true) do={ $LogPrint warning $ScriptName ("Running backup script " . $Script . " before update failed!"); From dbdc3e4718f5b0ec614baa9a9a942b52cbb19ad4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Feb 2025 17:12:30 +0100 Subject: [PATCH 2532/2612] packages-update: ignore available packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was introduced with RouterOS 7.18beta2 to list and install available packages. We do not want to install all of them. 😝 --- packages-update.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages-update.rsc b/packages-update.rsc index 788edd4..afec2f5 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -130,7 +130,7 @@ } } - :foreach Package in=[ /system/package/find where !bundle ] do={ + :foreach Package in=[ /system/package/find where !bundle !available ] do={ :local PkgName [ /system/package/get $Package name ]; :if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ $LogPrint error $ScriptName ("Download for package " . $PkgName . " failed, update aborted."); From 0fb5fd03230c2054a94d80ca72fc941e21b7f3ff Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Feb 2025 17:36:59 +0100 Subject: [PATCH 2533/2612] global-functions: $MkDir: create directory directly... ... instead of file inside directory. This requires RouterOS 7.15, so bumping requirement. --- README.md | 2 +- global-functions.rsc | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8594f58..a76d50f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ RouterOS Scripts [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/global-functions.rsc b/global-functions.rsc index 8eb6712..48f1676 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, fetch, scheduler # # global functions @@ -895,10 +895,8 @@ } :do { - :local File ($Path . "/file"); - /file/add name=$File; - $WaitForFile $File; - /file/remove $File; + /file/add type="directory" name=$Path; + $WaitForFile $Path; } on-error={ $LogPrint warning $0 ("Making directory '" . $Path . "' failed!"); :return false; From 4542c2b19e4b74ee37c02671c05f4025946d8bf7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Jan 2025 18:16:57 +0100 Subject: [PATCH 2534/2612] global-functions: introduce $RmFile --- global-functions.rsc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 48f1676..e41d352 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -63,6 +63,7 @@ :global ProtocolStrip; :global RandomDelay; :global RequiredRouterOS; +:global RmFile; :global ScriptFromTerminal; :global ScriptInstallUpdate; :global ScriptLock; @@ -1004,6 +1005,26 @@ :return true; } +# remove file +:set RmFile do={ + :local FileName [ :tostr $1 ]; + + :global LogPrint; + + :local File [ /file/find where name=$FileName type=file ]; + :if ([ :len $File ] = 0) do={ + :return true; + } + + :do { + /file/remove $File; + } on-error={ + $LogPrint error $0 ("Removing file '" . $FileName . "' (" . $File . ") failed."); + :return false; + } + :return true; +} + # check if script is run from terminal :set ScriptFromTerminal do={ :local Script [ :tostr $1 ]; From 727495d9c4f7ff00a9d0c5dc1fd06e22ba3abe39 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Jan 2025 18:21:28 +0100 Subject: [PATCH 2535/2612] global-functions: introduce $RmDir --- global-functions.rsc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index e41d352..b7a3b6a 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -63,6 +63,7 @@ :global ProtocolStrip; :global RandomDelay; :global RequiredRouterOS; +:global RmDir; :global RmFile; :global ScriptFromTerminal; :global ScriptInstallUpdate; @@ -1005,6 +1006,26 @@ :return true; } +# remove directory +:set RmDir do={ + :local DirName [ :tostr $1 ]; + + :global LogPrint; + + :local Dir [ /file/find where name=$DirName type=directory ]; + :if ([ :len $Dir ] = 0) do={ + :return true; + } + + :do { + /file/remove $Dir; + } on-error={ + $LogPrint error $0 ("Removing directory '" . $DirName . "' (" . $Dir . ") failed."); + :return false; + } + :return true; +} + # remove file :set RmFile do={ :local FileName [ :tostr $1 ]; From 7233dea5bb9e73a93599baf17077b80758934665 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Jan 2025 19:24:38 +0100 Subject: [PATCH 2536/2612] global-functions: $RmFile: add debug output --- global-functions.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index b7a3b6a..50202f0 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1032,8 +1032,11 @@ :global LogPrint; + $LogPrint debug $0 ("Removing file: ". $FileName); + :local File [ /file/find where name=$FileName type=file ]; :if ([ :len $File ] = 0) do={ + $LogPrint debug $0 ("... which does not exist."); :return true; } From 49d9fb1ffddfb973bed00aac3a36bf4dd8d6687a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Jan 2025 19:24:05 +0100 Subject: [PATCH 2537/2612] global-functions: $RmDir: add debug output --- global-functions.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 50202f0..2799f39 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1012,8 +1012,11 @@ :global LogPrint; + $LogPrint debug $0 ("Removing directory: ". $DirName); + :local Dir [ /file/find where name=$DirName type=directory ]; :if ([ :len $Dir ] = 0) do={ + $LogPrint debug $0 ("... which does not exist."); :return true; } From 4bfb591fa035a12e80edf8f2550f6237cd343cd9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Feb 2025 17:39:48 +0100 Subject: [PATCH 2538/2612] bump required RouterOS version for all scripts --- BRANCHES.md | 2 +- CERTIFICATES.md | 2 +- CONTRIBUTIONS.md | 2 +- INITIAL-COMMANDS.md | 2 +- accesslist-duplicates.capsman.rsc | 2 +- accesslist-duplicates.local.rsc | 2 +- accesslist-duplicates.template.rsc | 2 +- accesslist-duplicates.wifi.rsc | 2 +- backup-cloud.rsc | 2 +- backup-email.rsc | 2 +- backup-partition.rsc | 2 +- backup-upload.rsc | 2 +- capsman-download-packages.capsman.rsc | 2 +- capsman-download-packages.template.rsc | 2 +- capsman-download-packages.wifi.rsc | 2 +- capsman-rolling-upgrade.capsman.rsc | 2 +- capsman-rolling-upgrade.template.rsc | 2 +- capsman-rolling-upgrade.wifi.rsc | 2 +- certificate-renew-issued.rsc | 2 +- check-certificates.rsc | 2 +- check-health.d/state.rsc | 2 +- check-health.d/temperature.rsc | 2 +- check-health.d/voltage.rsc | 2 +- check-health.rsc | 2 +- check-lte-firmware-upgrade.rsc | 2 +- check-routeros-update.rsc | 2 +- collect-wireless-mac.capsman.rsc | 2 +- collect-wireless-mac.local.rsc | 2 +- collect-wireless-mac.template.rsc | 2 +- collect-wireless-mac.wifi.rsc | 2 +- dhcp-lease-comment.capsman.rsc | 2 +- dhcp-lease-comment.local.rsc | 2 +- dhcp-lease-comment.template.rsc | 2 +- dhcp-lease-comment.wifi.rsc | 2 +- doc/accesslist-duplicates.md | 2 +- doc/backup-cloud.md | 2 +- doc/backup-email.md | 2 +- doc/backup-partition.md | 2 +- doc/backup-upload.md | 2 +- doc/capsman-download-packages.md | 2 +- doc/capsman-rolling-upgrade.md | 2 +- doc/certificate-renew-issued.md | 2 +- doc/check-certificates.md | 2 +- doc/check-health.md | 2 +- doc/check-lte-firmware-upgrade.md | 2 +- doc/check-routeros-update.md | 2 +- doc/collect-wireless-mac.md | 2 +- doc/dhcp-lease-comment.md | 2 +- doc/firmware-upgrade-reboot.md | 2 +- doc/global-wait.md | 2 +- doc/gps-track.md | 2 +- doc/hotspot-to-wpa.md | 2 +- doc/ip-addr-bridge.md | 2 +- doc/ipsec-to-dns.md | 2 +- doc/ipv6-update.md | 2 +- doc/lease-script.md | 2 +- doc/leds-mode.md | 2 +- doc/log-forward.md | 2 +- doc/mod/bridge-port-to.md | 2 +- doc/mod/bridge-port-vlan.md | 2 +- doc/mod/inspectvar.md | 2 +- doc/mod/ipcalc.md | 2 +- doc/mod/notification-email.md | 2 +- doc/mod/notification-matrix.md | 2 +- doc/mod/notification-ntfy.md | 2 +- doc/mod/notification-telegram.md | 2 +- doc/mod/scriptrunonce.md | 2 +- doc/mode-button.md | 2 +- doc/ospf-to-leds.md | 2 +- doc/packages-update.md | 2 +- doc/ppp-on-up.md | 2 +- doc/sms-action.md | 2 +- doc/sms-forward.md | 2 +- doc/super-mario-theme.md | 2 +- doc/unattended-lte-firmware-upgrade.md | 2 +- doc/update-gre-address.md | 2 +- doc/update-tunnelbroker.md | 2 +- firmware-upgrade-reboot.rsc | 2 +- global-wait.rsc | 2 +- gps-track.rsc | 2 +- hotspot-to-wpa-cleanup.capsman.rsc | 2 +- hotspot-to-wpa-cleanup.template.rsc | 2 +- hotspot-to-wpa-cleanup.wifi.rsc | 2 +- hotspot-to-wpa.capsman.rsc | 2 +- hotspot-to-wpa.template.rsc | 2 +- hotspot-to-wpa.wifi.rsc | 2 +- ipsec-to-dns.rsc | 2 +- ipv6-update.rsc | 2 +- lease-script.rsc | 2 +- log-forward.rsc | 2 +- mod/bridge-port-to.rsc | 2 +- mod/bridge-port-vlan.rsc | 2 +- mod/inspectvar.rsc | 2 +- mod/ipcalc.rsc | 2 +- mod/notification-email.rsc | 2 +- mod/notification-matrix.rsc | 2 +- mod/notification-ntfy.rsc | 2 +- mod/notification-telegram.rsc | 2 +- mod/scriptrunonce.rsc | 2 +- mode-button.rsc | 2 +- ospf-to-leds.rsc | 2 +- packages-update.rsc | 2 +- ppp-on-up.rsc | 2 +- sms-action.rsc | 2 +- sms-forward.rsc | 2 +- unattended-lte-firmware-upgrade.rsc | 2 +- update-gre-address.rsc | 2 +- update-tunnelbroker.rsc | 2 +- 108 files changed, 108 insertions(+), 108 deletions(-) diff --git a/BRANCHES.md b/BRANCHES.md index 5d94077..8a0bdad 100644 --- a/BRANCHES.md +++ b/BRANCHES.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/CERTIFICATES.md b/CERTIFICATES.md index 589d480..5432d78 100644 --- a/CERTIFICATES.md +++ b/CERTIFICATES.md @@ -4,7 +4,7 @@ Certificate name from browser [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index ef1bd8b..0b35c40 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 84a88fe..424ef32 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc index 0c4eaaf..27546c8 100644 --- a/accesslist-duplicates.capsman.rsc +++ b/accesslist-duplicates.capsman.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # print duplicate antries in wireless access list # https://rsc.eworm.de/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc index 353fe1f..589815d 100644 --- a/accesslist-duplicates.local.rsc +++ b/accesslist-duplicates.local.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # print duplicate antries in wireless access list # https://rsc.eworm.de/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc index 4219014..ccbca3d 100644 --- a/accesslist-duplicates.template.rsc +++ b/accesslist-duplicates.template.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # print duplicate antries in wireless access list # https://rsc.eworm.de/doc/accesslist-duplicates.md diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc index 3ee53d8..527ebb4 100644 --- a/accesslist-duplicates.wifi.rsc +++ b/accesslist-duplicates.wifi.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # print duplicate antries in wireless access list # https://rsc.eworm.de/doc/accesslist-duplicates.md diff --git a/backup-cloud.rsc b/backup-cloud.rsc index efae055..9d76080 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: backup-script, order=40 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # upload backup to MikroTik cloud # https://rsc.eworm.de/doc/backup-cloud.md diff --git a/backup-email.rsc b/backup-email.rsc index f6ebad0..d097301 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: backup-script, order=20 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # create and email backup and config file # https://rsc.eworm.de/doc/backup-email.md diff --git a/backup-partition.rsc b/backup-partition.rsc index bfa7765..1f0cf2e 100644 --- a/backup-partition.rsc +++ b/backup-partition.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: backup-script, order=70 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, scheduler # # save configuration to fallback partition diff --git a/backup-upload.rsc b/backup-upload.rsc index dc5120f..533cc55 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: backup-script, order=50 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, fetch # # create and upload backup and config file diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index fa76ff5..2726af7 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # download and cleanup packages for CAP installation from CAPsMAN # https://rsc.eworm.de/doc/capsman-download-packages.md diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 912e279..0a42bb2 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # download and cleanup packages for CAP installation from CAPsMAN # https://rsc.eworm.de/doc/capsman-download-packages.md diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 3a5e7d1..037409a 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # download and cleanup packages for CAP installation from CAPsMAN # https://rsc.eworm.de/doc/capsman-download-packages.md diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc index abe066e..791b3db 100644 --- a/capsman-rolling-upgrade.capsman.rsc +++ b/capsman-rolling-upgrade.capsman.rsc @@ -5,7 +5,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: capsman-rolling-upgrade.capsman -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # upgrade CAPs one after another # https://rsc.eworm.de/doc/capsman-rolling-upgrade.md diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc index c1c7ff1..0b1cc2b 100644 --- a/capsman-rolling-upgrade.template.rsc +++ b/capsman-rolling-upgrade.template.rsc @@ -5,7 +5,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: capsman-rolling-upgrade%TEMPL% -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # upgrade CAPs one after another # https://rsc.eworm.de/doc/capsman-rolling-upgrade.md diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc index 44c99db..4afdee2 100644 --- a/capsman-rolling-upgrade.wifi.rsc +++ b/capsman-rolling-upgrade.wifi.rsc @@ -5,7 +5,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: capsman-rolling-upgrade.wifi -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # upgrade CAPs one after another # https://rsc.eworm.de/doc/capsman-rolling-upgrade.md diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc index 5a4043d..91a48de 100644 --- a/certificate-renew-issued.rsc +++ b/certificate-renew-issued.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # renew locally issued certificates # https://rsc.eworm.de/doc/certificate-renew-issued.md diff --git a/check-certificates.rsc b/check-certificates.rsc index 34e7537..25807cb 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, fetch # # check for certificate validity diff --git a/check-health.d/state.rsc b/check-health.d/state.rsc index bcc1fbc..2991935 100644 --- a/check-health.d/state.rsc +++ b/check-health.d/state.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # check for RouterOS health state - state plugin # https://rsc.eworm.de/doc/check-health.md diff --git a/check-health.d/temperature.rsc b/check-health.d/temperature.rsc index 9b84782..a2f632d 100644 --- a/check-health.d/temperature.rsc +++ b/check-health.d/temperature.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # check for RouterOS health state - temperature plugin # https://rsc.eworm.de/doc/check-health.md diff --git a/check-health.d/voltage.rsc b/check-health.d/voltage.rsc index 6394795..9071c88 100644 --- a/check-health.d/voltage.rsc +++ b/check-health.d/voltage.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # check for RouterOS health state - voltage plugin # https://rsc.eworm.de/doc/check-health.md diff --git a/check-health.rsc b/check-health.rsc index 827f597..f02a249 100644 --- a/check-health.rsc +++ b/check-health.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # check for RouterOS health state # https://rsc.eworm.de/doc/check-health.md diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc index 562b8fe..c5b6cb5 100644 --- a/check-lte-firmware-upgrade.rsc +++ b/check-lte-firmware-upgrade.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # check for LTE firmware upgrade, send notification # https://rsc.eworm.de/doc/check-lte-firmware-upgrade.md diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 5c9b392..361be34 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, fetch, scheduler # # check for RouterOS update, send notification and/or install diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc index f718e0b..17e09e3 100644 --- a/collect-wireless-mac.capsman.rsc +++ b/collect-wireless-mac.capsman.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=40 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # collect wireless mac adresses in access list # https://rsc.eworm.de/doc/collect-wireless-mac.md diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc index 0017875..4a38bfa 100644 --- a/collect-wireless-mac.local.rsc +++ b/collect-wireless-mac.local.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=40 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # collect wireless mac adresses in access list # https://rsc.eworm.de/doc/collect-wireless-mac.md diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc index 527e985..da901be 100644 --- a/collect-wireless-mac.template.rsc +++ b/collect-wireless-mac.template.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=40 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # collect wireless mac adresses in access list # https://rsc.eworm.de/doc/collect-wireless-mac.md diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc index 5f9de7d..cb217ce 100644 --- a/collect-wireless-mac.wifi.rsc +++ b/collect-wireless-mac.wifi.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=40 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # collect wireless mac adresses in access list # https://rsc.eworm.de/doc/collect-wireless-mac.md diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc index 3803963..36b31c8 100644 --- a/dhcp-lease-comment.capsman.rsc +++ b/dhcp-lease-comment.capsman.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=60 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # update dhcp-server lease comment with infos from access-list # https://rsc.eworm.de/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc index d5f1461..35dc6f6 100644 --- a/dhcp-lease-comment.local.rsc +++ b/dhcp-lease-comment.local.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=60 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # update dhcp-server lease comment with infos from access-list # https://rsc.eworm.de/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc index 2bddc26..47a8554 100644 --- a/dhcp-lease-comment.template.rsc +++ b/dhcp-lease-comment.template.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=60 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # update dhcp-server lease comment with infos from access-list # https://rsc.eworm.de/doc/dhcp-lease-comment.md diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc index 515b438..e0f9785 100644 --- a/dhcp-lease-comment.wifi.rsc +++ b/dhcp-lease-comment.wifi.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=60 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # update dhcp-server lease comment with infos from access-list # https://rsc.eworm.de/doc/dhcp-lease-comment.md diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index a6302f5..e4d0c7f 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -4,7 +4,7 @@ Find and remove access list duplicates [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index d658760..7286960 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/backup-email.md b/doc/backup-email.md index aedae4d..7b8bcfe 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/backup-partition.md b/doc/backup-partition.md index 9f62967..9d615a5 100644 --- a/doc/backup-partition.md +++ b/doc/backup-partition.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/backup-upload.md b/doc/backup-upload.md index f2858b2..6a5b0e4 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index d719934..5722227 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -4,7 +4,7 @@ Download packages for CAP upgrade from CAPsMAN [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index f366d40..d277db6 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -4,7 +4,7 @@ Run rolling CAP upgrades from CAPsMAN [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/certificate-renew-issued.md b/doc/certificate-renew-issued.md index 096e07b..c4615b5 100644 --- a/doc/certificate-renew-issued.md +++ b/doc/certificate-renew-issued.md @@ -4,7 +4,7 @@ Renew locally issued certificates [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 4188815..4c144ba 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -4,7 +4,7 @@ Renew certificates and notify on expiration [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/check-health.md b/doc/check-health.md index 51e71bc..7cf0c33 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index 66b2cf5..3693b71 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -4,7 +4,7 @@ Notify on LTE firmware upgrade [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 2e9b8aa..926b4aa 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -4,7 +4,7 @@ Notify on RouterOS update [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 84c111d..0197522 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -4,7 +4,7 @@ Collect MAC addresses in wireless access list [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/dhcp-lease-comment.md b/doc/dhcp-lease-comment.md index 6a4c930..b02f199 100644 --- a/doc/dhcp-lease-comment.md +++ b/doc/dhcp-lease-comment.md @@ -4,7 +4,7 @@ Comment DHCP leases with info from access list [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/firmware-upgrade-reboot.md b/doc/firmware-upgrade-reboot.md index 7ab6ac5..54f1da0 100644 --- a/doc/firmware-upgrade-reboot.md +++ b/doc/firmware-upgrade-reboot.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/global-wait.md b/doc/global-wait.md index 6787d20..799cae7 100644 --- a/doc/global-wait.md +++ b/doc/global-wait.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/gps-track.md b/doc/gps-track.md index 9685899..5e4878f 100644 --- a/doc/gps-track.md +++ b/doc/gps-track.md @@ -4,7 +4,7 @@ Send GPS position to server [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index 07d07dc..a2e9748 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/ip-addr-bridge.md b/doc/ip-addr-bridge.md index ddbcc0a..f9f98e3 100644 --- a/doc/ip-addr-bridge.md +++ b/doc/ip-addr-bridge.md @@ -4,7 +4,7 @@ Manage IP addresses with bridge status [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/ipsec-to-dns.md b/doc/ipsec-to-dns.md index a688e80..123656c 100644 --- a/doc/ipsec-to-dns.md +++ b/doc/ipsec-to-dns.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md index 42f0fe4..1f009b1 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/lease-script.md b/doc/lease-script.md index 1b59ff7..f83c383 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/leds-mode.md b/doc/leds-mode.md index c01472e..a194396 100644 --- a/doc/leds-mode.md +++ b/doc/leds-mode.md @@ -4,7 +4,7 @@ Manage LEDs dark mode [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/log-forward.md b/doc/log-forward.md index 55b1540..25be00a 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/mod/bridge-port-to.md b/doc/mod/bridge-port-to.md index 2ed9dc7..629c526 100644 --- a/doc/mod/bridge-port-to.md +++ b/doc/mod/bridge-port-to.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/mod/bridge-port-vlan.md b/doc/mod/bridge-port-vlan.md index ded2603..cf29199 100644 --- a/doc/mod/bridge-port-vlan.md +++ b/doc/mod/bridge-port-vlan.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/mod/inspectvar.md b/doc/mod/inspectvar.md index 4e2f4c1..7daba15 100644 --- a/doc/mod/inspectvar.md +++ b/doc/mod/inspectvar.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/mod/ipcalc.md b/doc/mod/ipcalc.md index 9f39429..c07853e 100644 --- a/doc/mod/ipcalc.md +++ b/doc/mod/ipcalc.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/mod/notification-email.md b/doc/mod/notification-email.md index 0bef455..34d1c09 100644 --- a/doc/mod/notification-email.md +++ b/doc/mod/notification-email.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index fbc9b91..89c1b01 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/mod/notification-ntfy.md b/doc/mod/notification-ntfy.md index 04dee35..51756ac 100644 --- a/doc/mod/notification-ntfy.md +++ b/doc/mod/notification-ntfy.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index f55f936..b85d09c 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/mod/scriptrunonce.md b/doc/mod/scriptrunonce.md index 0127c6d..955d12e 100644 --- a/doc/mod/scriptrunonce.md +++ b/doc/mod/scriptrunonce.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/mode-button.md b/doc/mode-button.md index 7feb19f..be15bc9 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -4,7 +4,7 @@ Mode button with multiple presses [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/ospf-to-leds.md b/doc/ospf-to-leds.md index 23248b5..3694d35 100644 --- a/doc/ospf-to-leds.md +++ b/doc/ospf-to-leds.md @@ -4,7 +4,7 @@ Visualize OSPF state via LEDs [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/packages-update.md b/doc/packages-update.md index 8b0d4a3..75225fe 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -4,7 +4,7 @@ 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.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/ppp-on-up.md b/doc/ppp-on-up.md index 7902f3b..305afc1 100644 --- a/doc/ppp-on-up.md +++ b/doc/ppp-on-up.md @@ -4,7 +4,7 @@ Run scripts on ppp connection [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/sms-action.md b/doc/sms-action.md index 5de7f0d..b696c85 100644 --- a/doc/sms-action.md +++ b/doc/sms-action.md @@ -4,7 +4,7 @@ Act on received SMS [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/sms-forward.md b/doc/sms-forward.md index 8e7417b..ccb6482 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -4,7 +4,7 @@ Forward received SMS [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/super-mario-theme.md b/doc/super-mario-theme.md index 2ffb25b..c72f220 100644 --- a/doc/super-mario-theme.md +++ b/doc/super-mario-theme.md @@ -4,7 +4,7 @@ Play Super Mario theme [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/unattended-lte-firmware-upgrade.md b/doc/unattended-lte-firmware-upgrade.md index e9a888c..cb96aa1 100644 --- a/doc/unattended-lte-firmware-upgrade.md +++ b/doc/unattended-lte-firmware-upgrade.md @@ -4,7 +4,7 @@ Install LTE firmware upgrade [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/update-gre-address.md b/doc/update-gre-address.md index 7e101c4..de9f622 100644 --- a/doc/update-gre-address.md +++ b/doc/update-gre-address.md @@ -4,7 +4,7 @@ Update GRE configuration with dynamic addresses [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/doc/update-tunnelbroker.md b/doc/update-tunnelbroker.md index 126d470..ee0fe98 100644 --- a/doc/update-tunnelbroker.md +++ b/doc/update-tunnelbroker.md @@ -4,7 +4,7 @@ Update tunnelbroker configuration [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.14-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc index e3d62de..86a9a8c 100644 --- a/firmware-upgrade-reboot.rsc +++ b/firmware-upgrade-reboot.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2022-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # install firmware upgrade, and reboot # https://rsc.eworm.de/doc/firmware-upgrade-reboot.md diff --git a/global-wait.rsc b/global-wait.rsc index bc98462..ca3fc0c 100644 --- a/global-wait.rsc +++ b/global-wait.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # wait for global-functions to finish # https://rsc.eworm.de/doc/global-wait.md diff --git a/gps-track.rsc b/gps-track.rsc index 5e35f8d..dea56d2 100644 --- a/gps-track.rsc +++ b/gps-track.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, fetch # # track gps data by sending json data to http server diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc index c21ec3e..033d0e7 100644 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=80 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, hotspot # # manage and clean up private WPA passphrase after hotspot login diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc index 1bd877e..0f8c490 100644 --- a/hotspot-to-wpa-cleanup.template.rsc +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=80 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, hotspot # # manage and clean up private WPA passphrase after hotspot login diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc index 8e36204..dfec697 100644 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -4,7 +4,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: lease-script, order=80 -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, hotspot # # manage and clean up private WPA passphrase after hotspot login diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index de9f9d9..3f51475 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, hotspot # # add private WPA passphrase after hotspot login diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index 003b12e..068241d 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, hotspot # # add private WPA passphrase after hotspot login diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index 0d6a7b9..cc5e2fc 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, hotspot # # add private WPA passphrase after hotspot login diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc index 91f6b45..26dab0a 100644 --- a/ipsec-to-dns.rsc +++ b/ipsec-to-dns.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2021-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, ipsec # # and add/remove/update DNS entries from IPSec mode-config diff --git a/ipv6-update.rsc b/ipv6-update.rsc index 7eb625b..c6e3d65 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # update firewall and dns settings on IPv6 prefix change # https://rsc.eworm.de/doc/ipv6-update.md diff --git a/lease-script.rsc b/lease-script.rsc index b6ceac9..bf27fda 100644 --- a/lease-script.rsc +++ b/lease-script.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # run scripts on DHCP lease # https://rsc.eworm.de/doc/lease-script.md diff --git a/log-forward.rsc b/log-forward.rsc index 379fa54..58ec956 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # forward log messages via notification # https://rsc.eworm.de/doc/log-forward.md diff --git a/mod/bridge-port-to.rsc b/mod/bridge-port-to.rsc index f00e10b..39a036e 100644 --- a/mod/bridge-port-to.rsc +++ b/mod/bridge-port-to.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # reset bridge ports to default bridge # https://rsc.eworm.de/doc/mod/bridge-port-to.md diff --git a/mod/bridge-port-vlan.rsc b/mod/bridge-port-vlan.rsc index 62e71e3..0eeb9b5 100644 --- a/mod/bridge-port-vlan.rsc +++ b/mod/bridge-port-vlan.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # manage VLANs on bridge ports # https://rsc.eworm.de/doc/mod/bridge-port-vlan.md diff --git a/mod/inspectvar.rsc b/mod/inspectvar.rsc index 0f05da7..c861557 100644 --- a/mod/inspectvar.rsc +++ b/mod/inspectvar.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # inspect variables # https://rsc.eworm.de/doc/mod/inspectvar.md diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc index fbed74b..477cf4a 100644 --- a/mod/ipcalc.rsc +++ b/mod/ipcalc.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # ip address calculation # https://rsc.eworm.de/doc/mod/ipcalc.md diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 404e74d..7b89d98 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, email, scheduler # # send notifications via e-mail diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc index 9b2b641..e989ee0 100644 --- a/mod/notification-matrix.rsc +++ b/mod/notification-matrix.rsc @@ -4,7 +4,7 @@ # Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, fetch, scheduler # # send notifications via Matrix diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc index 212fde2..aac6d6c 100644 --- a/mod/notification-ntfy.rsc +++ b/mod/notification-ntfy.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, fetch, scheduler # # send notifications via Ntfy (ntfy.sh) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index c3ef2dd..23ef942 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, fetch, scheduler # # send notifications via Telegram diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index e5368c4..b158c9c 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, fetch # # download script and run it once diff --git a/mode-button.rsc b/mode-button.rsc index 4cf5e75..edc5f40 100644 --- a/mode-button.rsc +++ b/mode-button.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, scheduler # # act on multiple mode and reset button presses diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc index 9d822c1..a8662b3 100644 --- a/ospf-to-leds.rsc +++ b/ospf-to-leds.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2020-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # visualize ospf instance state via leds # https://rsc.eworm.de/doc/ospf-to-leds.md diff --git a/packages-update.rsc b/packages-update.rsc index afec2f5..b11596e 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2019-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, scheduler # # download packages and reboot for installation diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc index 85e9689..e09bd9d 100644 --- a/ppp-on-up.rsc +++ b/ppp-on-up.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # run scripts on ppp up # https://rsc.eworm.de/doc/ppp-on-up.md diff --git a/sms-action.rsc b/sms-action.rsc index 34d2127..3c8307a 100644 --- a/sms-action.rsc +++ b/sms-action.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # run action on received SMS # https://rsc.eworm.de/doc/sms-action.md diff --git a/sms-forward.rsc b/sms-forward.rsc index 654fd56..8169022 100644 --- a/sms-forward.rsc +++ b/sms-forward.rsc @@ -4,7 +4,7 @@ # Anatoly Bubenkov # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # forward SMS to e-mail # https://rsc.eworm.de/doc/sms-forward.md diff --git a/unattended-lte-firmware-upgrade.rsc b/unattended-lte-firmware-upgrade.rsc index 74495d1..83925fd 100644 --- a/unattended-lte-firmware-upgrade.rsc +++ b/unattended-lte-firmware-upgrade.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2018-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, scheduler # # schedule unattended lte firmware upgrade diff --git a/update-gre-address.rsc b/update-gre-address.rsc index 6b169a0..cddfa92 100644 --- a/update-gre-address.rsc +++ b/update-gre-address.rsc @@ -3,7 +3,7 @@ # Copyright (c) 2013-2025 Christian Hesse # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # # update gre interface remote address with dynamic address from # ipsec remote peer diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc index a58589b..45afa6f 100644 --- a/update-tunnelbroker.rsc +++ b/update-tunnelbroker.rsc @@ -5,7 +5,7 @@ # https://rsc.eworm.de/COPYING.md # # provides: ppp-on-up -# requires RouterOS, version=7.14 +# requires RouterOS, version=7.15 # requires device-mode, fetch # # update local address of tunnelbroker interface From a8e5b5226bc6a11a0ccbca0f3becc85f9f4904e3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 10 Feb 2025 11:04:09 +0100 Subject: [PATCH 2539/2612] global-functions: $RmFile: fail on wrong type --- global-functions.rsc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 2799f39..ac37dee 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1037,6 +1037,11 @@ $LogPrint debug $0 ("Removing file: ". $FileName); + :if ([ :len [ /file/find where name=$FileName type!=file ] ] > 0) do={ + $LogPrint error $0 ("File '" . $FileName . "' is not a file."); + :return false; + } + :local File [ /file/find where name=$FileName type=file ]; :if ([ :len $File ] = 0) do={ $LogPrint debug $0 ("... which does not exist."); From 82020ddd73163194eb75aaa6f57d8e41597a7e6f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 10 Feb 2025 11:03:34 +0100 Subject: [PATCH 2540/2612] global-functions: $RmDir: fail on wrong type --- global-functions.rsc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index ac37dee..cf278eb 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1014,6 +1014,11 @@ $LogPrint debug $0 ("Removing directory: ". $DirName); + :if ([ :len [ /file/find where name=$DirName type!=directory ] ] > 0) do={ + $LogPrint error $0 ("Directory '" . $DirName . "' is not a directory."); + :return false; + } + :local Dir [ /file/find where name=$DirName type=directory ]; :if ([ :len $Dir ] = 0) do={ $LogPrint debug $0 ("... which does not exist."); From dbdf2952443ada35695925628999db4ddbe80be0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Jan 2025 18:33:35 +0100 Subject: [PATCH 2541/2612] global-functions: $CertificateDownload: use $RmFile --- global-functions.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index cf278eb..782c1a3 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -149,6 +149,7 @@ :global CleanName; :global FetchUserAgentStr; :global LogPrint; + :global RmFile; :global WaitForFile; $LogPrint info $0 ("Downloading and importing certificate with " . \ @@ -172,7 +173,7 @@ dst-path=$FileName as-value; $WaitForFile $FileName; :if ([ /file/get $FileName size ] = 0) do={ - /file/remove $FileName; + $RmFile $FileName; :error false; } } on-error={ @@ -183,7 +184,7 @@ /certificate/import file-name=$FileName passphrase="" as-value; :delay 1s; - /file/remove [ find where name=$FileName ]; + $RmFile $FileName; :if ([ :len [ /certificate/find where common-name=$CommonName ] ] = 0) do={ /certificate/remove [ find where name~("^" . $FileName . "_[0-9]+\$") ]; From ea8ec6b580071d832df28fd78a9e3c4c07a17bef Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Jan 2025 18:35:39 +0100 Subject: [PATCH 2542/2612] global-functions: $DownloadPackage: use $RmFile --- global-functions.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 782c1a3..b19ec56 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -343,6 +343,7 @@ :global CleanFilePath; :global LogPrint; :global MkDir; + :global RmFile; :global WaitForFile; :if ([ :len $PkgName ] = 0) do={ :return false; } @@ -386,7 +387,7 @@ $LogPrint debug $0 ("Downloading package file failed."); } - /file/remove [ find where name=$PkgDest ]; + $RmFile $PkgDest; :set Retry ($Retry - 1); } From d19b90df08dd179163c501a08d53eaf15bc53f15 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Jan 2025 18:37:01 +0100 Subject: [PATCH 2543/2612] global-functions: $FetchHuge: use $RmFile --- global-functions.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index b19ec56..ab6610e 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -457,6 +457,7 @@ :global IfThenElse; :global LogPrint; :global MkDir; + :global RmFile; :global WaitForFile; :set CheckCert [ $IfThenElse ($CheckCert = "false") "no" "yes-without-crl" ]; @@ -473,7 +474,7 @@ http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) as-value; } on-error={ :if ([ $WaitForFile $FileName 500ms ] = true) do={ - /file/remove $FileName; + $RmFile $FileName; } $LogPrint debug $0 ("Failed downloading from: " . $Url); /file/remove $DirName; From 4760515add1f753af7596245eb1a6c560ea37031 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Jan 2025 18:38:09 +0100 Subject: [PATCH 2544/2612] global-functions: $FetchHuge: use $RmDir --- global-functions.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index ab6610e..e680b60 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -457,6 +457,7 @@ :global IfThenElse; :global LogPrint; :global MkDir; + :global RmDir; :global RmFile; :global WaitForFile; @@ -477,7 +478,7 @@ $RmFile $FileName; } $LogPrint debug $0 ("Failed downloading from: " . $Url); - /file/remove $DirName; + $RmDir $DirName; :return false; } $WaitForFile $FileName; @@ -493,7 +494,7 @@ :delay 100ms; } } - /file/remove $DirName; + $RmDir $DirName; :return $Return; } From f5f00b70e325d80db939dcc2aa885b80845566fa Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 21 Jan 2025 18:41:58 +0100 Subject: [PATCH 2545/2612] global-functions: $MkDir: use $RmDir --- global-functions.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index e680b60..4b1f63d 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -857,6 +857,7 @@ :global CleanFilePath; :global LogPrint; + :global RmDir; :global WaitForFile; :local MkTmpfs do={ @@ -873,7 +874,7 @@ } $LogPrint info $0 ("Creating disk of type tmpfs."); - /file/remove [ find where name="tmpfs" type="directory" ]; + $RmDir "tmpfs"; :do { /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/get total-memory ] / 3); $WaitForFile "tmpfs"; From d748b69142a8b2b2d4328ef0e07dabe01fdbc01e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Feb 2025 16:13:43 +0100 Subject: [PATCH 2546/2612] backup-cloud: use $RmDir --- backup-cloud.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backup-cloud.rsc b/backup-cloud.rsc index 9d76080..c4e23b2 100644 --- a/backup-cloud.rsc +++ b/backup-cloud.rsc @@ -26,6 +26,7 @@ :global LogPrint; :global MkDir; :global RandomDelay; + :global RmDir; :global ScriptFromTerminal; :global ScriptLock; :global SendNotification2; @@ -97,7 +98,7 @@ $LogPrint error $ScriptName ("Failed uploading backup for " . $Identity . " to cloud!"); :set PackagesUpdateBackupFailure true; } - /file/remove "tmpfs/backup-cloud"; + $RmDir "tmpfs/backup-cloud"; } on-error={ :global ExitError; $ExitError $ExitOK [ :jobname ]; } From 81ba47a07d97a4cc36fc020cf35de7656e2abbb2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Feb 2025 16:10:46 +0100 Subject: [PATCH 2547/2612] backup-upload: use $RmDir --- backup-upload.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 533cc55..7f15a86 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -35,6 +35,7 @@ :global LogPrint; :global MkDir; :global RandomDelay; + :global RmDir; :global ScriptFromTerminal; :global ScriptLock; :global SendNotification2; @@ -170,7 +171,7 @@ :if ($Failed = 1) do={ :set PackagesUpdateBackupFailure true; } - /file/remove $DirName; + $RmDir $DirName; } on-error={ :global ExitError; $ExitError $ExitOK [ :jobname ]; } From 88ff03136805f40f14bb5d39af370c0ace62c4e7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Feb 2025 16:10:05 +0100 Subject: [PATCH 2548/2612] backup-upload: use $RmFile --- backup-upload.rsc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backup-upload.rsc b/backup-upload.rsc index 7f15a86..14c3914 100644 --- a/backup-upload.rsc +++ b/backup-upload.rsc @@ -36,6 +36,7 @@ :global MkDir; :global RandomDelay; :global RmDir; + :global RmFile; :global ScriptFromTerminal; :global ScriptLock; :global SendNotification2; @@ -100,7 +101,7 @@ :set Failed 1; } - /file/remove ($FilePath . ".backup"); + $RmFile ($FilePath . ".backup"); } # create configuration export @@ -119,7 +120,7 @@ :set Failed 1; } - /file/remove ($FilePath . ".rsc"); + $RmFile ($FilePath . ".rsc"); } # global-config-overlay @@ -140,7 +141,7 @@ :set Failed 1; } - /file/remove ($FilePath . ".conf"); + $RmFile ($FilePath . ".conf"); } :local FileInfo do={ From 63db96bdccc9c9c1356e71683157383322b40285 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Feb 2025 16:06:33 +0100 Subject: [PATCH 2549/2612] capsman-download-packages: use $RmFile --- capsman-download-packages.capsman.rsc | 3 ++- capsman-download-packages.template.rsc | 3 ++- capsman-download-packages.wifi.rsc | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index 2726af7..4387cb1 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -22,6 +22,7 @@ :global DownloadPackage; :global LogPrint; :global MkDir; + :global RmFile; :global ScriptLock; :global WaitFullyConnected; @@ -61,7 +62,7 @@ :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ ($File->"package-architecture") $PackagePath ] = true) do={ :set Updated true; - /file/remove $Package; + $RmFile $Package; } } diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 0a42bb2..744494e 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -23,6 +23,7 @@ :global DownloadPackage; :global LogPrint; :global MkDir; + :global RmFile; :global ScriptLock; :global WaitFullyConnected; @@ -63,7 +64,7 @@ :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ ($File->"package-architecture") $PackagePath ] = true) do={ :set Updated true; - /file/remove $Package; + $RmFile $Package; } } diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 037409a..a0c5e12 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -22,6 +22,7 @@ :global DownloadPackage; :global LogPrint; :global MkDir; + :global RmFile; :global ScriptLock; :global WaitFullyConnected; @@ -61,7 +62,7 @@ :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ ($File->"package-architecture") $PackagePath ] = true) do={ :set Updated true; - /file/remove $Package; + $RmFile $Package; } } From 6570a84904bcdd6d74090944f0fc94d1b94add90 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Feb 2025 16:08:40 +0100 Subject: [PATCH 2550/2612] check-certificates: use $RmFile --- check-certificates.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 25807cb..0907395 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -44,6 +44,7 @@ :global EscapeForRegEx; :global FetchUserAgentStr; :global LogPrint; + :global RmFile; :global UrlEncode; :global WaitForFile; @@ -63,7 +64,7 @@ :set DecryptionFailed false; } } - /file/remove [ find where name=$CertFileName ]; + $RmFile $CertFileName; :if ($DecryptionFailed = true) do={ $LogPrint warning $ScriptName ("Decryption failed for certificate file '" . $CertFileName . "'."); From 0fea300feaaaf8f3c87facb99e04126753713c76 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Feb 2025 16:12:51 +0100 Subject: [PATCH 2551/2612] mod/ssh-keys-import: use $RmDir --- mod/ssh-keys-import.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 35aa7ec..2fae4b1 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -19,6 +19,7 @@ :global GetRandom20CharAlNum; :global LogPrint; :global MkDir; + :global RmDir; :global WaitForFile; :if ([ :len $Key ] = 0 || [ :len $User ] = 0) do={ @@ -58,10 +59,10 @@ /user/ssh-keys/import public-key-file=$FileName user=$User; $LogPrint info $0 ("Imported ssh public key (" . $KeyVal->2 . ", " . $KeyVal->0 . ", " . \ "MD5:" . $FingerPrintMD5 . ") for user '" . $User . "'."); - /file/remove "tmpfs/ssh-keys-import"; + $RmDir "tmpfs/ssh-keys-import"; } on-error={ $LogPrint warning $0 ("Failed importing key."); - /file/remove "tmpfs/ssh-keys-import"; + $RmDir "tmpfs/ssh-keys-import"; :return false; } } on-error={ From b156fc43cfde99935eb78d95c6a5eae35b8f70f1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Feb 2025 16:14:58 +0100 Subject: [PATCH 2552/2612] telegram-chat: use $RmDir --- telegram-chat.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 8f29d8c..10952a6 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -37,6 +37,7 @@ :global MIN; :global MkDir; :global RandomDelay; + :global RmDir; :global ScriptLock; :global SendTelegram2; :global SymbolForNotification; @@ -154,7 +155,7 @@ $State . [ $IfThenElse ([ :len $Content ] > 0) \ ([ $SymbolForNotification "memo" ] . "Output:\n" . $Content) \ ([ $SymbolForNotification "memo" ] . "No output.") ]) }); - /file/remove "tmpfs/telegram-chat"; + $RmDir "tmpfs/telegram-chat"; } else={ $LogPrint info $ScriptName ("The command from update " . $UpdateID . " failed syntax validation!"); $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ From fc3beac83b8a6fd35a7b3736759f15bb8b71a723 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 10 Feb 2025 08:42:17 +0100 Subject: [PATCH 2553/2612] log-forward: make empty string a special meaning --- global-config.rsc | 10 +++++----- log-forward.rsc | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/global-config.rsc b/global-config.rsc index df26ef9..5df7b34 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -119,17 +119,17 @@ :global FwAddrListTimeOut 1d; # This defines what log messages to filter or include by topic or message -# text. Regular expressions are supported. Do *NOT* set an empty string, -# that will filter or include everything! +# text. Regular expressions are supported. An empty string has a special +# meaning not to filter or include anything. # These are filters, so excluding messages from forwarding. :global LogForwardFilter "(debug|info|packet|raw)"; -:global LogForwardFilterMessage []; +:global LogForwardFilterMessage ""; #:global LogForwardFilterMessage "message text"; #:global LogForwardFilterMessage "(message text|another text|...)"; # ... and another setting with reverse logic. This includes messages even # if filtered above. -:global LogForwardInclude []; -:global LogForwardIncludeMessage []; +:global LogForwardInclude ""; +:global LogForwardIncludeMessage ""; #:global LogForwardInclude "account"; #:global LogForwardIncludeMessage "message text"; diff --git a/log-forward.rsc b/log-forward.rsc index 58ec956..afeb3f2 100644 --- a/log-forward.rsc +++ b/log-forward.rsc @@ -57,6 +57,11 @@ :local MessageVal; :local MessageDups ({}); + :set LogForwardFilter [ $EitherOr $LogForwardFilter [] ]; + :set LogForwardFilterMessage [ $EitherOr $LogForwardFilterMessage [] ]; + :set LogForwardInclude [ $EitherOr $LogForwardInclude [] ]; + :set LogForwardIncludeMessage [ $EitherOr $LogForwardIncludeMessage [] ]; + :local LogForwardFilterLogForwardingCached [ $EitherOr [ $LogForwardFilterLogForwarding ] ("\$^") ]; :foreach Message in=[ /log/find where (!(message="") and \ !(message~$LogForwardFilterLogForwardingCached) and \ From 2e42f7963c2186512c4fa2cd75de7ab07754f229 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 10 Feb 2025 08:45:25 +0100 Subject: [PATCH 2554/2612] mod/notification-ntfy: use empty strings as default... ... which should be fine now that the credentials are not passed with fetch's properties, but as properly formatted authentication header. --- global-config.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/global-config.rsc b/global-config.rsc index 5df7b34..b0f0c64 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -56,9 +56,9 @@ # install the module: # $ScriptInstallUpdate mod/notification-ntfy :global NtfyServer "ntfy.sh"; -:global NtfyServerUser []; -:global NtfyServerPass []; -:global NtfyServerToken []; +:global NtfyServerUser ""; +:global NtfyServerPass ""; +:global NtfyServerToken ""; :global NtfyTopic ""; # It is possible to override e-mail, Telegram, Matrix and Ntfy setting From da280586b5012feb576cd7cd3e911d00ac7bf63e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 10 Feb 2025 14:00:37 +0100 Subject: [PATCH 2555/2612] doc/log-forward: add a hint on defaults --- doc/log-forward.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/log-forward.md b/doc/log-forward.md index 25be00a..93f6a7d 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -53,6 +53,12 @@ Just install the script: Configuration ------------- +The default configuration should provide reasonable presets, filtering +*info*, and effectively forwarding *warning* and *error*. + +> đŸ’Ąī¸ **Hint**: Please try with defaults first, especially if you are not +> familiar with regular expressions! + The configuration goes to `global-config-overlay`, these are the parameters: * `LogForwardFilter`: define topics *not* to be forwarded From 8af67af462369968238afe874a24c26141b0b5c9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 10 Feb 2025 14:08:06 +0100 Subject: [PATCH 2556/2612] doc/log-forward: mention ntfy --- doc/log-forward.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/log-forward.md b/doc/log-forward.md index 93f6a7d..3c19569 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -22,15 +22,15 @@ server (see `/system/logging`). This has some limitation, however: * does not work early after boot if network connectivity is not yet established, or breaks intermittently * lots of messages generate a flood of mails -* Matrix and Telegram are not supported +* Matrix, Ntfy and Telegram are not supported The script works around the limitations, for example it does: * read from `/log`, including messages from early boot * skip multi-repeated messages * rate-limit itself to mitigate flooding -* forward via notification (which includes *e-mail*, *Matrix* and *Telegram* - when installed and configured, see below) +* forward via notification (which includes *e-mail*, *Matrix*, *Ntfy* and + *Telegram* when installed and configured, see below) It is intended to be run periodically from scheduler, then collects new log messages and forwards them via notification. From 4d0b4a1ff4137ae0b5508fb16428ac4da7205410 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 11 Feb 2025 14:30:14 +0100 Subject: [PATCH 2557/2612] fw-addr-lists: these lists are deprecated and discontinued Any alternatives around? --- certs/GlobalSign.pem | 28 ---------------------------- certs/Makefile | 2 -- doc/fw-addr-lists.md | 6 +++--- global-config.rsc | 4 ---- 4 files changed, 3 insertions(+), 37 deletions(-) delete mode 100644 certs/GlobalSign.pem diff --git a/certs/GlobalSign.pem b/certs/GlobalSign.pem deleted file mode 100644 index 47035e4..0000000 --- a/certs/GlobalSign.pem +++ /dev/null @@ -1,28 +0,0 @@ -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 -# Label: "GlobalSign Root CA - R3" -# Serial: 4835703278459759426209954 -# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 -# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad -# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b ------BEGIN CERTIFICATE----- -MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 -MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 -RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT -gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm -KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd -QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ -XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw -DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o -LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU -RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp -jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK -6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX -mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs -Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH -WD9f ------END CERTIFICATE----- diff --git a/certs/Makefile b/certs/Makefile index ba25303..4e252b4 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -23,12 +23,10 @@ DOMAINS_IPV4 = \ 8.8.8.8/GTS-Root-R1 \ 9.9.9.9/DigiCert-Global-Root-G3 \ api.mullvad.net/ISRG-Root-X1 \ - feodotracker.abuse.ch/GlobalSign \ ipv4.showipv6.de/ISRG-Root-X1 \ ipv4.tunnelbroker.net/Starfield-Root-Certificate-Authority-G2 \ mkcert.org/ISRG-Root-X1 \ ntfy.sh/ISRG-Root-X1 \ - sslbl.abuse.ch/GlobalSign \ www.dshield.org/ISRG-Root-X1 \ www.spamhaus.org/GTS-Root-R4 DOMAINS_IPV6 = \ diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md index f581fd2..b888d4b 100644 --- a/doc/fw-addr-lists.md +++ b/doc/fw-addr-lists.md @@ -19,9 +19,9 @@ Description This script downloads, imports and updates firewall address-lists. Its main purpose is to block attacking ip addresses, spam hosts, command-and-control servers and similar malicious entities. The default configuration contains -lists from [abuse.ch](https://abuse.ch/), [dshield.org](https://dshield.org/) -and [blocklist.de](https://www.blocklist.de/), and -lists from [spamhaus.org](https://spamhaus.org/) are prepared. +lists from [dshield.org](https://dshield.org/) and +[blocklist.de](https://www.blocklist.de/), and lists from +[spamhaus.org](https://spamhaus.org/) are prepared. The address-lists are updated in place, so after initial import you will not see situation when the lists are not populated. diff --git a/global-config.rsc b/global-config.rsc index b0f0c64..2be4752 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -98,10 +98,6 @@ "block"={ # { url="https://rsc.eworm.de/main/fw-addr-lists.d/block"; # cert="ISRG Root X2" }; - { url="https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt"; - cert="GlobalSign" }; - { url="https://sslbl.abuse.ch/blacklist/sslipblacklist.txt"; - cert="GlobalSign" }; { url="https://www.dshield.org/block.txt"; cidr="/24"; cert="ISRG Root X1" }; { url="https://lists.blocklist.de/lists/strongips.txt"; From e1c561dd91dff9ad7c6bdd1e3496e126a8ac8b2c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 11 Feb 2025 14:56:43 +0100 Subject: [PATCH 2558/2612] global-functions: $MkDir: add debug output --- global-functions.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 4b1f63d..645ce3c 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -891,7 +891,10 @@ :return true; } + $LogPrint debug $0 ("Making directory: " . $Path); + :if ([ :len [ /file/find where name=$Path type="directory" ] ] = 1) do={ + $LogPrint debug $0 ("... which already exists."); :return true; } From d41f7585504b592938da5ea0fc68870d1f68c0f5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 11 Feb 2025 15:32:05 +0100 Subject: [PATCH 2559/2612] introduce DEBUG info --- DEBUG.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 DEBUG.md diff --git a/DEBUG.md b/DEBUG.md new file mode 100644 index 0000000..3d7f025 --- /dev/null +++ b/DEBUG.md @@ -0,0 +1,49 @@ +Debug output and logs +===================== + +[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) +[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) +[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) +[![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) + +[âŦ…ī¸ Go back to main README](README.md) + +Sometimes scripts do not behave as expected. In these cases debug output +or logs can help. + +## Debug output + +Run this command in a terminal: + + :set PrintDebug true; + +You will then see debug output when running the script from terminal. + +To revert to default output run: + + :set PrintDebug false; + +### Debug output for specific script + +Even having debug output for a specific script or function only (or a +set of) is possible. To enable debug output for `telegram-chat` run: + + :set ($PrintDebugOverride->"telegram-chat") true; + +## Debug logs + +The debug info can go to system log. To make it show up in `memory` run: + + /system/logging/add topics=script,debug action=memory; + +Other actions (`disk`, `email`, `remote` or `support`) can be used as +well. I do not recommend using `echo` - use [debug output](#debug-output) +instead. + +Disable or remote that setting to restore regular logging. + +--- +[âŦ…ī¸ Go back to main README](README.md) +[âŦ†ī¸ Go back to top](#top) From c8759381e90408a01dd842e837724b77f2d8c237 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 11 Feb 2025 19:14:42 +0100 Subject: [PATCH 2560/2612] global-functions: $WaitForFile: check that we can get properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks like RouterOS 7.18beta2 brings more breakage. Having a file available in listing is just the first step now. We also need to make sure that the file properties are accessible... đŸ¤Ē I have seen this taking several tens of seconds at least... đŸ¤ĒđŸ¤Ē So let's just try until we have properties available, or the file vanishes. Reported as SUP-179200. 🤞 --- global-functions.rsc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 645ce3c..13dca64 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1669,6 +1669,7 @@ :global CleanFilePath; :global EitherOr; + :global LogPrintOnce; :global MAX; :set FileName [ $CleanFilePath $FileName ]; @@ -1682,7 +1683,20 @@ :delay $Delay; :set I ($I + 1); } - :return true; + + :while ([ :len [ /file/find where name=$FileName ] ] > 0) do={ + :do { + /file/get $FileName; + :return true; + } on-error={ + $LogPrintOnce warning $0 \ + ("Hit the infamous file handling breakage (SUP-179200) introduced with RouterOS 7.18beta2..."); + } + :delay $Delay; + :set Delay ($Delay * 3 / 2); + } + + :return false; } # wait to be fully connected (default route is reachable, time is sync, DNS resolves) From df631b987d86b3b20cd55de9a005b13703576784 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 12 Feb 2025 12:13:17 +0100 Subject: [PATCH 2561/2612] fw-addr-lists: add a collective list in default configuration --- doc/fw-addr-lists.md | 3 ++- global-config.rsc | 4 ++++ global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md index b888d4b..cb560d7 100644 --- a/doc/fw-addr-lists.md +++ b/doc/fw-addr-lists.md @@ -18,7 +18,8 @@ Description This script downloads, imports and updates firewall address-lists. Its main purpose is to block attacking ip addresses, spam hosts, command-and-control -servers and similar malicious entities. The default configuration contains +servers and similar malicious entities. The default configuration contains a +[collective list by GitHub user @stamparm](https://github.com/stamparm/ipsum), lists from [dshield.org](https://dshield.org/) and [blocklist.de](https://www.blocklist.de/), and lists from [spamhaus.org](https://spamhaus.org/) are prepared. diff --git a/global-config.rsc b/global-config.rsc index 2be4752..b364a25 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -90,6 +90,7 @@ :global BackupPartitionCopyBeforeFeatureUpdate false; # This defines the settings for firewall address-lists (fw-addr-lists). +# Warning: Mind your device's resources - memory and processing! :global FwAddrLists { # "allow"={ # { url="https://rsc.eworm.de/main/fw-addr-lists.d/allow"; @@ -98,6 +99,9 @@ "block"={ # { url="https://rsc.eworm.de/main/fw-addr-lists.d/block"; # cert="ISRG Root X2" }; + { url="https://raw.githubusercontent.com/stamparm/ipsum/refs/heads/master/levels/4.txt"; +# # higher level (decrease the numerical value) for more addresses, and vice versa + cert="DigiCert Global Root G2" }; { url="https://www.dshield.org/block.txt"; cidr="/24"; cert="ISRG Root X1" }; { url="https://lists.blocklist.de/lists/strongips.txt"; diff --git a/global-functions.rsc b/global-functions.rsc index 13dca64..5996370 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -13,7 +13,7 @@ :local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 132; +:global ExpectedConfigVersion 133; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index c7e566f..6f9e96e 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -57,6 +57,7 @@ 130="Dropped intermediate certificates, depending on just root certificates now."; 131="Enhanced certificate download to fallback to mkcert.org, so all (commonly trusted) root certificates are available now."; 132="Split off plugins from 'check-health', so the script works on all devices to monitor CPU and RAM. The supported plugins for sensors in hardware are installed automatically."; + 133="Updated the default configuration for 'fw-addr-lists', deprecated lists were removed, a collective list was added."; }; # Migration steps to be applied on script updates From b7b3b43f3b11a280dbb465a425a5a554c2e8e471 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 12 Feb 2025 13:59:31 +0100 Subject: [PATCH 2562/2612] mod/scriptrunonce: use $FetchHuge --- mod/scriptrunonce.rsc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index b158c9c..683e416 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -4,7 +4,6 @@ # https://rsc.eworm.de/COPYING.md # # requires RouterOS, version=7.15 -# requires device-mode, fetch # # download script and run it once # https://rsc.eworm.de/doc/mod/scriptrunonce.md @@ -18,6 +17,7 @@ :global ScriptRunOnceBaseUrl; :global ScriptRunOnceUrlSuffix; + :global FetchHuge; :global LogPrint; :global ValidateSyntax; @@ -30,11 +30,10 @@ :set Script ($ScriptRunOnceBaseUrl . $Script . ".rsc" . $ScriptRunOnceUrlSuffix); } - :local Source; - :do { - :set Source ([ /tool/fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data"); - } on-error={ + :local Source [ $FetchHuge $0 $Script true ]; + :if ($Source = false) do={ $LogPrint warning $0 ("Failed fetching script '" . $Script . "'!"); + :return false; } :if ([ :len $Source ] > 0) do={ From 1c957dbc6d0a35d48f18f2fde0f2061f334feca8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 12 Feb 2025 14:01:10 +0100 Subject: [PATCH 2563/2612] mod/scriptrunonce: resolve nested conditions --- mod/scriptrunonce.rsc | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index 683e416..9d990a1 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -36,17 +36,16 @@ :return false; } - :if ([ :len $Source ] > 0) do={ - :if ([ $ValidateSyntax $Source ] = true) do={ - :do { - $LogPrint info $0 ("Running script '" . $Script . "' now."); - [ :parse $Source ]; - } on-error={ - $LogPrint warning $0 ("The script '" . $Script . "' failed to run!"); - } - } else={ - $LogPrint warning $0 ("The script '" . $Script . "' failed syntax validation!"); - } + :if ([ $ValidateSyntax $Source ] = false) do={ + $LogPrint warning $0 ("The script '" . $Script . "' failed syntax validation!"); + :return false; + } + + :do { + $LogPrint info $0 ("Running script '" . $Script . "' now."); + [ :parse $Source ]; + } on-error={ + $LogPrint warning $0 ("The script '" . $Script . "' failed to run!"); } } } on-error={ From 5715bc7b57ced8f38b394d535028659655a71801 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 12 Feb 2025 14:02:33 +0100 Subject: [PATCH 2564/2612] mod/scriptrunonce: always give proper return code --- mod/scriptrunonce.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc index 9d990a1..7fcd5b5 100644 --- a/mod/scriptrunonce.rsc +++ b/mod/scriptrunonce.rsc @@ -46,7 +46,10 @@ [ :parse $Source ]; } on-error={ $LogPrint warning $0 ("The script '" . $Script . "' failed to run!"); + :return false; } + + :return true; } } on-error={ :global ExitError; $ExitError false $0; From 584e507fd18f0a0d97f6e3cbfc4f3f6e0d4854fc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 13 Feb 2025 08:50:49 +0100 Subject: [PATCH 2565/2612] global-functions: $DeviceInfo: show commit id (if available) --- global-functions.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 5996370..71e5c66 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -13,6 +13,7 @@ :local ScriptName [ :jobname ]; # expected configuration version +:global CommitId "unknown"; :global ExpectedConfigVersion 133; # global variables not to be changed by user @@ -284,6 +285,7 @@ # get readable device info :set DeviceInfo do={ + :global CommitId; :global ExpectedConfigVersion; :global Identity; @@ -324,6 +326,8 @@ $RouterBoard->"current-firmware" != $RouterBoard->"upgrade-firmware") \ ([ $FormatLine " Firmware" ($RouterBoard->"current-firmware") ] . "\n") ] . \ "RouterOS-Scripts:\n" . \ + [ $IfThenElse ($CommitId != "unknown") \ + ([ $FormatLine " Commit" [ :pick $CommitId 0 8 ] ] . "\n") ] . \ [ $FormatLine " Version" $ExpectedConfigVersion ]); } From 0199ea8884d9b45a184717bdbd5dccf829eb527d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 13 Feb 2025 09:07:43 +0100 Subject: [PATCH 2566/2612] global-functions: $ScriptInstallUpdate: show commit id (if available) --- global-functions.rsc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 71e5c66..204f824 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1105,6 +1105,7 @@ :local Scripts [ :toarray $1 ]; :local NewComment [ :tostr $2 ]; + :global CommitId; :global ExpectedConfigVersion; :global Identity; :global IDonate; @@ -1137,6 +1138,7 @@ } } + :local CommitIdBefore $CommitId; :local ExpectedConfigVersionBefore $ExpectedConfigVersion; :local ReloadGlobalFunctions false; :local ReloadGlobalConfig false; @@ -1251,6 +1253,10 @@ } } + :if ($CommitId != "unknown" && $CommitIdBefore != $CommitId) do={ + $LogPrint info $0 ("Updated to commit id: " . [ :pick $CommitId 0 8 ]); + } + :if ($ExpectedConfigVersionBefore > $ExpectedConfigVersion) do={ $LogPrint warning $0 ("The configuration version decreased from " . \ $ExpectedConfigVersionBefore . " to " . $ExpectedConfigVersion . \ From dafcc1a0cb8d18b191919c4876fa1db6c3fe2e27 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 13 Feb 2025 17:49:42 +0100 Subject: [PATCH 2567/2612] global-functions: $RmFile: fix type safeguard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ups... đŸĢŖ The type is not just literal 'file' - but what ever type the file is, like 'backup', 'package', 'script', '.conf file', ... So let's match those types we do *not* want to remove. Fixes: https://github.com/eworm-de/routeros-scripts/issues/90 --- global-functions.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 204f824..221b1b5 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1054,12 +1054,12 @@ $LogPrint debug $0 ("Removing file: ". $FileName); - :if ([ :len [ /file/find where name=$FileName type!=file ] ] > 0) do={ + :if ([ :len [ /file/find where name=$FileName (type=directory or type=disk) ] ] > 0) do={ $LogPrint error $0 ("File '" . $FileName . "' is not a file."); :return false; } - :local File [ /file/find where name=$FileName type=file ]; + :local File [ /file/find where name=$FileName !(type=directory or type=disk) ]; :if ([ :len $File ] = 0) do={ $LogPrint debug $0 ("... which does not exist."); :return true; From 75633872aa8a09a328e2bef07211e182bceb2725 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 17 Feb 2025 11:45:02 +0100 Subject: [PATCH 2568/2612] global-functions: $DeviceInfo: also show commit info --- global-functions.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 221b1b5..c6625c1 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,8 +12,9 @@ :local ScriptName [ :jobname ]; -# expected configuration version +# Git commit id & info, expected configuration version :global CommitId "unknown"; +:global CommitInfo "unknown"; :global ExpectedConfigVersion 133; # global variables not to be changed by user @@ -286,6 +287,7 @@ # get readable device info :set DeviceInfo do={ :global CommitId; + :global CommitInfo; :global ExpectedConfigVersion; :global Identity; @@ -327,7 +329,7 @@ ([ $FormatLine " Firmware" ($RouterBoard->"current-firmware") ] . "\n") ] . \ "RouterOS-Scripts:\n" . \ [ $IfThenElse ($CommitId != "unknown") \ - ([ $FormatLine " Commit" [ :pick $CommitId 0 8 ] ] . "\n") ] . \ + ([ $FormatLine " Commit" ($CommitInfo . "/" . [ :pick $CommitId 0 8 ]) ] . "\n") ] . \ [ $FormatLine " Version" $ExpectedConfigVersion ]); } From 2c92c78b4647e43c44da567e98adee69b7857393 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 17 Feb 2025 11:47:26 +0100 Subject: [PATCH 2569/2612] global-functions: $ScriptInstallUpdate: also show commit info --- global-functions.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index c6625c1..f5fa5cb 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1108,6 +1108,7 @@ :local NewComment [ :tostr $2 ]; :global CommitId; + :global CommitInfo; :global ExpectedConfigVersion; :global Identity; :global IDonate; @@ -1256,7 +1257,7 @@ } :if ($CommitId != "unknown" && $CommitIdBefore != $CommitId) do={ - $LogPrint info $0 ("Updated to commit id: " . [ :pick $CommitId 0 8 ]); + $LogPrint info $0 ("Updated to commit: " . $CommitInfo . "/" . [ :pick $CommitId 0 8 ]); } :if ($ExpectedConfigVersionBefore > $ExpectedConfigVersion) do={ From 58da92e36a704a0bd5915451fbace686e8d9456d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 19 Feb 2025 22:21:03 +0100 Subject: [PATCH 2570/2612] global-functions: $WaitForFile: drop the warning on file handling breakage... ... but keep the workaround for now - just to be sure. --- global-functions.rsc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index f5fa5cb..99e52f8 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1682,7 +1682,6 @@ :global CleanFilePath; :global EitherOr; - :global LogPrintOnce; :global MAX; :set FileName [ $CleanFilePath $FileName ]; @@ -1701,10 +1700,7 @@ :do { /file/get $FileName; :return true; - } on-error={ - $LogPrintOnce warning $0 \ - ("Hit the infamous file handling breakage (SUP-179200) introduced with RouterOS 7.18beta2..."); - } + } on-error={ } :delay $Delay; :set Delay ($Delay * 3 / 2); } From cad104879cbc758717f6cbf18f2f1b8946078c19 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2025 14:49:30 +0100 Subject: [PATCH 2571/2612] mod/notification-telegram: simplify the queue... ... and pass http-data as a complete sting. --- mod/notification-telegram.rsc | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 23ef942..be4a915 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -22,7 +22,6 @@ :global IsFullyConnected; :global LogPrint; - :global UrlEncode; :if ([ $IsFullyConnected ] = false) do={ $LogPrint debug $0 ("System is not fully connected, not flushing."); @@ -41,9 +40,7 @@ :do { :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \ ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ - http-data=("chat_id=" . ($Message->"chatid") . "&disable_notification=" . ($Message->"silent") . \ - "&reply_to_message_id=" . ($Message->"replyto") . "&disable_web_page_preview=true" . \ - "&parse_mode=MarkdownV2&text=" . [ $UrlEncode ($Message->"text") ]) as-value ]->"data"); + http-data=($Message->"http-data") as-value ]->"data"); :set ($TelegramQueue->$Id); :set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1; } on-error={ @@ -145,6 +142,9 @@ (($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%_!") "plain" "_" ]); } + :local HTTPData ("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ + "&reply_to_message_id=" . ($Notification->"replyto") . "&disable_web_page_preview=true" . \ + "&parse_mode=MarkdownV2"); :do { :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={ $LogPrint warning $0 ("Downloading required certificate failed."); @@ -152,9 +152,7 @@ } :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \ ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ - http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ - "&reply_to_message_id=" . ($Notification->"replyto") . "&disable_web_page_preview=true" . \ - "&parse_mode=MarkdownV2&text=" . [ $UrlEncode $Text ]) as-value ]->"data"); + http-data=($HTTPData . "&text=" . [ $UrlEncode $Text ]) as-value ]->"data"); :set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1; } on-error={ $LogPrint info $0 ("Failed sending Telegram notification! Queuing..."); @@ -165,8 +163,8 @@ :set Text ($Text . "\n" . [ $SymbolForNotification "alarm-clock" ] . \ [ $EscapeMD ("This message was queued since _" . [ /system/clock/get date ] . \ " " . [ /system/clock/get time ] . "_ and may be obsolete.") "plain" "_" ]); - :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; - text=$Text; silent=($Notification->"silent"); replyto=($Notification->"replyto") }; + :set ($TelegramQueue->[ :len $TelegramQueue ]) { tokenid=$TokenId; + http-data=($HTTPData . "&text=" . [ $UrlEncode $Text ]) }; :if ([ :len [ /system/scheduler/find where name="_FlushTelegramQueue" ] ] = 0) do={ /system/scheduler/add name="_FlushTelegramQueue" interval=1m start-time=startup \ on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;"); From a22b62f58803141a3055db046363f4d41b12ea83 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2025 14:57:26 +0100 Subject: [PATCH 2572/2612] mod/notification-telegram: support sending to group's topic... ... when a group has enabled the "Topics" feature. --- doc/mod/notification-telegram.md | 3 +++ global-config.rsc | 2 ++ mod/notification-telegram.rsc | 8 ++++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index b85d09c..8043716 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -58,6 +58,9 @@ Sending notifications to a group is possible as well. Add your bot and the *GetIDs Bot* to a group, then use the group's id (which starts with a dash) for `TelegramChatId`. Then remove *GetIDs Bot* from group. +Groups can enable the `Topics` feature. Use `TelegramThreadId` to send to a +specific topic in a group. + Usage and invocation -------------------- diff --git a/global-config.rsc b/global-config.rsc index b364a25..2524ded 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -33,6 +33,8 @@ :global TelegramChatId ""; #:global TelegramTokenId "123456:ABCDEF-GHI"; #:global TelegramChatId "12345678"; +# Use this to send notifications to a specific topic in group. +:global TelegramThreadId ""; # Using telegram-chat you have to define trusted chat ids (not group ids!) # or user names. Groups allow to chat with devices simultaneously. #:global TelegramChatIdsTrusted { diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index be4a915..d04893f 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -68,6 +68,8 @@ :global TelegramChatIdOverride; :global TelegramMessageIDs; :global TelegramQueue; + :global TelegramThreadId; + :global TelegramThreadIdOverride; :global TelegramTokenId; :global TelegramTokenIdOverride; @@ -108,6 +110,8 @@ :local ChatId [ $EitherOr ($Notification->"chatid") \ [ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ] ]; + :local ThreadId [ $EitherOr ($Notification->"threadid") \ + [ $EitherOr ($TelegramThreadIdOverride->($Notification->"origin")) $TelegramThreadId ] ]; :local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ]; :if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={ @@ -143,8 +147,8 @@ } :local HTTPData ("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ - "&reply_to_message_id=" . ($Notification->"replyto") . "&disable_web_page_preview=true" . \ - "&parse_mode=MarkdownV2"); + "&reply_to_message_id=" . ($Notification->"replyto") . "&message_thread_id=" . $ThreadId . \ + "&disable_web_page_preview=true&parse_mode=MarkdownV2"); :do { :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={ $LogPrint warning $0 ("Downloading required certificate failed."); From 757fa60e6f37cc684abec5582d1b6051f6ef8d6d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 25 Feb 2025 10:46:25 +0100 Subject: [PATCH 2573/2612] telegram-chat: make $IsReply a boolean... ... and check for correct data type. We need this for a group with topic feature enabled, as that variable is set there, but is is an array. --- telegram-chat.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 10952a6..eacbbcb 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -97,7 +97,7 @@ :foreach Update in=($JSON->"result") do={ :set UpdateID ($Update->"update_id"); :local Message ($Update->"message"); - :local IsReply [ :len ($Message->"reply_to_message") ]; + :local IsReply ([ :typeof ($Message->"reply_to_message") ] = "string"); :local IsMyReply ($TelegramMessageIDs->[ :tostr ($Message->"reply_to_message"->"message_id") ]); :if (($IsMyReply = 1 || $TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={ :local Trusted false; @@ -130,7 +130,8 @@ " from update " . $UpdateID . "!"); :set Done true; } - :if ($Done = false && ($IsMyReply = 1 || ($IsReply = 0 && $TelegramChatActive = true)) && [ :len $Command ] > 0) do={ + :if ($Done = false && ($IsMyReply = 1 || ($IsReply = false && \ + $TelegramChatActive = true)) && [ :len $Command ] > 0) do={ :if ([ $ValidateSyntax $Command ] = true) do={ :local State ""; :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); From 7928c5f0543765e27379e39bbaff6bdb19638971 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 24 Feb 2025 15:31:34 +0100 Subject: [PATCH 2574/2612] telegram-chat: support reply in group's topic --- telegram-chat.rsc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index eacbbcb..07e3816 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -104,6 +104,7 @@ :local Chat ($Message->"chat"); :local From ($Message->"from"); :local Command ($Message->"text"); + :local ThreadId [ $IfThenElse ($Message->"is_topic_message") ($Message->"message_thread_id") "" ]; :foreach IdsTrusted in=($TelegramChatId, $TelegramChatIdsTrusted) do={ :if ($From->"id" = $IdsTrusted || $From->"username" = $IdsTrusted) do={ @@ -115,7 +116,8 @@ :local Done false; :if ($Command = "?") do={ $LogPrint info $ScriptName ("Sending notice for update " . $UpdateID . "."); - $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ + $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; \ + replyto=($Message->"message_id"); threadid=$ThreadId; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("Online" . [ $IfThenElse $TelegramChatActive " (and active!)" ] . ", awaiting your commands!") }); :set Done true; @@ -150,7 +152,8 @@ :set State ([ $SymbolForNotification "cross-mark" ] . "The command failed with an error!\n\n"); } :local Content ([ /file/read chunk-size=32768 file=$File as-value ]->"data"); - $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ + $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; \ + replyto=($Message->"message_id"); threadid=$ThreadId; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Command . "\n\n" . \ $State . [ $IfThenElse ([ :len $Content ] > 0) \ @@ -159,7 +162,8 @@ $RmDir "tmpfs/telegram-chat"; } else={ $LogPrint info $ScriptName ("The command from update " . $UpdateID . " failed syntax validation!"); - $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ + $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; \ + replyto=($Message->"message_id"); threadid=$ThreadId; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Command . "\n\n" . \ [ $SymbolForNotification "cross-mark" ] . "The command failed syntax validation!") }); @@ -171,7 +175,8 @@ " (ID " . $From->"id" . ") in update " . $UpdateID . "!"); :if ($Command ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ $LogPrint warning $ScriptName $MessageText; - $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ + $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; \ + replyto=($Message->"message_id"); threadid=$ThreadId; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ message=("You are not trusted.") }); } else={ From e5de9de391283f64763ad16446fa2f6727191306 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 25 Feb 2025 12:19:49 +0100 Subject: [PATCH 2575/2612] notify on support for Telegram group topics --- global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 99e52f8..42782bc 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -15,7 +15,7 @@ # Git commit id & info, expected configuration version :global CommitId "unknown"; :global CommitInfo "unknown"; -:global ExpectedConfigVersion 133; +:global ExpectedConfigVersion 134; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 6f9e96e..a735ff7 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -58,6 +58,7 @@ 131="Enhanced certificate download to fallback to mkcert.org, so all (commonly trusted) root certificates are available now."; 132="Split off plugins from 'check-health', so the script works on all devices to monitor CPU and RAM. The supported plugins for sensors in hardware are installed automatically."; 133="Updated the default configuration for 'fw-addr-lists', deprecated lists were removed, a collective list was added."; + 134="Enhanced 'mod/notification-telegram' and 'telegram-chat' to support topics in groups."; }; # Migration steps to be applied on script updates From c33eb41c9cfb73e7e5b5ec7a3c37aa9e92ebc9cb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 18 Dec 2024 17:50:56 +0100 Subject: [PATCH 2576/2612] global-functions: $DeviceInfo: add license level, re-order --- global-functions.rsc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 42782bc..b3166dc 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -309,16 +309,19 @@ ([ $FormatLine "Location" ($Snmp->"location") ] . "\n") ] . \ [ $IfThenElse ([ :len ($Snmp->"contact") ] > 0) \ ([ $FormatLine "Contact" ($Snmp->"contact") ] . "\n") ] . \ - [ $FormatLine "Board name" ($Resource->"board-name") ] . "\n" . \ - [ $FormatLine "Architecture" ($Resource->"architecture-name") ] . "\n" . \ + "Hardware:\n" . \ + [ $FormatLine " Board" ($Resource->"board-name") ] . "\n" . \ + [ $FormatLine " Arch" ($Resource->"architecture-name") ] . "\n" . \ [ $IfThenElse ($RouterBoard->"routerboard" = true) \ - ([ $FormatLine "Model" ($RouterBoard->"model") ] . \ + ([ $FormatLine " Model" ($RouterBoard->"model") ] . \ [ $IfThenElse ([ :len ($RouterBoard->"revision") ] > 0) \ (" " . $RouterBoard->"revision") ] . "\n" . \ - [ $FormatLine "Serial number" ($RouterBoard->"serial-number") ] . "\n") ] . \ - [ $IfThenElse ([ :len ($License->"level") ] > 0) \ - ([ $FormatLine "License" ($License->"level") ] . "\n") ] . \ + [ $FormatLine " Serial" ($RouterBoard->"serial-number") ] . "\n") ] . \ + [ $IfThenElse ([ :len ($License->"nlevel") ] > 0) \ + ([ $FormatLine " License" ("level " . ($License->"nlevel")) ] . "\n") ] . \ "RouterOS:\n" . \ + [ $IfThenElse ([ :len ($License->"level") ] > 0) \ + ([ $FormatLine " License" ("level " . ($License->"level")) ] . "\n") ] . \ [ $FormatLine " Channel" ($Update->"channel") ] . "\n" . \ [ $FormatLine " Installed" ($Update->"installed-version") ] . "\n" . \ [ $IfThenElse ([ :typeof ($Update->"latest-version") ] != "nothing" && \ From 4eafcaa3ace2be0f17618c90c0d320647dfd8e38 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 25 Feb 2025 21:26:52 +0100 Subject: [PATCH 2577/2612] telegram-chat: say hello when awaiting commands --- telegram-chat.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index 07e3816..5db4860 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -119,7 +119,8 @@ $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; \ replyto=($Message->"message_id"); threadid=$ThreadId; \ subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("Online" . [ $IfThenElse $TelegramChatActive " (and active!)" ] . ", awaiting your commands!") }); + message=([ $IfThenElse ([ :len ($From->"first_name") ] > 0) ("Hello " . ($From->"first_name") . "!\n\n") ] . \ + "Online" . [ $IfThenElse $TelegramChatActive " (and active!)" ] . ", awaiting your commands!") }); :set Done true; } :if ($Done = false && [ :pick $Command 0 1 ] = "!") do={ From 53b13b295af835658dc4ef6192624b2ae898bab1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 25 Feb 2025 21:33:08 +0100 Subject: [PATCH 2578/2612] mod/notification-telegram: introduce $GetTelegramChatId --- .../notification-telegram.d/getchatid.avif | Bin 0 -> 3896 bytes doc/mod/notification-telegram.md | 24 ++++++++----- global-functions.rsc | 2 +- mod/notification-telegram.rsc | 34 ++++++++++++++++++ news-and-changes.rsc | 1 + 5 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 doc/mod/notification-telegram.d/getchatid.avif diff --git a/doc/mod/notification-telegram.d/getchatid.avif b/doc/mod/notification-telegram.d/getchatid.avif new file mode 100644 index 0000000000000000000000000000000000000000..779296915de91a9b21e2f05685e34a1539d9c73e GIT binary patch literal 3896 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 â„šī¸ **Info**: Copy relevant configuration from @@ -54,9 +61,10 @@ reload the configuration. ### Notifications to a group -Sending notifications to a group is possible as well. Add your bot and the -*GetIDs Bot* to a group, then use the group's id (which starts with a dash) -for `TelegramChatId`. Then remove *GetIDs Bot* from group. +Sending notifications to a group is possible as well. Add your bot to a group +and make it an admin (required for read access!) and send a message and run +`$GetTelegramChatId` again. Then use that chat id (which starts with a dash) +for `TelegramChatId`. Groups can enable the `Topics` feature. Use `TelegramThreadId` to send to a specific topic in a group. diff --git a/global-functions.rsc b/global-functions.rsc index b3166dc..43cd7f0 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -15,7 +15,7 @@ # Git commit id & info, expected configuration version :global CommitId "unknown"; :global CommitInfo "unknown"; -:global ExpectedConfigVersion 134; +:global ExpectedConfigVersion 135; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index d04893f..7782fcf 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -10,6 +10,7 @@ # https://rsc.eworm.de/doc/mod/notification-telegram.md :global FlushTelegramQueue; +:global GetTelegramChatId; :global NotificationFunctions; :global PurgeTelegramQueue; :global SendTelegram; @@ -58,6 +59,39 @@ :global ExitError; $ExitError false $0; } } +# get the chat id +:set GetTelegramChatId do={ :do { + :global TelegramTokenId; + + :global CertificateAvailable; + :global LogPrint; + + :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={ + $LogPrint warning $0 ("Downloading required certificate failed."); + :return false; + } + + :local Data; + :do { + :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ + ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=0" . \ + "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); + } on-error={ + $LogPrint warning $0 ("Fetching data failed!"); + :return false; + } + + :local JSON [ :deserialize from=json value=$Data ]; + :foreach Update in=($JSON->"result") do={ + $LogPrint info $0 ("The chat id is: " . ($Update->"message"->"chat"->"id")); + :return true; + } + + $LogPrint info $0 ("No message received."); +} on-error={ + :global ExitError; $ExitError false $0; +} } + # send notification via telegram - expects one array argument :set ($NotificationFunctions->"telegram") do={ :local Notification $1; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index a735ff7..459326f 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -59,6 +59,7 @@ 132="Split off plugins from 'check-health', so the script works on all devices to monitor CPU and RAM. The supported plugins for sensors in hardware are installed automatically."; 133="Updated the default configuration for 'fw-addr-lists', deprecated lists were removed, a collective list was added."; 134="Enhanced 'mod/notification-telegram' and 'telegram-chat' to support topics in groups."; + 135="Introduced helper function '\$GetTelegramChatId' for 'mod/notification-telegram' which helps retrieve information."; }; # Migration steps to be applied on script updates From f6c2225f68fae8494d620dca0fc41b50a0450977 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2025 13:37:57 +0100 Subject: [PATCH 2579/2612] check-certificates: catch and ignore import error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hmm... 🤨 When was that runtime error introduced? I *think* it worked before. --- check-certificates.rsc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 0907395..94f23a7 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -59,10 +59,12 @@ :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; - } + :do { + :local Result [ /certificate/import file-name=$CertFileName passphrase=$PassPhrase as-value ]; + :if ($Result->"decryption-failures" = 0) do={ + :set DecryptionFailed false; + } + } on-error={ } } $RmFile $CertFileName; From a6d4e7e82cc9870c6cfd1e0ee9724eb6129ce5ab Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2025 18:03:17 +0100 Subject: [PATCH 2580/2612] check-certificates: drop dot from type... ... and add it in file name. --- check-certificates.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 94f23a7..20ac2e2 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -50,8 +50,8 @@ :local Return false; - :foreach Type in={ ".pem"; ".p12" } do={ - :local CertFileName ([ $UrlEncode $FetchName ] . $Type); + :foreach Type in={ "pem"; "p12" } do={ + :local CertFileName ([ $UrlEncode $FetchName ] . "." . $Type); :do { /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) \ ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; From 3d40b4419d47f41edf5059c00c1ab575f49c6da1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2025 13:40:12 +0100 Subject: [PATCH 2581/2612] check-certificates: add more debug output --- check-certificates.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 20ac2e2..6862015 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -58,10 +58,12 @@ $WaitForFile $CertFileName; :local DecryptionFailed true; - :foreach PassPhrase in=$CertRenewPass do={ + :foreach I,PassPhrase in=$CertRenewPass do={ :do { + $LogPrint debug $ScriptName ("Trying " . $I . ". passphrase... "); :local Result [ /certificate/import file-name=$CertFileName passphrase=$PassPhrase as-value ]; :if ($Result->"decryption-failures" = 0) do={ + $LogPrint debug $ScriptName ("Success!"); :set DecryptionFailed false; } } on-error={ } From 512c54bd590503af27e754c5c65c34b5307cf9c9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2025 13:55:09 +0100 Subject: [PATCH 2582/2612] check-certificates: ... and even more --- check-certificates.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/check-certificates.rsc b/check-certificates.rsc index 6862015..6dff9ba 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -52,6 +52,9 @@ :foreach Type in={ "pem"; "p12" } do={ :local CertFileName ([ $UrlEncode $FetchName ] . "." . $Type); + $LogPrint debug $ScriptName ("Trying type '" . $Type . "' for '" . $CertName . \ + "' (file '" . $CertFileName . "')..."); + :do { /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) \ ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; From e833dfcf25175fb1d5c652dcf898c6332ce70404 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2025 13:51:25 +0100 Subject: [PATCH 2583/2612] check-certificates: simplify return from function... ... and also break earch on success. --- check-certificates.rsc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 6dff9ba..5065c33 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -48,8 +48,6 @@ :global UrlEncode; :global WaitForFile; - :local Return false; - :foreach Type in={ "pem"; "p12" } do={ :local CertFileName ([ $UrlEncode $FetchName ] . "." . $Type); $LogPrint debug $ScriptName ("Trying type '" . $Type . "' for '" . $CertName . \ @@ -84,13 +82,13 @@ $CertificateNameByCN [ /certificate/get $CertInChain common-name ]; } - :set Return true; + :return true; } on-error={ $LogPrint debug $ScriptName ("Could not download certificate file '" . $CertFileName . "'."); } } - :return $Return; + :return false; } :local FormatInfo do={ From 14195c51ca381063789ca58c760d70037328e600 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2025 18:25:58 +0100 Subject: [PATCH 2584/2612] check-certificates: try PKCS#12 before PEM... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... as that is more likely to have a private key. Is that true? 🤨 --- check-certificates.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-certificates.rsc b/check-certificates.rsc index 5065c33..be8e4df 100644 --- a/check-certificates.rsc +++ b/check-certificates.rsc @@ -48,7 +48,7 @@ :global UrlEncode; :global WaitForFile; - :foreach Type in={ "pem"; "p12" } do={ + :foreach Type in={ "p12"; "pem" } do={ :local CertFileName ([ $UrlEncode $FetchName ] . "." . $Type); $LogPrint debug $ScriptName ("Trying type '" . $Type . "' for '" . $CertName . \ "' (file '" . $CertFileName . "')..."); From b11be59b0824efac6df128fde46a529ced14a2d0 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 27 Feb 2025 10:44:53 +0100 Subject: [PATCH 2585/2612] README: quote the certificate file name --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a76d50f..fae6986 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ file to your MikroTik device. Then we import the certificate. - /certificate/import file-name=isrg-root-x2.pem passphrase=""; + /certificate/import file-name="isrg-root-x2.pem" passphrase=""; Do not worry that the command is not shown - that happens because it contains a sensitive property, the passphrase. From e2fe653035ca2217dc56235de780f72dbb790e1d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2025 20:16:12 +0100 Subject: [PATCH 2586/2612] mod/notification-telegram: $GetTelegramChatId: use last message --- mod/notification-telegram.rsc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 7782fcf..4528615 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -82,12 +82,15 @@ } :local JSON [ :deserialize from=json value=$Data ]; - :foreach Update in=($JSON->"result") do={ - $LogPrint info $0 ("The chat id is: " . ($Update->"message"->"chat"->"id")); - :return true; + :local Count [ :len ($JSON->"result") ]; + + :if ($Count = 0) do={ + $LogPrint info $0 ("No message received."); + :return false; } - $LogPrint info $0 ("No message received."); + :local Message ($JSON->"result"->($Count - 1)->"message"); + $LogPrint info $0 ("The chat id is: " . ($Message->"chat"->"id")); } on-error={ :global ExitError; $ExitError false $0; } } From f5189b8bd7ca01fb6e26414960764960a03066c4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 27 Feb 2025 10:45:30 +0100 Subject: [PATCH 2587/2612] INITIAL-COMMANDS: quote the certificate file name --- INITIAL-COMMANDS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 424ef32..8b64d28 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -19,7 +19,7 @@ Run the complete base installation: { /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/ISRG-Root-X2.pem" dst-path="isrg-root-x2.pem" as-value; :delay 1s; - /certificate/import file-name=isrg-root-x2.pem passphrase=""; + /certificate/import file-name="isrg-root-x2.pem" passphrase=""; :if ([ :len [ /certificate/find where fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470" ] ] != 1) do={ :error "Something is wrong with your certificates!"; }; From 0c4fb42616f8015dd128ec7df1d1afce590d26ed Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 26 Feb 2025 20:18:12 +0100 Subject: [PATCH 2588/2612] mod/notification-telegram: $GetTelegramChatId: give thead id... ... if message was sent to group's topic. --- mod/notification-telegram.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 4528615..68e913f 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -91,6 +91,9 @@ :local Message ($JSON->"result"->($Count - 1)->"message"); $LogPrint info $0 ("The chat id is: " . ($Message->"chat"->"id")); + :if (($Message->"is_topic_message") = true) do={ + $LogPrint info $0 ("The thread id is: " . ($Message->"message_thread_id")); + } } on-error={ :global ExitError; $ExitError false $0; } } From 33c02e06092eded4b3344a6eb22742c9be531fb2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 3 Mar 2025 09:10:54 +0100 Subject: [PATCH 2589/2612] ipv6-update: ignore if prefix is no longer valid --- ipv6-update.rsc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ipv6-update.rsc b/ipv6-update.rsc index c6e3d65..beccde0 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -20,7 +20,9 @@ :global ScriptLock; :local NaAddress $"na-address"; + :local NaValid $"na-valid"; :local PdPrefix $"pd-prefix"; + :local PdValid $"pd-valid"; :if ([ $ScriptLock $ScriptName ] = false) do={ :set ExitOK true; @@ -39,6 +41,12 @@ :error false; } + :if ($PdValid != 1) do={ + $LogPrint info $ScriptName ("The prefix " . $PdPrefix . " is no longer valid. Ignoring."); + :set ExitOK true; + :error false; + } + :local Pool [ /ipv6/pool/get [ find where prefix=$PdPrefix ] name ]; :if ([ :len [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={ /ipv6/firewall/address-list/add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool) dynamic=yes; From 469f783a92c8e67088d70572157ff4cd7d47fcd8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 3 Mar 2025 09:12:43 +0100 Subject: [PATCH 2590/2612] ipv6-update: check for availability of both variables --- ipv6-update.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv6-update.rsc b/ipv6-update.rsc index beccde0..94bd1bc 100644 --- a/ipv6-update.rsc +++ b/ipv6-update.rsc @@ -35,7 +35,7 @@ :error false; } - :if ([ :typeof $PdPrefix ] = "nothing") do={ + :if ([ :typeof $PdPrefix ] = "nothing" || [ :typeof $PdValid ] = "nothing") do={ $LogPrint error $ScriptName ("This script is supposed to run from ipv6 dhcp-client."); :set ExitOK true; :error false; From 3ccaafd1b38f4335aa28361778aa37db2ca22d5f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Mar 2025 00:28:01 +0100 Subject: [PATCH 2591/2612] global-functions: $ScriptInstallUpdate: move code into block --- global-functions.rsc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 43cd7f0..8fcd56d 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1163,7 +1163,12 @@ } } - :if (!($ScriptInfo->"ignore" = true)) do={ + :do { + :if ($ScriptInfo->"ignore" = true) do={ + $LogPrint debug $0 ("Ignoring script '" . $ScriptVal->"name" . "', as requested."); + :error true; + } + :do { :local BaseUrl [ $EitherOr ($ScriptInfo->"base-url") $ScriptUpdatesBaseUrl ]; :local UrlSuffix [ $EitherOr ($ScriptInfo->"url-suffix") $ScriptUpdatesUrlSuffix ]; @@ -1182,10 +1187,9 @@ } else={ $LogPrint warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!"); } + :error false; } - } - :do { :if ([ :len $SourceNew ] = 0) do={ $LogPrint debug $0 ("No update for script '" . $ScriptVal->"name" . "'."); :error false; From 0c1d96f89dfb4d209b0848d5ac2d81a640e0f056 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Mar 2025 00:18:43 +0100 Subject: [PATCH 2592/2612] global-functions: $ScriptInstallUpdate: get and compare checksums MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The file 'checksums.json' is generated when deploying to my web server... This should speed up the update a lot as it reduces downloads to a minimum. 🎉😁 --- global-functions.rsc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 8fcd56d..8405c92 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1150,6 +1150,14 @@ :local ReloadGlobalConfig false; :local DeviceMode [ /system/device-mode/get ]; + :local CheckSums ({}); + :do { + :local Url ($ScriptUpdatesBaseUrl . "checksums.json" . $ScriptUpdatesUrlSuffix); + $LogPrint debug $0 ("Fetching checksums from url: " . $Url); + :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certificate=yes-without-crl \ + http-header-field=({ [ $FetchUserAgentStr $0 ] }) $Url output=user as-value ]->"data") ]; + } on-error={ } + :foreach Script in=[ /system/script/find where source~"^#!rsc by RouterOS\r?\n" ] do={ :local ScriptVal [ /system/script/get $Script ]; :local ScriptInfo [ $ParseKeyValueStore ($ScriptVal->"comment") ]; @@ -1169,6 +1177,11 @@ :error true; } + :if ([ :convert transform=md5 to=hex ($ScriptVal->"source") ] = ($CheckSums->($ScriptVal->"name"))) do={ + $LogPrint debug $0 ("Checksum for script '" . $ScriptVal->"name" . "' matches, ignoring."); + :error true; + } + :do { :local BaseUrl [ $EitherOr ($ScriptInfo->"base-url") $ScriptUpdatesBaseUrl ]; :local UrlSuffix [ $EitherOr ($ScriptInfo->"url-suffix") $ScriptUpdatesUrlSuffix ]; From 10374afc182cd8b08e07a3d45890518e8b6be73c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Mar 2025 01:37:42 +0100 Subject: [PATCH 2593/2612] global-functions: $ScriptInstallUpdate: support checksums for CRLF scripts --- global-functions.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 8405c92..d883aa0 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1177,7 +1177,8 @@ :error true; } - :if ([ :convert transform=md5 to=hex ($ScriptVal->"source") ] = ($CheckSums->($ScriptVal->"name"))) do={ + :if ([ :convert transform=md5 to=hex ($ScriptVal->"source") ] = ($CheckSums->($ScriptVal->"name")) || \ + [ :convert transform=md5 to=hex [ :tolf ($ScriptVal->"source") ] ] = ($CheckSums->($ScriptVal->"name"))) do={ $LogPrint debug $0 ("Checksum for script '" . $ScriptVal->"name" . "' matches, ignoring."); :error true; } From c9de6d85790897a945910316a14db16b0435c41e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Mar 2025 01:39:59 +0100 Subject: [PATCH 2594/2612] global-functions: $ScriptInstallUpdate: put checksum into variable --- global-functions.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index d883aa0..a9fa938 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1177,8 +1177,9 @@ :error true; } - :if ([ :convert transform=md5 to=hex ($ScriptVal->"source") ] = ($CheckSums->($ScriptVal->"name")) || \ - [ :convert transform=md5 to=hex [ :tolf ($ScriptVal->"source") ] ] = ($CheckSums->($ScriptVal->"name"))) do={ + :local CheckSum ($CheckSums->($ScriptVal->"name")); + :if ([ :convert transform=md5 to=hex ($ScriptVal->"source") ] = $CheckSum || \ + [ :convert transform=md5 to=hex [ :tolf ($ScriptVal->"source") ] ] = $CheckSum) do={ $LogPrint debug $0 ("Checksum for script '" . $ScriptVal->"name" . "' matches, ignoring."); :error true; } From b13360e4b86838d95cd8c9a1a4e2ea8d757dbb0f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Mar 2025 01:53:04 +0100 Subject: [PATCH 2595/2612] global-functions: $ScriptInstallUpdate: simplify check This one should suffice... --- global-functions.rsc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index a9fa938..4c777a1 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1178,8 +1178,7 @@ } :local CheckSum ($CheckSums->($ScriptVal->"name")); - :if ([ :convert transform=md5 to=hex ($ScriptVal->"source") ] = $CheckSum || \ - [ :convert transform=md5 to=hex [ :tolf ($ScriptVal->"source") ] ] = $CheckSum) do={ + :if ([ :convert transform=md5 to=hex [ :tolf ($ScriptVal->"source") ] ] = $CheckSum) do={ $LogPrint debug $0 ("Checksum for script '" . $ScriptVal->"name" . "' matches, ignoring."); :error true; } From 1b46a5fd9bc69f4d609b28e7ff8d36717a3b9a8f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 5 Mar 2025 08:55:06 +0100 Subject: [PATCH 2596/2612] global-functions: $ScriptInstallUpdate: checksum only for same source So ignore if script is fetched from different base or with different suffix. --- global-functions.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 4c777a1..da31165 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1178,7 +1178,8 @@ } :local CheckSum ($CheckSums->($ScriptVal->"name")); - :if ([ :convert transform=md5 to=hex [ :tolf ($ScriptVal->"source") ] ] = $CheckSum) do={ + :if ([ :len ($ScriptInfo->"base-url") ] = 0 && [ :len ($ScriptInfo->"url-suffix") ] = 0 && \ + [ :convert transform=md5 to=hex [ :tolf ($ScriptVal->"source") ] ] = $CheckSum) do={ $LogPrint debug $0 ("Checksum for script '" . $ScriptVal->"name" . "' matches, ignoring."); :error true; } From e341e1c30ca4ff8b87bc757cc5c0effbc50a7ea6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Mar 2025 15:02:31 +0100 Subject: [PATCH 2597/2612] global-functions: introduce $LogPrintVerbose ... ... which is a declared function, but has no code, intentionally. It can be called as a no-op by default. If you want this output set the function to be the same as $LogPrint: :set LogPrintVerbose $LogPrint; --- global-functions.rsc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index da31165..911ff6a 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -55,6 +55,7 @@ :global IsTimeSync; :global LogPrint; :global LogPrintOnce; +:global LogPrintVerbose; :global MAX; :global MIN; :global MkDir; @@ -848,6 +849,8 @@ :return true; } +# The function $LogPrintVerbose is declared, but has no code, intentionally. + # get max value :set MAX do={ :if ($1 > $2) do={ :return $1; } From 6d718ec9877c3ecfc10681e85d050d15ed4d4b80 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Mar 2025 14:38:35 +0100 Subject: [PATCH 2598/2612] fw-addr-lists: use $LogPrintVerbose ... ... to reduce debug output and speed up execution. --- fw-addr-lists.rsc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index d41dc04..af8c65d 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -24,6 +24,7 @@ :global HumanReadableNum; :global LogPrint; :global LogPrintOnce; + :global LogPrintVerbose; :global ScriptLock; :global WaitFullyConnected; @@ -120,14 +121,14 @@ list=$FwListName comment=$ListComment ] do={ :local Address [ /ip/firewall/address-list/get $Entry address ]; :if ([ :typeof ($IPv4Addresses->$Address) ] = "time") do={ - $LogPrint debug $ScriptName ("Renewing IPv4 address in list '" . $FwListName . \ + $LogPrintVerbose debug $ScriptName ("Renewing IPv4 address in list '" . $FwListName . \ "' with " . ($IPv4Addresses->$Address) . ": " . $Address); /ip/firewall/address-list/set $Entry timeout=($IPv4Addresses->$Address); :set ($IPv4Addresses->$Address); :set CntRenew ($CntRenew + 1); } else={ :if ($Failure = false) do={ - $LogPrint debug $ScriptName ("Removing IPv4 address from list '" . $FwListName . \ + $LogPrintVerbose debug $ScriptName ("Removing IPv4 address from list '" . $FwListName . \ "': " . $Address); /ip/firewall/address-list/remove $Entry; :set CntRemove ($CntRemove + 1); @@ -139,14 +140,14 @@ list=$FwListName comment=$ListComment ] do={ :local Address [ /ipv6/firewall/address-list/get $Entry address ]; :if ([ :typeof ($IPv6Addresses->$Address) ] = "time") do={ - $LogPrint debug $ScriptName ("Renewing IPv6 address in list '" . $FwListName . \ + $LogPrintVerbose debug $ScriptName ("Renewing IPv6 address in list '" . $FwListName . \ "' with " . ($IPv6Addresses->$Address) . ": " . $Address); /ipv6/firewall/address-list/set $Entry timeout=($IPv6Addresses->$Address); :set ($IPv6Addresses->$Address); :set CntRenew ($CntRenew + 1); } else={ :if ($Failure = false) do={ - $LogPrint debug $ScriptName ("Removing IPv6 address from list '" . $FwListName . \ + $LogPrintVerbose debug $ScriptName ("Removing IPv6 address from list '" . $FwListName . \ "': " . $Address); /ipv6/firewall/address-list/remove $Entry; :set CntRemove ($CntRemove + 1); @@ -155,7 +156,7 @@ } :foreach Address,Timeout in=$IPv4Addresses do={ - $LogPrint debug $ScriptName ("Adding IPv4 address to list '" . $FwListName . \ + $LogPrintVerbose debug $ScriptName ("Adding IPv4 address to list '" . $FwListName . \ "' with " . $Timeout . ": " . $Address); :do { /ip/firewall/address-list/add list=$FwListName comment=$ListComment \ @@ -169,7 +170,7 @@ } :foreach Address,Timeout in=$IPv6Addresses do={ - $LogPrint debug $ScriptName ("Adding IPv6 address to list '" . $FwListName . \ + $LogPrintVerbose debug $ScriptName ("Adding IPv6 address to list '" . $FwListName . \ "' with " . $Timeout . ": " . $Address); :do { /ipv6/firewall/address-list/add list=$FwListName comment=$ListComment \ From 7be26a07125b9c946859560bd59323f84feb9494 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Mar 2025 14:54:38 +0100 Subject: [PATCH 2599/2612] DEBUG: add info on $LogPrintVerbose --- DEBUG.md | 14 ++++++++++++++ global-functions.rsc | 1 + 2 files changed, 15 insertions(+) diff --git a/DEBUG.md b/DEBUG.md index 3d7f025..d5e9beb 100644 --- a/DEBUG.md +++ b/DEBUG.md @@ -44,6 +44,20 @@ instead. Disable or remote that setting to restore regular logging. +## Verbose output + +Specific scripts can generate huge amount of output. These do use a function +`$LogPrintVerbose`, which is declared, but has no code, intentionally. + +If you *really* want that output set the function to be the same as +`$LogPrint`: + + :set LogPrintVerbose $LogPrint; + +To revert that change just run: + + :set LogPrintVerbose; + --- [âŦ…ī¸ Go back to main README](README.md) [âŦ†ī¸ Go back to top](#top) diff --git a/global-functions.rsc b/global-functions.rsc index 911ff6a..8ae7bb8 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -850,6 +850,7 @@ } # The function $LogPrintVerbose is declared, but has no code, intentionally. +# https://rsc.eworm.de/DEBUG.md#verbose-output # get max value :set MAX do={ From fb343c99e399d679f3e2a22e76c14a5899024319 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Mar 2025 22:59:31 +0100 Subject: [PATCH 2600/2612] fw-addr-lists: put timeout into variable --- fw-addr-lists.rsc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index af8c65d..331d2c6 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -120,10 +120,11 @@ :foreach Entry in=[ /ip/firewall/address-list/find where \ list=$FwListName comment=$ListComment ] do={ :local Address [ /ip/firewall/address-list/get $Entry address ]; - :if ([ :typeof ($IPv4Addresses->$Address) ] = "time") do={ + :local TimeOut ($IPv4Addresses->$Address); + :if ([ :typeof $TimeOut ] = "time") do={ $LogPrintVerbose debug $ScriptName ("Renewing IPv4 address in list '" . $FwListName . \ - "' with " . ($IPv4Addresses->$Address) . ": " . $Address); - /ip/firewall/address-list/set $Entry timeout=($IPv4Addresses->$Address); + "' with " . $TimeOut . ": " . $Address); + /ip/firewall/address-list/set $Entry timeout=$TimeOut; :set ($IPv4Addresses->$Address); :set CntRenew ($CntRenew + 1); } else={ @@ -139,10 +140,11 @@ :foreach Entry in=[ /ipv6/firewall/address-list/find where \ list=$FwListName comment=$ListComment ] do={ :local Address [ /ipv6/firewall/address-list/get $Entry address ]; - :if ([ :typeof ($IPv6Addresses->$Address) ] = "time") do={ + :local TimeOut ($IPv6Addresses->$Address); + :if ([ :typeof $TimeOut ] = "time") do={ $LogPrintVerbose debug $ScriptName ("Renewing IPv6 address in list '" . $FwListName . \ - "' with " . ($IPv6Addresses->$Address) . ": " . $Address); - /ipv6/firewall/address-list/set $Entry timeout=($IPv6Addresses->$Address); + "' with " . $TimeOut . ": " . $Address); + /ipv6/firewall/address-list/set $Entry timeout=$TimeOut; :set ($IPv6Addresses->$Address); :set CntRenew ($CntRenew + 1); } else={ From ea6de35699a5b62dfffcc583c1a7181e1a6a688f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Mar 2025 23:00:50 +0100 Subject: [PATCH 2601/2612] fw-addr-lists: do not clean up Cleanup is important on renew (so the script does not attempt to re-add), but we do not care here. --- fw-addr-lists.rsc | 2 -- 1 file changed, 2 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 331d2c6..70893e3 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -163,7 +163,6 @@ :do { /ip/firewall/address-list/add list=$FwListName comment=$ListComment \ address=$Address timeout=$Timeout; - :set ($IPv4Addresses->$Address); :set CntAdd ($CntAdd + 1); } on-error={ $LogPrint warning $ScriptName ("Failed to add IPv4 address to list '" . $FwListName . \ @@ -177,7 +176,6 @@ :do { /ipv6/firewall/address-list/add list=$FwListName comment=$ListComment \ address=$Address timeout=$Timeout; - :set ($IPv6Addresses->$Address); :set CntAdd ($CntAdd + 1); } on-error={ $LogPrint warning $ScriptName ("Failed to add IPv6 address to list '" . $FwListName . \ From 2f55bfaf009d726e1174b50887fdb8f9b4b57573 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Mar 2025 12:21:22 +0100 Subject: [PATCH 2602/2612] fw-addr-lists: strip cidr for host addresses This makes sure the addresses match later when we read them from address-list for renew. --- fw-addr-lists.rsc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 70893e3..fc53795 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -101,10 +101,16 @@ } :do { :if ($Address ~ "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(/[0-9]{1,2})?\$") do={ + :if ($Address ~ "/32\$") do={ + :set Address [ :pick $Address 0 ([ :len $Address ] - 3) ]; + } :set ($IPv4Addresses->$Address) $TimeOut; :error true; } :if ($Address ~ "^[0-9a-zA-Z]*:[0-9a-zA-Z:\\.]+(/[0-9]{1,3})?\$") do={ + :if ($Address ~ "/128\$") do={ + :set Address [ :pick $Address 0 ([ :len $Address ] - 4) ]; + } :set ($IPv6Addresses->$Address) $TimeOut; :error true; } From e148df9e573801803e35d8dfaef277f571952fdc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Mar 2025 23:05:45 +0100 Subject: [PATCH 2603/2612] fw-addr-lists: put addresses into "branches"... ... effectively adding another layer and some complexity, but: The addresses are sorted inside the array, and sorting less addresses in a branch saves a lot of processing power. So this is a lot faster now... --- fw-addr-lists.rsc | 65 +++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index fc53795..a97f7ed 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -100,23 +100,24 @@ :set Address ([ :pick $Line 0 [ $FindDelim $Line ] ] . ($List->"cidr")); } :do { + :local Branch [ :pick $Address 0 1 ]; :if ($Address ~ "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(/[0-9]{1,2})?\$") do={ :if ($Address ~ "/32\$") do={ :set Address [ :pick $Address 0 ([ :len $Address ] - 3) ]; } - :set ($IPv4Addresses->$Address) $TimeOut; + :set ($IPv4Addresses->$Branch->$Address) $TimeOut; :error true; } :if ($Address ~ "^[0-9a-zA-Z]*:[0-9a-zA-Z:\\.]+(/[0-9]{1,3})?\$") do={ :if ($Address ~ "/128\$") do={ :set Address [ :pick $Address 0 ([ :len $Address ] - 4) ]; } - :set ($IPv6Addresses->$Address) $TimeOut; + :set ($IPv6Addresses->$Branch->$Address) $TimeOut; :error true; } :if ($Address ~ "^[\\.a-zA-Z0-9-]+\\.[a-zA-Z]{2,}\$") do={ - :set ($IPv4Addresses->$Address) $TimeOut; - :set ($IPv6Addresses->$Address) $TimeOut; + :set ($IPv4Addresses->$Branch->$Address) $TimeOut; + :set ($IPv6Addresses->$Branch->$Address) $TimeOut; :error true; } } on-error={ } @@ -126,12 +127,13 @@ :foreach Entry in=[ /ip/firewall/address-list/find where \ list=$FwListName comment=$ListComment ] do={ :local Address [ /ip/firewall/address-list/get $Entry address ]; - :local TimeOut ($IPv4Addresses->$Address); + :local Branch [ :pick $Address 0 1 ]; + :local TimeOut ($IPv4Addresses->$Branch->$Address); :if ([ :typeof $TimeOut ] = "time") do={ $LogPrintVerbose debug $ScriptName ("Renewing IPv4 address in list '" . $FwListName . \ "' with " . $TimeOut . ": " . $Address); /ip/firewall/address-list/set $Entry timeout=$TimeOut; - :set ($IPv4Addresses->$Address); + :set ($IPv4Addresses->$Branch->$Address); :set CntRenew ($CntRenew + 1); } else={ :if ($Failure = false) do={ @@ -146,12 +148,13 @@ :foreach Entry in=[ /ipv6/firewall/address-list/find where \ list=$FwListName comment=$ListComment ] do={ :local Address [ /ipv6/firewall/address-list/get $Entry address ]; - :local TimeOut ($IPv6Addresses->$Address); + :local Branch [ :pick $Address 0 1 ]; + :local TimeOut ($IPv6Addresses->$Branch->$Address); :if ([ :typeof $TimeOut ] = "time") do={ $LogPrintVerbose debug $ScriptName ("Renewing IPv6 address in list '" . $FwListName . \ "' with " . $TimeOut . ": " . $Address); /ipv6/firewall/address-list/set $Entry timeout=$TimeOut; - :set ($IPv6Addresses->$Address); + :set ($IPv6Addresses->$Branch->$Address); :set CntRenew ($CntRenew + 1); } else={ :if ($Failure = false) do={ @@ -163,29 +166,35 @@ } } - :foreach Address,Timeout in=$IPv4Addresses do={ - $LogPrintVerbose debug $ScriptName ("Adding IPv4 address to list '" . $FwListName . \ - "' with " . $Timeout . ": " . $Address); - :do { - /ip/firewall/address-list/add list=$FwListName comment=$ListComment \ - address=$Address timeout=$Timeout; - :set CntAdd ($CntAdd + 1); - } on-error={ - $LogPrint warning $ScriptName ("Failed to add IPv4 address to list '" . $FwListName . \ - "': " . $Address); + :foreach BranchName,Branch in=$IPv4Addresses do={ + $LogPrintVerbose debug $ScriptName ("Handling branch: " . $BranchName); + :foreach Address,Timeout in=$Branch do={ + $LogPrintVerbose debug $ScriptName ("Adding IPv4 address to list '" . $FwListName . \ + "' with " . $Timeout . ": " . $Address); + :do { + /ip/firewall/address-list/add list=$FwListName comment=$ListComment \ + address=$Address timeout=$Timeout; + :set CntAdd ($CntAdd + 1); + } on-error={ + $LogPrint warning $ScriptName ("Failed to add IPv4 address to list '" . $FwListName . \ + "': " . $Address); + } } } - :foreach Address,Timeout in=$IPv6Addresses do={ - $LogPrintVerbose debug $ScriptName ("Adding IPv6 address to list '" . $FwListName . \ - "' with " . $Timeout . ": " . $Address); - :do { - /ipv6/firewall/address-list/add list=$FwListName comment=$ListComment \ - address=$Address timeout=$Timeout; - :set CntAdd ($CntAdd + 1); - } on-error={ - $LogPrint warning $ScriptName ("Failed to add IPv6 address to list '" . $FwListName . \ - "': " . $Address); + :foreach BranchName,Branch in=$IPv6Addresses do={ + $LogPrintVerbose debug $ScriptName ("Handling branch: " . $BranchName); + :foreach Address,Timeout in=$Branch do={ + $LogPrintVerbose debug $ScriptName ("Adding IPv6 address to list '" . $FwListName . \ + "' with " . $Timeout . ": " . $Address); + :do { + /ipv6/firewall/address-list/add list=$FwListName comment=$ListComment \ + address=$Address timeout=$Timeout; + :set CntAdd ($CntAdd + 1); + } on-error={ + $LogPrint warning $ScriptName ("Failed to add IPv6 address to list '" . $FwListName . \ + "': " . $Address); + } } } From d71ea804b077d35183df318fb305b213fb961d27 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Mar 2025 20:35:36 +0100 Subject: [PATCH 2604/2612] fw-addr-lists: two characters for branch Using one character for IPv4 is ok (1 to 9), but IPv6 global unicase (2000::/3) results in just two different characters (2 and 3). So let's use first two characters... --- fw-addr-lists.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index a97f7ed..9ad5b3a 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -100,7 +100,7 @@ :set Address ([ :pick $Line 0 [ $FindDelim $Line ] ] . ($List->"cidr")); } :do { - :local Branch [ :pick $Address 0 1 ]; + :local Branch [ :pick $Address 0 2 ]; :if ($Address ~ "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(/[0-9]{1,2})?\$") do={ :if ($Address ~ "/32\$") do={ :set Address [ :pick $Address 0 ([ :len $Address ] - 3) ]; @@ -127,7 +127,7 @@ :foreach Entry in=[ /ip/firewall/address-list/find where \ list=$FwListName comment=$ListComment ] do={ :local Address [ /ip/firewall/address-list/get $Entry address ]; - :local Branch [ :pick $Address 0 1 ]; + :local Branch [ :pick $Address 0 2 ]; :local TimeOut ($IPv4Addresses->$Branch->$Address); :if ([ :typeof $TimeOut ] = "time") do={ $LogPrintVerbose debug $ScriptName ("Renewing IPv4 address in list '" . $FwListName . \ @@ -148,7 +148,7 @@ :foreach Entry in=[ /ipv6/firewall/address-list/find where \ list=$FwListName comment=$ListComment ] do={ :local Address [ /ipv6/firewall/address-list/get $Entry address ]; - :local Branch [ :pick $Address 0 1 ]; + :local Branch [ :pick $Address 0 2 ]; :local TimeOut ($IPv6Addresses->$Branch->$Address); :if ([ :typeof $TimeOut ] = "time") do={ $LogPrintVerbose debug $ScriptName ("Renewing IPv6 address in list '" . $FwListName . \ From f0e6cbcfe1a0be05f30d37cd495d4dbea0888f07 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 8 Mar 2025 10:09:51 +0100 Subject: [PATCH 2605/2612] fw-addr-lists: get branch from calculated checksum The addresses were spread very uneven before. Let's calculate a checksum, and take the first two characters of that. The addresses are now spread evenly on 256 branches (0x00 to 0xff). --- fw-addr-lists.rsc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 9ad5b3a..f0940fe 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -37,6 +37,11 @@ } } + :local GetBranch do={ + :global EitherOr; + :return [ :pick [ :convert transform=md5 to=hex [ :pick $1 0 [ $EitherOr [ :find $1 "/" ] [ :len $1 ] ] ] ] 0 2 ]; + } + :if ([ $ScriptLock $ScriptName ] = false) do={ :set ExitOK true; :error false; @@ -100,7 +105,7 @@ :set Address ([ :pick $Line 0 [ $FindDelim $Line ] ] . ($List->"cidr")); } :do { - :local Branch [ :pick $Address 0 2 ]; + :local Branch [ $GetBranch $Address ]; :if ($Address ~ "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(/[0-9]{1,2})?\$") do={ :if ($Address ~ "/32\$") do={ :set Address [ :pick $Address 0 ([ :len $Address ] - 3) ]; @@ -127,7 +132,7 @@ :foreach Entry in=[ /ip/firewall/address-list/find where \ list=$FwListName comment=$ListComment ] do={ :local Address [ /ip/firewall/address-list/get $Entry address ]; - :local Branch [ :pick $Address 0 2 ]; + :local Branch [ $GetBranch $Address ]; :local TimeOut ($IPv4Addresses->$Branch->$Address); :if ([ :typeof $TimeOut ] = "time") do={ $LogPrintVerbose debug $ScriptName ("Renewing IPv4 address in list '" . $FwListName . \ @@ -148,7 +153,7 @@ :foreach Entry in=[ /ipv6/firewall/address-list/find where \ list=$FwListName comment=$ListComment ] do={ :local Address [ /ipv6/firewall/address-list/get $Entry address ]; - :local Branch [ :pick $Address 0 2 ]; + :local Branch [ $GetBranch $Address ]; :local TimeOut ($IPv6Addresses->$Branch->$Address); :if ([ :typeof $TimeOut ] = "time") do={ $LogPrintVerbose debug $ScriptName ("Renewing IPv6 address in list '" . $FwListName . \ From eb59dd21caf8026748eada3aee137b8e3b6590b7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 7 Mar 2025 17:33:51 +0100 Subject: [PATCH 2606/2612] check-routeros-update: check perpetual license... ... as these have to be renewed and can expire. --- check-routeros-update.rsc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 361be34..8d200d2 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -66,6 +66,27 @@ :error "A reboot for update is already scheduled."; } + :local License [ /system/license/get ]; + :if ([ :typeof ($License->"deadline-at") ] = "str") do={ + :if ([ :len ($License->"next-renewal-at") ] = 0 && ($License->"limited-upgrades") = true) do={ + $LogPrint warning $ScriptName ("Your license expired on " . ($License->"deadline-at") . "!"); + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "warning-sign" ] . "License expired!"); \ + message=("Your license expired on " . ($License->"deadline-at") . \ + ", can no longer update RouterOS on " . $Identity . "...") }); + :set ExitOK true; + :error false; + } + + :if ([ :totime ($License->"next-renewal-at") ] + 1w < [ :timestamp ]) do={ + $LogPrint warning $ScriptName ("Your license will expire on " . ($License->"deadline-at") . "!"); + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "warning-sign" ] . "License about to expire!"); \ + message=("Your license failed to renew and is about to expire on " . \ + ($License->"deadline-at") . " on " . $Identity . "...") }); + } + } + $LogPrint debug $ScriptName ("Checking for updates..."); /system/package/update/check-for-updates without-paging as-value; :local Update [ /system/package/update/get ]; From 788400c4586b6a2e61c6e36acd10ab5d20da00c9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 10 Mar 2025 16:29:06 +0100 Subject: [PATCH 2607/2612] fw-addr-lists: raw.githubusercontent.com requires 'USERTrust RSA Certification Authority' now --- certs/Makefile | 2 +- .../USERTrust-RSA-Certification-Authority.pem | 41 +++++++++++++++++++ global-config.rsc | 2 +- 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 certs/USERTrust-RSA-Certification-Authority.pem diff --git a/certs/Makefile b/certs/Makefile index 4e252b4..3ccad6e 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -15,7 +15,7 @@ DOMAINS_DUAL = \ git.eworm.de/ISRG-Root-X2 \ lists.blocklist.de/Certum-Trusted-Network-CA \ matrix.org/GTS-Root-R4 \ - raw.githubusercontent.com/DigiCert-Global-Root-G2 \ + raw.githubusercontent.com/USERTrust-RSA-Certification-Authority \ rsc.eworm.de/ISRG-Root-X2 \ upgrade.mikrotik.com/ISRG-Root-X1 DOMAINS_IPV4 = \ diff --git a/certs/USERTrust-RSA-Certification-Authority.pem b/certs/USERTrust-RSA-Certification-Authority.pem new file mode 100644 index 0000000..0fbeef6 --- /dev/null +++ b/certs/USERTrust-RSA-Certification-Authority.pem @@ -0,0 +1,41 @@ +# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Label: "USERTrust RSA Certification Authority" +# Serial: 2645093764781058787591871645665788717 +# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 +# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e +# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- diff --git a/global-config.rsc b/global-config.rsc index 2524ded..fa32b16 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -103,7 +103,7 @@ # cert="ISRG Root X2" }; { url="https://raw.githubusercontent.com/stamparm/ipsum/refs/heads/master/levels/4.txt"; # # higher level (decrease the numerical value) for more addresses, and vice versa - cert="DigiCert Global Root G2" }; + cert="USERTrust RSA Certification Authority" }; { url="https://www.dshield.org/block.txt"; cidr="/24"; cert="ISRG Root X1" }; { url="https://lists.blocklist.de/lists/strongips.txt"; From 97b99316b2f96fa9c5d2f539e31aa308e86c99b4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 12 Mar 2025 10:31:11 +0100 Subject: [PATCH 2608/2612] netwatch-notify: increase timeout... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... as a timeout of one second expires immediately. 🤨 --- netwatch-notify.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 8b05c5e..9a4c9d9 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -61,12 +61,12 @@ :global GetRandom20CharAlNum; :local FwAddrList ($ScriptName . "-" . [ $GetRandom20CharAlNum ]); - /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s; + /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=2s; :delay 20ms; :if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ :return true; } - /ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s; + /ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=2s; :delay 20ms; :if ([ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ :return true; From 155542668719f9feaac45fdb786b2e5fc5fd1e71 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 12 Mar 2025 11:18:18 +0100 Subject: [PATCH 2609/2612] netwatch-notify: increase the timeout even more MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This interacts with the number of addresses in the address-list. Having a lot of addresses there (for exemple from script 'fw-addr-lists' 😜) makes the 'find' take longer. We have to make sure that 'find' succeeds before the address times out. As this does not hurt... Let's just bump to 10 seconds to be safe. --- netwatch-notify.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 9a4c9d9..2a5050c 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -61,12 +61,12 @@ :global GetRandom20CharAlNum; :local FwAddrList ($ScriptName . "-" . [ $GetRandom20CharAlNum ]); - /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=2s; + /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=10s; :delay 20ms; :if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ :return true; } - /ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=2s; + /ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=10s; :delay 20ms; :if ([ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ :return true; From b63e0fcb2fc282ac69cbef74b35bd40e8df5a464 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 12 Mar 2025 11:26:22 +0100 Subject: [PATCH 2610/2612] netwatch-notify: check matching address type only --- netwatch-notify.rsc | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc index 2a5050c..0b8a8dc 100644 --- a/netwatch-notify.rsc +++ b/netwatch-notify.rsc @@ -61,15 +61,19 @@ :global GetRandom20CharAlNum; :local FwAddrList ($ScriptName . "-" . [ $GetRandom20CharAlNum ]); - /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=10s; - :delay 20ms; - :if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ - :return true; + :if ([ :typeof [ :toip $Expected ] ] = "ip") do={ + /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=10s; + :delay 20ms; + :if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ + :return true; + } } - /ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=10s; - :delay 20ms; - :if ([ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ - :return true; + :if ([ :typeof [ :toip6 $Expected ] ] = "ip6") do={ + /ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=10s; + :delay 20ms; + :if ([ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ + :return true; + } } :return false; From 20bf609c44c2b4111bb387b36b955b8c3243fbf1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 13 Mar 2025 10:51:39 +0100 Subject: [PATCH 2611/2612] check-routeros-update: fix condition for license check Turns out that `next-renewal-at` is moved forward when renewal failed, so it never matches the criteria. Just start complaining three weeks before deadline. --- check-routeros-update.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index 8d200d2..78161e4 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -78,7 +78,7 @@ :error false; } - :if ([ :totime ($License->"next-renewal-at") ] + 1w < [ :timestamp ]) do={ + :if ([ :totime ($License->"deadline-at") ] - 3w < [ :timestamp ]) do={ $LogPrint warning $ScriptName ("Your license will expire on " . ($License->"deadline-at") . "!"); $SendNotification2 ({ origin=$ScriptName; \ subject=([ $SymbolForNotification "warning-sign" ] . "License about to expire!"); \ From ce39b79f69f978a8de521643b07b9c19de02b06f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 13 Mar 2025 11:50:38 +0100 Subject: [PATCH 2612/2612] capsman-download-packages: fix parameter for $RmFile The function can not handle ids, we have to pass a name instead. --- capsman-download-packages.capsman.rsc | 2 +- capsman-download-packages.template.rsc | 2 +- capsman-download-packages.wifi.rsc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index 4387cb1..25c43f5 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -62,7 +62,7 @@ :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ ($File->"package-architecture") $PackagePath ] = true) do={ :set Updated true; - $RmFile $Package; + $RmFile ($File->"name"); } } diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 744494e..b269838 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -64,7 +64,7 @@ :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ ($File->"package-architecture") $PackagePath ] = true) do={ :set Updated true; - $RmFile $Package; + $RmFile ($File->"name"); } } diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index a0c5e12..901bb0a 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -62,7 +62,7 @@ :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ ($File->"package-architecture") $PackagePath ] = true) do={ :set Updated true; - $RmFile $Package; + $RmFile ($File->"name"); } }