From 7d5c9679952339c8064dc34967c13d0c7779ae87 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 14 Jan 2022 07:34:50 +0100 Subject: [PATCH 0001/1786] global-config: add $ScriptUpdatesUrlSuffix in overlay for RouterOS v6 --- global-config-overlay | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global-config-overlay b/global-config-overlay index 37f78cf..63034c9 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -10,6 +10,9 @@ # Comment or remove to disable news and change notifications. :global GlobalConfigVersion 74; +# Use branch routeros-v6 with RouterOS v6: +:global ScriptUpdatesUrlSuffix "\?h=routeros-v6"; + # Copy configuration from global-config here and modify it. From ee9818e34dbdfeba3104857a54c8ec1bc6aba4ce Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 14 Jan 2022 08:55:07 +0100 Subject: [PATCH 0002/1786] global: send notification on 'routeros-v6' This is mainly to keep the version in 'routeros-v6' and 'main' in sync... --- 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 024e52f..75fbba4 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 63034c9..c443bea 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; # Use branch routeros-v6 with RouterOS v6: :global ScriptUpdatesUrlSuffix "\?h=routeros-v6"; diff --git a/global-config.changes b/global-config.changes index a070ecd..6f0e2f7 100644 --- a/global-config.changes +++ b/global-config.changes @@ -78,6 +78,7 @@ 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="You are using the branch 'routeros-v6', well done."; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 625bbe4..9579f5c 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 d03b6d9374b4f4884bfd90bfc04b1d26802d6666 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 2 Sep 2021 08:59:09 +0200 Subject: [PATCH 0003/1786] 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 0004/1786] 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 0005/1786] 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 0006/1786] 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 0007/1786] 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 0008/1786] 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 0009/1786] 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 0010/1786] 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 0011/1786] 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 0012/1786] 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 0013/1786] 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 25338ca384ddd41c4b9d3ad2a937228562043235 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 17 Jan 2022 20:15:24 +0100 Subject: [PATCH 0014/1786] global-functions: $DownloadPackage: give url in debug output (cherry picked from commit 51cd11c80380eac0bfde4649cb30747c198881b7) --- global-functions | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/global-functions b/global-functions index 9579f5c..40cd271 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 5363df356875325420a62273f00df1ea404d2aa4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 17 Jan 2022 20:50:52 +0100 Subject: [PATCH 0015/1786] global-functions: $DownloadPackage: handle special case with name For RouterOS 6.x bundled package version and architecture are swapped. Closes: #21 (cherry picked from commit 1e6931c8e34d5035cb07baa98b57eccbcd4278ab) --- global-functions | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/global-functions b/global-functions index 40cd271..c6d311f 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 0016/1786] 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 0017/1786] 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 9024e20c0b576d7d22c28ead3c6461e228bfda49 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jan 2022 22:05:05 +0100 Subject: [PATCH 0018/1786] global-functions: $ScriptInstallUpdate: give final url in debug output (cherry picked from commit b4a5d824a268fae9f06ccf61fff4f67c760773ed) --- global-functions | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/global-functions b/global-functions index c6d311f..fc70cc2 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 0a9d0473f37b0091ff115ac7d47d93a521c37c7a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 20 Jan 2022 22:11:30 +0100 Subject: [PATCH 0019/1786] global-functions: $ScriptInstallUpdate: quote names in log output (cherry picked from commit 5e32105e7ea4bd357f9826d1ca24ca6e2c455bdc) --- global-functions | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/global-functions b/global-functions index fc70cc2..70f1077 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 0020/1786] 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 0021/1786] 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 221b0409d5198c13c11b0dddb730bd0bf5752efe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 30 Jan 2022 22:05:58 +0100 Subject: [PATCH 0022/1786] check-routeros-update: use correct syntax (cherry picked from commit dfe995be270f1ee9621454e7feada84c33168db0) --- 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 52bd08b750b16b03494af7f7bdd66225fa82995a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 30 Jan 2022 22:06:37 +0100 Subject: [PATCH 0023/1786] packages-update: use correct syntax (cherry picked from commit 27a81bcbca52d513c5b9c10578474a1863bd08af) --- 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 0024/1786] 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 0025/1786] 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 0026/1786] 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 0027/1786] 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 0028/1786] 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 0029/1786] 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 0030/1786] 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 b2f45c03501b8f1ff446ec770c05fefcfa36d0ef Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 3 Feb 2022 14:29:37 +0100 Subject: [PATCH 0031/1786] doc/packages-update: link backup-cloud (cherry picked from commit dd19aea3628471ce54fefa30913879322f20e63a) --- 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 8d49babb0114ad55ec3094f7d9cec2f1bfea43be Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 8 Feb 2022 17:39:53 +0100 Subject: [PATCH 0032/1786] doc/netwatch-notify: add sections (cherry picked from commit 42c203291a7db814be00f40caddb6980632358fa) --- 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 c03da561cdf7cf6f47de79772749ef459f6ee495 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 3 Feb 2022 13:51:40 +0100 Subject: [PATCH 0033/1786] netwatch-notify: allow to suppress notification on host down (cherry picked from commit c6e581d4f90c9bea0adf405685aa634e264d1f3b) --- 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 75fbba4..5f0f4db 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 c443bea..dfa2b99 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; # Use branch routeros-v6 with RouterOS v6: :global ScriptUpdatesUrlSuffix "\?h=routeros-v6"; diff --git a/global-config.changes b/global-config.changes index 6f0e2f7..37aa074 100644 --- a/global-config.changes +++ b/global-config.changes @@ -79,6 +79,7 @@ 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="You are using the branch 'routeros-v6', well done."; + 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 70f1077..68d8250 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 0c607a8f9ce7ed9d33df775f03b0292787d9326f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Feb 2022 21:46:10 +0100 Subject: [PATCH 0034/1786] 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. (cherry picked from commit 0b46c508dc8f76955dd528900882b54c07b62ef3) --- 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 c95e8161485ac47aa3c4f65efe99f335cf330d46 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Feb 2022 09:58:53 +0100 Subject: [PATCH 0035/1786] netwatch-dns: flush cache on configuration change (cherry picked from commit a47f5723cc4cdd287d36aaffd7619c17494f9345) --- 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 32cc55f7d2570e80ab270ae6e5ce97e3c1bc7644 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 2 Feb 2022 21:10:10 +0100 Subject: [PATCH 0036/1786] introduce firmware-upgrade-reboot (cherry picked from commit 3c358980cb416c61419a0aaa384ab1db1dab8d29) --- 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 990aef9..70d3ff5 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,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 5f0f4db..0554cdb 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 dfa2b99..9075df5 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; # Use branch routeros-v6 with RouterOS v6: :global ScriptUpdatesUrlSuffix "\?h=routeros-v6"; diff --git a/global-config.changes b/global-config.changes index 37aa074..d8cd39d 100644 --- a/global-config.changes +++ b/global-config.changes @@ -80,6 +80,7 @@ 74="Extended 'hotspot-to-wpa', it can now read additional configuration from templates and hotspot users."; 75="You are using the branch 'routeros-v6', well done."; 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 68d8250..0a0b1ff 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 943b60bfe38139e617b8f8eb58eccd0508d8f51a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Feb 2022 14:28:09 +0100 Subject: [PATCH 0037/1786] 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! 😊 (cherry picked from commit a50d9d30e3fbf6b4236f99cb40df656206492f8f) --- 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 0038/1786] 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 3dd34523037ce356092eee59bc35acaa8d7020ed Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 10 Feb 2022 11:05:21 +0100 Subject: [PATCH 0039/1786] global-functions: $MkDir: do not act without directory (cherry picked from commit 7b48b25c271111570d27708ceac437e24f05e6fe) --- global-functions | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/global-functions b/global-functions index 0a0b1ff..9721b8b 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 0040/1786] 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 0041/1786] 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 0042/1786] 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 b60dcb5fad6181692a057a541a47cb1bc8ef2671 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 11 Feb 2022 00:19:41 +0100 Subject: [PATCH 0043/1786] 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. (cherry picked from commit 3f8e835233d8d9ac6f31572a1a115eb73c46ff92) --- 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 0044/1786] 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 0045/1786] 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 0046/1786] 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 a9805365d22ee32539b26509df21a0b8316d8ecc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 11 Feb 2022 23:35:02 +0100 Subject: [PATCH 0047/1786] README: put hint into block quote (cherry picked from commit a5e421faebe8ac82c1ade73f8c1ea26ef728030b) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 70d3ff5..fae49a7 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 2f965630fac97cce6d46614818e3cebca10fc2f7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 11 Feb 2022 23:37:29 +0100 Subject: [PATCH 0048/1786] INITIAL-COMMANDS: put hint into block quote (cherry picked from commit 4b16dc06c4b1bcd7c7ec5e3849736765799e32e6) --- 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 5f52e3e3f47706fa3edced5521796c38512d2aa3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 11 Feb 2022 23:34:39 +0100 Subject: [PATCH 0049/1786] doc: put hints into block quote (cherry picked from commit 9e91ed56aaed77c6776ef95ebed791c40d7f21d2) --- 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 cdbd72b..8581ccc 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 0050/1786] 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 5e7735a507e1b447f542c1251a28982fe5b30130 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 11 Feb 2022 23:50:56 +0100 Subject: [PATCH 0051/1786] doc/early-errors: no site structure, hint only (cherry picked from commit f0b0951968bc865877c1f5b6607935490ba68033) --- 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 0052/1786] =?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 d1c9fe4dce55feb0a77dd90eb9046897a89f8a35 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 12 Feb 2022 13:05:56 +0100 Subject: [PATCH 0053/1786] =?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 (cherry picked from commit cd2a7dcf8ce3324179768b48a785f24f0d53aa19) --- 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 8581ccc..9cee6e6 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 0054/1786] 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 798fd7cc86eeac7e460a6dd670fdfdfeabdfe754 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 12 Feb 2022 13:15:33 +0100 Subject: [PATCH 0055/1786] doc/mod: put hints into block quote, update info icon, fix links (cherry picked from commit fd36241be649989e7b26348db31a3d3461888a1c) --- 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 0056/1786] 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 0057/1786] 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 0058/1786] 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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

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 0059/1786] 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 0060/1786] 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 zcmXw3c{mh$7aqGiA~7x^NtWzGWQ4>Z`;zR8of%^pJK1+7O!hKl8HUN$SO$sV%379^ zHB{HWi;4#GjlSoe-}9XJJ@0#-bIxBs001E95fqMc4ncSTsBw-y2oE_QgtLc{hMWdf z`tIW%5#;m7qoHO2gtwpTd8Gva&`{rb z2GCpv0Dy8-eglE<{j>XzbD3JW)1Eg|dz?eSa!@~SzdtLz5U2nYRX0GOT>YpBLIk4R z&l>>%I$>%%h)UQ|h%m$-g_)U|iWi(ihvhtbo}CeTx_Quc9k4&nd+fe;UQNFg&bTp?Dz1Z3z&JFftBSy<@APM2K$wzEVt zx*sn`OgEvk+lhNX(#b3dp^VH)%sRfgZgN8`m<+aDU`gD0-FH*u-QOz%tmJW?AiI@H zr46=^q%4oEd#g9Qm;`h^C2wOXVEYZPfROHYH7=u}h}I+bq-J*rIOtYmaf6+hj)4Ci zUVD#+ysX24`GZdd?hfFJd|(CT>&|him+YN%Zga7W7ls+g#Dip+!Y<P(&)HWwae;&A0npGD~QRtag!+^i=& z@ec2yri}UVr7GPH=dX5$3aLJuRw)!Y0kdBKvar?J8iLmv|P&C3t$9;656|`ecCn6s{L^%e;4SrNmI* zKffoF6jzJ6bg!r<7WS9g*NrTfxwU?C-7C;hd2OsocXZi7wJ_PL`3arCseQE*z}oOZ zDms>2>o>7yqQfAsB6;%~w`%N)99-t4jrI~akJ%G=RcNZiWg`pX>@(`dp^$N+WC;P& zjkVvtJC<9B6_HQVjG$e%tVhK3ve><>XCh07Ga1ns(d?foeA z+OkNSW$&ap3oKf8C1SXS*;{2hla27~bNecUTize0z;^{mE8`=t76yRPkC1mJ;^M@8 z<>CnI-@gbkip#1^)U@babVvwUf6gHE4s>n*Jws_vj9qU*4CQq^lb$9a=aT-U(yWcJ z)|hUxn4VkaS#G|C!>H+&mmuw2xRbIYH>mD?NOt;_Mx{bZz{XLLJrj_fGt&Puk}p$= z%c!$N@c!>qO)kdf=V@msfx!Yg8Fszz$O`2TTm||JJ%i{mcB!}@^b*W3d7>5%7cl97 zC%P{euC47{{|qggX7kTUouz<<39BO!6!sAfn=UIzDfw-! z1ul243^W>^fnH&m97c;Qm~EcYf>kbPPJ4AFKNI8EAkw`25EyMgZ0`2JYC9eDb|EDt zqVVVLqk>dOjor)Pk@WQoQcEkAZ$#AFYk0TOmv*;@%a7_a2j(>*vr+;4RX_@;=5^`b zBRny-Q2WQf9lVF6MLK$Q4xdaW$AKxSc57RG&6u>Hnk#V#=iN#*^f zp6=-g7~IvIG{g?8E^7H!UXL6fb_(|X)tr;WqizNn=M8Q6CKlKDm(|ZsSXgKMcDQCFbQau;Yl6KQ@ z7sROG~XP*TsrQr6nwI`R=6b@xvwsu@ES z3h$v$vjA0NXp^bCl%pu=w&&)%wGa0uqkSetPT5V4EJ+nKT9 z137!D1|Ot=`O-Z&zYzFJimqRYWMpv|z1v1Gs8ir$FPT{XoM&)%Z(VB8upXqT{-#P( zLuD3uAgxy*WHk}^L6>DqE@tH8%Qr13bh~9lb_Yw!Gg~YssVy)Uh2J{+MhBK8G<3eG zT?C9N&BsjB_<6{W=-mv)FkTWAM-I3@8=^gX^)f!r2#sfH=Ktg) zdL=f(v}|t1`&cINmVnYlOabARn|ZD0w(?o4o&4iZKdLEX%iPa0xYzmTtLCm{%weZw zqScsLmSxcgnd1Z^o@kvZE&cRNS#i68IWtuE2Uq0FBPJ1~gokb#jD%a+6F;)KDXtwq zhMzx`ThEtDF?uG>-hs|R3}gJDPI|3u{)F7n3QBR}XPD1L#u zFy&m*k=+3j4|Ah=_-f27z=U_~!;gAa3vK)8F+VL3{pQMbJfC~g(FVKsrG)|(0lKbx z`Q4-`wxBSEknq`{4ap8RuA16NGN|qp&Qxz{{@M7%9`cG}4bRpY(^Q{_h|VSx=F;QT z(tLJ=KkGFJ&Q$IBrl=^KQvYZ2J@~Q_y$@68E8j*?duDt~vSL|*uJl(w5_}-iG34a% zMRjr@3zucmM@{c30$vg1R9sAS*S^5daRxUSdg6F&#YzWMu;u@dqP-Y(%xTxj>gUkD zw_@gbr;|IV8FvEYe9VZad)+7M>^;V%p0#N0rn)GrDQo`~_P#2x;fC9Z8`EPRo#S?W zoDF3PDWKG3@ro;}X$yk>P;~1BWs9qPjB}Rvfdxjg*pdl>cFnaXM zcQmR+)WI}X7Lu)}crg4G@&U733eS@h`{V(%k!mPTd|HWQ`FB~y90OTW_Lo-f<}`Pl z$btx!qTO%Mdz4rUZrLP7ygy{{{YKUS2X|t 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 0061/1786] 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 17b3e04d4141072a650b877ac601a6ac7fe0a800 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 20 Feb 2022 23:34:35 +0100 Subject: [PATCH 0062/1786] doc/check-routeros-update: mention e-mail, matrix and telegram (cherry picked from commit 6f27553f15787540a7b4bc353d89aa4d3d268830) --- 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 06bdce1378f717d4f5c3bb61f5d560cb334f82fc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 19 Feb 2022 14:13:23 +0100 Subject: [PATCH 0063/1786] Makefile: match all *.md files, incl. doc/mod/ (cherry picked from commit 886cd67edba86906fea4c0d753b13b7c68c5e78b) --- 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 cd1de8145b9000f0adec87c1a991007043ef5171 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Nov 2021 16:03:43 +0100 Subject: [PATCH 0064/1786] add doc/mod/notification-telegram (cherry picked from commit e6a686187c3d3c981b7ab86b4cbce46fc6466da4) --- 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 fae49a7..eac6855 100644 --- a/README.md +++ b/README.md @@ -239,6 +239,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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

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 10bb0a9f52a9dbd4a92c72f444ed5b831c91e4df Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Nov 2021 16:03:25 +0100 Subject: [PATCH 0065/1786] add doc/mod/notification-matrix (cherry picked from commit 07fc5c898ad36debad96d06e3a65fa06ccdadde8) --- 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 eac6855..732afd9 100644 --- a/README.md +++ b/README.md @@ -239,6 +239,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 d1c4eb2303fc4ea3c2acbafe5b31825ca07b56a9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Nov 2021 16:02:55 +0100 Subject: [PATCH 0066/1786] add doc/mod/inspectvar (cherry picked from commit 002315035c25b8569d2b6f232a6f8dfba37cf07b) --- 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 732afd9..80e4693 100644 --- a/README.md +++ b/README.md @@ -239,6 +239,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 39871f22210d6b48775bef4f78c73a78626fa7ba Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Nov 2021 16:03:10 +0100 Subject: [PATCH 0067/1786] add doc/mod/ipcalc (cherry picked from commit e9953c361267f10fd15d3280ccd985062c1dde28) --- 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 80e4693..f9a4fb1 100644 --- a/README.md +++ b/README.md @@ -240,6 +240,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 0068/1786] 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 0069/1786] 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 9419e3407731eea0594c8fbdff27d9688e656397 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 16 Nov 2021 16:03:56 +0100 Subject: [PATCH 0070/1786] 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 f9a4fb1..80657af 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,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 fed4757eaaf9468b488a07ecaa67b7f63c04bcee Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 20 Feb 2022 23:17:16 +0100 Subject: [PATCH 0071/1786] 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 0554cdb..a664cb6 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 9075df5..946559e 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; # Use branch routeros-v6 with RouterOS v6: :global ScriptUpdatesUrlSuffix "\?h=routeros-v6"; diff --git a/global-config.changes b/global-config.changes index d8cd39d..2764d78 100644 --- a/global-config.changes +++ b/global-config.changes @@ -81,6 +81,7 @@ 75="You are using the branch 'routeros-v6', well done."; 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 9721b8b..ef7fa15 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 0072/1786] 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 82d45eca088d6fd42f3d8c6a667a7d7517878d63 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Feb 2022 22:15:08 +0100 Subject: [PATCH 0073/1786] update list of contributors (cherry picked from commit 8e401bf498065814442c4c39e2fcc949f73bfc3b) --- 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 0074/1786] 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 3f6b5595f39044cf26700b2ac9a88dde5fa4b8ac Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Feb 2022 22:31:49 +0100 Subject: [PATCH 0075/1786] doc/mod/scriptrunonce: document optional configuration (cherry picked from commit d50f6ffb79c448b8ffef246a0e7ef90d51c8dadb) --- 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 0076/1786] 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 a45b8d7d8c2ddef51db4ffb25695f2b40ae3c1fb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Feb 2022 22:41:59 +0100 Subject: [PATCH 0077/1786] doc/log-forward: remove extra character Looks like copy'n'paste error... (cherry picked from commit c872c18d76553647ebeab613df4edc8cabef84f2) --- 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 0078/1786] 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 a7da21e18583d8bf22b9669f5ce43c02ba66ccb9 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Feb 2022 09:24:10 +0100 Subject: [PATCH 0079/1786] INITIAL-COMMANDS: give another delay before fetch (cherry picked from commit 0ab99fcdbb9b9210b3ebdfeb59b8185b4d760567) --- 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 0080/1786] 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 0081/1786] 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 0082/1786] 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 0083/1786] 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 0084/1786] 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 d0699857c96295c4befa013bbe822c197d1b5817 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Feb 2022 12:36:57 +0100 Subject: [PATCH 0085/1786] doc/backup-cloud: warn about possible issue (cherry picked from commit a78b2bfcdef7e7cc84fd777e7fe0f7aa4cb5fe0c) --- 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 b11a83aac2789f7e385ccd62996705fec7163aac Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Feb 2022 12:40:54 +0100 Subject: [PATCH 0086/1786] doc/backup-upload: warn about possible issue (cherry picked from commit a754932211d3cc87563a483302350e65a03ceba1) --- doc/backup-upload.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/backup-upload.md b/doc/backup-upload.md index 72781ba..6c12c82 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`) 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 bf6c7d27dfa08756800df15432e0ce5e518184cb Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 23 Feb 2022 23:31:29 +0100 Subject: [PATCH 0087/1786] doc/backup-cloud: break long line (cherry picked from commit c72702cc51a732242d96904d04dad41573439378) --- 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 0088/1786] 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 0089/1786] 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 0090/1786] 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 0091/1786] 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 184959bc77a5e39b795fdd97dea5ad97edac4af3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 24 Feb 2022 11:58:22 +0100 Subject: [PATCH 0092/1786] global-functions: $DeviceInfo: firmware only if upgrade pending (cherry picked from commit a00e912bb5c556eaead42a4213c545a34c3959d9) --- global-functions | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index ef7fa15..ffa5789 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 0093/1786] 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 0094/1786] 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 6336da6bd702201ac7f74557cee6ce68677059d0 Mon Sep 17 00:00:00 2001 From: Michael Gisbers Date: Mon, 21 Feb 2022 18:21:26 +0100 Subject: [PATCH 0095/1786] doc/mod/notification-matrix: add verbose steps for setup Modified-by: Christian Hesse (cherry picked from commit c35485454c60ae489fd5b9fb7d0afde566cae645) --- .../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 zcmXv|2RIw<*9~g4_Gs<@;f{d2_{Rviqc8#vb<|N5R=kr=5DwnZf8Jei zJKMW?{(lMppx`j?|KDMUm>cT56B3oD1Q{ZjzcFn2dkB+Sk4ZZau=0COkN!chq5KkqK?4!ehg z8-DNZs&@!`s5ceh!F@^26KQb@iV3(#9ILiH?l)0oyXEEfck}tIYX=)RuR1kqZe}N-SIj5-%*`@sl_z zaD=TKq96WIUnP8@IC_2jW_j36GKe_-n_ipML%#xa!>tO1q? zY+l>I^W$F9nmHYCOkw&Del71o5*^N}sbpUB@dVxj_1Cy@jyU`LE3}+8BV;V(hD2tP zpKPXnrKkAlUCq?+_y_2_mTTrPhQ3_WoVFA<15YX&pA(wvHJM9!6nsMk@jqevrAybs zo|0x9gBPHfP}ENra#<({3}c6VJTh@XJB#BG2U#7@*5Utk<%yddEnO>hP2~zbd9Nf< zWEo4;wE(4;kS^Rhi1dp8UOh(1Zv%TjeTf$_ON^)n`Fy*nZc2Cg{eW+lQ1!$d&0+=^ zT>JTSzOiz*?#*)V2E`2xiFo{q(6~TpFsQOz>x)y)9z(TXw?&K0N8MdIPoekm_dUcO z4zsapACw$ldUN@_XpZ_5&E~RMV82XcFfVCe7+}gp5!t+ORfFe{CyBwW8`THr)~6i* z5Lpr){4)EyH*9?6^6f62Pz2dZ6RD+pERP}ytLU-nZJCR)+_?g64sfHN-Y@E!sM!Q1 z5mo<1Oel9wDGMJ@<(Pb(5%eBC&(y#29x0`iq#G2fgtyiOr3(CMyUl%0Mw{z~jXR8N z3al|oVrpd8pfLWP&Z{@=#nQ6-ahxSAsi@d?>_Ht1uOe$}iDrC6jH)kAXlIK5bV<0n zM^O6r!^dx$CbJa{N>)1hKe$>FZqNPuAXfdVDUC#j(yNl{_d@?+LVV^OdBc7&Z*F?R-2&a^He~PiI8Eo z>uTwN^NBs?Hpe+uy1lsKM4?3gM^4w1d+9_Zn=y% zNbofEHZB4Bx!TTM?(wpt77Y$#^_ca}esWVeoi+$n|nSS(k$r4swxf&AfrCXd*M0|#>r(H6Z zx|DPKS|KT=KP4R?HH3oiGGrjkn|B;2an`%ZoO(=;Z=XUnL~}&*U3wgl7a?c=h)T}u#S?dBUaMy5 zt|JE};4QfA&@b&15!%vv>_WY)^<#$ccAFV6fL5StK;mb{lv*)DRncQ1*ii0Wl&NK9 z4zGgr1jF(`Z8^I@q73a5^C^9p^(*i`$@s~&>zt-e%4rqXo zmBzatjAVTK!Lip~gvR!g(H}F~?pjCC{Fi~!py3bQ20Ze?s{y_ZcfrYtQu~%>IGPT% zY%TsQF0Pn=jQVUadhME4E8{@j1d9#Yb40$%=%yoPy>GhQ6f9ii$lAvEFR-@W^NA2RYL) zb$w@U0A_g%6!-!4x?FhGf`Rv!D4Yi89^~z;lwVO=Y5DQx8DrOs( zGdBFgweQ5dRStK}+&p?eso67TB~WpwEDnv(3!)e4pRl^5ITm zYZU1gXo1N9c2e_Bu(Q=~7Z2Mq-)fo-=?n+BS;0YdJJH-ae@tRKHSs5?I`1u8{Pesh z&z7_WFFaUEm;_PI2n6$4rdM}*9$ZjQ{mJCscALpWzD$t}K0c^Jo$A&QE^ayrTF|X* zQEuT{DzA6%4b1_wW~kSuKgjFp{1vJ6*|_?NI`-hUuQ2@F>iVe%)8AioTdH&^ z{ZY}I0}0*vCS5l^^V1%G{s`4IPjT$u^PV)_;AIV|my>&~DXb{}sxQi)y~`wPfu;YY z>iw!9oRHD5AEry@>rNoam~s=u+z@bP+ps6(kxR}I>)OgaMq+b7^6MoYo$EKw?hO8A zuB!PKWIkVPxrbqDlv8#rsa%VrQ_o@a4NFcI^6HzzNJ}Zqwr2g-k{KoK|Z7JgSMLLFJpCwhD3;RsIMZU zdG6<9CmxZZ0`^^>+w_JDg2e`_S31hl!=9idKrZ(b%hXl#vutmeJ-y#sNGl`uCgZUzh0sBYcb;;dU3S0FGp*~^g;?{0xy%-fP40oLe-A~Kni)iJG^01 ziIG>?$v;~q*}RDeh$t;T_drxbUUGpSg*g1cwz)%b;~GsgpgJcHeQw^~3ypq-LFC|A zl9$zlo`hg-;1vtsGsPHI z$3929;kzc-I2at-EW0eUmu0`>CgRZ-v;Q@krwth(q$$pn3=b<$Gbzmkw^!PFqBw0S zXD?ms>U1Rttz4-~9!Ie6u|<`3JZJ(c;fIh{2qca?I(cOCdw?muw#az-!Zm76Hq)&a z&wKrF;q|^>2o7QiptHMUc$RZ%lr20NhKhelteFr=aADuD1cD&DdG2|`8%8QSj-SL$U|Jam* z8G_C6!3}rTWfbkAx~pw2&}5#ZHO06}mnr7ZcEf|Y<~GQI3_<+qnos9`02yc?47IN- z{~{eU*W$-LAeq-gSk5O>8F01`?d5Bpt$h6HCs}5JEF*19Qo&Bz)Q90voz|?;n_Za| zuw2))2xipEL76+&2vl@FW3jYNMUzFEdHAw=^b1L?<~7qRqTNPMN1Eqs*Qqp8zTL)1 z%#phX)I#Sk0eG*QkiIpZWJ;#$XP z;A8a7r7QAdKAn(is_OT%E>0Oq)jmf z;zFw~fok|*R{_9p^-#QQnaA}qd3^)l?We*g+&cZoH7>r z=A1gl=Cu*vC~xCe`w?UNsjWYZX%>o_IvRBiE&N8FvDzK`ujzcR1PZ(%7eITx!sY1V z-kf(-z}*IYFz)hV;-mC>)8+GGsLWWO>D&7Nl+NsKv{zrl{RLyEGl&iiwZ+p(AgZL8 zX@6dO{0p0@Ca75bgQ4U--&o0^Yf2Rrpo=98VkG%S<-Kr+yES2xm(#S>coOZ25_+l5 zEu!qkLD9$7UwyX;|D0Qzswr4htcT4{$j4!E-`UCP=?nx@Gmag$O_w2o879kD;t;lI_t;%YV5OGR?+q( zG8eej1j$j9P}oHra+)(^D~#$z)y(iwDMg$Mcr3j>;-CkG9%~Z%`ZHSm3C~5Q5Nr1e zG#dpe9(ipm5_(UziS~q4)~(65;piyfQZrvG>zwpCPIyMl7#Vjf%&(Pe(=v2&)b}lM z$@1zM_$L!nVHNj$zp%mP>zY71WCpV%5xgn6T70(S;Cl#4Q<2#F!b{A^9E{y-h{N&~ zJjUB-pMGo@v^le37^55JQB^SYoWA1y^U=jfH>VD%8qNdSC+ha{oqcECDMRN$=+g~u zl=JWeuGEZ_Vt%0Uwl#ks){w;9joI7UC^;&%ao9jRp$F_nh>J(nSgFx)p2nVTFdI@m z?lg7eda_6=9Bu1>q+`v>Zt88|V=g6aSaHWp?3^QhoRz_b)IAuA1R0E)y^M{45X;Fk zicLLIhiOcRBIrgfMrfi=BZpBq<9!*?1pNMD|ruJH2YNVb-lon+&JYbv=4 z@7a5Gd1ppdBFpxMRL2yX*QRF7Qd@Z`jnT9pAy1_kFH&&OZ+T01$A)2jLw3(QW{WU7#1*P1+0X=w_%Utwy1C zy;VZfpBUVk+pCGw#$Sm%pM0{{S0{2~H? z+yDTr1SJDG|m}IK~}UM&h?@Z z000S5f(zv_;n0ETzs%*!mnlf+=r64vDR996Se&sKUvFnjAZ0Q=fF^=MaiDQtju#rm zD2IW8RMB9{RkB_#j(BFk)hqXeYn3npkfP6b3fK)?sK_$vPIGf@C6h(`3)@S;p`9q{ z#>d7W+wDm6_gbk%{^x@;V$;ZXH;hF^{yCAdoTDXx3^~h}70w5iMmu=yWEH>7k!u}R zA)daungl=yGM0EO1)2HXwBw^%%eDkJ&hM7+r&VcDW>}SJ+=IJjk*DTHZjXhOSl=9z zZu-UnS?wzS(UZ?*a^)ZcuaA-w;(i%xGU?w|cW3CsTHe!e7%BmXq)y&fCg^J9ABjgeTQVs`kz3#Sg_ZcTg9@?$-VLyVPJq&(^yRZ-%CIb`Yl z&OGGn%^-C7D#KNack^)i>kX(4D{IWuzm199$B&;oXiQCniJQ$(MIXxWwJ+RxYr9*$ z?{7A^Icu@^<$>TenFcmLzqIRbT=EWV-YjgJECY|gJe3U%(jVa12?MT7QZSp5uKx^= zUMp0)wffqNcQdO25;_`NeAXgCcOV=uf&=P67 z<(!Dhngdi1!GnD)+e$XVs(eG(joe+o>t; zjI`wZ&pcfsC22fWG&biDwU8MpYt#WI^|>NWL4u5ttLO(w2!jcdM<%PSk>e_kXgUY zj2{p=Se(Q8p!jJSRZLHOXlg3n+YP4hA z`tGeCXIO@N8G6J^9~VhlF+Re4Zwd)N8s96WCO!MU=dg|pU~89#7MWLjYML=I_xpws z^tuAq3Py0#!HRSV!}a|l@?Q9Uq_z5z=Cb?sb38|*>6#bup=tfRL3I5u)alRzzSh?z zv_br~dvD$6I2kJt92qZZOIS1&MincE7)zSLWw>pjXnrN6-7%cM(!cB6jiIgTPSn(^ zUj=z&@!>!Hbuvl_Cq>MWg|iv;<`v9tqJ4maXn#u0TW~S}_{sV8((Bk6pncybu0mpK z&`mdva}Fyc*e~ugd<&#n$Q)s$8pYH5!=jw8E4}BZx!CKQ!_eLK_Df0OpF04;k;*%>c6@Y&+z74)>fAq)lQgaqtYLRfdBnrrN@-Tox!tz- zbwvjgle-JuSB4=wU(_|M7^L+PkTo|`j5TSeO;puVLnoZhImX_MRM^XYyRi@&l53Y@eC`qyI8<%Rms zvcXd|-1hWS;hVHC}d^6o!9o^>;4aIOm|w(d=F{CTtX2LG-^a zNQgiBFGs86zH_X3PRkZ>%P4z{H#<0%c31sVL{;}n45-unfEua2gjt0ilgi0Vr+()# zwPxE1*k@$w%v5a=UMBCWTg`t|A#RVW7UJF#E0x0Cxn}{}+_mTm*jPjnG@ZN9i3aT6yXXbZF<=xJsx6Y~x6qCKhtDc^N zlNt15_;1IIg>B3wss|OMNHL3nkD6{Uk^EnvOc0Nv+iVwSC6dB^OkbP5&XeORa;yCO z$Qz~#|NNp0sx~K@=^j?QxFUKCA|13@V;@Neqho zS;?WpeNe?_?#d-WOEL&ID%y37Pmzq;kKA;0Qhsg3A=rY=q~XG2$g}`uh~F!;fSqFa z@06dDosj`S!xc_v5g`Iy+-FA6wtl7wFwL){_o?HdWjo2$N&F%@^aG^5^Gx5)dX{}L z#}1+*q`&@qpTWc~&bH&8b8d+78<&*<_IGL_^2K2eUG?+maJ`q+n=6%X0V<(|PQWKH zrB=v!>Ub8^^UC`L-|`;4yFOxg9)?E}q~ixSchhCleT<0tOJBS{z?{FbM^636|4=24 z*gjKq-}PGKT7gJ{=H^|?O@yRA+$V$BFzE#1ZfNK3)XD^ASx$E&=9O{S@x{)s%cp;gn!^re}})Ugbn^Ay?~h7oLFAD z)Fj+ai!v$&d&7bTBIKlz+KIA5DKH5&LB-W}Zw2|#o!nPrWLl)fewd|LxeyU>i4au%u-vwnF&jE-*fR1=Nn^{6_2_#6$HvWNVJVQCagO5 zn~w=cxj0SxVplC)J{b(c<#x;X$=Y~@hfT4IT}7!xyw#m%y#Q{7o`+^Nm)%F1tEMXk zBkb7dzTEeKID-e`t8h5S;rL-AuYks_K2$nJb>z3)h>?JiK(COx_^u&zm{`loUv*dt zcYyEHlx&M<*M~8jOfb+D!rQ#h`&wkvL&=CRr}fU}jGJrRl^%PY;oP6&Wy|ir9Rn zEM18sok7IC_-}(YWro4~%sdO>$~#6kCo)-Xx(=+{UuJL0@nTz+oD9%BT$_~SaXd3J zE7RdU*H*7AiS>J6OTTp^Tcq>E?4!PYz18|AVVYV{B}hbi&deZz7kl=zL3>{6*KksR`$dK|JdenmL#{1hm)m%2s_Yi^*7+)yy-7St5rOKt_ zZvFy0?H#>!J7@5koS4CC>K{!;sT5sBPyOR~mZ7ppNyBAAp*Ks$8-8G!`arN|MLdt0 zA) Date: Tue, 1 Mar 2022 12:47:23 +0100 Subject: [PATCH 0096/1786] global-functions: $FlushEmailQueue: delay if "in-progress"... Something else is sending a mail... Let's wait and hope the status is not confused. (cherry picked from commit c9b6cee83f686a532183016712c9441e77558917) --- global-functions | 1 + 1 file changed, 1 insertion(+) diff --git a/global-functions b/global-functions index ffa5789..6ae4549 100644 --- a/global-functions +++ b/global-functions @@ -358,6 +358,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 b35e39b0facb84b20efe62f7c53cbf3ffc06f887 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 4 Mar 2022 15:54:18 +0100 Subject: [PATCH 0097/1786] global-functions: update upgrade instruction The branch 'routeros-v7' will not exist forever... And the link is gone already. --- global-functions | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 6ae4549..3b88a2a 100644 --- a/global-functions +++ b/global-functions @@ -1270,8 +1270,7 @@ $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; + $LogPrintExit2 warning $0 ("RouterOS v7 brings some incompatible changes. Please switch to main branch!") false; } # signal we are ready From df0d826999f198c650d50585c72d92ef7eb6a4c3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Mar 2022 22:25:38 +0100 Subject: [PATCH 0098/1786] 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 0099/1786] 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 e25250e27be6884cfbf4276207b05561ed594b9b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Mar 2022 22:25:38 +0100 Subject: [PATCH 0100/1786] hotspot-to-wpa: initialize variables earlier (cherry picked from commit df0d826999f198c650d50585c72d92ef7eb6a4c3) --- 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 ddb181fbc2d04d04743253b018cac00ffeb70de4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 7 Mar 2022 22:26:41 +0100 Subject: [PATCH 0101/1786] hotspot-to-wpa: support ignoring specific hotspot (cherry picked from commit c1fa0f3579573b75cadba585c1aeb7e68313645c) --- 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 0102/1786] 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 0103/1786] 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 98b08bcbd2e0bd131f3a8f8c53fed0c74198f630 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 8 Mar 2022 22:28:48 +0100 Subject: [PATCH 0104/1786] global-functions: (re-)introduce global $Read ... to interactively read input from user on terminal. (cherry picked from commit 07cc38e973a6037649083494332fbae1946b48b4) --- global-functions | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/global-functions b/global-functions index 3b88a2a..91297b4 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; @@ -640,6 +641,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 fab05ecd7d56b1d70eeb541990dfcec8df482237 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 8 Mar 2022 22:30:01 +0100 Subject: [PATCH 0105/1786] accesslist-duplicates: use global $Read (cherry picked from commit cbb2f067e64d09d3d1443d9c2b17266fa56b2e99) --- 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 0106/1786] 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 0695c9931824bd9f1a1b858cce2e06934738d285 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 8 Mar 2022 22:47:26 +0100 Subject: [PATCH 0107/1786] firmware-upgrade-reboot: ignore firmware downgrade (cherry picked from commit 122f90b6930ba499f917887b6e25adae3109a513) --- 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 0108/1786] 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 d21cd2271f0032984d23e1c5b6cfe8f2ade59363 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 22 Mar 2022 22:33:46 +0100 Subject: [PATCH 0109/1786] 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. (cherry picked from commit c4a5f8787a57836bb3e8463cdda6cab6043b0169) --- capsman-download-packages | 19 +++++++++++++++++++ doc/capsman-download-packages.md | 15 +++------------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/capsman-download-packages b/capsman-download-packages index 333f01b..64b6304 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -53,6 +53,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 9cee6e6..bac8a3c 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -26,18 +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 system "" arm routeros; - $DownloadPackage security "" arm routeros; - [...] - $DownloadPackage system "" mipsbe routeros; - $DownloadPackage security "" 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 0110/1786] 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 0111/1786] 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 0112/1786] 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 0113/1786] 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 5570258ce8418d03000c863403a25a184da4d13e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Mar 2022 12:31:38 +0200 Subject: [PATCH 0114/1786] check-lte-firmware-upgrade: be more verbose (cherry picked from commit 5aecc9f1a316874f9c2935b6065347223927a299) --- 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 aef27fe..558afb2 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 info $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 info $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 1cddf5590de5f410a0b7ec00d5323bbfe25c47a1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Mar 2022 12:37:58 +0200 Subject: [PATCH 0115/1786] check-lte-firmware-upgrade: support starting unattended firmware upgrade... ... from terminal if script is installed. (cherry picked from commit d952e7e6c703dcc949478de351e9bf622be9d319) --- check-lte-firmware-upgrade | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade index 558afb2..d861784 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 58f5a4fced9c35b4f3a5e25bebbac72e0a2c943a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Mar 2022 13:36:11 +0200 Subject: [PATCH 0116/1786] check-lte-firmware-upgrade: rework code and its logic (cherry picked from commit 2aa93a06716350d5e29fff4cfd1e7deb338ab80c) --- 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 d861784..5f6bb69 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 info $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 info $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 0117/1786] 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 0118/1786] 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 82c0e1c44c07013f6bc8105489181152b46b126b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 30 Mar 2022 18:03:50 +0200 Subject: [PATCH 0119/1786] introduce backup-partition (cherry picked from commit 71b69fc1898babf490b7dc8e7b0769022d5a2f79) --- 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 80657af..215274d 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,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 e6bed51..9c2edb5 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 6c12c82..08d64b0 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 a664cb6..d6509e0 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 946559e..b5be658 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; # Use branch routeros-v6 with RouterOS v6: :global ScriptUpdatesUrlSuffix "\?h=routeros-v6"; diff --git a/global-config.changes b/global-config.changes index 2764d78..5f9ddcc 100644 --- a/global-config.changes +++ b/global-config.changes @@ -82,6 +82,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 91297b4..05a111c 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 2c2a3013f3d6170867a7416ad6533e4d31fc3dbe Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 31 Mar 2022 10:27:07 +0200 Subject: [PATCH 0120/1786] 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. (cherry picked from commit 0786111c5c5bd3085a52fec749fc68a1584c1a4c) --- 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 0121/1786] 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 0122/1786] 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 f5465d3e34a3cf668eff8a061b109743993c1dbf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 6 Apr 2022 17:40:21 +0200 Subject: [PATCH 0123/1786] capsman-download-packages: try to warn about missing logs (cherry picked from commit 9dbc56457b1fb25099f7d487b8284a03b47ffbe4) --- capsman-download-packages | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/capsman-download-packages b/capsman-download-packages index 64b6304..fc7ecc7 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -53,9 +53,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 e7481f3ca8db9a879a445db4b7f86f8e8f5b97e7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 7 Apr 2022 09:23:16 +0200 Subject: [PATCH 0124/1786] capsman-download-packages: break long lines (cherry picked from commit 57fab952908c9ad52e73a0103d0d5e422f8cdeda) --- capsman-download-packages | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/capsman-download-packages b/capsman-download-packages index fc7ecc7..0eae744 100644 --- a/capsman-download-packages +++ b/capsman-download-packages @@ -47,7 +47,8 @@ $WaitFullyConnected; :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; } @@ -65,7 +66,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 0125/1786] 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 0126/1786] 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 0127/1786] 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 0128/1786] 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 0129/1786] 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 0130/1786] 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 0131/1786] 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 7a714ad182baf8e757b908d6298d6eec085029ab Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 Apr 2022 14:19:50 +0200 Subject: [PATCH 0132/1786] hotspot-to-wpa: move code for marker up (cherry picked from commit c132d2840843a5da40f30e5b66cb1495f5c02357) --- 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 2e8f457109ed2689866501137e93a7378654b195 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 Apr 2022 14:21:28 +0200 Subject: [PATCH 0133/1786] hotspot-to-wpa: create template if missing (cherry picked from commit 3f8d3acd60dab580c590a5a5e87f65cdcceb3433) --- 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 d9c4e1e8d5cdc1beb447cfbc2d7c6fc2c672d082 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 26 Apr 2022 14:29:46 +0200 Subject: [PATCH 0134/1786] 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/" (cherry picked from commit a058c9e1edd8dc4895a64881ee1b495e86fe7510) --- global-functions | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 05a111c..65646ad 100644 --- a/global-functions +++ b/global-functions @@ -688,7 +688,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; @@ -715,7 +716,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 006e054517954b4bf97f11f9d9a5061bf32d3a3e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 28 Apr 2022 10:11:00 +0200 Subject: [PATCH 0135/1786] global-functions: set $0 with script name Now that we have some active code at the bottom... (cherry picked from commit 9bc2123ee5bd7af4a8e1ca47696a3f3379d5a028) --- global-functions | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/global-functions b/global-functions index 65646ad..a86c1ea 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; @@ -1273,10 +1275,10 @@ } # check for required RouterOS version -$RequiredRouterOS "global-functions" "6.47" true; +$RequiredRouterOS $0 "6.47" true; # ... and give a hint on RouterOS v7. -:if ([ $RequiredRouterOS "global-functions" "7.0" false ] = true) do={ +:if ([ $RequiredRouterOS $0 "7.0" false ] = true) do={ $LogPrintExit2 warning $0 ("RouterOS v7 brings some incompatible changes. Please switch to main branch!") false; } From 4cda1281f1d83208bf6a6c704cbf67b7e7e83b8a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 28 Apr 2022 09:34:12 +0200 Subject: [PATCH 0136/1786] global-functions: validate syntax of modules (cherry picked from commit 7c8e230521f1a936da034dfc05197fe9434926ed) --- global-functions | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index a86c1ea..89234f9 100644 --- a/global-functions +++ b/global-functions @@ -1271,7 +1271,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 0479f59aa43bb706abed42c233cde000c7f86ffc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 28 Apr 2022 09:55:28 +0200 Subject: [PATCH 0137/1786] global-functions: catch runtime error when loading modules (cherry picked from commit e74bec7e5b62e54d10b1f3ba058868536b35fdc6) --- global-functions | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/global-functions b/global-functions index 89234f9..f212759 100644 --- a/global-functions +++ b/global-functions @@ -1273,7 +1273,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 0138/1786] 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 2b647bef80b014e0d3d751506fbf6bfc54871293 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 28 Apr 2022 11:01:57 +0200 Subject: [PATCH 0139/1786] global-functions: $LogPrintExit2: handle empty name (cherry picked from commit f417bcbcd4ab7458f1d0b4265ccda2854ba96b4f) --- global-functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions b/global-functions index f212759..038f149 100644 --- a/global-functions +++ b/global-functions @@ -485,7 +485,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 0140/1786] 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 0141/1786] 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 087e7bc3b7cf46054c17bf91558c69a1802dc043 Mon Sep 17 00:00:00 2001 From: PackElend Date: Sat, 30 Apr 2022 00:20:19 +0200 Subject: [PATCH 0142/1786] doc/lease-script: reflect actual action of the script (cherry picked from commit 56c5da8ed4097018300c1cf284ce7308acd7ece4) --- 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 c84017de2c1b45866e04a03fea587bab2d9e077c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 May 2022 12:05:11 +0200 Subject: [PATCH 0143/1786] update list of contributors (cherry picked from commit e9575ead7ab16b1af0ce1407db7706b6e3f805b2) --- 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 0144/1786] 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 af589df82cfcdbedfbab7d3d8e62b5238d318bb6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 4 May 2022 21:11:26 +0200 Subject: [PATCH 0145/1786] global-wait: do not claim to be a backup script... Probalby a copy and paste issue? (cherry picked from commit 7189a3bbe5320a80d1cfbcbf940c1a2d57c45b73) --- 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 0146/1786] 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: Wed, 4 May 2022 22:23:17 +0200 Subject: [PATCH 0147/1786] README: installing custom scripts & modules (cherry picked from commit ecde864263f8572503eeaba2ad7c806847adb594) --- 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 zcmXv|2|N@08y~sy8Zt-jV~*KSpk9v=@?@B|X}u(AXI z_;~LS0elJofCz|}L-2V2U%P)f3cSLH|FD_Y<4rqhXh9;7ey#My2ap4Jx-~ukOX9IK zJ}AKFun_<_qR9hC-j@u(-@*Si9q(p67KLO0|7!&JV_28 zK=eNJc)>eNfR8^`fOnN5@uoLL3Ltv)wAM=`K~24A&?r{Y<|hB7u?1#os=0KuNR_$9 z;_KUtF=V9L9l5?1?b!2Ra)k9oY~w)RGTf+Mi@ZYAguRV}`{!Nj->3&gQsMTF&@h3a z?QSzsX}^iBvcJur>np|#)G4~vseW|-{h`Nt-5@!J95+sp6n`RRYmW>jB5S`AKrkmo~S-4>JGnUiNLfZuTt?Ib-5-=$e2{};RL zVdd(wY_qdh2Y2C2Ymwi+)+jFJ)XYvcm!0fKbLBgg+~{xJ=5yvhzk!_d_J+E;{eV?u zf~qP5NuNp}$xWsR~qB$wPpG*10 zY9;j=__-=_`AYw^nz-zgfjeMn(~qq715v>xuTAe8p`nkX+VM`}=2(S<+gK6Rin-Wt zK@JojQaEHJ6+!S7^?D3n!<`8e-CQm-x0+|VEC0^98N$m*rK7nxt^eqF-${Nz#?sr4To;Fp^oj^R;CCz>KE5uOuKwT zUO?!&&`F0OFjG6*v7=8a-Bqq2+}{y5=+ou|`Ep)@9iIL=>8xonN3erEBy53iZP=Mk zDAWnQtEc5CkyCz8=I!?B0nlc@uYs#aH~{<;f8rXdRlVBB{KjTC3n?|Nfyw@o{3^KI zy|XuSsd9J<^lfIK*v7Q~bleO*wBc^#+@)8g?j{uCWwq#2-;R}@8GcUqM+h9F7utx? z_)Zd0mr2NWJs#YJf(CN#^qk(m^~TzHyy74;CZ6$Uq}W#%>M1XHt^KNj=Zl`B7=F+H zvOIO;?*2g6!Zfj|xfbE!QrJSU2lL)-ufa^9;FlI7Rfb0H7Y}Z--%4>7oi^=#o61h8 z-jZ0rn8D*^m84aV%I3t5=`(Ch`CSKRe@Nl`xA@A*Ls~c>D`q&%n1VyWh2Nkz_2MWN z=Y>y+`io4wOg$rC_Cg@4;nN-Ie5*Y!k=aUym8<4#Y#A_07s18Cb^0UOvTdtI1+OT` zN1adI^eu0DMzeZT_8&HF>l7M4QO(e~uJ9t<b*PL&MC}`MlgBMiVO$f+$ zDd!e9I}?oSG-_%}TNIMEcL+*FLOYD4hCty?Tg=hNY;GeLaE?$2mehh3cz6V!2hkO_ zPx@NA)IcNrLPw@o)X}W(l2dZBqMXrtrQi1Z6!K~=;3D_?s^#PTO9MAc1OqRw(m9L- zwUiwX+D}l#Igm$=v=VEo?TrIIE$v#OAEG|LMMr|VZop4=^cg=hf7vmkO4Si!WHh3{a22hygKw_DrsJ-VcEI)^fIt}+DL2x!+BME6NFS4fQnwp zgOlDed%nR|$CMX|g^s|;Yw^XdL6tDe?%r8l>w`?ze6ry!aqILW z?;y1Hw;vMZzv8;ay;hDju86<4(H0e`o@ct&r2lnUshB+?f^=E9#4&eTcqxJ{)an$x zYS8X?w#4&nBM9iC*kdot-A{wXEWP;H-%&T2vAb93gnW2{L+`xFRdnWNSPy8vqZ;c8 zFab7G7po6s_T<(YdfS8JsYjk6eB6FIwfLI1KY23~pW*VLMia8u7}kS!6Y7y}=$==p zM--+MlNPk2uHSW?S-vOvv12X^rG!oSdQDR&WMQo(cZ7UkftPOHLl>#11igoQZT$y# z=7aXdJY<8UhRxEUJ-W5kF^l%_Lno1DKOI!wv*G+e`%~O z42@?gp*aT7^}pRhg*|4YM&gH^pAd$lyQHACR4_RNB(A$#;3;9aL|3W_aG~{^Z9lG% zON}HS7Xx1!FI^tvI!ZdXXT1|*BW!c-1)G>w=FRrkKiGlZZ_~={o0xDOy0R|KMG5}7 zmSPdj#O+Li<(ecd&3_YgqqEs=S@D%hJGf` zxkeM`-9jubMy^o4W4`)U3jf%=Ic0V*AnypuS9~1?$_+bcRsFG({JK8u9jVr*Uvr$H z`}hjI$uhZO>F#9z9UJH?LWfMXeMYw#m@N!QZn}T#)}GqvW6*AX_IFx|>jyA3NtE&P z%;fnp`N?;RNGJ8IpE8t}qb!wHhljfkACw`0if4(TJBgVT-n*;|`*8IJ^As;6@j z3g)T$s0!==Hb^v?;jHDaKC9&eLcDS<75tovpVC-ICC=ZQ5h6s)sG0^yf0o(6BTZD6 zEQ9wN%*An~O(nYyz=MOVp;h-T7Ft8aG`!cWxHjfocswAfd-*xXBx|6~GM&VzRg Date: Fri, 6 May 2022 08:20:34 +0200 Subject: [PATCH 0148/1786] 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 0149/1786] 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 0150/1786] 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 e49e454381ba63273b79130020d9e9334ca8a9c6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 May 2022 08:20:34 +0200 Subject: [PATCH 0151/1786] doc/check-routeros-update: mention neighbor discovery (cherry picked from commit a4ebc18af7973c5263adc6bea01af4c971a57922) --- 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 58f77824779f0fb0f968a5105984cc44c8c27175 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 May 2022 08:20:53 +0200 Subject: [PATCH 0152/1786] doc/check-routeros-update: give warning about possible breakage (cherry picked from commit c4008b91cd1eaea7789b2c4b40b590e5eb2f8ed6) --- 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 1b5f261f3dec01e12809652755fcf179f044c2e1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 6 May 2022 08:26:00 +0200 Subject: [PATCH 0153/1786] doc/check-routeros-update: link changelog and forum (cherry picked from commit 6784f82593c1af6b9db7cef39ba0326292fe654e) --- 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 0154/1786] 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 5f0a7efe1e7919951d6f5ee61801797cc2851ca4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Jan 2022 10:44:55 +0100 Subject: [PATCH 0155/1786] cleanup dummy scripts from backup scripts renames (cherry picked from commit 93ec9afe558ef6eba5d513fab359bb5f6618666d) --- 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 0156/1786] 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 0157/1786] 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 0158/1786] 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 0159/1786] 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 0160/1786] 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 0161/1786] 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 0162/1786] 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 0163/1786] 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 0164/1786] 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 0165/1786] 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 0166/1786] 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 0167/1786] 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 0168/1786] 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 0169/1786] 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 0170/1786] 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 0171/1786] 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 0172/1786] 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 0173/1786] 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 0174/1786] 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 0175/1786] 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 0176/1786] 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 0177/1786] 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 0178/1786] 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 0179/1786] 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 0180/1786] 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 0181/1786] 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 0182/1786] 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 0183/1786] 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 0184/1786] 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 0185/1786] 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 0186/1786] 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 0187/1786] 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 0188/1786] 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 0189/1786] 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 0190/1786] 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 0191/1786] 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 0192/1786] 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 0193/1786] 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 0194/1786] 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 0195/1786] 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 0196/1786] 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 0197/1786] 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 0198/1786] 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 0199/1786] 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 0200/1786] 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 0201/1786] 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 0202/1786] 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 0203/1786] 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 0204/1786] 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 0205/1786] 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 a5c233b28cf1bf23712fe839ed417bf47cb01e16 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 18:56:44 +0200 Subject: [PATCH 0206/1786] README: hardcode url suffix, update info --- README.md | 24 +++++------------------- global-config | 5 +---- global-config.changes | 4 ++-- 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 97cf318..7b01c54 100644 --- a/README.md +++ b/README.md @@ -82,14 +82,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 . "\?h=routeros-v6") output=user as-value]->"data"); }; ![screenshot: import scripts](README.d/04-import-scripts.avif) @@ -118,10 +113,8 @@ 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: +Let's consider RouterOS v6 being legacy. 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"; @@ -130,15 +123,8 @@ 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"; +RouterOS v7 is the future, and default branch `main` expects it. Just drop +`$ScriptUpdatesUrlSuffix` from your `global-config-overlay` to use that. Then reload the configuration and continue below to update scripts. diff --git a/global-config b/global-config index d6509e0..ea5176e 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: diff --git a/global-config.changes b/global-config.changes index 5f9ddcc..e82f242 100644 --- a/global-config.changes +++ b/global-config.changes @@ -73,8 +73,8 @@ 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"; - 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"; + 70="MikroTik started pushing RouterOS v7. Changes are required if you run it, see https://git.eworm.de/cgit/routeros-scripts/about/#requirements"; + 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."; From 1b3f2620a7e521ef33a7e2273b57e1ec0d69dda7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 18:57:17 +0200 Subject: [PATCH 0207/1786] INITIAL-COMMANDS: hardcode url suffix --- INITIAL-COMMANDS.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 66db40c..33e424a 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -3,18 +3,13 @@ Initial commands [◀ Go back to main README](README.md) -> ⚠️ **Warning**: These command are inteneded for initial setup. If you are +> ⚠️ **Warning**: These commands 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: +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=""; @@ -24,7 +19,7 @@ Then 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 . $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 . "\?h=routeros-v6") 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 b6ddc5968e7a3393bb6e9b0c0ccf96379efc62b4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 09:42:44 +0200 Subject: [PATCH 0208/1786] 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 0209/1786] 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 0210/1786] 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 0211/1786] 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 0212/1786] 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 0213/1786] 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 0214/1786] 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 0215/1786] 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 0216/1786] 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 0217/1786] 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 0218/1786] 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 0219/1786] 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 0220/1786] 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 0221/1786] 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 0222/1786] 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 0223/1786] 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 0224/1786] 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 0225/1786] 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 0226/1786] 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 0227/1786] 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 0228/1786] 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 0229/1786] 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 0230/1786] 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 0231/1786] 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 0232/1786] 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 0233/1786] 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 0234/1786] 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 0235/1786] 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 0236/1786] 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 0237/1786] 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 0238/1786] 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 0239/1786] 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 0240/1786] 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 0241/1786] 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 0242/1786] 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 0243/1786] 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 0244/1786] 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 0245/1786] 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 0246/1786] 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 0247/1786] 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 0248/1786] 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 0249/1786] 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 0250/1786] 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 0251/1786] 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 0252/1786] 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 0253/1786] 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 0254/1786] 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 0255/1786] 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 0256/1786] 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 0257/1786] 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 cdb698acbf9c30cd6eb8345e79b4be8799d814ff Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 11 May 2022 18:46:03 +0200 Subject: [PATCH 0258/1786] notify about freeze of routeros-v6 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 ea5176e..d428da5 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 e82f242..19630e9 100644 --- a/global-config.changes +++ b/global-config.changes @@ -83,6 +83,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-v6' branch entered soft freeze state and will receive important updates only. Happy to welcome you in 'main' branch once moving to RouterOS v7!"; }; # Migration steps to be applied on script updates diff --git a/global-functions b/global-functions index 038f149..e40e384 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 0259/1786] 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 0260/1786] 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 0261/1786] 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 0262/1786] 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 0263/1786] 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 0264/1786] 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 0265/1786] 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 0266/1786] 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 0267/1786] 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 0268/1786] 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 0269/1786] 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 0270/1786] 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 0271/1786] 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 0272/1786] 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 0273/1786] 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 0274/1786] 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 0275/1786] 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 0276/1786] 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 0277/1786] 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 0278/1786] 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 0279/1786] 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 0280/1786] 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 0281/1786] 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 0282/1786] 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 0283/1786] 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 0284/1786] 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 0285/1786] 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 0286/1786] 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 0287/1786] 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 0288/1786] 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 0289/1786] 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 0290/1786] 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 0291/1786] 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 0292/1786] 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 0293/1786] 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 0294/1786] 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 0295/1786] 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 0296/1786] 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 0297/1786] 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 0298/1786] 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 0299/1786] 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 0300/1786] 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 0301/1786] 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 0302/1786] 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 0303/1786] 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 0304/1786] 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 0305/1786] 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 0306/1786] 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 0307/1786] 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 0308/1786] 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 0309/1786] 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 0310/1786] 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 0311/1786] 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 0312/1786] 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 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 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 0313/1786] 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 0314/1786] 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 0315/1786] 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 0316/1786] 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 0317/1786] 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 0318/1786] 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 0319/1786] =?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 0320/1786] ... 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 0321/1786] 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 0322/1786] 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 0323/1786] 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 0324/1786] 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 0325/1786] 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 0326/1786] 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 0327/1786] 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 0328/1786] 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 0329/1786] 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 0330/1786] 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 0331/1786] 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 0332/1786] 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 0333/1786] 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 0334/1786] 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 0335/1786] 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 0336/1786] 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 0337/1786] 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 0338/1786] 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 0339/1786] 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 0340/1786] 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 0341/1786] 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 0342/1786] 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 0343/1786] 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 0344/1786] 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 0345/1786] 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 0346/1786] 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 0347/1786] 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 0348/1786] 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 0349/1786] 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 0350/1786] 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 0351/1786] 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 0352/1786] 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 0353/1786] 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 0354/1786] 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 0355/1786] 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 0356/1786] 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 0357/1786] 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 0358/1786] 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 0359/1786] 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 0360/1786] 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 0361/1786] 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 0362/1786] 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 0363/1786] 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 0364/1786] 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 0365/1786] 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 0366/1786] 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 0367/1786] 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 0368/1786] 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 0369/1786] 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 0370/1786] 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 0371/1786] 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 0372/1786] 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 0373/1786] 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 0374/1786] 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 0375/1786] 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 0376/1786] 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 0377/1786] 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 0378/1786] 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 0379/1786] 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 0380/1786] 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 0381/1786] 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 0382/1786] 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 0383/1786] 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 0384/1786] 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 0385/1786] 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 0386/1786] 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 0387/1786] 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 0388/1786] 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 0389/1786] 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 0390/1786] 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 0391/1786] 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 0392/1786] 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 0393/1786] 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 0394/1786] 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 0395/1786] 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 0396/1786] 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 0397/1786] 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 0398/1786] 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 0399/1786] 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 0400/1786] 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 0401/1786] 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 zcmXv|1ymGl(_OkjIz@UZLD&W9?(Ps+YFS)iX_RiHyL*vzK}rN9rMp9S1AAhXpiq-2B6Ua03-{KoD&Xr z`fvAt9lFQD4*j3`(PRDgg@C-Xqw{|&-@skmTpo3GxQngxBT~TKUF`lD0RZ%W2I%8| z;sW=A|5GqRKF-hDGYI`liAyykDO5#sE81fZ;CN#rq5HLWU{1*^!8G_h4q zitAXQc_WIBkaT~|h%*r$ho68Qpq0l=dTn)=Osx;W{#1@nkx|0 zYaR-Nnd>8ZDY?G{w3BPxp7P?K<;o4Y;!rge2@E7YD1 z%GFxhKHMv8Qch0Hh<<$mIpz&Kvpr4$l$;mJ0eu&+R@2&LYAUeuH?~tom^!xmxq}+K zv)2lD+o)|{A9vYfFLqLYIX>Il-9R&Q(@&lkmGQhJiwp#>#(yqDidc30(XTsYZYxnR zQbBIZ=^1?KGwV5Zi}AycqBGv>Y+PVE-;w6V1W9pKVQsHv_y}S z-WW++#SymSoSZ`&*HhFfR~MxWDw`W(qi3IwaE3TkLakJ((9F01utZQUbGp_^qek)C8N}C!ptxw$UTfH7V_FJnm zFuP?wxU%(6eyG4ZZ^=u$U4_wvlIXKkNeWKsJ=xuXc9ofluDzQ7w`$2UyO>G|kP1IIE0 zz6=;fli4|b)alj2_AIKd)`Z2JgZ!IuGu3f3=d;}DDjr`AtoZee-;|{T=}&G%JpD>g zEyUyBz}NEAfsqmf9&&Qz8CajYvqJq&bDSs6r!8B$j-`h!tu+;VpAK|NDAkO{8JAO8 zq-OBUh-R*2dPRU(yNhDlBqfIIM2kuV^fznl#FELs8MwIiMYw1K%jMnhk^im&sX!9bk@P}+POHj z@&Wnyi^Dt`n~g6N<$xJ1-xljAN7Iveg`o!j;!Mmn9 z#q{eCB zB%Vj*1*7lxqX(6WbY@}t@RD(sr8t#l{4A2{`_x$ZocT04uGQ!K{sdAaI+cx4Kec7% z%=Uljb$!ZEbHw4+VUySlNA9m*{i!z_0o~$}zN^A48(c`zmqw6zr*a=;6V9XR>23tn zdt-Y7$)dA8Ikl8Z6_LxnI2_@b7k!NKKMhUog7VvJ6bBeapz%5m3_M(TgWMC)T>B+s-(pE+D&mBu(rf#$sNoJ8ARwv$=dR46qrj3l@2-K{x10l;D^c zzT&MsW7|>VthF=$K*Xy;MH0lq-fh8Z*TfOTFL1esd_bcu0SQ7EKTAyE?A6G^&;T2y zA23|JweLew70=fKR!hJ1|1zM&!J8}7eNe_EfyvPSSd?mKo+`a$E+oCaj-!431V;lJ zJ3v9NfWq~;A2XVy>ky8>2Hr=&8fpC5b`l0-{Hz+O|kwOsYM8KyRJcwXIE*aVouNwNVC>MLW5h!Vp)7H z0I^4>IujD>btzMpex>T1J)}|b;;_NAVY~$G66&n=B~35vFbs*!yGvD-i!z4t%_`7U zx0FgyYXr+;LAxk@dloOx%J_RiY=Wb6Mxfu+O!&zwvea+Kr=*D~Y84~x7HX`o7{;ok zh`gyy#Ps{PWI>Lj-QOtm_}v%?>5ca<{n@4F&STnxf9f>-Jm7n&c3GKRwzBmidOsb@+`|+WsH+Cm2N6rPN%cfLTHS5t$P_*|CS54yH5i$@}@wHf##?v-n ztwTCTa+uC{cSABRZj3CbfoZ;n_cn1T?k|$^ zzj&Cump?rZ=?j*=K#CQ$kue}GugMNV#bsMsnx;pwfHQ_Avc@l2H{uis&xfsRgc6(0&Rx;S>%QNpsmzeW{ zNq$dJxf;^75jeC+XSTg;vk#$e2-!aV#qi7Q#U}qa3U)tG8oV%1Sp6(*0p zLI*TYz*Lzf^8vd0GEvL$br?Uvs}!iJJEt1j94U)fOIl%Zvw4nro?HQ5y^Z5yunemz z25z?`EZ&XD@76`;E%Zj{+OxQXQQpuwwAz>sWu6>hu&;!%D+DBq}b;}P)A__H%r=HuuAtpG-dla4y~y;0AB^K+aFzfR^o|x{~z4mHGOFI_!?b={$=)Aquua zXFHw%I-=B#-3i%Dn0P{gJa5#37lXaIa=TXUUn(KAkR>uCGtLiXc_c)%GJu6niN0mh z)VG@pq#9|##G%@k+}xjpt6zzwjXGUrx3t@^%H0s_C(|RUDyuglo?v^P+|Qeq=cdCF&fw^i=BHywR?)^7-i^Q3(G*ovj`56=a^N= zO)gYTDDGi`F>Wp4MxSYpX5`{@sY;0*mqAhl*)zqLp;E=}7 zo;G$;OzTKa*;)3TKFq^I+}l2sp1PMb?ALK1IcX7lbo?u+mfUA8j1?m}( zJqvi{olI)7dIhUHkd5}dZzZI`hzSGw6oTw|lcFca0a_P}g-CwA&bRrDrni~-GtI|` z`m!UU;ePt0>2Go|i`2~tyYJY64BRB)2=9D1G}1UZLMt<2 z+}`T*m}A$_-Pn`&v!OVxqzzvtW#sZ(m_8X>&J_>{cCvJ({~!UJ$ZGLdw}{@}n4x(& zHOjin-q6exmu}^}(J@+w-1N2?$9OvOGPip2FjxD;c8fgEUg$U^P^2!Nr(*Er9!Ocy zWpuEJph3~iLIzzKN@E7XcL}m4M|Vv(gSmZYGqmlgjhVzOdc7Sa5U~=J>C`(r&1hk+ zA8Rr4ged2to)KT^h;xYazw#s??X=e}?AL92`wkMTAKvK0ps=$xVUD=c*eVa|wy%#P ztdefeGlxgiNOkjpOwQ*tvzd9luNt<`TQu}1D - - - - - 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 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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 0402/1786] 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 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 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 0403/1786] 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 0404/1786] 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 0405/1786] 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 0406/1786] 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 0407/1786] 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 0408/1786] 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 0409/1786] 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 0410/1786] 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 0411/1786] 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 0412/1786] 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 0413/1786] 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 0414/1786] 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 0415/1786] 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 0416/1786] 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 0417/1786] 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 0418/1786] 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 0419/1786] 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 0420/1786] 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 0421/1786] 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 0422/1786] 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 0423/1786] 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 0424/1786] 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 0425/1786] 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 0426/1786] 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 0427/1786] 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 0428/1786] 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 0429/1786] 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 0430/1786] 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 0431/1786] 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 0432/1786] 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 0433/1786] 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 0434/1786] 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 0435/1786] 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 0436/1786] .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 0437/1786] .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 0438/1786] .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 0439/1786] 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 0440/1786] 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 0441/1786] 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 0442/1786] 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 0443/1786] 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 0444/1786] 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 0445/1786] 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 0446/1786] 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 0447/1786] 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 0448/1786] 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 0449/1786] 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 0450/1786] =?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 0451/1786] 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 0452/1786] 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 0453/1786] 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 0454/1786] 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 0455/1786] 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 0456/1786] 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 0457/1786] 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 0458/1786] 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 0459/1786] 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 0460/1786] 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 0461/1786] 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 0462/1786] 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 0463/1786] 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 0464/1786] 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 0465/1786] 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 0466/1786] 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 0467/1786] 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 0468/1786] 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 0469/1786] 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 0470/1786] 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 0471/1786] 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 0472/1786] 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 0473/1786] 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 0474/1786] 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 0475/1786] 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 0476/1786] 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 0477/1786] 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 0478/1786] 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 0479/1786] 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 0480/1786] 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 0481/1786] 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 0482/1786] 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 0483/1786] 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 0484/1786] 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 0485/1786] 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 0486/1786] 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 0487/1786] 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 0488/1786] 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 0489/1786] 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 0490/1786] 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 0491/1786] 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 0492/1786] 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 0493/1786] 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 0494/1786] 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 0495/1786] 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 0496/1786] 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 0497/1786] 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 0498/1786] 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 0499/1786] 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 0500/1786] 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 0501/1786] 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 0502/1786] 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 0503/1786] 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 0504/1786] 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 0505/1786] 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 0506/1786] 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 0507/1786] 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 0508/1786] 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 0509/1786] 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 0510/1786] 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 0511/1786] 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 0512/1786] 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 0513/1786] 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 0514/1786] 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 0515/1786] 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 0516/1786] 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 0517/1786] 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 0518/1786] 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 0519/1786] 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 0520/1786] 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 0521/1786] 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 0522/1786] 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 0523/1786] 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 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 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 0524/1786] 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 0525/1786] 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 0526/1786] 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 0527/1786] 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 0528/1786] 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 0529/1786] 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 0530/1786] 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 0531/1786] 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 0532/1786] 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 0533/1786] 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 0534/1786] 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 0535/1786] 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 0536/1786] 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 0537/1786] 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 0538/1786] 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 0539/1786] 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 0540/1786] 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 0541/1786] 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 0542/1786] ... 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 1343/1786] 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 1344/1786] 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")) ] . "" . "
    " . \
         [ $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 1345/1786] 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 1346/1786] 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 1347/1786] 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 1348/1786] 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 1349/1786] 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 1350/1786] 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 1351/1786] 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 1352/1786] 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 1353/1786] 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 1354/1786] 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 1355/1786] 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 1356/1786] 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 1357/1786] 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 1358/1786] 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 1359/1786] 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 1360/1786] 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 1361/1786] 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 1362/1786] 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 1363/1786] 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 1364/1786] 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 1365/1786] 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 1366/1786] 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 1367/1786] 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 1368/1786] 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 1369/1786] 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 1370/1786] 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 1371/1786] 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 1372/1786] 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 1373/1786] 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 1374/1786] 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 1375/1786] 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 1376/1786] 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 1377/1786] 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 1378/1786] 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 1379/1786] 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 1380/1786] 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 1381/1786] 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 1382/1786] 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 1383/1786] 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 1384/1786] 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 1385/1786] 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 1386/1786] 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 1387/1786] 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 1388/1786] 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 1389/1786] 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 1390/1786] 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 1391/1786] 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 1392/1786] 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 1393/1786] 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 1394/1786] 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 1395/1786] 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 1396/1786] 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 1397/1786] 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 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�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 1398/1786] 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 1399/1786] 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 1400/1786] 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 1401/1786] 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 1402/1786] 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 1403/1786] 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 1404/1786] 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 1405/1786] 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 1406/1786] 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 1407/1786] 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 1408/1786] 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 1409/1786] 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 1410/1786] 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 1411/1786] 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 1412/1786] 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 1413/1786] 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 1414/1786] 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 1415/1786] 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 1416/1786] 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 1417/1786] 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 1418/1786] 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 1419/1786] 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 1420/1786] 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 1421/1786] 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 1422/1786] 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 1423/1786] 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 1424/1786] 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 1425/1786] 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 1426/1786] 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 1427/1786] 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 1428/1786] 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 1429/1786] 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 1430/1786] 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 1431/1786] 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 1432/1786] 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 1433/1786] 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 1434/1786] 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 1435/1786] 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 zcma)%_dnE+G8IIZh!dJ@ z0g;0UCMQ62h^%Om=OFbE!KN6Z6$p4g-eGH-5|P>?Ds4GQavHbx%Ld%iwW;)QWWt+#+l<^V!ww42Bj)VXOYhKU zqT=#3kJnPWG)604)dbNNjSTtUUWLDw#fjer2af) zDr7kSsFQV6FiICvOmED}za@8hgPmT|C>ss9m{Adi8#!67Il^FJI`-b~(w zO_g_0-j9a(-(|+%w^~0KIMC~mctnfHCPxag)InZd%u+hL%J<)O*;+7e(c}3L_C>BmiZ42U#qY6 z7#WF6Kl*Cq1JTy|F{_}rGWh5DjP=}ZdPJbuwI=PVK6C3^SfjShZTJA<%OT4~@;_?D zJHc}^z2%9Y&?C{Bi;bA}Bo)WRZonB4(;0+Tsyo&xi{6alay9c`aOm4}RBuE7ynp(( zg8vbPxePy9r~K}&9x;ojqnlKw>GH6Hw6o#rjIxSj_;QDDivs8u&Y(0FkZO;FsgGFQ z<3^F>h%0U6mwFkgm5<~z)!?(q84*7?}A3_^Nlk_d9y!TFsMlp1`k#J zN#$k>&d8Mg5A?E~BiT)qNP$!gI&U7O-4q4GMd9e9!UKK}fM|LwOdt1x9An~L!$dew=gpvBkzLEFY0C`t8qZqn}`MApcH(c|el5v+Ue~$O< z73amU73*AFlXtNIvD_#L*GMg2vJVE19;@vh(q$f$*pvi_OO3q5;abaaXG06AX$Gm5 zlkaK4N=FrQbI!j&pc)?kg!f3LiE2aEWGN+!T$Ao@9H2?nD!|gcRZH(R&Zb>mgza2& zZHfQ9`gBq%JBpdzdhYhY$i$Oyhw|MUsa@0o(~~=eKMp=OdH1eV?7qamn{FbU)u`XN z@qKJPx&M+#R-mAqjN6$ybDQ&223y|NhW+jc;@HFBIAvv_tZM!TC!(FGP#vlupIjZe zj_diWBxxy|U<$D{Z2LIDH4O>vr(G;b_8f#P6(Az?Cg;`pT(Cz&}Z%K*)CCbLrQ~Yq?6`n0JD`t<%cWc+> zWD0i+HsbG8>N9F&XqntQ-&Yx;>6&2cBS?P?oC zYmjTLP~NM)w#`q*j23;om}oV6#Mvmzh1AwjbO-Oxr0e#Ou27g~d(Lx?CUai1#}m>h z!;l3ku7Sqev}q9n29mK&pjRL?mJTN_zvse$lo5$b-dg08Nd7(@rnnp8`yneONN|VlPt8v!@}s2` z2e{&6C^wAqn1&=a0b}idr}9^}-t^L_X3HIaPnN`u4oMgfU!s8^3y$J=p;R6?_V`*h zg=MdJpB0P;Gx;J3@!BbA<|E!Tw%c9yWF^S|y7C6k1!~V;=r0)Q77to4DjeUPdkh4B zJm-?waLxjz->tg7-puJOobj&R`W6W}Cd0?NBB3u{P^qdw1H!Qkhzj%!z>A{y1K}K9 zyV;?6*m0}98~Tp;IjkoG{;km55VX=YcS;r!2tM;NA_r(Ci>Zx?N>FA!GKYGSztXMK zF!ux#h83E4YR%FBSD&xTzuv6#b8}*@Ygjp~>7=v8yGb)%e1688rqEd05)~o#(*Wz_kEK zEEywEK=l8Vde8ib^7lx775RQ-gEg+AUZJ$#a9#OpZ_awxy5YoMV3m8Uy7t-HhlWHp zyU}g9#J{Tcy+m;Qa@OijrIE}Oi~il5I#!_|ut%A{Hz@s$(-gSU(*8~-I75G=kY%n1 zSn-jw-vP+`sLl4bU($us+!*4V`E0i{O@XOk-2C^wj~_Xy!h z&x14)PI%t64`{u_nCI5~kgnRhO=y1ga|0xL29LL`G10O43*4cx_`ynRB@j#cPx+oq z?26Y9c_`SZ=qg#)TZ7P`M0u2TCH19d$@25F-iV>GxN%hu#INuQ8YPkVoGL}MuVsdq zszlu4DTmLPA29>h8-@4kuZ$*QpUN!7v4RC1kk)gXZ~pJ2^Mx6KVih zA&dmz@uSu{N2R3`KOcuPw#&!)AGjcywE4G271htKisLV9{bB&T^RKANud>bQd75 z`wK+9sbF>S``%ni-?FVij1q};j$2HU+m_l1g}ILj6Db-1jtkhB0lj`!r>^99$-r8L z|61ACsLLlVBc_KPyj%X!?O@>yKU&~=6c27?BG-rYhm95#DV!yQQLys;eqvUBf3wNo zNya|5SVqW{-ui*brWI*N*1wjUf-!s00tEcTSMjS#F)=<9Ty=6^8%Cwg_dKx)z_6o# zgh56Ky4}}R3IA>O{(4!d1ABKjFPAk?vlu2UuG-HfTgKVCF1J?9MR(>k-eipg_rG$b zQN-O46uf>Yw*^~pX#u|dxC`9({pEifDeB)NV2eI^ddo?H_?hsX2jHsWlm=0vHI4*_ zDzCm}P?dAN7-2!CoDqNa%|w+6E23^^VcOc6Yw|RAs9r6KY`$__3t%+)Kf%9q06lP< zLhk;toD41P7*etT`lyMB!GIDBl!}dZVek19MSlpN-zNQ3w8KifB&^sZnP%Pp@Hu-# zAe_l$(YWXGDTBRi*wkOw!u-5Jx$xrNanO8^w1H&oshlfcYS^+&o4oShThZulZb9xq zhTsbz#Iw=+?JeygJ&RR5Q(-e&)$l#Hn7@1rW)baxMxu6D~AN~$ripJBH7t0XFz z^+WP+#DMjXyZdHFr@(6{UZz!$3isB`Ds-Y`$Pk9Pr;V_>nTeKCuG#Z3AW9BC)}|uT zy%_hNRbRc5&4rhDL=ZF`>lRlOGmqS>%=dTBPvevv_I0nOx&xltWeIX1jN4q+iO0vZ z(GY{=@yJ<~YbAJnC>EsdyW6khwk&;Rqwag?^U_tUS(uvasvPxzZmhiHQ}oHV^Ibxi zLcEW<11E-hc?hS)!5*$s>ANF%sLR4u$i&{5Yk!)iwPj`PaW`D%%+qX_GMX{Xu>+p- z23A!XkN0Q-nvNLE$SD;alCA=}aUxrt4o!!4mhDlf{;Ez9b&I~D4|Lt1Pv37=*XOx3 zOg5{|REUrX&r#ggE@j&JrjkwmHi^VR`IAHYTb%Ua%aikAae>Wh zrxdOFBhRUattyU5>Ha2E@hle0;u0UjQ(492jKdHa-RtrlxX0sJGe&=_W2OOQBPQ}u zy^#TaBKZg;o-$9($It0qRpdH!_m6#Z;=?t;MUEyCL`tdZ8y<&}Kk~qJ%bp<+Os)E?I$1yJ9 z>U!gjJDxGcPLM(Nt6_fzgK)%29{&I}TMfz21mI_mq>i<{Z=vZaH1|{Zw%$vLBqiBo zjZ5?(GQpD7H4nnh;cl`A9tm(n!D!o-3jR0L@OllMWLl``Ldj!#p^zZ~|aTft|xTxgd~Az6PmmP55yVaHbFj!$gh zV-=<>wE6C!OHUE4x<*tpP9egTLc;(s$R1-a8RQ(}12$*2(`|zl@hUy3Srp6PJg|h!l^uQG?8tw zlt!|W>4UkK<;Z{a{{Z#ZXAP#2b|!nz5*1+(V9jw3ORz$4pdOe%mmal6G<^wXEWRW~ zjpC7+cd02Lz&zvT1dadzk%BwZbAyj7{E_Kl`C&uZ)ZOoGe;28Z7}Cix9U|%FMgl;L zP7kLBlG%(pjl097N|wT8^O8j0<}U7^Fu>y@uX^bq(|mtF2bm?eh{MYy>RF7D#kF?l zKQK8YvFXQS(B+G#*g+)F!{TUu$gZ1yXm_?0^ljXMz&RZ8+nV5&DJeG{SDR-qB}#LX zr1bM_u^zdh83GRqhi6@Yi&%(Lg1P$c8Oc4mcdYvhjXL7Z+Y@yLLsof@w z%G;hc5HZG7jANpXGBJwLIjv=D8&gwlsawdatgVa|Kj_{Xy0lf4lJ{{)I*t^!;6?^M zyq+sd#8J&GNBb+o#?_Wj-UPLYnMS~I@??*^803F{5{@y?HGkrbYgC8Hy}oIp++SlN z;GbM#oonK)YR#O%e9PuO_xTs*KQFiY3;9*GeHm%nR7L%bs(BGd{f~NN4$M#4o8|{- z1EzX|`PIRvO)h-R7U&RJfbxoEcWuBNZaFG2GfO{>b*qcJd75+)+qyh<>Yuw^j2H}c z##DbEzO_jBi&i&+?A|w?BN2z%yeMGc0gQ0K8n{ivV&PTCYkkFuZAFCAHTIJ_J)}taawbK<~RE!RUW7E>Ps=|MApEB#_*W__lr&4ts;`j4w@J6nQZKuyX zR+m~e%=b?ul57lDF>M3@ODGt_5=iGG)18Se{5t67-@;m>0z)guBS@eStOiwx&eNa7 zeJhMQh1r-)W@8|YqRt20WhzJF2_KDV>HaO%^yMiO=Yw7xac8H0YDinc8mHJyUn&Kc%vZ?gImR)c#MF~oXsuwrPlWX^wH0I} zGl9HyC3g~|k&OPeh`uk^7WPZie9v<5`2t2zO0Mwy3}ZPRYMgrBr46H6$8^FLE=u5X zSYf%wc@({sN4xx3Dm8AM_VZ@GnHzt{s>y3{rXj-!Vz-rJBsi4|09zZlRvmlep{}D= zvrEe>xGj7u6}*yLsftWnpP#JjHAb2F`K^PQKM} z_^Vqo2|nKYgKr-y<99sc81MQIL5_$fm6_b#^?RM4_BFGvm2Y|B3xg-wyt04LG9Z!F z23eV04^#7CocnW~Z(ygyM(}uL#e`6#FKsAA`NDu(EO2wQoQ}Qvl6m+%TdrFqX$|+5 zv8yTti3ZSmfyaJ7AxQoz)})uslJ|Upm4iG;NFz8SBeqZHRwGkd()B%0&b+bFjjo>> zg3IJb3jzmHpy!_0>ySA;b8mmNT}9$sl+vzaQ}PkyZDX|)b8Q^sCppGB>ryw3d_?>A zYH#!X@7s2J<6U2X@TxMnC16epNiG_bZv&#E;=!X%)${ z8Af#~CPLX!mH|U#kTJmZ6&$`B)uDmqmel$>|5J)V%7$A)c29UHW!LU@Q7&*Zs9OU44Ijmn2 z>S8e-LZ>+TV$AsT{Mi?aK4= z}Ue&Y-bo=YA0r%OGa^OV5AiBaGpcvVqVqPDTZD z1H?M~1{lV%sYYPOl%nQA<=_xDjPb!eJxu_55_st98n^Z|Iuu`OlIdApZy6VQj)xJ3 zBaVlu>J3_)>b@+o)_%vN+l9Hai_B?n3&#q^(jjF}ED*%R=js9E@m^f|j<0n*b3N7M zvp`5$H?d?Sl6imYlh5VtS{@qJ=Cajeitkd?t?benRL5;JirEP4hysz;M(M!$j&YJ` z16nVIz9E)PifsWMcSyhwkUlfF`>a1-Lx}$X;aPZu+&l`l%_=gfQ6U{m0C^ogQhmk< z&TFZ%zVNl}g`m{+{d7wutE|zPE?pF`17YCg5yl2V1FwHdY?s~=wzIh_t?P45_J(+2 zhD(()AR&SIfE%|noad>}u>kWuQ%sjhycW|-431+-GZ7>J${2M6oDhE+rCz5kr^7qD zo7r1YznV26V34ft#YVt0l;8!(=g@l!;I-&9{{Zb-n?#OQ(}J&-({HV0JL>AYlhClYgxGxRjw zEqs4Lp;+BnM{i*)Z6@dQi!owA9f$;H9eeXwLgT}PL|W49GRGKoUW~y2bIbFV+(t3R zDIRYP{_rKW@C5v%k&r*{uTR(7wMsVE^Zx*Va8#*XO{m`A;r)4zyTlrgi4$12wz`i- zdzcE`FOwTMAx|7OamhT4A47_xdE#AdZ0vv9TTL_><#;1>hCv`;6P~~H(Q$xzQN~nO z7N>RLskI&2eTCJ%p3l1NxwmJ~vEv!%Jx@+BXw5E|V6|9ak!4w(r)CEY840ujyRi@H z)N@?Xa^`95bw$gar?;o-be6itu?DfJTC5sqc_%?J!-U`Fa5o{#WsZJgP5~SYgHL}= z{?wCReQwxVO*?OwYlkSo_o3kP*|^WA(zN_Ax(wPkjAWA1JPT~teWEcV#&*fkvGSk0 z`f_oa;VWd(N)-8Gqp~@fusC zZD*!9M=Tht6O)2Z-uBLZwdd4TsZ)QpvHXAF9W>=lM$=b*w*48~N#i|bE-r1J$4g%| zUPnP2ZNOZSfZyy4XV7-VO$Uy(o5YMIj*!c>kVMeA2Lv8Q>~|lXaCB5B9&5FrDMOm} z)70#w@fNgN0PtB6G=U;Pyagnao*TJtbJqZ#MrzR2yh5`|=@y=$Sow*$_U?an^A2*~ z?vA*?1J^tq6`e%eyd9U{{zf&Fr7P2RUw`=?gAa)OL3yiNMID}!CAf!rov*c{L@k5! zX8-_4`=EM?)fT=qFht_dNxn|vy^6vI02kFvW+xWg+?;_}1A&J;T44`3( zatCZ|80o_>?}6kLR*5ycH*V*v*h%86i&!pg?EF0{UNcCrjIbmUgp#Le&fcV+-k14MJP;?E)M;pIdQn1y#`wckTZ(%`YDL@3%maS6n|ZtZl1iWp;#Nmx9NK^s9JHzenhJF)k#Fpfuw zi$=v*sZvLw1QGaxMK*>A>*DcluW@#6A&$_hOur^13dd}K9B%Fj&(VD;lYBzerGerW z_EGP1A#_F!xT##{cPD?G^W0Y`2~&_rIL8!}l6M=mj=20p)x6E=X{VvjMTxP{jB?y{ z{{T5O;qf0<-4n@Yr^@lJ-O@(qaP&VmG1rfC>s);l#C2)o?Ls&j6|mFx85T}a&&;Hd ze*XYml5^KQ_2!)y#64aX20MEd8FExaa6=rhBX>;m>z=2Ro=P-|0GjgU?{8CGt5o5D?I5GUFe!PZ3NEf0d*DcBlYP zvowE8<=rpMsFTWpxzukmSlEJf8*2|*4MtBu0b^zC``Cpz__*4dtUn~+$>~!i$K4ZqXYQL zL|6LeyVx>0nt9_|TtRnE6x9SOhUs}4zlD``ZTc%g{O zLun*VcXeK1MGGa=YarvUwmSKy#)k>Nd>f{7kg^kpe$o&BTGf1W>%aPPbADlym!bo$n5RO`y$PY~)#Z@l#QN9+HK1xw5xwU3+h zXT&Z~Y=Y!^Iww`4C|K9u)QW2iUm{skMX$IX=&tm(R`c5LiuTi0O_W7~jxWxiS#J_S zVlsRzXN_Iodj+C+C}nEMKzajp8hJnibOAps_^h%*bU)=~f8N0QaULLsJ4vuUAR^S^ z+9lS3aAz=1n058pjo#M_+DV%T5_xT|f->0Zg*BPeaR5DqlZ(UxSgY)m1Nevh4r#Yx zW3l`~0nL*pD1Zuom&ZPFh0NQT;?>Zv1k-$J5)fma=QY;a{{aUe3JlrPxWfZLW_GL; ziAvy|Sw`BYfAOI^>rF6xIVcz!?BRZs<0^(!?AyrVF6dzH$din+Oo&_aaf~ZISPi>skqZ`ZU=k}K$L4@I1M;|*S7Ckg$A)R&!;JbHhQ{WbCS{>+w m?X8>I9uN Date: Tue, 23 Apr 2024 10:14:47 +0200 Subject: [PATCH 1436/1786] 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 1437/1786] 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 1438/1786] 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 1439/1786] 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 27f7ef169f11d0be54c044843be311737069020f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 15 Aug 2022 17:13:56 +0200 Subject: [PATCH 1440/1786] logo: optimize the svg file (cherry picked from commit 83372d8b074194c011151f6c7cfc8bb2702731ec) --- 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 68fdcaf25949d9ca960d5d76c2decc5a7091d744 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 3 Mar 2023 17:18:23 +0100 Subject: [PATCH 1441/1786] use a new logo (cherry picked from commit 154a036c64a0dc5961ef4de0f0d931617ed95d4c) --- 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 23ba2ce67af2d580c2e042f0cdddcf59881b755f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 23 May 2023 11:25:43 +0200 Subject: [PATCH 1442/1786] logo: rename SVG ids (cherry picked from commit c2e7567c13bba80190ad5c2dd7c6ad7b025619e3) --- 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 ef437367a7c66709880485c15c808e1ca0f42e75 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 20 Mar 2023 16:32:34 +0100 Subject: [PATCH 1443/1786] README: badge in style flat and with color (cherry picked from commit 524c1fc032db7e4c361b90fe912fef036f1f59e2) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7b01c54..166ec97 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 06bd3a96b5b056c458307127d3aa298452d3cd43 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Apr 2023 13:53:04 +0200 Subject: [PATCH 1444/1786] README: add badge to hint required RouterOS version (cherry picked from commit f585b6ee32a6c7a4e860f17e4f9d332021f856aa) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 166ec97..8f40eab 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-6.49-yellow?style=flat) ![RouterOS Scripts Logo](logo.svg) From 79665d29ce738540c9994ade3f8ae357e6e4c5ad Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sun, 16 Apr 2023 22:04:20 +0200 Subject: [PATCH 1445/1786] README: add badge to link Telegram group (cherry picked from commit f1c634b984c5ae25bab1abee296f59e9bb74c6c7) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8f40eab..879e55b 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-6.49-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 eaf972d61850920dac3bd2f7de77b800bfdbe65b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 18 Apr 2023 18:23:41 +0200 Subject: [PATCH 1446/1786] README: generate a donate buttom from shields.io (cherry picked from commit 5324bffd840fd4201d231044f28e7f30e876d6d7) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 879e55b..82e9931 100644 --- a/README.md +++ b/README.md @@ -284,7 +284,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 646a7f8c117a651714d5f381e9100934a7c8bc43 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 18 Apr 2023 21:59:47 +0200 Subject: [PATCH 1447/1786] README: add a donate button to badges (cherry picked from commit f7eb123f3d35b0bad19e94ee74f6252865743b89) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 82e9931..2d0c7ab 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-6.49-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 fe7543cef512dc93ecb371f4be4a5c426315351f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 18 Apr 2023 22:00:39 +0200 Subject: [PATCH 1448/1786] README: make the Telegram QR code a link (cherry picked from commit 69ea231efcbfcb967cbcbfecf802ca00b130a931) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d0c7ab..6b025ad 100644 --- a/README.md +++ b/README.md @@ -263,7 +263,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 c6adece2714098f46ae7364864c05d25227aa0ff Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Jun 2023 16:24:25 +0200 Subject: [PATCH 1449/1786] README: link the RouterOS button to changelog (cherry picked from commit 4e411728e676050c4c53efafc3fdde1b2547f52e) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b025ad..b14359a 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-6.49-yellow?style=flat) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-6.49-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_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 d4305b53bf4872a14c2edd5eb1d5bd5bb26dc50b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 15 Mar 2024 11:26:44 +0100 Subject: [PATCH 1450/1786] README: add QR code with (shortened) upstream url (cherry picked from commit 2cf4f333d4ab3a0db2742965a430a5d5836c588b) --- 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 b14359a..75173cb 100644 --- a/README.md +++ b/README.md @@ -305,6 +305,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 c28574b8f4484463e326e895fcac110d805efa01 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 19 Aug 2024 10:35:18 +0200 Subject: [PATCH 1451/1786] 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 2ef06e4533677594b68dd2734dcfd3ccbd6c1145 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 19 Aug 2024 10:35:18 +0200 Subject: [PATCH 1452/1786] README: make the QR code a link (cherry picked from commit c28574b8f4484463e326e895fcac110d805efa01) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 75173cb..0dcb909 100644 --- a/README.md +++ b/README.md @@ -305,7 +305,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 2cda1e9c4c3dd16c72c457e7ad2061da4992941f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 19 Aug 2024 14:42:29 +0200 Subject: [PATCH 1453/1786] adopt all required certificate changes --- INITIAL-COMMANDS.md | 11 +- README.md | 16 +- certs/Cloudflare Inc ECC CA-3.pem | 166 ------------ certs/DigiCert Global Root CA.pem | 29 +++ certs/DigiCert Global Root G2.pem | 29 +++ ...igiCert TLS Hybrid ECC SHA384 2020 CA1.pem | 174 ------------- certs/E1.pem | 243 ------------------ certs/GTS CA 1C3.pem | 242 ----------------- certs/GTS Root R1.pem | 38 +++ certs/GTS Root R4.pem | 20 ++ ... Daddy Root Certificate Authority - G2.pem | 30 +++ ...addy Secure Certificate Authority - G2.pem | 178 ------------- certs/ISRG Root X1.pem | 38 +++ certs/ISRG Root X2.pem | 21 ++ certs/R3.pem | 237 ----------------- ...rfield Root Certificate Authority - G2.pem | 30 +++ ...ield Secure Certificate Authority - G2.pem | 179 ------------- global-functions | 6 +- mod/notification-telegram | 2 +- update-tunnelbroker | 2 +- 20 files changed, 252 insertions(+), 1439 deletions(-) delete mode 100644 certs/Cloudflare Inc ECC CA-3.pem create mode 100644 certs/DigiCert Global Root CA.pem create mode 100644 certs/DigiCert Global Root G2.pem delete mode 100644 certs/DigiCert TLS Hybrid ECC SHA384 2020 CA1.pem delete mode 100644 certs/E1.pem delete mode 100644 certs/GTS CA 1C3.pem create mode 100644 certs/GTS Root R1.pem create mode 100644 certs/GTS Root R4.pem create mode 100644 certs/Go Daddy Root Certificate Authority - G2.pem delete mode 100644 certs/Go Daddy Secure Certificate Authority - G2.pem create mode 100644 certs/ISRG Root X1.pem create mode 100644 certs/ISRG Root X2.pem delete mode 100644 certs/R3.pem create mode 100644 certs/Starfield Root Certificate Authority - G2.pem delete mode 100644 certs/Starfield Secure Certificate Authority - G2.pem diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 33e424a..212e8be 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/ISRG-Root-X2.pem" dst-path="isrg-root-x2.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=isrg-root-x2.pem passphrase=""; + :if ([ :len [ / certificate find where fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470" ] ] != 1) do={ :error "Something is wrong with your certificates!"; }; - / file remove "letsencrypt-R3.pem"; + / file remove "isrg-root-x2.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 . "\?h=routeros-v6") output=user as-value]->"data"); @@ -24,8 +24,7 @@ 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 "ISRG Root X2"; } Optional to update the scripts automatically: diff --git a/README.md b/README.md index 0dcb909..ebc406b 100644 --- a/README.md +++ b/README.md @@ -53,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/ISRG-Root-X2.pem" dst-path="isrg-root-x2.pem"; ![screenshot: download certs](README.d/01-download-certs.avif) @@ -61,21 +61,19 @@ 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) Then we import the certificates. - / certificate import file-name=letsencrypt-R3.pem passphrase=""; + / certificate import file-name=isrg-root-x2.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**. +For basic verification we rename the certificate and print the count. Make +sure the certificate count is **one**. - / 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="ISRG-Root-X2" [ find where common-name="ISRG Root X2" ]; + / certificate print count-only where fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470"; ![screenshot: check certs](README.d/03-check-certs.avif) 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/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 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/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/certs/E1.pem b/certs/E1.pem deleted file mode 100644 index 4c3c212..0000000 --- a/certs/E1.pem +++ /dev/null @@ -1,243 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - b3:bd:df:f8:a7:84:5b:bc:e9:03:a0:41:35:b3:4a:45 - Signature Algorithm: ecdsa-with-SHA384 - Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X2 - Validity - Not Before: Sep 4 00:00:00 2020 GMT - Not After : Sep 15 16:00:00 2025 GMT - Subject: C = US, O = Let's Encrypt, CN = E1 - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (384 bit) - pub: - 04:24:5c:2d:a2:2a:fd:1c:4b:a6:5d:97:73:27:31: - ac:b2:a0:69:62:ef:65:e8:a6:b0:f0:ac:4b:9f:ff: - 1c:0b:70:0f:d3:98:2f:4d:fc:0f:00:9b:37:f0:74: - 05:57:32:97:2e:05:ef:2a:43:25:a3:fb:6e:34:27: - 13:f6:4f:7e:69:d3:02:99:5e:eb:24:47:92:c1:24: - 9b:e6:b1:21:8f:c1:24:81:fc:68:cc:1f:69:ba:58: - f5:19:22:f7:74:c6:16 - ASN1 OID: secp384r1 - NIST CURVE: P-384 - X509v3 extensions: - X509v3 Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - X509v3 Extended Key Usage: - TLS Web Client Authentication, TLS Web Server Authentication - X509v3 Basic Constraints: critical - CA:TRUE, pathlen:0 - X509v3 Subject Key Identifier: - 5A:F3:ED:2B:FC:36:C2:37:79:B9:52:30:EA:54:6F:CF:55:CB:2E:AC - X509v3 Authority Key Identifier: - keyid:7C:42:96:AE:DE:4B:48:3B:FA:92:F8:9E:8C:CF:6D:8B:A9:72:37:95 - - Authority Information Access: - CA Issuers - URI:http://x2.i.lencr.org/ - - X509v3 CRL Distribution Points: - - Full Name: - URI:http://x2.c.lencr.org/ - - X509v3 Certificate Policies: - Policy: 2.23.140.1.2.1 - Policy: 1.3.6.1.4.1.44947.1.1.1 - - Signature Algorithm: ecdsa-with-SHA384 - 30:64:02:30:7b:74:d5:52:13:8d:61:fe:0d:ba:3f:03:00:9d: - f3:d7:98:84:d9:57:2e:bd:e9:0f:9c:5c:48:04:21:f2:cb:b3: - 60:72:8e:97:d6:12:4f:ca:44:f6:42:c9:d3:7b:86:a9:02:30: - 5a:b1:b1:b4:ed:ea:60:99:20:b1:38:03:ca:3d:a0:26:b8:ee: - 6e:2d:4a:f6:c6:66:1f:33:9a:db:92:4a:d5:f5:29:13:c6:70: - 62:28:ba:23:8c:cf:3d:2f:cb:82:e9:7f ------BEGIN CERTIFICATE----- -MIICxjCCAk2gAwIBAgIRALO93/inhFu86QOgQTWzSkUwCgYIKoZIzj0EAwMwTzEL -MAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNo -IEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDIwHhcNMjAwOTA0MDAwMDAwWhcN -MjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3MgRW5j -cnlwdDELMAkGA1UEAxMCRTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQkXC2iKv0c -S6Zdl3MnMayyoGli72XoprDwrEuf/xwLcA/TmC9N/A8AmzfwdAVXMpcuBe8qQyWj -+240JxP2T35p0wKZXuskR5LBJJvmsSGPwSSB/GjMH2m6WPUZIvd0xhajggEIMIIB -BDAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB -MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFFrz7Sv8NsI3eblSMOpUb89V -yy6sMB8GA1UdIwQYMBaAFHxClq7eS0g7+pL4nozPbYupcjeVMDIGCCsGAQUFBwEB -BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gyLmkubGVuY3Iub3JnLzAnBgNVHR8E -IDAeMBygGqAYhhZodHRwOi8veDIuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYG -Z4EMAQIBMA0GCysGAQQBgt8TAQEBMAoGCCqGSM49BAMDA2cAMGQCMHt01VITjWH+ -Dbo/AwCd89eYhNlXLr3pD5xcSAQh8suzYHKOl9YST8pE9kLJ03uGqQIwWrGxtO3q -YJkgsTgDyj2gJrjubi1K9sZmHzOa25JK1fUpE8ZwYii6I4zPPS/Lgul/ ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 41:d2:9d:d1:72:ea:ee:a7:80:c1:2c:6c:e9:2f:87:52 - Signature Algorithm: ecdsa-with-SHA384 - Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X2 - Validity - Not Before: Sep 4 00:00:00 2020 GMT - Not After : Sep 17 16:00:00 2040 GMT - Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X2 - Subject Public Key Info: - Public Key Algorithm: id-ecPublicKey - Public-Key: (384 bit) - pub: - 04:cd:9b:d5:9f:80:83:0a:ec:09:4a:f3:16:4a:3e: - 5c:cf:77:ac:de:67:05:0d:1d:07:b6:dc:16:fb:5a: - 8b:14:db:e2:71:60:c4:ba:45:95:11:89:8e:ea:06: - df:f7:2a:16:1c:a4:b9:c5:c5:32:e0:03:e0:1e:82: - 18:38:8b:d7:45:d8:0a:6a:6e:e6:00:77:fb:02:51: - 7d:22:d8:0a:6e:9a:5b:77:df:f0:fa:41:ec:39:dc: - 75:ca:68:07:0c:1f:ea - ASN1 OID: secp384r1 - NIST CURVE: P-384 - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - 7C:42:96:AE:DE:4B:48:3B:FA:92:F8:9E:8C:CF:6D:8B:A9:72:37:95 - Signature Algorithm: ecdsa-with-SHA384 - 30:65:02:30:7b:79:4e:46:50:84:c2:44:87:46:1b:45:70:ff: - 58:99:de:f4:fd:a4:d2:55:a6:20:2d:74:d6:34:bc:41:a3:50: - 5f:01:27:56:b4:be:27:75:06:af:12:2e:75:98:8d:fc:02:31: - 00:8b:f5:77:6c:d4:c8:65:aa:e0:0b:2c:ee:14:9d:27:37:a4: - f9:53:a5:51:e4:29:83:d7:f8:90:31:5b:42:9f:0a:f5:fe:ae: - 00:68:e7:8c:49:0f:b6:6f:5b:5b:15:f2:e7 ------BEGIN CERTIFICATE----- -MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw -CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg -R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 -MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT -ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw -EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW -+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 -ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI -zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW -tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 -/q4AaOeMSQ+2b1tbFfLn ------END CERTIFICATE----- -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 82:10:cf:b0:d2:40:e3:59:44:63:e0:bb:63:82:8b:00 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 - Validity - Not Before: Jun 4 11:04:38 2015 GMT - Not After : Jun 4 11:04:38 2035 GMT - Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (4096 bit) - Modulus: - 00:ad:e8:24:73:f4:14:37:f3:9b:9e:2b:57:28:1c: - 87:be:dc:b7:df:38:90:8c:6e:3c:e6:57:a0:78:f7: - 75:c2:a2:fe:f5:6a:6e:f6:00:4f:28:db:de:68:86: - 6c:44:93:b6:b1:63:fd:14:12:6b:bf:1f:d2:ea:31: - 9b:21:7e:d1:33:3c:ba:48:f5:dd:79:df:b3:b8:ff: - 12:f1:21:9a:4b:c1:8a:86:71:69:4a:66:66:6c:8f: - 7e:3c:70:bf:ad:29:22:06:f3:e4:c0:e6:80:ae:e2: - 4b:8f:b7:99:7e:94:03:9f:d3:47:97:7c:99:48:23: - 53:e8:38:ae:4f:0a:6f:83:2e:d1:49:57:8c:80:74: - b6:da:2f:d0:38:8d:7b:03:70:21:1b:75:f2:30:3c: - fa:8f:ae:dd:da:63:ab:eb:16:4f:c2:8e:11:4b:7e: - cf:0b:e8:ff:b5:77:2e:f4:b2:7b:4a:e0:4c:12:25: - 0c:70:8d:03:29:a0:e1:53:24:ec:13:d9:ee:19:bf: - 10:b3:4a:8c:3f:89:a3:61:51:de:ac:87:07:94:f4: - 63:71:ec:2e:e2:6f:5b:98:81:e1:89:5c:34:79:6c: - 76:ef:3b:90:62:79:e6:db:a4:9a:2f:26:c5:d0:10: - e1:0e:de:d9:10:8e:16:fb:b7:f7:a8:f7:c7:e5:02: - 07:98:8f:36:08:95:e7:e2:37:96:0d:36:75:9e:fb: - 0e:72:b1:1d:9b:bc:03:f9:49:05:d8:81:dd:05:b4: - 2a:d6:41:e9:ac:01:76:95:0a:0f:d8:df:d5:bd:12: - 1f:35:2f:28:17:6c:d2:98:c1:a8:09:64:77:6e:47: - 37:ba:ce:ac:59:5e:68:9d:7f:72:d6:89:c5:06:41: - 29:3e:59:3e:dd:26:f5:24:c9:11:a7:5a:a3:4c:40: - 1f:46:a1:99:b5:a7:3a:51:6e:86:3b:9e:7d:72:a7: - 12:05:78:59:ed:3e:51:78:15:0b:03:8f:8d:d0:2f: - 05:b2:3e:7b:4a:1c:4b:73:05:12:fc:c6:ea:e0:50: - 13:7c:43:93:74:b3:ca:74:e7:8e:1f:01:08:d0:30: - d4:5b:71:36:b4:07:ba:c1:30:30:5c:48:b7:82:3b: - 98:a6:7d:60:8a:a2:a3:29:82:cc:ba:bd:83:04:1b: - a2:83:03:41:a1:d6:05:f1:1b:c2:b6:f0:a8:7c:86: - 3b:46:a8:48:2a:88:dc:76:9a:76:bf:1f:6a:a5:3d: - 19:8f:eb:38:f3:64:de:c8:2b:0d:0a:28:ff:f7:db: - e2:15:42:d4:22:d0:27:5d:e1:79:fe:18:e7:70:88: - ad:4e:e6:d9:8b:3a:c6:dd:27:51:6e:ff:bc:64:f5: - 33:43:4f - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E - Signature Algorithm: sha256WithRSAEncryption - 55:1f:58:a9:bc:b2:a8:50:d0:0c:b1:d8:1a:69:20:27:29:08: - ac:61:75:5c:8a:6e:f8:82:e5:69:2f:d5:f6:56:4b:b9:b8:73: - 10:59:d3:21:97:7e:e7:4c:71:fb:b2:d2:60:ad:39:a8:0b:ea: - 17:21:56:85:f1:50:0e:59:eb:ce:e0:59:e9:ba:c9:15:ef:86: - 9d:8f:84:80:f6:e4:e9:91:90:dc:17:9b:62:1b:45:f0:66:95: - d2:7c:6f:c2:ea:3b:ef:1f:cf:cb:d6:ae:27:f1:a9:b0:c8:ae: - fd:7d:7e:9a:fa:22:04:eb:ff:d9:7f:ea:91:2b:22:b1:17:0e: - 8f:f2:8a:34:5b:58:d8:fc:01:c9:54:b9:b8:26:cc:8a:88:33: - 89:4c:2d:84:3c:82:df:ee:96:57:05:ba:2c:bb:f7:c4:b7:c7: - 4e:3b:82:be:31:c8:22:73:73:92:d1:c2:80:a4:39:39:10:33: - 23:82:4c:3c:9f:86:b2:55:98:1d:be:29:86:8c:22:9b:9e:e2: - 6b:3b:57:3a:82:70:4d:dc:09:c7:89:cb:0a:07:4d:6c:e8:5d: - 8e:c9:ef:ce:ab:c7:bb:b5:2b:4e:45:d6:4a:d0:26:cc:e5:72: - ca:08:6a:a5:95:e3:15:a1:f7:a4:ed:c9:2c:5f:a5:fb:ff:ac: - 28:02:2e:be:d7:7b:bb:e3:71:7b:90:16:d3:07:5e:46:53:7c: - 37:07:42:8c:d3:c4:96:9c:d5:99:b5:2a:e0:95:1a:80:48:ae: - 4c:39:07:ce:cc:47:a4:52:95:2b:ba:b8:fb:ad:d2:33:53:7d: - e5:1d:4d:6d:d5:a1:b1:c7:42:6f:e6:40:27:35:5c:a3:28:b7: - 07:8d:e7:8d:33:90:e7:23:9f:fb:50:9c:79:6c:46:d5:b4:15: - b3:96:6e:7e:9b:0c:96:3a:b8:52:2d:3f:d6:5b:e1:fb:08:c2: - 84:fe:24:a8:a3:89:da:ac:6a:e1:18:2a:b1:a8:43:61:5b:d3: - 1f:dc:3b:8d:76:f2:2d:e8:8d:75:df:17:33:6c:3d:53:fb:7b: - cb:41:5f:ff:dc:a2:d0:61:38:e1:96:b8:ac:5d:8b:37:d7:75: - d5:33:c0:99:11:ae:9d:41:c1:72:75:84:be:02:41:42:5f:67: - 24:48:94:d1:9b:27:be:07:3f:b9:b8:4f:81:74:51:e1:7a:b7: - ed:9d:23:e2:be:e0:d5:28:04:13:3c:31:03:9e:dd:7a:6c:8f: - c6:07:18:c6:7f:de:47:8e:3f:28:9e:04:06:cf:a5:54:34:77: - bd:ec:89:9b:e9:17:43:df:5b:db:5f:fe:8e:1e:57:a2:cd:40: - 9d:7e:62:22:da:de:18:27 ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- diff --git a/certs/GTS CA 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 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/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/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/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/ISRG Root X2.pem b/certs/ISRG Root X2.pem new file mode 100644 index 0000000..9cca880 --- /dev/null +++ b/certs/ISRG Root X2.pem @@ -0,0 +1,21 @@ +# Issuer: CN=ISRG Root X2 O=Internet Security Research Group +# Subject: CN=ISRG Root X2 O=Internet Security Research Group +# Label: "ISRG Root X2" +# Serial: 87493402998870891108772069816698636114 +# MD5 Fingerprint: d3:9e:c4:1e:23:3c:a6:df:cf:a3:7e:6d:e0:14:e6:e5 +# SHA1 Fingerprint: bd:b1:b9:3c:d5:97:8d:45:c6:26:14:55:f8:db:95:c7:5a:d1:53:af +# SHA256 Fingerprint: 69:72:9b:8e:15:a8:6e:fc:17:7a:57:af:b7:17:1d:fc:64:ad:d2:8c:2f:ca:8c:f1:50:7e:34:45:3c:cb:14:70 +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- diff --git a/certs/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/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/global-functions b/global-functions index e40e384..172173e 100644 --- a/global-functions +++ b/global-functions @@ -282,7 +282,7 @@ :return true; } - :if ([ $CertificateAvailable "R3" ] = false) do={ + :if ([ $CertificateAvailable "ISRG Root X1" ] = false) do={ $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; } @@ -401,7 +401,7 @@ :global LogPrintExit2; :do { - :if ([ $CertificateAvailable "Cloudflare Inc ECC CA-3" ] = false) do={ + :if ([ $CertificateAvailable "GTS Root R4" ] = false) do={ $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; } :local Vendor ([ / tool fetch check-certificate=yes-without-crl \ @@ -711,7 +711,7 @@ :global SymbolForNotification; :global ValidateSyntax; - :if ([ $CertificateAvailable "R3" ] = false) do={ + :if ([ $CertificateAvailable "ISRG Root X2" ] = false) do={ $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; } diff --git a/mod/notification-telegram b/mod/notification-telegram index d42d459..d50f6d7 100644 --- a/mod/notification-telegram +++ b/mod/notification-telegram @@ -122,7 +122,7 @@ :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; :do { - :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ + :if ([ $CertificateAvailable "Go Daddy Root 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 \ diff --git a/update-tunnelbroker b/update-tunnelbroker index d454cd7..53b0edd 100644 --- a/update-tunnelbroker +++ b/update-tunnelbroker @@ -34,7 +34,7 @@ :if ($PublicAddress != $InterfaceVal->"local-address") do={ :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; - :if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ + :if ([ $CertificateAvailable "Starfield Root 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; From 342d459436414ea94b9081474122c60b50f61569 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 19 Aug 2024 14:54:17 +0200 Subject: [PATCH 1454/1786] 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 1455/1786] 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 1456/1786] 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 1457/1786] 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 1458/1786] 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 1459/1786] 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 1460/1786] 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 1461/1786] 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 1462/1786] 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 1463/1786] 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 1464/1786] =?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 1465/1786] 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 1466/1786] 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 1467/1786] 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 1468/1786] 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 1469/1786] 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 1470/1786] 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 1471/1786] 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 1472/1786] 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 1473/1786] 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 1474/1786] 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 1475/1786] 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 1476/1786] 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 1477/1786] 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 1478/1786] 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 1479/1786] 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 1480/1786] 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 1481/1786] 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 1482/1786] 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 1483/1786] 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 1484/1786] 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 1485/1786] 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 1486/1786] 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 1487/1786] 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 1488/1786] 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 1489/1786] 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 1490/1786] 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 1491/1786] 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 zcmeFYbx>r>(l6T3xVt;d;O-3WGPt`lxVsECxWnM?4uiY9yEC}EyIf|U@0`8wi!b7S z??$};UUgJeR%KSM{AI4SD!ZZ^000n~IJ(*DJDZsRKFXio%FKk(%1qxxT7Xdi008N> zGIrGe!}}-{rbd?b{~`eZTQft)f75?@OEZIit3j|ebF})42lCN!nOWKx{uv1a06@T> znUDG@6#$TR1AzW(M0)TsS@XgDiwAN901&@@(3)mu)_>Xc7YFBKVEkvnpY{6A42(iH zmNtKx^Ec;%{f8r9X=|$gM-ux#Yd&;~xSE;#sec$0X7bZKMLs1hb6Zk1d^?ptJ$9!AQTkTM+c|x z%qZkb_GbowYG`9=Z*6Gl`k@;h0O9j7_2Hd=iG%zt42JhdnB&6`p+AI^y)~DWt?{?N z8bK~YGecW02R8>tV=D))4;eE{GktqEF8zO_BrvnJ`U~#I(hnG5AfWzW08lUx@IXia zz=6riNdK=$Nk~uu{#^3IgpUdhcmsg_h4>H7k5zxse;SbgqRT&~K|z3jIp61l27b_g zWFh|4f6(avMgJ8((0}O({Ez|tFWQ0lWAIU+{`$NxzHb1KBt<1eKQ8nqmLJXg3P1<| z1pxsG0S*NT2?-4i1p|i$4+jeihmC@Yh=z|tNPv%nhet$4M@~dSLyCt-!A?oTz{tYF zLP*ZZ!@e1IhZfFgqckwM;j z0fZlRf`j~3{srY@3qC;*p)vW!WJ8e(R&}8(OkI#M8`%3n!(d=yVdH%IOin>b#lp(Q&cVqgBrGB-CN3eV zsHCi-s-~`CXk={i&D6}?!O_Xt#nsK-|3^SzP;f|SY~0WIgv6xel$_kW{DQ)w;*#o` z+PeCN#-`@(p5DIxfx)5S>6zKN`Gv)$<;|__o!!0tgTtfCtLvNFyZeX7r$4y<;QV*_ z7qb5cF60kfpkQD?Fvvf+KtNso07nJ`CuW2|5s-(}w?idi@`XYZjLEL*f+l5FxIj0s zpMt?4W7+(4`3Krx$o^-*{Qj?y{Ri0JxRwEMK#-5%0g(ZGfa}F=S=#R+2VWHH$?q|* zN*NFD3s~O)LX8J}yK&wDU!J+{-#pLw&S$&>0O~atr+v4X%el{7#p83%Aejxo4sI{= zcYtqg3$1G3lT-X@^N0;up*sOkA8R|xmI~JFmfBQ5+{}2C&n|_MiPxYf8?X^Ks}kiq za>z?RQ(38(LG8NxWwm?2T0YQ~AWsgmy1~yAufb%|)p;ph89O*C08SkLRcV^tpBt$< zX+`uGLK&K0kpJOram9y`aI3!u96nuMldgn|zMOJmKYE}lNNn-Jj!MLCV#UQJ=~hP}_vY;zu#`73} zUoy6Q2)T2K$akE82wO!_t5;~l{3LU@1J(Vbz% z`Z++~!lMQyRvCtEQdR*RAitQosyiGJ^4j-Ovi?uo_-ZP>_s6&2UfCbyz>t?&s-#E+ zu}J_;09)ujMgtYSY!I>yIF)cl^Ms2rIF*{-CRZf?^1HS2c|Cjd)wO5WD zy1!0pa|jc=km4aq0-lnz#f)?FN0+X)10*_!4ybyW$u7?Y?Pj7yM9hWMI$>hrB%w%` z3*gWIXg(YtQL{R09j^-d}RapI6KR-SGxP*df>C}mxPlf_5Xg9c>PpKyWE&;jh zL%s4_igtEV%F^I!3Xd>YYsiFpHq*_P>Q@0NC?J(ewkt+bUi%s7;ubH-u`PGD@}{M0fe zV}(O{`@oASFk`Y+qR5=RYJep&>(?;T#zwgRq!(}2f@pINv*CR%05xN2;z1R?)U5i! zK`nHPx`|;BlyRI1dK)a}MR{3Gm=&LGZMQY>+7Qk*8GC>vUxIB*FvZ^PC}^Nqght0e zyw82V5NqP9prRmrQ^0OWK^BXY^G&oY70wSaenK~H1ud*FfGmohW+j9=!^?dRLymyB z=95_Z=RH8tvc16hO)=@b)lQ6@1QCrmSTQilz2P+j3W&4;=UsX#^Nf5O_V$nk_w3~i zn>3Q0=+^`8MQFyiaQHCiTU4AR%sn=6vx9i7SneYT6Z|tWDGKWyz{xTP`JN4yRr!8Sw77cV+0Z6~q`U-hz-aS^Lp{wM0}M&_~nK)x8pe1Q9I&=kvfjp!`V0e0f=8$>y20G0JU3&*_f~ zM^3qV6tBMjHiVyu-4bs-@VC^T48LJXe?o^udp!-aYm6m}1_e@Z@ZQSI$YU!0xC*5X zGF`F#;ul>Wv$%8f4!Bhwdk35}?8=E)fiY3%Sz{~Z?8MdL83APRA$PyVSf5Rgv$~-N zlM_;mFPE zWv5&FpSQ{00oDv=cgS4dK=KU7oHOWZpI!X=+OJBsczWIKv=W2LYFF@?UMe!d7NUs6 zNBW|tDwq@AP+Od3XUZwRP*)W-eIeOPz67ezqK-a)O8UAHZ{SuQaG6%MF@eVK(p7=k zr%{*Q5mH`Wn}kAXL#)dJ^^$kZBx?8Q{>D1?kiR#xjI}@K*BUAj-mgk1S-j23`rEa8ZOdYerO(l7>PO5D z!2UVcmO+5fo)f~|M~3p?j+v`D;vKLs@UW1sBT=I5>b{51cE$0{G$(TH6t78QYctwE z#z%m2Wn9)1dD7KcjJ;R9x(b;QkzDsS(j5W9A^aO3J&yxFKKfW5rd_Q=Kfaot9}`re zre>d+b+n)_sX%}n1E3^G`3D~U5)ZHZ#Ie+CF=p;NV4d{E6!aBc=vjeY>>bc9_Au>j zE^_b=xF386-~bBk49n9c3hLV;^j1F4#gPSmalY%H^0Ql5%jC(ZA@Rk(u}cW22`}~2 z#Ea<~V72&Ch(1AlC5 z-l!y>u6PIheR;k*k{j>m9q$N$O6-D$g;L*%!KM*yG(#B!2e+5EOda|O&Pm`r7P%ZW zElai%$TcWr<<}d?j5?41){OL70%9YQ>9cueAIPNCs;etmytG%YDcXi$9P+F4(|K7& z=Uot7zA$d5k30Eu#XsEew;h7Njv*D)rAMjFVwxG4#P7C4=Sm2dW8C>(ulV|-PQ}{@ z-yR9K`7sav+u5T}?|`U=cR+>3%W}y-fmXNv=6iL}-J1nrMU&?T|5H_F`F3zWo=Pp< zN1PhvI>bka-`)$DZ=yb&nK-LM7909x!jQdssLQQ2{FmBS+6A$bV#M()sBu1ARTIZL z`P-?g%@5y?vAdKaI^tbJJK;>TgA<9Hw?8(z0oJ~-N*Id-O}}0$rrGuRjllC>^NZ2Q zyZPg$c%Pn~%+5W)ei<<^1lOC- zb(k8AW>Vh(D=n^`2)K~De7YJNYDH(sg$qS%(k%s%_nVQK@Nugw9Mojy0{DGSyq`xt z$#GVmfDn{CtElJo2s9aKp#{ni3%QHMOhl(9_08Ui?_4da-q9?THfIW=Yk|mYJ!{~ zF)M7S>@+y+cV>4}ssR~v#-dq0v-XeX10`fNQ4jQcDUJh&)>74ADw z2V1V*)*~1`szf=64QWSYc$I~qcj!WB;zwL0-OM1wNt^gsGcooc_hdX0sC$adPsQKA z;V{AZ`{w3_x)5hKB!l9|kH_qK25hiE*r?H|&kcsCOtlg5F}WOq-}Q$Gv$NomX7eNi z!q5RI9y6sf($2$Vt0&t(!K`+yIlw|=wN=(ovGg9IeGt}|T)Z#IGxGsP@*3x*8hO-| zhJj=tkrMb~3mHG*H5NN-jPEd)?mafrz9(hDg;JZ<;To$Lk`I?u$YybL@urJugdbxV zkWxBBLE+YC9PO44k()6}WCnX!f_mO9vf#@B;8l-txV8(yxMZ;^%U; z9`*3-*XC-JGoW@`?T=$gb@u0qfV}fhN3JeId%{co^YV{3#cxx5FSmTrAL)9--52l2 z{il=?oY8Ruqy_{ph2p4>V-<-K*J~mk&+5;+YDRSkwNz5B1?w`tR8+DYzIq{>RRJ zjtTwaCzXuscL32!<-zKqhsaKYIsQ+>U%0uw-WVAicSxtdjCNi?^At)8V(E z#+ph3f`Wo*TaXD+XkkYYN&YF)u1~OMTG!aC`_A@6VVavh{~$KmGAG7}sMsVr&Hr?| z-ZZB!TuC{nEL4IPNy+A|ov%NyX#LgEJAyG*S*kckbcu}kipd^avm}u%g4;LVXB%%4 z!jo$+(T*_`6(}jY3dfED;SgEqpY}YLS-XPx=p;L+{KXqiV|i##0EhH^J$=-zOXu~M zEu?^|cTL{g(t@`2Hgjp(+spKAJns3JANnrL znr})m+|YL=UkYqenxvmd-uLQ)qbM?MN3R;mTuPenq@s}u-NA#}x{o`o|WMU$Q&A)(AEF z)!cQU_?894Af+k?gDMMylYDl@v;Q5C!SvnYjm7OFt>89#S$Hu8c_8ph1WsprMA3j= za`|Vt-b_^1sc^NG#A0nkW>sH4O@f~wN>&zm53(JFwV^6IG|KF__G$J+2{Ac=NH_ox!YA+wEg zE9!22!j4H-;&s#uSd>?Bs~$Hmr6!?(fiM|U6A2UyFyxl_9iuc4xM**fHd1Ml?LjB& zQ9L8%5(?0uM3q82)l7zLTFXWv$ZJU{jb`q3y>>uB1pdg4u=__6Jv zVA-ITP;qIk95{I70SDPQ|HQDi+ebG0XCbkIGH<)V+%N@@Tf`ZWp7XeWCr_=Sf3@}0 z*FQnV>sT}tP|$6k2bL^>hfH$$Rs3wOy5AXl9G0T=Mh=`D6Yd9*2O=xNd#bA%N63JPg4S6pH+c-{0^AU z&YqPjg*KLJ8un|nsq`MMqsW3=r+WuHPdrvW%xq~Eg&1PH@JKOyEERJ92$tEyaQ8!DFcKo91qm(eOa>S7aQ&|mISD2&Q(npvK>NQImAtEd^C^< zivnB;pompNv<#N>0KQj%POFI((?K&Dui}L`PlRU4a?p#vb;ohoJAjlQvF0PCq2N1C zc?VF9UYgX<2encbA6@ju4t)bk7VU#nEpFAGyaTp}5uf%thEu)uEs7V%j6Gl`te8$> z*$;XqCn3?lT|(@cN*1IgD%RE{iJSNu1tMh_Zu(MnwoeuoiYQYipf?s<4ezSgiu@9fQ0FGMM}uNkG>c^s zeDaV;i?F4pP_|`YIuMe+;6jpjaz(aL|ZY&Z`-AZJ2T%}szXO)TaXKv)pdl; z!hRa9b~r?{B@nW0YH%%toZWaM3t2gUIX`J-DCF)A=7390-8hadqqLn(bi-2wOn(Rb zSbNgc=Gs~jKq)A;)vtoMpmbV1!+z6^J9FHx{2rfbb_ro2h5h^Hu!6MVS$JmT(;`hw z{z$JaDEuO9G#}i3MgMw_25a6SPkSbuf*55o%nrCc)F3`2+}}BvhZhWEBTWI@qHUQjyWJ^d_8_EL1VuR0$0Wr zJBn~DB^U!3l09cxSSF0AYLxvwjwPLSrsv~08OO2&_CBfq@mf7HIHLK)5sLVT1a|1K)#^~RE2Y}|Km>(32^ez1$pqGvmGShIn z-g}d1)|Vj+o*i)(j6*-8!@W^!j&fPLg`h=eEwKr#@^F1}*XBjLxZi5{xJJ`0Rtj6; za->@il0&{0W3cO{1m$5uLtHzq5AMt-wp{}*%@*?NT>E!M150yyTX}zaA=U7v%wSX3 zL`R)7q5j7^AybX-e6gZL*-)7sb+la2QA6R#R^B!6HAmqo41%YD;w??VoR?&lboyrh zZQ9jyrC5FkSHQMNvO=85Xye;j8{|p-JK(yT{&_=gev%2y)Q|!}Fdl2ne)A%pQd&~c zMwaiIb5?`fa(=!NL;p|FfE3^IE%3WW5|`UAzNA zZ>c9x%v1)HV_ggFKZS&{U&KYC*=4*Q&wTGO`#AUf<-J}dE2ZhW$RvRB>p&U6Iwe!4 z4~dCelTnU6ZZ4@Jx$OBWiyYP8JUd@C=qWk%RR|k7SBvs@05Iwupo&j9(2vv20l!s1 zxd;BqKxn|3V14suq7D~V(B4Y#6C~;&$hOKylv$c zwt?%SCD~^zz5R$b*W2^ywyM*tXo^^FMpEZHfPwGSq zcql82a%8z^W%m;TkRGzu_T}FTDV{$yygc{413Y1P8xVJNgB~GgOS~rr9^L`T!w>YT zZL<~UInAx?lsLo+{8;3ihuQ&59Jyh> z<$vc_CZ*n3Upy|;4v;gTYsoKOnD|D^si z@lY|Z|Hn6=N#Nf(MnTcvZ|;ID1oEx+e1`&0z77u$eWr2n)-qiJ4Ze|<^;ig=<59;5 zUFF(K@<5ThV3IJg8SZ-m`?x!MXtRlI*zvViRsG6`u->Q4NLE?sL+57C%Mwyi>s)Zd zN8~Uzdqi?zG`&{ z42RV@Nt|YS-j88rA5za$aY7eAkIa^ZG}UU=0KTAsz!#g`LmhlaFB4bpxu!;|OU+%} zFA$s??6i#=3%^{y^VrjJ7j*EH-Rlpk)+=OH8hAb3fEM7*-#4)La?yD=$*h@_qsc4j z{hxNlfAarFJEYQFj9H1nILOXBV1)IJ-X>rAwe%hE)%)`Ntq!24=Bn|uu%(l~#qQzo z%>fXB#&`_^;~x|54SlZmMt9K>+A6|2mMf4o@s0Eykh?m93w^pUN%#)Xv1oXkdj}No zJ>0(oG@?#*pA0|pNblPsU_i@*Q;Au%X-a~>7g|b2G9aLREU13nS>*Lv)1}oDmR1z!NVb!$aZH4(} z4Z%0yB~g6%s>B&rU%$qHtF76L+g1)nmifUy1Klei9S(sb*hNdSJI9_+zlqiqUPOx- zO#|F_QQCpedSOv$TLr>dl0(sj>9LiRhEtO}uduP|{F8NQeYpHu0$anxkT^)>`NF~A zU9cgF#U5@2$w7|76s$XezvpXKGmPtU05-;z4;W=X0n}L=^GEP!-;%?cg){n2{3uo)P(A&|sw8Nh#m^^4PRb`NWd0g=o%UUzAVP}|m zJQyMc)j?*GRBT@|OLld=<hI`AjAD4ol0KE) zVBuYGmO)1jM?7dIQk=Vn@ONjP%Al-YcVpGu<0fjV#s{w_RRsx0#OGgVst=lZC~2k) z&PRXHJJl*eB3IvI*=Tca@sp?SI4h9%qW-M*t?l#a3)5Jd=0vZC5mWq?T-T;z&to0) zt=ag9wc@?6lrb+@u(wSd(xKu`*Wb_ET0d=UByLS5Y%dM5T}>&3g`g`LgC$1E!hTEN z#;H!iM`CC<<~744i;41DG0dgWsVnVPieS0pH!>E9@7niX`l_}gHI&UcnC17C3O;ik z+D#y^C!Bs*AKcKcg8y1SNowr#cR9hAIu(qhV*qLPu)p(qTP0h8Gpc2b zw&lsKpW6ia#nVq>+K!h52JEIyps(o*OH*e_G4hjN*67ZXoFqx*EQ{`i3t$wH?KK(G zk(GeC%|3PLj2dgUQAnO65-_$3kyEg8>qeASDDYvj7^A3H?aP(gt@Sc;7_F_K(=%#> z?ZR_Q8@0f_u$YZn-E8LI2S^6tdfb9k4yC2-nS&qYkRd_!qa4{ZSai>eW3Dja$xmxP zdTt9zc%o<+O2UILAFh0?o^>)xKOY+Idh>>lQqYo9Vg_3j0CIpUEK+F=$RAFhCEVl_$U(WFq&h= z8r?DD_=2X7!}0|ALVDCi9{t#xjRHopyND-dVaIWu!}R+nAwOl+rxeQKA^~W;!@HSWnv-8K z`&fBQi*MwozYp%y2ENbmdEF`^P*BzVh`icEW^?NCFl(9&@y9Vk4nmOHy8MaO@awC} z^(>J<;ki5XDBWjSunqi+l;|J}2K)q(+TC3;NDTJLu=B2q#b(3TFNZ(XdgCPKHPj+I z#V`qsVy=5#a&5%5fdRtd&~VH#V!yC1k8~B%TC+k7XGVA}T(qPrQV{h3l8wAKXM=mV z=KP>wM0xo-8d8^ly(b*zsowF3ixEbR(r<9(}^qUmnthkqcfK zt1jcM`n{=QAIWj}q(6o?9_z-3V-kOD2 zWcG}7bzN}K&RQw=>#xkZ{+6%mpLJ-dg=RRf)m?qb9+MDz!j}rjnhIjOe`^lC+p8Il zYq;e|VaD4UXs73SB`8kL$%M!H!VtcvjHO%@I!7rrvC(6es4gr+wApV}U5gg%JAc~w zbiY1sw<9JjIq$FLe-=J-Owfo|=uM+WfGI)dg`wPP`7Y)UH?+_5Om|UrUv4Y%h`pkF zk;=`M?zRuNn`NNZM2dncX(*+dTBA{;(5`QnAN-bdrXhWQtEknE;`g~&UM!<6nmrCx zahD4#W?jglt+-A!pzJ%+nC62$?mY+}G$yNzshz)l{~cKx2VFvs)=KL!um5(bSKmb|?RN+I@F_yPEc`%;c)ECJ&^F&5#=4j80_tkU2HwUb9)omtKb zE+jI?6;M^uU64BGWVew~_)!BOSLE2QBPse(+4DzcrpEm;90DFIkU23k6sIUnd38ZR zAUbBMihL}*Y7^c3D}t`S6LI4Vz%r<5qewh*AUiHwFG=sT!+fMirgG|-H#|#+sLBys zWXt;ia$i3DYy^9tdy&1Lhwmz)P{*K<`012_ZB~LnxnUo`(40;zBm(2ayq9gaKX9wt z%rF|0S5$B!m}a2(wfkiMY7+{!)<2mqw1uNsRBIa&Hf<`(DWiOO6n2q0I9n~gKB2|= zK}B|fqQA}$l_wPJB>K~2b43HqE@$d@gxuW*ml&tXb&Yf}SY+h!Db$5+5Wo@|Bc*-S zw$B$yh`ddVUVN9&8o=Z(L))Q8iP;|$<9SNEGlUJR249Yy?ORQ!S6z*44@IhL z6{&!CKizVgcPTIOkc+XDUn@=_t;gxLXf_M&KN8}xmL42KR*bP_y2JtYS$E&&ecM{% z0{OcpLVYvD8ZlY`$mM;9(qKm6n1KCHTIG;+US`ORd*8V@Fh7r9Pxh*>G+zBd)pW)z{c#K4tt$8=tl%3)-lEi`bGX(9cl z$E8OrEvT6snd6&t$Y_!Avlia(AY62cCS=}EsgmVp7}>mv#Tb!2JF+CkC*BaAgvO7j zMFO|BGaUGp87U7{+B-S5m`O%70$T~+XB>#c>0PJ=+lmh2_jHENDeBw)UBJTuPvW@& zhc|HMH*1;Ie$mykqWKi8`l8tpf?r7%Y;Umhp`gX`sND)vK!Czvd9`qX&5 zf!ng|a(LRsc%l0V5DN}BRiAjfbvnLh$mu|h=<+CSwrv=?V7w&khEDW9#B9-CTzj1R=OU8niFnANXh1Q4A6B-OS{p82{^D`dB) z3(s(OJEN3I7#?6=O6HqquXN#12^MKxo3+iJDTxg0nrdbC+>kq_&u|2e1=7U4L|Nu*1r0eMr@9CxRA z+KK^+-4hJR_#gPJ!V! zlM{M;s+(<+kD)`Cj1Ui3$m1EEwOSKwU5zLXTr&@7TKjgwlJ`-T)Xu~SNH+YhZ%{Y5so~3Z1IoFlTH-uXdvK zC&f`q+NvZ#VHkSB%#~cq-8za1NJsAKuMlD15blBjX`{Da%rzdco8{Db@Hv|91}+! z=OcOU=Y#FXPB^Sh&N1IO2GzEcvF-A67;iB*>QBlRk6%3#&8Gs4Erm9we*qJtLWEmG ztrjEr@;!`dE9)tRj3${C-V}hVkH3W!dv~Hs%aw-7*)g;g&597ITNFa)A88a$`O?!v zTjLja62Z|%Wi8wt8qcO62Gm294!_<)hP!r8B}5}WE{45DJ1(_L{EVlbozb%D3TSsWKtP4mKjtXgKIFHuS)S=MaH<_%w-0p()I%LZM!O$O! zf?Z1yx``DEXDP=G-+y`Nwb1N7t?2|D7PuRJ-hBpUn!|(r4nH?zMB4Knp61xZkRt;L zS|PiOT^bHaIVd)6x$0Y;f+#U|#xx0~hT6N^5bbc7!iRf*!`KKgW$xyyZQK)clB+O` zTgGd5Kc*n;?4*5caT-!>(oKHq$0dm`Za)pF|WglGw~>fxM7iy6GA27=xuf* z7wL*VQg3xcnS51ig;Ujz2K}1J-B=$@)e`kZ#>8s}LM~knQ!KuJh?G-ZQ-pE&Xhxa0 z5u)2JxZjQGX&q5jymwxgql>k6n5(PMX^7kPT)1m-O$7O{(2rvxz{Ccb?zbF}a^WYO zrrTtG!Nb{JSkt5h)&?cLPO=YdWx+Qq>!hKaXTq6|#4{W?kBuv=GWksNR&+~zHeH+H zQYF>u2P=AkxKkf~lVHt49;(PdL}f-oN6?{OIIVtYXA;>m9% zUK(en)yW>SwnooL^CJh!&xq)*15c8+Gq=%1*$GF5aUj34%KUN}g`A;T@}!f;12gxoz=0OeZB51Q zVFE^kop19w-5qUP0hDBS(g_3DSgU%VuJz+E{oh@``b-xI~7jA|@VZhDJBO*0}6e@gwrDy)vhA$uAARzl$O z9oB?@Y5dv(-oLG63I!+a0^g0xMQ4OQ?FVfdBG+isz$5s}eC-@G#zx9Ht2F+uX%3Uo zDo~+dt##Je*E>Qe8O9Of8Q3h$!x@kAv;MduG;HQwfMf_{m5k?8dq4qC z0*ITR9EPj==)Bi?n^IBOgs2Hf%AM#mk`tdDB+-vsLAqq@2o8aVs0^^rD~*uMB5t1SL%1j9-4K+P2x=U{Bxlrt%_y_E#Z#n8o!m zQ?f`Q3*}_+f=jy;8~#luJ@WNt@>cE-^yjQxVRdMV^I3nd7qs z;s*78 z0&9Y?$D zh^#NABR106m8ZGQ>L97OTAnt%0-gkBL*8xR`H`On5mB(`8RM=LkCt9IX`4MwFv#m~6vs&VKooHoi41u*75 z9eo**HtN5fSl>E)NIjfGG1)=PT0z)DBmb!zW12r+kp6w)oQ$V~(F8XMwh(Jsu55XTxar1f!*DR4zk)pVy5oF&<|{ zlmd7LNb1gw9EgL-qywDG&KzYVUP`~5G|=62u~~P5x|Co!{INDdYR=Dx;YLlR3`l2r00D_uK zjx_DyEE3C7zpRdI3F>_L>ss#b90YYl7G8(vbL(YJPthN6cMzLf8eBD}jKqjnsnDoO zD~b47vJurW9}O`kZe@qX6kOp#4ea(rcSTVt280MN+z6`&egHirhG&qEvTDo8e>z3Fxp)VcDNx}ykg`c5D%pUL!#DV? zzcLx2sjSlJ)SAJnPL)$P2^vI~gN632d-wS$=u8*hd0v^uSbXOd&Ni>+>!WPjM0r)u z1sk=@FIMOg9Dg+^g!4%PP6g@Koa|HC>PxjOmMm)Apr8|NS6$A*MD7YN7iiWbP5xEz!L+qMr$X~V~V^LJ%Lk(mu&uDdi zD)x1oUE$7ooewNIRG8!K^*+)|*~NB11XZ5keI;)hpr%ESl*8(m8zneENRKbM+_MSvJ@w54Wh&m)X<<6?8>==b0O~fI1JZM1*b3La9Sl%^n?l2kdTBah2+y$kHhn zy}_yl&G7`{{T{DIE`xp6JQ+=3oksWwpok=^>vqU}%=HhI;hu~97~3SUCvdJQi!_)%h4X^`P^YlV+8u26DKoGnMcz=p&xI;HvbbsMR`|aj_}lpA z&CcZnoxJ%R`l>o%-{7QD8=PP&hx;z=z|GyAnN{*z-3;wxY1WdtppnU{Fkw=fPxY%Ta_fvJY`Tic|7#71nnN)_5AREi+UM@uh`Q}QAE(a#LEJ`Hw~tr{h2T|xTj5< zy1VDJ*TA{6iutl{KRL{|%GxYJZ*SEL1|RYUP}vFJ3ZuhgS`^(!-#!4DV?kAiJ$jnX^ot{zF=U7& zMXM1cxtkA=d~b>SxrzHE-!lJa%7nX1IdLS#sbT}cFHm|!x z9%P~Q?o!oSM%H#xc41X7_u%`2nu2p8`OA^O=akShpUb4$bwKOYWcqTg!hJ?&MJ>bJ zPGRYzRv~9#oIV}d7sLuNF0#&?v}(TW^QL;uZcn3bF~Qe&Q-c!IiimD^;_E5tf^CUZ zQy?eq4~Y!oCcfiZ?F(Q@yOR7clUKZ;?P4-x(;I=GJ|*(Vg06#jn>|5x6YD#CW{#M;D`I-6#vWbGG`yHOWX^3MshAdL->^QP?moV?{C z-Y{mrM0G={6X&%t8mQ0Tzb3EBZ}?J{jsKQYc9QNT6A1@pXxyWo)7N-NGTrgqF_8Y$ z9s!2wB`o_jkIEdOBGrpz>CMi+%mN~dxeutHh3`1J)}&f$Db@ueb_dU6BtgMTcxkHN zri&{BV}{cyj%jX1bIg9SM0^sFJoI;G0YmNXROmVf6iqZOI*2y}U1eQvLzi%<|! ztv=I4lnKWanaIfXuguwJqQ;3}cl0h4zBUX}0WvcZC6C4LqK>wIM!<=l3+y-K8y9|T zz~agMN$j6pSyox@@Zd#d$ci)o83kZ8OVKUVjTImv%EJQf=sv8jhQNXB&%RLC?e|<# zg#PO5!!R;XIcN(Nb5^0kD6bucaKAso|Fc*4D&Fh+HDHK7DyKghnc?QX=7=pp#kK2g z{Q+Rdx823u1uOvl(#J8!BwyBfh58w)DKB)dmCRWt5aJUN*Zc^UWf+hC!(=A2sM+3} z<3dry)?3mu5+g{zhLlzKf`)D#0wFPz-PSw2KlS@Nyz@#q0$?*5$D!JsB%su>!6nNTv;{p7E_Vo5$H;6a9Xo+82fToz?e z#K=O76LrfAtKU4bN`TXggB#MMMGMyusI)lZJ+}obv1F*Z1M>H5^IwML8#4l$fL+JP z(>HR3%tq>h9>g)Klr=n9b0!7 z$Dr`-nn;B6le?lofb>UeGTiDdn+V?(r!;3$gi?t*ra3*3R3r$nJ(3oH+R+bavD%3V z+|-~y5Q{AkQ9vEk@EQ>leB{L02xjCP2^v#$ej3digKSsPY5O*V{LXkcubtwxA1l$* z2e}DU((`&)b*sIz2Rdn{zBl~pJXxSpa!2tly>U-Jw6cIvBi_y1RO;7u)W+ecK|Kyy zaVuypC_lVW1lVqlN_{7LEozLwo0P1agbH{Ltz%zCp-Y8Lusn_Wc9=%HsB1yQb!SX% z-=!tNDjy%Xcr+qvrxBSm*;F5^m123s4lTqg|8<8VG1nn?MI_y2b>&&+G4Q^PC}uo` zy!Gdz;Vru;HID5)R99jq3VF6FSUMRzdXL4xGe069koBoBIL+z@7QZuRL#hMIRAB9f_vRUinjwq?oOr0k&uhe+cVMKksDcMuS{|2?T85V zTM#|%{R4EfH)~`so z?_-u*cb&iX&wQKp&yM)s5IcoInM>}&k50?=|@%S}+)+z z8*uAk=?bp(6<$fB%Pv~7al#xA!`3uj!U@LyF)Bg-`=e!tM0fs=fP?oL5`*&EoXT<+ zy5pEOvm}x4Papp_kvt^%itMC}Dn3)of?>OiMM7nI_%(sSJU7O~lizYG8dq87?SBPj zFPhLr#c&G#W=|b{Erqlw@Jgi!v1~Y@z?*-nrH-AZBy3S=F*RG-AdyF^98I1D;i9j- z4k2i<83bWf`8m(@-JdQ-0A&raoi!jR~bp^IICl3gP@U*C?EmOo)ufrzX{<#*-}AV{pw7Rqn)N?flr2%5P8=r4kj?>X3p!Fa&?>?D1Maj^_0i zpveuTl2jr)oIct-vzt}-*C6s*$C&4qB!nQYdqs(jCcJ&y)~6plXYTMsg!bg!Z?H-J zlZSZHN_`zk#8Konnfz6wtm3@xqHDq@^8f!K>6vS~g6joXmbk(QQ5eM$@D|4Exs|^_2^x*vZ_E>ORic*2M0I5WX6P*zG$V_Wk&ZmI;8S(>R&QziUMB3BS=EAca&j z(z1VSfF5&Lw+RAmpJo&r!pTX`VQ46NDXJq~h|o-S@2b>YD~rQk0^OD@Xt_J< zZCN5PH(J00D*=ynHENEr+pM*gei88AtF_J8lyk{S$`FVjO)by)V#>$KQ1v;XEbC-f z*mcVBO`W*|*;e5?YWP0Ma*Ka*1PPygP+{qvzkp^{?a5vk{U2z1TgRjLpwy8JO ztEtYUMmcmQ&GX^0z}I=8XeGgN70qZEJ_1T%G+Q~%|4N2=c1vSCTKc-q(~`nsVuYQp zR;-t#+A!;Q2o2yyC}Ouj9D!$JIzn|;VW?$fp_hb<>jR~S7yu{*?>u0hG<*}8eK_NL z>9H<``c$dQvU^1P$LYAb<3I(lhADvoFT$1NTrhu+d6zR+|Ags!U*mdwforW)fAUV$ zrOA^s!c3mot(;MiAEc7q4ODyhJh|y8(dy{DY-}Q=ucMspT&2g%pM6Q%BG_aCaC~*S z70Xs1MXumEseY#^B{wMak zAhM?IK1k(RTFg@lVA*%Raz%?vb{I@YjhaQTaHn3$pLddDY7f3BZF8VDu52ca-LiN@ z?b!|;+@tX%yr70R_SN}0d(PS3cJ%V_l>(*rHYuTrYX2eAED6s0E%TsM`oWsCssiv! z@(-=XK=pM{`fij8zGtZ`4s8)M>bc^dVdRC4)krhHNj@gOHXpE+aK&iAM;=yeZ0eCN zYSySB)Svl3@1M)ypi)O4z-+jq!uU8$MK%Cb2+ReOH%*+pC@rayyYZZ%e82- zTqzqQdm1~g$P#1218sxgJ4||i-7v+;BtM{fY zm+Ey|1n-?{ILj5B(&1Db41gBYJL%20Q0Q7S@w`E+si7;K0Hhz+kxshRPZY3223PH4^d)+7zc$$@9yx)Y zW}DylBBBuWUFcnc(ofuHWl4ra;%c7J{;s!xOO(*Nh!gmf`ylB17r?8*PAVqpa6L*& zS)_;RSB?TU5zJ4wOD%)k_VJJXR_H7ToE5roDwGUiK3WkPFfnG1ZUEw;6CIO-KtoL> z^Uy(2K7C@EzTxgpmBpT|JR+ELnINF2J`uKQ2EftOz8$O#bjog668o3Lk;e$hlWp?Q z0$H~ir+=8h*HUiZC|uK5>a&q6pRSgLcDbGewsck%c_42N!W6ZMlQD}1u!f-j>rNQo zmV-`Wv=F4TB!on!knKYBO?*mp1#1fm+5@0Jo+l186K;d@Sx|>~0qU8+dV`7m*Yh4c z`%IX!nzUp6A*m79O2M_N*a1P3s9vH!k&HG(X;XYjN*?`d`mD~=x(3pCYM(FxM~v4l zJy-M-1W+!&Px}=98(6I9?7;(qNJp2FSE<+_lsCXNek^JbMaL+sU~lWJT^W*wVdmQ_ zDOrgjNvGyC_1jO2>E*HjXj`To5lTb?ExRcEcjWY~Iz0%5oWBcbZcp9|LDE)#Nr+|m zBvKuk<}lN80|@`LOS6W80ljSf_sSrAoNridC5%LpqZ0m zv4g1z@|tj9pil%6nJvP__JQb*2OIo5JQ`NGsWW z^v^b5VX{7h?&k_CfJdN^tr6gn%Vr8Cua&L1+rZT))7MQtn=^tz_6Cy4zduoH?#ZR3 ztW#k#4~=)Yqo$Wge>yxxZKvDw=oKqXlilI_r;G&C5YlmWe4{Cz@JB~h?u z4SxSQ*A}W&T~Pb0)zTM&qJ*PE9XZ;H7L_yk*b-sRQc$8#36Ay2<4DmlvqF!9V3*d~FP$zVpx1*2 z%8Cn^$fz081H-T@xL<-R+l2iMV9kzZ+*PS`G$=~Bfx^nccIhFGeepDqyLhR264_@~ zuhX$fcX{h1z0WfmJTx%jg^i=vE1q5e>#p{$68-QZeP#o3%AE0;lx#>yw<;7#c)xQe z!o?B(=5FO)u|%}I!F_3o(+u( zs55^k5-7@iIaW-b&j>fI&++ZVYj^B)yvTj%P@xtQXa5KIb0x{AOl}(0T%&Zus&`SE z>8_cwiH@&2EnjNL1M_E^va%s3?lBnHjJ9i8ZEtx^Ftnk31piUT1r1`Ma-;ZL3UmUx zA9l@Qz3&>ixO`vj`WBAZb4sH(vAtvhYaQHPY`Ab~0u%!#_L7liXyY#5(@=q6h|0eo zstSkAmy1)`i=Uzne{C%APsfDYiXV{q`$0EuHX`LnepC29a5pGLU$13o=GPSNXC1q5 z8}V@I+!5Xn^X)&C^q0|EFf$eVEDje~b*&lmW=jjiSs6>uz;s?K1sdoYB2T=fSmnRoi_Zjm4So;Ea;4=6m>;JM)@9u|!@Z zf0$i8@-AZy*6#Y~{chbd5WKj2>J_YmC5$B-d`Zt$%m4a4Ua_B1r&xUo#CaZEziGkn z_Bful{cac}#dEos^RGZC59*5m?qhkZSK42;uvT{MntjjUhL~s?nw}|p_Xz}Ie`ecz zYXsTxMM|MzF^0NKgiSS8n)2BoA<@#{p6q9&~*ueo=&%LW}BGhjz! z1-`ck1aJ((O40RaMk7DvO%JW%DB1sVoEPO_VU5JjldLD0^gYdPckY6jxs zq=YgOD|e30{!(7Ip?X7L!HnApY8Yr?^sef|);7b-LzS3h#f#iJ%q__0n<{5H<8Q#M zxK{!NumO=(o*gQ9^U~dQRl7{7sPwr2wGwoXADJBgzpaIdvS}U-e?&2(aMPtIlq5>9 zv~V`TPFm$(R}Fm$+d$(~+DMMgSboY4u6Y~V&j4Yeo&|cDiA=&yuzvaf=WSn)Yl(i5 zB}>Gx12XcQ@cywU5m+ood`gZO#>L$M)fu#TbvG#)vUpQH&zGU8L_#M0^loTv4c#Cyf zVatDHYN{&vplGHa%6c1>Un)mX=?AmK_z3zbd(L>Fp=R{J# zuwXaZ$l)Y()9n)uiuaI-9{%*#v-iN5x&bv=!JVqK-infSntAHhcVU7$T)iYN;CoP$ z&mnBdwnp=1F z_1FKdHa=4|jAvadj%087mc!4B%!!Yv4bU_DSGLD%HUueoMKrPe6xO$!W$wyx8?s|z9u>gE!_sNH??zS=n4w8O0i=AhLA|sS+`0)AIBFQbK!vUS zn7#c-yUq!c@jO~)M$vuo&oshr^`oEfL(`_~I?(4U7+OzElqOY?;TS}do+~|W^Q^$< zyya_;svnJ9z^t!fI3Br>=?lf+4}8#lB}OqNtH*P*{J(+t^|X(j7|+W6m`idbb|p4Y zzNXlTt6|&9_MRF?n3Z=+>HP%4+u98&AkOX!UV?$DDJLsFzzR}`%s_&mY6Hc)TDRSZ zPQKJR)&%#w#5%}AB6Zv;u}Yh3xHefF1nj5j7tq#)+d;|@ep1xOH`&RE>dnY`u?eOw zED4y?-4sGZA^d$$fE7ocCw?;@c&{3;(x&jyf{ERY_&hjJO-zqfkID%qNM^t$OX|K! z!_CS0_a;!)T}HwSbtezQ#OSy0B89(!ZDCAKr6M4n?|h{pWt7Rk^?UnRIbGchCQVx$ z8PP(7U&Ue#km4#sR*=49s4vuq)o}18#fa8)v1U@AAS{HhSP+Dl#v#yjW+eGA+_1=$ z1O~u?kJr;))=cYP25?`rZMq4z<>tH?PW1Jn?MsQ1g3s-QJbw5@vYDRQp&09I3{n=O zRsWSLWt1{=mq?83$G1qZSL9hMcZN1<>&z-bBVCyyHmBa0=c9ZCV2VU%zD;%_%&+?( zbM*pyhRb+s{DeTt%zscluIC7%BjIy6rXfXkq-mh2d0W9ZVzaB z3S^rdmt9c(b@nC$*U@VTjSwGn-_4LZ*TA=Gmcw5o#@PPG4As8YQWvJ z`x{uru!hO8yQjK2pD3I(wupcjLxbyoV3j|W=wt2DKZW+iqZh08<@(>@;RKcjq{BOK zLwwO*jwR^>3C(f}73mZ9;`e%EIL&?Ro^cH&xZX?hh-PUOT{M~#hAK@yesN5>PTfT9 zjl13F`?9uQzVezk$x2SxB7`x@=if*tNJVOq$mUVtscw^3%@&ug!Mzw=q`wG|Sxtqf z&C)%v442B12@-Tg9^AG<4Tbp!)+nmtMLQ zJxh)J>S0=~k}V9RekAEOQ$auWk}9MQlH{b-`2b~`9#py$xqh@Em@jnH=i)m7TK`79 zr=v`vpJ(vXTIf!y^Z!Ld_*KFp|FCvSb7t$VNOg1x;rhKxREH@Ojslom#MgcO+8QSa3%u0CiBZNbpR^KVP3bNB(=PZ zHlvEnJxUL=0sC9#nVy3WCckyMlB9EN%w+~hJ$7fx=&o^^x;SWWK31Z%L#}=Cv6@tR z@^g;ot{&E{Uv{UouYU1r^`y3WS?96rZ5=1zM#zw^aVNntt8xdfPBDm~L2K}&*-(z8 zc^0h~J^b@YBxzqv^gbyu7?c6#qNf$RFihWK>nw~8> zL%I}RoZlIm)`&5}G0W!%j`1*($lH9K8CXGQy=mW8ZCW7F>wD^V-Ar!!MtZK?XDYQ8zi z+b(_tME1#o79+;x8lQ@Co_T{~xG@UFy_jV5D1^)l56qFiWOu{if-U5q|TB73hfZdLx*sz`P68fPp?X3v!JWfSuVB8L_O=$ou}Y@jzqBWai=pMFySrr)IjlQky%wb|{?ktK4M zo~HFmIpCBae((;;G}jKJg$b%#@v@g-q* zDkmdl)4B9UgY{sQ#|M{tl|7H@$w5$c)5i}d@yyIMGVgJwGoNlr!vU1qGX?$@59v3x zsgWA~@HQO**}5axR3d8zg3Q?8S@J%phq+`rk$qC4oduMHB4V_0XlV{l8fE&j!yUQ; z&0GdTI3?^C*Xjaq_)q4S*&H|)(f|m01##^_;2{#2TAYRW9W^#*-&{|dIWrv@VZylt zjx2A!%T170cpE4?IQ6G#=E6l>{zObwQKD%xB|$5mHw-VowG3OU#-He=9ufbtM;YA{ zDgf_x+>^2kw5g8!xPt91DJAs=EWH`2eg=jdI|P!rd>M02_n$svpH@nPCzu%qrRNQ0 z2;Ai_lyAT`^Q#OydXqsL7m2nCzNW~JalgmIZKSH|B%-xY!}5u9b`=k6e_HP-alQ!Il6R1tE5CyN8EkF9Uq9^hnPT1@ihNDND8S&$MJ* zAm=%^gt(ez<_6_)D;PBD?sHRerZ4L>Tv5)3x1{?^bs!doKPQ!=la+tsFP1+EGEhud zKcY^G9q2m69hUvh4h<{Sf@-p;pqe!;%eehi=mdMrcgoez8PpWTkZNHWi#o4rJ*6_s zA@aVAmIv0g^%bIL{$?U3+geLK4`; zuaJdE(447*&^02Nd(Sw1a2EKl`_~$zUncw`UkceT7UsN03jE#w89uqwrz3JUuFwU> z@YoJ^-e^E6AwnQIGAiiE91H8YZYY;S;|$wb2L87*sj!HQC=~n+nRprI6D35G#o(F~ z+pssw#Yk3)d5^nHfj(!FiCVkd1j3of*3eU+=41XIa_+HF6rf5k=lVG_DGVn-OaiKy zB^f9)mcT_QO}CuZ+S`FygV|U2k<;hs~O{!MaGi@VLOT;XO@ z?W8&Mr~A&vwsO+S?Q}WZ%(n|uzdcWbPmm{R-mXTqD95i6RBYh0N4s zG6ud4`?AQq#1emeQ|Bx;Cv%{^Q{LsC^lE8B)T;`nK&e!VdaUeXc23_clw}!EYS9wtKxQoA2 z!z?+{0Xdd?ToM1Y7{1+&1G{g>CjmMi`JC;}#QcLa=Pu1E$f z(1U8U&@B47CSGDpVSK|j28ND{e;y6B>{V;64mLw<{cF4`vqo@5XebVS-?(Y^e`3ex zNO;J@LKu%w%$W!kMc2nr+qMZ7cB}f%RadiTOuYn|XyDs7sFK>VRcW$^!njH8reRq2 z?u|+!=oKofv~OUXX{f8A*dM+0Q%MrWL-f1IQAEu1EeDOlq*XWRiDKjL4g+-xxv6xwQGG2FEPp9jwlLz#d(8*6$#A+K+ZKb!RLpZOv{aY8->lOA zSW`ycRf>kYhCqlS!PT*|;$2CjYb^tmG@6wx zjF)XiJDyvS%79aQ@rk53j$aB}`l~p#9Z$MyI!3ppZb^{kCz1)bUvL?jCA74|MNiTD zh0Smki#LuO`$xD6VM)poyC`s)g6~oJ)rb=7Q(g!7el0pk=}yW4in@M5ij}{b!!1KZ zaY)E(UR8&|rl`IF_GWgIXMUO=o>y&D@{Mg&*v*LQ*4UT9P$VME**n+cb_uY*AX%QU zC!I^xlxd*X=%63L$7S7DZFlq>ymDz0F86K+<5N+Lp=Y6)MG1(9yrQCbTK-=XneZPe z1>FC!h!->q^8lE&J%Mkim-l%ZBQgd5ig`JH#iA@S3zr|EFOdv{tQ6n}VU`(7KSKx0UwV|Dk8OV(PpYV87 z-oIhIB&LB2t6guV@*0#dPnPQ`N4$vfHDK;(k*1hRCi%$`(p>wvokiwk%|fv_22mi zm24R#S?&=n;57KedY!Jn3=+(C-TO-zxBq0Ea%$wY;@6Z|H~H41^u3n~Bku&8Z;pM& z0!4xD{Jm&nbVmE_PxAXs_X~jMKb|vV`DPXt4+D3y>p)v-8j?r5u*H@zKu0SEheB# zI`Nez=pD%?p<4wdBSy{CG9)R%@^B=*9%_4SxyzB0)ujPgKHooE}h1f$c}ArEF@<3x4A`i(8& z#E-T5#&a9?)3|Ql=B)x*KWXnH_Ol5mDxwpDNG{D1lSkM0Cjv?~(yl3Q14j|PHTTcF zbeQsP$^>@+L%*bBL>hLNwI5`@c8tTyS|nE)D@-fRBYWqDi&MkK8mw+WIj1qcqMS_| zDaH~BmOWP@Vgtbd*`2udwSCnkDm(xyQs)z_cK(p%bH9OIt%p(GBSP|YNowr!!|t=0 zMNUcQc8fx@3jrnOwK`s@WsIQzi^w6_6Y9>e0^us_m1~%lz}qkr25@!GWHfx2A_3Kk zG{dlOU-P-l6i&A|7W)_GBnhWrkg(#Z`_)@NrGFmbC*|66I*_;UEM03jIPMM#$Zbxo zbA6qVN3M3laG@tx@YWwTL9&{YgCuVqP0o4+x`moZS6589;n5IpaSH9tPnmk1F6+n1>S0215W;LLNVcDywQb zlzO)?MoTqj&{V&YWS!mz-cP;i>t}+xu+m2oU1bg3obw~!>o^&HZ+q5+gG5#A;@TZT zHnAYj+H9ke17Z(qfuFP^;M7FJ(Pn!y-bDC`jju7z$d9h)|1S$w+USgo7 zw0e%LtT=LCic#*VQjYlA$@2Y8%?#FL!&*e0{tkUh?RLQH?W9yw;ioH$z?#-1=1hf% zoRh|}`v0cv^B_>}Zb13rn>U{>u%bWK8xTli5xK_NnAKp=8q^Iwc>J81|Ni29tk4R( z^hAdgls#@S)4_2UA1|rog_rF)u2XOx=EJ%3#np3bo|liZTZ~$FFEw)y_WXT>JYe1V zZmfd#6Pk>WA`?t*GpSj8ov5cBj`nk90sY}$CawG7?87x2*-eA@BN~o6%)naZPqe(p za_%m9MRdprzcdimQvB6(`T z2HfmnX)niKGBW~DJ4#r?$FE2@DpC#0JWM;Cz)IlPq>VmYda(ys`!&!dw|m7z`3&-g zjSy>84cE>06KS=UQt=u!!5PfU!W$*0@s3A)d9N*4^Yd%AL{d{JH4h_3SD@iF{nq_@9t|1ee#S1IvTrWL6G$lHmW zW!ndB#)H8gG^J(T5KN#GQfl7tNjS*bG&L4zvUTwkZsN(sT>WP67Q8kXqvPg8-trKH z{Qrz$o?AKssvnfqX|Wcim`5aL@&H>X`m(p1cohqFxt#&yy3++AeFcIq3j{EtrC$w& z-k{n(maydP6J1JHQ%3!q$QJ_Tf9)A+qPxY?Vl22uiLRzA>ZcOqSv0B9!TNwe5{Mei4KsTrRLEl^8@^~H`x`gT$7Gp?ZWiYI-y%B?{)A&CjhDU0c35DHK|DK7%k!GlS53XB7oH8nlau8HV_py;>?@T zyEs);h@hMzQ91os&J;mkmW14XNUL>=&9wZ~bMSSL4sPU2~ryb688m!L^q zISx#bjwHA&bi8N0+`4P>xC741#@L)pA0pf7e8j{fBTg{SbC8f{VI0;{>g|w1Xz)MQ za>9i`U6f#*{%HgJJ;1)5JqL}?iHtzS>EXCRZiQxa2(zg8j1M9!n;V{JSpC^6$>*a- zhXDa(%4M7TqbqMfij4T(RSsqxKMFL~BrEt;vun@UskODHO!spg(EQZAD>falO8O?U+Wjjs(IhOJB6O5` zngjP9DA^K=Q?y7C4&-yasb=%2rPHCxl&c)I}_6_;4?8hzTrRPTeLw$A@YgA zwoy@Rb>A`!g_QCTBiZO}f&O1mMXXFBZmNwFuC$U-0H;*e;n#}b6V1|RMym9Fa}MN0 zglV+E<#b&}yB~0b1Z=*BDHwn4BzfWDLSK5ctUywo9S$zUahB1c%A40TDgJqrh!RlN zktUn`Qaj}1?Rm_w@*%{}I752I2n=UBwcDVg4E0u@Y-+RZv(mC#GQZ^A*+Kr6u_qiY zJ~@eUJ&$2V*+?QrD5gmS(V$sq1pxY8?c|CUglRl1;V^0ykH6( zLf8+-^1r6@xBJRdQXM)C)yZyLMSXDAt+g4P_wzeKud~PZT2OK<-Ke{V7hTXD5(d9o z6FwE?N}-z77Rq;~BrUvPibdV-2ZNx)L*=t0J7U3ED-uL*|J3%2J- z3N9>eews^pccSu1&UWqFY3$v!M$@G=J?|SeoMw z1{KM7xVck%j36fs50+q4$#Bi4Yp$(%z?f}vFs2?@!6P9kf(C}24}~{*iJ$H}CfsG! zAqX&9^%$DN1-xmu$W=&Gl7lh1c8Hy_d`mf8Onu;{B;OL1Eg!xZK(CvA_4+|t-|0Ev zxp|qe;X1ucSnv-tX&bme!llRDqS7F9$o=^YmM^zgT~uo(UVzHKapB&5C*H5-%yKDM z!s9I4TI|gxbQ6%&&~|c{!Uj7UTAuiWk2wyln2B-+VA`^TaXZ`1}4bX5OjB5@+zjDs!zC0J2BDjDtX5Or`V`@;(5}y z+r5vGt8lSNsQFDRNu#my{|ZS0VDEqZ2+@l|$Lp7#YBF8*R|R6@4DD2Q-Oxqcg-|QS>LA5?*(atH8Q_)vDPz(&?-%+$>wtgU%mVqx3Z{WSOubPJcaB| z;sR9%z@+Jj?($SaT7|T|7O538#zDKMM0d*YkS5?uR5kN7{w}uQxxMJeKCup8AKU3? 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 zcmd?PWmsO#&M>;*#@*eaxVyW%ySux)w#BW`7AR2Mi#x^Li@Q4%cRTdi`~A-DzK;Jr z!!=B1O(v6MWhFD28vp004~5!NT3-&)8d` zwl=qS{TB!T&NgQ5{{#PN?QKl|hYXUljl07?V_22(t%>MMm0RSBM^W?2EyaGV% z*<1gg9+=)6THYHhVq@d@4=4YO;JtM${-FGsVdBZmBIac8^bZ5L|7+xJSi;-J@=yJP zh-c$!@h<`ZfMjOwX7!CRi?{ZzfMdO_aQOzHINNyJ z{CNU`fq{8z5KKH-#6n2_JOR+noa|j4&FsD3m_Y=fg5Mrt+c-Oz{26;IU;r2d72 z05oSfn4A2g8W|Z{;18KMR^BQs@B%>mk>sEHhW_vNt^aTM^lc0r3&)@6(>pFlUD=8!Sw$ML}0>JAMAO^rd zK|w=7!azeq!@|PAAz&aPz{4ZpqM;*W5aJON5#kXLkWesEk&w}o6A(~y(atiU;%IA00b%|8Yzni6uOED zG?@zqYe?dE7;@37PE6IwGYU3S*HBnEENmQHymypT)HJm09GqO-JiKD!5|UEVGO}vw z8k$<#I=W`&7M51lHnwi=9-dy_KE7e$5$`{IjEqW3{*;pX`ODX|oZP(pg2JNWlIoh; zy84F3rsl5hp5DIxfx)3)Q`0lEbMp&}8=G6(JG*=P2Z!eumsi&}w|Dmsf8_cj=l_&{ zN%miIp}xrl4gmpzfc_&F7`WFT!BHU~Nm-!KL{y+nT+qo_LtrpO6Teq=!jiM8o?)80 zPQqbPuy4FO|0CKzlKnpuEcE}AWdBRB|6Q&{009K{_VPfefDo`g%~q)~XzC1{DrMr9 z7g$?L%3y4yG)FaIg_XNP)n#O_i++b1x?o?MkL1QH+F@ko!LNhLvqDnoA~lhxQ?#iMB(yql>=DVAWh zvWwOl80b9Nw{wzfKaWet>v1oa^hSlFaI(EKY`fXM7WxJ#D?!*nT`dZIO2+Zu@AUtG zpW@OlmP%;z3Y>);z6d*UE{(D}px$>U*6Dfrn(e8)0^k_=Pc}DG-u1jmN)5&q)sEOC zA-4g-PenTZj!6{Jb|p~q5kh8;ho#SJ;zmQkEbUbsqDhT4pYr5~j(Ndb@fI4+C=1=3 zAiMPSU@Su{HEmd8Qtp-7N9cHJgV3s6-Ba+Osg7#yO9K&vY!3%Szo01i1x^u=XP{Z) zKyw#4^5d5+E{h?Q!mz$44euy|Yl)<4z_cFU3N0yE(&*YE-jAK%d#oM&@niv`mB}Ci zP(jJbd*BFY{d#}Wh?LyXoQK_oyUGzfPGRV5|J>D4&%3qlG!$(FepubahLg%M;E+_x z%ss}EcsFA?)2cxAb+>#Zq9-^tEU`6dp2Ukjh_^M9@|^5o+}^>`Mtg6ZnXo&?ywy1eb91F2P7UXI7qbdCaZE{`QHWRRPNZ%*rWXZg`#v|W33}NqQF*-B zJ8qrn%jb8&F6{#(-;Szk`aL$wx{L3IoQL5KS)bBz-c>mYoo3CI!>RZ&H)9zAM~SuR z5Xg9F{GH6ex|_z{nPHO?LEJYe)>CAXr0(I|S)Y*YXYo~POKotS(2+YaI3lA-Q-pdb{!>`y z)*i-gR^JcQ*kcbgE-1AdN_=Sx{}`s*6r~L%yEVc_VCgV}^Yre5JX2`lhByTf!4Bal zOtue&`HbLIn@a#5bfc!-9GCgvT!&0;l?nN!=mn)`Jy2UH*6F#lUmJA1SOLN!-naT8 zbo`h}$NMOIPW0VvZ`t}GB%mY=D-M7IK!w@a2=ZBKl1jzp*6czkdWy*sxrgv%1jU?j zL83Hsx)?k-7;dBp zp`btWPWy$q*j{drg_B!Pe+<_GUxA-YnE(uKRFK9 zR@V7%EydB|j}q%!ru{yW{V6g$aAH4{+e8%uCQK}Ir}rX3i2c$^@(N7aX`SMf=Y@NK zqP}l9-D9{LJ)DKT0utqhKe=lIVGky(+5lIsv~Hb{Jz2~zPq~gVPmu0ul*Le`#?`&7 z1BafC`|6Kjqt0oMGKF`kv(M$bnFG|w)vU7XdpI2V>)ei%({&8e{S=(lPl@C)=wohC zYYS2fZfk0oJZ=|DVl8D1R+<4qYW30dXcE+|t)yq8$p-&@Y+3)vatOQfq5YF`}?=pBFqPB?odl=lvMBX)OxoUg`Xqygh zofQS_N~aw58fxL4AGd!yLtktb|2TRO@2%d!P*GL+z?gmHwSzc-q z`(mt=&aE|$%Q(h7;Pi57w#KSH@^_}|F3*SqUPG!Equaz(ExuN5lY~!9ejWt^3moTG zsXE^!V=pxoHr>(u;Zgee=ch1}SD+&6SF`Nylf^4QG9PqQcvV&v)baUyic&;|lt2j8 zgyvTZDLJR(J(e>(HPG*Egp93*tFmGoS~NxIatE#_@>jq-9R5o~e=2diBTk&(Tyj{! z4%W=iptF&_7}MFZ0edIorVa{(7%h$UAJ+{*zsp_fOCnLFU)Igy-1_XQ&$J$v+HW;e z@%S5C7>~bDl;{vfV5k`0&tj-Z0RLSvqqmUn(XQJc&eLB3VU9ZOpUkg7B9q=L@B_E~ z3M7o?{h!vNvRZf6p6KwY289!AY=-c;M&-_gZ9@QmH|Xv>>~8$&Qg>!v=;teNyO530 zWI8K-ucIT43xTk;eQr$x^C+~G{PM^SjLJ*T(vwke zZf{!^Y-DC!jarEzm1X}}gqK7f=rK-=<9(bh7{A$m1%8g=|7!|Z%J$(a&~x8Ua-KN% z3Y1Hu>zJe}!vK5a$L%t6ny;VV{^@0kYKCSHO@tXuqz^ruCig zV)z{M+Q*bz2aR{q+o%HvPh#=93uo<5QMz2u-kq;N&TL6rMRkK~t1B|yx9o<-{(S{N z#R=gsYKomVnKS`3a^XJ$Zd}hYWpfbodpFMr$yUzY5--~S!pXIUn*z!eIuLmKe*I@^ zu&N`5cpUFcnfpPYrJq4?t|BGcZM+;oS0K=-o+v z#@-ii^gJ(vo_Lws5Bea6E)Evq85zZy&UgffS0cEJN`?l!xHil}xvComGu&K54`0`ArICT9x@{&}$$sU=Rg@nMp|6){kwWaLhJK?DUv$DM0pcXFy{!n)}1x6DqlY%GA}z1K{0a+vD_;a>WXaQ ze$7EE*g(PC=5^{0*pyp8bwGh2wVH2EN z{$q~OPZ9EBz$|3E&0a+q2XWIFn`~8J!KjTzB~;mp&)4G3+6AwWQKgSX7qj8CoG)30 zNzfDHkoi5v=sYIP0p3tB1hzvY394kGIfF1H*Y4S1)`Hm;hLilbDW7j%w78tfNdPF$ zcl!ZZ_lMJ_Rg)1bANtN-aYCq85sAa^d?ca8e%mz-xbN!5NB~AHSUA53PmHv^iW;t| zBb4wMA85Sj=(^w)a2hGWlXE9He;lEK`~)teA6M6|;I4yhS7egl93V3AW{tE8h8j_` z>J7`5(LQ377_PY$%bBh2B}YG&i}_B-9TuodNudc_+zTAFN7{_R#;e6yf zrJx?qGG@GD(+y9rt)cKOp8d`Kl6exPaL*NmY1x}CAr>r;dQK^jn6pBm{^kaO;wN6* zHwyJ(uvj-jm3FBa#+HfL?qh&aO)O6{f{Qu(VhzCSZe1 z8ehz=IVMzuG3^;LXP1UN5ya421l%->{!hF@$bzcna)&vB`LnGrHHcWXo-3)tES0%5 z;ojfe^C=EdH2_NtKYaRTV7$f0)cgJ;&KPgv9o&Jl0CmSzHiAqUS05_l7DQJSwxhOL zBhMBG_Kj$0S%WnJIIDIB0$9J`%!IM8O2~mQ!7;DU!YeSnDlT~5N#IE0zv6rTkd_-@ z%iiLiDffeGPlGl_#Ocdc#^X!Mys@vQ)W_r1OPNG6V1Ri*pqFZ!%Fmj2PP1m(*aaeY z1U?Mkx%;f>@3-58Nao|@&*)5X2rNMeFD-cKm~bkh~Ye%m_9Nxm5Yj?k6v6tRJ}d7?!`iWWD|O&XdOh2*5{=^N{HW^iCAz5Ioa*hN48)<=`s^c#Y z(M%oXA?brGv)ST!G&^|fljltN;}~J%c_cDT0N^!GoGU8#oO4#uByT4tjbnvX$$Ikr zbQgltg$6y6L>t-0ZMncR0!gReeIAZiR2yG2?QmurCp_=9x8WKuwmDy6 zH`Mx?RGK-X>0sQ?*G&Pk)bWBEmj~;Af{U0niB|GyP1T5ouS6h{!XbJ>?hCH^Az>QS zC4~{$3`5wr4HgglHqPGLcavQu(bTZs;2~kw;vOL983i0vbV^He7uk>C*SUppwkRIc zLOkx)hCL#>q>+}_9eG6V0v>>coEoS~iaKo64*zx*tzCNp6r>vi{RL|r=EClNHxDXf*k+lcgt#}$FVgF?ziMi@D7-2C+vNA5x5i3zAS3{B6% zQpzur_lc=mn(sn7aQdJ(r7^&AB{XZ>;x2 zg{!-?4N91nx$pgCMRzSP;-hx|-r_iDaz(dqE6lbZ^*KEQ6A+ny*~v_@iwV=0yq;b# z`aFbS-V6<=|MW06ECpiD7x*klj3v@fBRE*6oeLuwj_??Ug&+jMZ9*!bY95$RrPlkY3KW>tG&`JEr zQXrGPFo1(jjW~xqmn!tg^Gpq{-d>sLvMW~gv2T;P|KLuocP#71(&b%yLhRtcBL0&t zdd_0%vi#Rqz^`7We=05LMx!wzNA(aMYQRwhL_8FXp-}M26>q)_PVTA;>Hg|ep&?z~ zMoxqtp&ztk?CTDA<||Ona+^nrK_tSVX7(gM+k{DlIBtG}M`nm#&n(P3X9vqw8HQks zkwcT|6ZC+7y25;CVY{cQhOZ6YLFcFvC(}U~z#|j^SocCOL!tB}zUSe?K*-WXI139S z+dI-Yrf5l!yUAO6fA8I^Nk|QnIzf2_#?_zpAH{_(XM}h=ZLCp&iDHBJ^yk$b7*&%7d#zY;1p8V%KI_214t|3vw(?+^GpBFirteCi2nYNB%b;xcY1 zz@~g>^diB4|I%vwCn2Ido+~|0-s_H5`b)SO#+?7fA|X3sH=FA9zF%-;INF zuv*rgHwv%MItD)o8%tQ-gFeM`2npCtY9rh_nt;r}I;y&@hg@F*^ z@7Q;$xM1w^ho4k9R%v2gP_aXHs7qE?_4efLd>Q1-Hqw|upIgQ&5G$TWKUu5C=v-Bu zz|#R1*(dk`1FTL0Lm5m0^J}SXl1(|TwttU>X@4U*5Lgh*eh9Kb6+nKzvgO0y@TKUn z;3RN$OKT8D2}ojki>^OoiOr)Y+fQ><2VC&Yeq}mrF1ld&oTOlY867A3ay?&JKT;UJ zof-r1hVh!?zm|zWoM>nedzU9{i4tvg)>Iwh3I?NV5qdyAqy{Pd*Lt~LfeeiK zP-C2-{NSBDgT#t9AG8}(y|ja&+*0;gvXo?j$^T(Za1c8;Xic(ubIxH$bW4#06bcu! z7nj+Z8TjcHI5Ee@$Lj&tTXpg+Dj`2()s+h4lzwL& zGH`^;V&?95`WpF=+(I0jLkQ7xp2eRKmN@0Im`k;`^Q_>YrYXJhO=adQ5)LS-5V!Mc zJqoZ#DMO)KB34jf;|M%urAqFPJc0a0MW8tJQq8WLyS}i!U ziw@CWD$?VK-8{WV_xSOz>=!%m3jAm6wGCgzZ`2zstZdX1p)V)*fi|It0e2R3^uwF@ zE9HVv>-MP$g$Xmva;Nnv4f@g^AvqWDD^+*i_qa*k@W&3eFW}=ADrHD_N%*ceuX}$;~68J^)V)q1XJW^vw7)UhfG|b&e=`&Jd8deZxHg` z?(xr@6aDyBBKo7A8~5Z?brkba@S2|Dky)c(go;OKD0ttT>H|ko;{9UWjl%r%ik zdy>S}W<8vO&_0|B0{)_GHgH9y=}UER+Xw?g(L(3NZU~3LXP2m=A7%Q*`pu5=SAD!M zZPcKgoXRLWq((~;Y<@;oDDS-~!hl1Y6G!u=l)k4Arj7Q9E!?j_e~mESm8L$T3+8;P zMS}Qb@KV#_JR$I8+q`rrxzAtLhxKJRf6(;W5aCKyM9JG8Ftq4f2c{Y~e~?KCOjJw$>O^r!)UeH5X&HZ(CJ2{W3+6 z*wXL#ohz49hP)hbn$*56_Hq$?qzouamvQ>U)OdTKT>i5xsfIsh03ixI0}Z|j`V1d> zPZ)n%6GNsvFXC(1kKv0NWc#h_Qm#@r_eypme~4VP;g}yo!Z-pKZgqjeUmg4PgcbaZZKt*)@?rm(#I+1@CVfJ7X0dI@vmCxhlT8 zufs~>Va#<%ru2-zx0D$Z0(&X~8Ac6o&Z!Jiu5p=th0>@N=3ex9vK5ay(_5&4LdJ+O z00r!HgJlJ^2;;eHS~MF(KmT&NxaH&`cxuEU{$?`)_Q$LKmnZmdGY6yk>&qv&JWP-u zMe+GOYEqT6{sX5I@Xho&Q1$*RDvkVM1YPo6sxhDgi&j+IU@4hOsaDO&^~ zwr`evXMK;H=-VOotOqeq@^L6>J1~fj#42U@tvM!6Lhk09#msmz3N3{N6eR^}aPANP zObPPgl0oK6k{AkmX7P7lV&^G*T^57i@y2DRa$dBxTKbqT>_nKvKOR9B*wim(W?zaY zEmUebxAZVVagVv(x+L)&Ma}DTYc5?a^SpVPo@CV-gqkwWAbLm9&k=p=TtUIxR$;38 ztG0ADsB$LcgXmcEahwUTH{|?at9AR?NWKPo+8?3tyggQj>&OzSgWbj}gzZr~Db%u5 zW{f2%r%~8ux%hXQ-3HcOPW7&0N)9!qSu?X^qJX|EwP`auCCUkXDcUfK#P6gs+yV#o zbqu0DTRJDWs14x$pY@H=*fN2WwX}JF`t2TmACdtuVazT4Bx%RK$CqO2AMfZgbq-y} zf2bSEiw?&sLnfZxweKqYu1NrT^j>p@6iASUi2DRK+F53Mxzx|Q7+Mkh%;rz|XMC4K2B5ydi|XorUFFYdHFm~+B>%K_lrdM$op72DCfZ^;=Zi5&X< zw!LkbxKzo%DQ<(UH~LcSN}h}}1d7=rU?cig>KX-f*H3%EM^hKhr;mI|;)sk?so^H) zA;|n0u8Jt9K|jC%Mhix7?2L>{;`VIkKrTIJZ(Z^;ikW5_EYyR+Adb9FMUpIM&vceWEq?s^3-Xsp++x1e95bv0-C%f6a8 z6o>}L3k#1Q$^4b+(ZVaEb2Z^48Ty3+=Zb`^)(;g-72t_8F>uZuBUz0FK>$U;v?;rF zj?p*wsfDad@>gf10JC-wJBOr!>!7iC)6|lS2#<7}$kJuVk^sThbC@Q&O5I0xn}T{* zbNl#BOGnoLpQi_9$ox4{D-Bd3hM4n1s32V(k4BRw@4VO)M{NdaY52VVM3FaeVh?uYm23qq|_)pA-#N78hB;EFsgs>EcH;!b)lC zQ#E2!a*gxxe~=Y1R@t5rros?|Y^(4Ug&ni~UIE@T0bNc_RGVWTiY)*Qx?LB@+|x!8 zbL?Zv)X*g7r=~#eFV~3gLEddhcZ49%g&L$f&}3vH#k0p&Uh1XvR_BMjm+6;}3#&t0 z6+=iQU!u{$ltW=H&GNUp%7$o~Q^ho{OilE%@bZNcdSnpX)8cHP!|zUE`7q$P=hDAj zcvW(7h`OXNO;H)sSJqMOI!}Paa;m^PLXU}*(PJ-fj^L_Ieelxx)Jyugy)Fl#ZrXc9{nBUwQW5l11j!3>C=B>S=G-xj*52e|u!7`m?uDQnAZr@lxN z84GhE9pVd>ix56BK>QLj!%0QU4>Lwcj>{%mej&>aP@S`RZ-)uR6W3$-0cjsUsbgTid-VM=I&>;w5NQ&VU9-*$W@MfmmJe~IqE_V)jO|#z{l1;Sk z)%lErkl3DSvu<|EmgKbA9O2MO2)0T4iBIDPW=g-wa#vs?rt>)D@_XU-0_@(QYbPke zlhQxffb4k94x#Z2_8L1=a$0(c6qSDfIGhT`?goX8;0-aHvw^Ocm5@D zJ2J!_NtkC52KxL+O|Y`qvO!SJez`M*KZeHXKsi=&LOY;nAwv04MfSq&pcn0sMIbzh zp=6hfe8^?`gesHo(K47|m83z&kTUkRVnTQ?xdn9eiTo%^>12OFWtIx2nB=g>2%BUV*^Xqd(Scu^DRI^Fj_W#HS&3>$Ez!u#m zMGFZQBM3C0@5vf)I*9MRxk1F7TxP_#r)LA@IUf~ei^q$ybBIdXQvfruAmaI*3;Hdi zn(T||IGC-)BmsG!Qh4nObB89Ci^PtX_Iw8jVHmhv0qtye`EECVKHHf3sR#fI28gDCHCp~X(`~O_B6V+*D(5x7 zxOUwD3}Bp=-)vYus99*-MC3hrOkYM&_1gggLdF5XRJf`LjiB**3u6mG3O5#s*FWd& z9Kqa;3gAp^6%KJ1Jg1?P^Tf)rp70PhZ(+V2T)HvLjr+m_gvRq}V)0MOGM}P6Fu-s^ zNn^yrpviX#h;_YEa7~x6sfzn`-v;0pJIU;=l`Gcg`*92OwRKk*7rtxa4uWE`{5?w9 zV>;EV_Mxo7e#+~~-rIz_N=^=5e>aVl#Kb_@1JtURZn0k;@=T9nJE0VzjM@O&A`Q4~ zfEP?o9!Zuip1yR;X03BPpU=L1+34{w80){UF_uOo=#`CK18oQXN^SpFV4JBB>;6gm z%i)PFU+i5sblez*$xZ_V33Q!JP?u3|(0KRT+4Jr02M$=tsche1nrz?Ocm+82`oJ=yEcMH}r(GCDM#70<7CY4?5o2yDaEGu>MjtM7&5G%!}N#7fe)s%@b{D zd|RC7UV)^-+i#TfBa*r@&7X-h=Z1~-#w7>Qb+(h{QvMtHd+74 zX?3g8<~Pc{uI5@)#XcE^cN#=`2uX#6MWELO01beHkf3u-y-hq8QlKSO>TJ5vD-GRz&JrrqP z)#!tTH^x$Oj$yD6{rRFS({^Alx8-iW$JGkRSF^QWNk zLj1~F43Vyou@W?WX~yM?IUh?@Yj6kV^OxPWy}iu*V`Qmkz!fIdUb2YGpMqaG&#G)e zKs?HUyKH=tvt}T?kONouJWrb#nk57JK8|8FrK@ftyge}GHfUS)F>A>Yfl-b_N@PK{ zcJ9N^gl>;c6W74ps@t|Ja7#&oA3sf-7Db_92D7GVp=uwa_Lyxhv8i5EadKy8^ay>< zYq@x4qB-SWDchx|t}oB5(VRRvr)a@f#6vAYy+gPjkbw1`xRE;!3fBWr5H1&or(3ow zGDxhZURslPuZSQ9``Mlw*FrSmA$1y#!Fy+_I#%)c$uJnh+b5Tc9f#eB7TUv&+6#Q0 zhft{w`EKev-$cH}@Of^iSgW#DiEls&f5-alpy8CQ-u=wGutlg*oiF3!Li?Vt&{dU? zmR_m)EJMGdd`T(!Jbh5uckkL%WTOWU<7vFKD)W6{X)8!~+a6|h*r}rD6>P4ZR;aE$ zOwZetQB{OtyYQ+>(yR@()mQZ-T7UO^ZXU6u9(7LM@*FJMr}v5}8xLW8UP^gVr1aLs z+~?{c6N{KiYk+t?*n`WA`&gs z1eQS2xS#;)zKO#8#KHNI>cr2)?s~KJB+zsnaZ;!qI`M3r&`|8Vtr#SGh`a!GgCKQ! z{>z9tnNI;%*o*K}OKg1$Rle)sYPG3bGKC)uM}uf6ZP+# z=Y61RqsVtiVl?mZ$<%4hzrj=B{lP`S9{UCie{X zTqZAF6GE3Y9AHHj+Gs0qR&Z?;)%%_y(2ofrgd}g#kFzl| z?{6pv$>?O2V$uyPrN?;gwTJEp7H(Z>X2DV=^HW;Jv_L_Ywh(O5)FNhci@lEe%1Wau znkoq^8y)ev1VX&sW21L))90b{mR048KKw~69AwzH(;e29UPz;hU(M;Nl_>CuuY9hq?=a59$tkc?F_#rzK{{FXl)dtynLNuwaVD zxJSE%!9-y)DChkyShnyEZ zJL*s2hzoA9SKl^RF;^v+qA1P1xw19zTmju)#BGxL;L?mw?_<^leOlWq38q2MjYF3Q zyi_EuKlN92^!#Fkx@z?X!i{IRaMOcm(fVC5mL@}tLn7ZR@%9Ajq*n4SLr;MRcazy% z2#GSjtF`y&*c4Rj3J3!;V}BRt^_-fz)m#RU_5m0%2fnpSW;1~z7h@lp>%!I%33XgpQ!+wxCa zhkQ?T9;>cuLS_aA5`Wk~d9&x`BGK|7nU%(4z3?p?rqSW{6OFet(iOdEy7+FFC37_z zO)t3`%%yT~)Sb9V%Z6v9A~)4}ydI#Q`AuO;;q4_!=cAes5@HPSZQfMLM&p$$8QGgK zf2*_J9)^%FboCbMw`_yM?EUO(kFQM==1&5~idpXx^h91zOIJDLzl1~u@5flq5){u4 zaoCLk`%xv}mFa?}p1yP}0F*-bzN90~9KWaH^y+&6Rm^i-=>SPwfQ98zwQO9m_*v_X@+n6kqGSIBVJC30X^*6dK6fN z%hDLwb=prvsnPp#I?Cv05|+Y~ssblP1>^Yw)4b;uE!g-%BoeIOh_5um9Ocnbre?m& z!?lmFY5W)=N^U|3VOLP)$A%jjTWEPDD;3{xtig+uXN5eDSj^=!2+n7XKcWz2^A1At z9gJ;kbQ~TUQj{Oe!~Pnw@$u|g`KZvA^HBP2g4%)U($3%@Y#F;L^xs>q*$taRYC_YjMPF*6ig z_T4+_{R$%ABqjiw)ZwQlwqJeB?c;@jqsW+(He%1HZjMsF+Yy?Ba=EkJ8zfm+$G@D2 z=LcDF{oawy`qA<1NyChMEmax)dbv`>Uz^2=v=oq-=}E`9+^4opI9@C^14A%=dMOev z!bcRGTVIX42hlSXPT%&KNu5vvS?urtFM9;?8=JG7xgl^=)0+UF9Fm^4DB;A5V+o!g zVAj&r&l6srGImOaZ)foAJKA5hIa#C<<~O4#M4@;HPVrLK*dNO(-O1P$CBqg+fVAQ( zerqJ7xZW(p;UH0_qrCp563%(AM?b(vEoITK*ldn9Wm|(A8d4mvFtQ^O14Grm))3se zHtE3X{v60$dHe-0M-P;9{D5b;~~^PN22Qu?&CxY z(g=E}YHwKx_S-y0AVU8Dqgu@eqZS!Tt1Vh0yv-qj}wlv2&W(UFSlJyqZqlrS+h~yt*e||9d|?V6aU0+cjQB-o|}28>dc~IZU@tE1~L~ zb`=8!LkAgVy;}jzdE1Uyw+?c!K#q6~?(G94nVJJC@zkTKsXdo9 zL;qJoMFq}`?4Q{`v#I|Su^L@GSTsLXZ89CX zgclHJY=exls}7c3`zp}k?q@0>{W|jaJzmQzoPpveddi0dpivBSNwIkz$t!y+wOwVy*5;w%!e)Lhrx*YB zY)HzG>sbY(it7T;`E=btx=&U>0}){v(@SWhs^5!t9*bhHm8Lm@}QcK zEI&4uy!=fkGpBuN2QNz9-32~0c9I1;7;}-~(ISoD*%P6f&%=TKkgF4dz;%?cE$ID^ zrS%_7X{+cLi8F0OW9qy}(?L&5#_dRh4vQ*!?|a2Cxvt&MOjNmO5i&m6e{mIe$=nrA zg(IJcm%WweVXF;|mcCTmyY%8 z8B84JF;AZ&cod&|+1nSBBYV+Svn8%1j}Bg2g5cKiCDyw-P+amrissX3^9zPUjwD_j z^h~x`jGekI)jYBS>D^J#Q`6vMClO|97h4`5DRH^>Pdzq?p*Vfl8W0%vl$V81#Srk7 z?Obm}{b;5sKJYXopPcA; zg9oxxi@|oi#CrrjspBIwgV_ow+j)Um9;O1~0m80(uasWG z(|o%yKR*bU%ECqcRO5F(LYacB+^Ea*_u0B&o-#*=uoR7av19N$U4blN z5p^+{`N47kGhzMs%rwsRXJc^B?&mwj{u2iDjjSjh70&}f*Kt+LAI`*1k`_JLyG8{0 zC8V)S&`%XEpIh#vFdOz;nx?j8OZDHi;TG*ZQ!?dyhdy7MyTEvVjA#9F^uF5oF#akh zvTd5wq}c9AluWoY>rg5?@l&`Y3bYqR8U=*gdqQ-%IS!8wIV(6RPTYM4ZEo&j$CJ&1 zdkL#-x#zQi^@#1iZs&?x|rocNe_cBZM3yWOT|mbKT=((pHI#yrPooomp3(8}K<>S`M~R- zz$3hyYb?EUddJ4fiY&JMfp|`9ZwXK+6JQ}wDR;4oo@JLJpZhr`4c;+F7ECVn9xTn%a|?A zo2{x_X$5Z}gqZm@Zme`aCw_`*qK|d&uqxaIF+3_Ns>o1Vc)y44#Fm3_Wfcgg)Y@_x z6)XDs?ute@@W*ZY*eFZdC;X4>?4Nn8-6HY4f+x;Uk3ddhJGawEC4F{h)GclLf0%Rt>|I6f5QF9_|t-LkI7sdr5+j5h+j zPxLI7{9(#b8{nmBx^0>?*PljAJ~vts4Gfs21x8jB5qR@w7$mJVhCC_v37WphK zQ93%qp1mrDVj3H!k(`SG(BOACc` zc~3d~(sBaR&W9Wm2YVf3A0ibVnw)?Q5zMcw_xw`0?z^ki(m(IA6;U?d-B&=`ZZ>El zXJ_F0m4ZWw`H8)Z;~>l;XK}_G5QuXU58wF9LyG-MR`}@LyQ8*@b`ZN2@=IeHdLViR zGVdbJQ?5SC!q^zR$_j=4hv{F>;%x>PD%>Gs{9OB$eh`xbl`yLeMbZzVBU4 zR~*-pib2X;dQvFRxa{bRoHx5kHCcX*mcPU1BXsYh&f<;dktwHc6g9fpo>%92N!T$0 z9~FW4P^^$9DZM0?A0ld2j@))slXz!xL*iX0(sv47480*xXLn34_;7$<0ZylF(*@Ww zbo+v%Zs-jOuM(MNu*-C?tmUxDs+CQ8tR?pyr3Um5IRM9Bp2^A%Gq!Ky>(XV+xY+}T z)z}Mr(|(SvTgz$vZeX%^qVG9oYOAwD3X^M5kh=e1jm$Q`sD%zmSS|7~{eIWE`(FDM zI-A+zBe6uPJFO(n3m!95EXt~y?6wzjS?2AQak31AmZB>#m-|l**Yz$x8~q%vG`YgC^@=L5F$JlJHIIv3MLt^A<)mETBTu(K4>8vm zfRx-A^5hzBL`X%gs1pj8muux63~Y+gqA*#g(0l@zTf|K zj-~ikMmRm6X@HvNRHLY{>>*3?c?@qy>{enCA+_QKz}bs|GrJmLfGLLF`hg@>LNS4R@2i{o=b+cO67c3@t{@9c3^xS<1%W_1!)q@ z5@p5u{Sz?^jIKzl*^;R$)jak5OGcM~L}zVZZ4`peLuuBg{M!VUWRdnL@XizIbs?|f zCcta`luV`Fh4Oytc(#5Vs1<4=1s_z@RBd_&uRa%Psg}wm#FS1Zu4xQ$V=Ow!H}a#+ zxm6XI)2ab~ZO7{>S%-hN(>QWug_@DRwCntC4-r=@^_-2I51t!DMut$oA>Q z{i0-~fDSyfO%!C|w?*j=UP^MBQDr5v96DNQ8$VW53zA5m2iavroWKhU@*5z1y(1=$ccekqkm~>7m8&KMj&=``-W~K-|A$N6z#Gxkjun9wI=< z#2uu*_)yKI&+%wF4T;_4tq3Low~}w|xKED`I|z3kb}VXRYs(BLofJ?zRA!MRtE4El z9ZI((`Y98qJ)MbcHsJzh7<|Rm55n{)rKun*h=XKx`+cdUINJ@!Ge1*1o#KtUw-8>d zNCn>iJG}G;p&Ez)w0i%~k%AG9suy)`QMQ9?C*H3n=eZWyw@&h0v8Ae(L*fICfP2o1z-~Pg&%dy*$r83*?>V(*PsdrA`EfAHU{GjG z@0}s2tqDyvlyv!0c~q1)>J7AGiEVo;oV8 zWca-pkztSEQ|!xsnj`{wMZ$S2(8z_BLa{V9|A9v!3@;5?;o2Pu35`GAT(^;i?f>gf zEcK`Wt3!E>DUT`|03IUuH7tg!@L7*@n^XvrtE^fZD)E5Z1~%{JS#$%)uqIF6!Ze?S zkw)kH+c~4$bw}*RH5Z$wN`e(ejcTA2>4>h@aK90eldD7Nt?UIs=mvV~QgO^&;}f-5 z6Dzz^R&P>(z|-Q{XJ=K9R^7Yt;O-2}nO{7tEh^-Knwkwu^@`S5ieqWO?4r1)JqV!a zPj2{DY)EuGjzI+g_4WLB4{0++e~7I81Sy=<-abc%VwKxoFWZ%69fHCZNE2lQjF zsJGI)5fyfp3FUG(gcO~Bm#9?3w_wR@ASo;yxYTMKP10h`kCQ8yZ(;KVfL41!|UMsz$R> ziII+08WvMEVZN#&%vE)noULzNy`nXdqyE4d49$gzO0j z8ms48PDRJtghXpmWN1S6&Rc*;^S~G{3yE@>3uTqjElblC=i?8|9W||Sh}EY2b?cOG z>Eu=_f3=>V_`WS0lYHsvfKI)ef!pG~1pCAp|#gK#ZUp4a4did+k z=6%jWv-JVfU9;8T;SV{F>U=2OU0^UWA($GjhtbyV_i^rPBut_!dRouo!lhv*_X%`X zBP2XYn8flEqsqN7wGk1@u^50B`HVu*NSY5{uaYm%iEU zqh*9ZM0Dq0I$B_Xu#ub2G_u?+BM0r5>ia9-;;VOwCHFAJ@)oPEQEG#4z4hS*;hQAN zs%!#$XY619=Xvy7I_=v0`ib;CVQ7Z6Z?ZAr?Ww1i>Pfv z=hLI#7y64Y=AsB?Sfq%di(e}$AmLs06(%nZB?%jllmDrXI!MZXU8{-U`*lKc_8^ji zJ?GkkcHFhoBRB{HRy8K?$P!#k5{VhYZ0j}sAwzL57$mW+-xmZMkU8(7q+~ikU#{H_XQio3olvxh^fOQ8v!+$?C9}m^p zY~X%?VnbagN?-hB6A38*$!Bwx$8q}@Z?{~ig&8tWOX!!W#h-MUX z8)~6GIqd=P(=brs1!#E3e~B$ByLe~vrW>NH>lFwmbMl^R7Zm>+A_6|+qa^TB?8haK z9X?(|S^p;BjQ6twrois3_+YQXFH+=|n2ooJYhL{rHNNe|+6g{*mD_Ddn9;CV+RP|I z=JiCB+DLKqulBNY@>T$%()Jm^o7&u&b{&?x~!LNbdwoV9)G1o|AN0 zh6qSI_On~TSSF*G3y%{{a2`u~;q3<`Gdt_4n|WxjjVpS*hos<9 z^TmOhq&^7JW$JZTwyv{zvg?E^$$Cz>JTT<67z`q$#^O~Cli0l$Q8S3-p>9}%YJNG~ zPDUW7h;ooU);bnyec&YCpQ(!0!fG)O7j#0rW&-M@YMw zXgS1|kOj76p>Tz&G_4~XfG280)u!XL)S>io+LWUhQHkkFNq>gWuk0#Q^2ElwF2)YO zr(HJPk(ycqmOk1%wd{gR8MJ*w;%_kS5)AY@PdLVw4?6|RiOvFT>6!nGMET<%6t2rG zUI?9|!-X6kR4Ga!9NO4Oi=q$xZXPi$ouJ-^%p~~Gs)m2uGKX*J-Gt@XAE+Uz5uc~Pi_(k; z5`dT$f;1y@UUmIx3)m8_SxNgMZy}}qUC_W7L|5m|UOP7uuSI6$fqZ&3+FUD52Km~0nEZ72A?~QtPu8cM=dy}dyq)4aS%7iYh+k@tr*^3Ay z)&;bTLn$`=eGx;aFwRtqpWL7wJ%zh+3hzzrXm96Gywog8PZ|sL+2b{8RIFJP2d91@n19c|cQ$e_Zq%op;!!c4;TuFl&-vF$IdsUP0 zm`uL;iw_nx3Xa8riiyxGj!flC&4Sh&SpyP*!wXc`D(rLhrxUOJKQ93MS zOTY6*8#ZIn1q}A~3t4MzgD8$<fxK~aj2*Z-5T>Kb8@yH^wB}hYo zW^uQiu0z^qYUid=5l-(mk2H}*sEXf#`K$szC2c@J3Yxln=(5~$K3pn3HjP=O4uS*}uD1VSeJi4WrezvuX6UR+_0oY_ zi!MVH%9ljor>6=Ic)ls+(*!6Gy&~{xIN!hIvPQ_2rORa-m4fAG2!%vO->^*&It9PQ zu8KlgwkkeWPZa`}*QT#KqLckiF-$b_06pa7D%_Ji80xC!1mT3l#KxJ{%Qzdr$k1YX zbs`F-_Jok^x9nwA<498>F!Vx&H);~om#uI|li^uqAVp2V-egxZ6_Nz^z$?ohwS*6o z+9ogb%=euK=;jYc_D|hRHgHuoQd}moXoqm-lFqKl3d4u)poLP`zr-f%Krs*ouE3ae zS7-@P%g?v0Ua!o&_PD%D*}eqg8%uh8j$RmpM|jS;?X2(Ei#WE3#u0!dnz`~mWE1gA zwcgmFQaXOetAY>yUhK*Ugy^1+mfAU9LP5n2#~y7kiA7kzwJ{%c1n|_d!QUHfJR0rm zyw|TZl-AvzG_k zYFj{sW-@Ho=bje8hD59^a=rE`5ES#vwgNvjxVs=Jf$!#`5JOfqPE1YlfXU);F~=4R zl6(*lFj$nPygg|T_tur0g7y*;%v_LqOBW)AQN?fX-L29SPmQCo#3V(ac?9n!`0pQzsL1TcL>E( zE^~37C|d$f+yLM?K>7W_16&e*YwwLFm20RdBU?68+L$K70Z&XGJiY}K5ZPAFo`lY zn@s3^drH(`0HaozN8O@Gl?vz~+zY)`*(r}Au?1&@(Jo%g*Yj$+zOs0vPO{36RS zU!_|58FHQZYrQ>sAd1Q)Y(b%%ge4@U%oX!8rzQ;K9D-;oZ{JERmn0(?uG@*+|Gh7y z*k?0TYb48UO>6Qv_!HW@vi#!5{E&wLyYE?e3E%5PdUY)TT;Oz^WddEOr82?Rg~|ix zx7CeQ=O;7xDAlyAw7*NR$pM=URi3`EUvVpN|LpRXN)C!e=js|yu>ol5`g8p%&KAYo zOx=v{dU7Lqwrkfu|nMjZS+NbvEIbbMIQ91V~MBj^CTtvyH=?IhzwbUSoEy-a2zoG7@bRC*4Jym8T9nnml0oU=r6jkKS>rSr-DJ(vYZKLc#Yx9P;R z2SL+N_S4~AVxCLgnZ!n4e#Q)&KmXXl-5OXONyHM(XRGd+cYbXy#u()3OROhA7J zwGxe|lE|TII&(}85-xFEJxs1#Dx&^b)*Qy7BR-vm{EHP7J5&YCCY=Z>s~ zJQF<4HP|Po{`vVXOjjDz-G6YlA5qT0u+BXPwuARAbAV?r3JcX=IkBNGHZc8%kpTj- zYm;rrCd0Gp7h;#Rv)z2KNsY>HuP#2a@uXIMP zT7ZcK!|nh6xG3Sa-LS5uzN5>_`xcv}iQ($+lCQFbI;HY}4yPz81mltFO2i1FxCDmV zNPX_e!(3WA@0*R16YH4oeZZwhCk0-LA2eU_(?Gj{PtDN?_-L9WQvmjlI zSFoha)!||()?|ABrjgNBI!J@&{%m$a2#6qt>7SydB+eocy_LTQCd=eFu~;!c)sU44 z8ozv~oVe5~dOG|KY}{*~t$0ksSH+{3a|xO~yaBji`N?@@iK}Q*jPsy(PfN1GB?QB1 zuT27aT8&5#CC%1d-{ym~pxIT&GBpB%q$KYwunNd4=Wcw%6}vXHJu({Oh65e3aCP5P zp6N_YE&G28SH9`-9#mwAy_gzMPp;iuC_OUp65>S5;i46_)@Q7EM}1z{YTAHq{bbI- zLhsf3ZvOqEIv~ras=ux{bh=Y%IG~Xg>66|Yy*B<}Nee(LKuP>pxw)1rZBeZsl(@Q- zTmGc&G_ZqFMv^WOJEE2%zCbH8<5l)gr+!M98xo7uIu}j>$Pjv-`}PSyHP>qC zcxs1%1@5o%P<)#_kBv&uOAykNR#(mB&;up+U!{LhUR=(%pN@KCqApBC6;bMp1ok45Q3eh*`{Hof z1*^ti6jzgv483($h=xLF(X3XZ|1}WkY<>MD`XsyIKeDVdOX<*hD3-q6nexgWbU20N zqR09Hh`m{eGo(<$wcMdtnV^CPhovMP8 z?QE&t2TLf`@2rE`0&XM1x2aZ(XEBIZM_P8Y>VH)@njhGAII1QI?t?`= z_$-vJW+|}GFem@<$JrM8;U6J51g};q_X_~!!gP8)q=CK^Ku`8Wc~jt6sW;d9;6E?rY6Fl_V(?okrn{z9}x#h*hhjrT+b_mF3eKt*yBvtHN>SVgwhlPjr zNa0Tmb=;WDdn@GxBO{776zG%lUq^07hSto#as>HsFD6268D*2XfWW+qU%URjq;9cM zBa|9Hn1|$~K1!DO)Y10Ri*2G^pa7j4S+q2l^!EwJd>7wNt~H z(#en@X4#nx4^0)sR;tfOY|5=KnJdG7$?SPnO&JXtUhk4%Se(?eLizLl_chw{5OjOg zNA=wwY=XV;I6wIk;alNaWcRc4jR$Nm%!kiZN^GNOBmr3_l+NKP)noa%`-F^S2- zxbAS%S`f^K7rgn>jQ~ey*!`)*ee^=X2h@pFu|{hAr5gA$wJ@#4PoK55NhO~{>>g-i zx1|nT+Bk>L;+fepU)vr!C@<}mHrBp6i$SYA3Qjw1%MylI^ksQ&KFp*J@gYv>1jJ{` zJaxE8s)Bc$${3ZkQOeNw1TPp~TW9~QKLTW(onJ6G8o8xrrxmSw1+&?v1O;77%HTmR zI=}qs%{lHqS};^_8^-9BIX(I+tVJsgU1ZzHxw{j=+ooA zgh5?$3nKZarjOIr7z9{K7^p#r&8o^jMY_}$*mY&WvoBD9I=L&@R*nd$+XOrn*Tn_s zs|;_U4g>ZzSk=Ez+#k*o{0*TavD4B>)?kt0ycjo0=MA|b52-+-XaXtTbCs@qfJGrG zd_ogj;1MHpx~8&(w%o7sEcdBT^$Jtk#@jk!d6V9U!aTjQNgiB&OgulIF-BKXA)rf9 z>*i=Z(eS=%cP$2R3|w47r5(tI0pf-{@?ii@yn1;oYJwd*Dn+oyaKK)8xb^3mmX6F; z9YI3ty2;!Tt)V5!{>ych+pE`1;1UFeu%$F$)Mt0Lal}6}(&tKJ9nW~Ml9N4P zeK#*APHiV)vqev6lq{S2d&fJ$Fc4r4d@zcl0JGAH?;p9~q&tIN^J#`K z6yE8m!^a5YrH=KD3J6S`zSU4Nq^qazD_pi+_{U0JzhX_<)HVftBmtAK$V&0^jz;gJ zm>b2h;!g6EuL3XS`=cb>#`z^!((6gXT0p2Uas@2_8fFh3eM)1DeDNsHGB2i}t_)5n#B|Q79oXW=OtM)s&HiELCF; zJAJ~Cm^e^zx|>uPgCzGvt#yBF?2k6sm)@X|4ueh`x;n#W*War0V|LLE8jL!wyg16W z0u#2ypG1|O6#E*tSu7a|+GsQ}`WMz%{C-%{s84tV^As}4^Fk@D56CP-liCt!zFP9a zZRP%lZ4v|~e@bZDjJD~!C1h+k;rfDV^~^lt{kkn7U!j55Z=y|pu;&h({z zd-B8OAeLM^onMjWm6`u`Nkz~FkFXIph-`y62Ox}N)_3bxMPmPCB4u#aded@g2b#It zO#ORhEvQgDck5z~t@UqiA-Xf;%uDMhcQZ%hJPJFQ8mJL7wegOhV_PvbC(@u_1Kq&S z!eEKczxwn?=3-mVmnPChiP55+m&QN!5?{lPoTqoCd(5>kCuslzmP@FK#$E<6Ki<+_ z^*YwUcR+heTE!4X^G|DgTQyr$!D0Cl)ra#Fg@Mj++3r5yQ6xOx)qXGEy=fuLY1lKH zS_kTp)pQu6)D8=kDX1WzU~QQI{QB1#)$KSOz;~;WCqKc5eDzR@VdqUA(A+{TD@aPc`Ev{1+-xwr3hfDfqfBWRX#3Yu zJCDagOEL~Z3GA(A%p~bZ``g|+X8B9%U@yTg^+D08M3Hg=ouy(<&b!zN52i6V9wXoz zrn?;TyF?bZ%RN;6H~d9HGmyy>H&*;O74EhrxBpr_B0_ouy6>UqMsZ%voEVlE)1H6@ zKvYDWX1%~32S9N;ePqQ-#%q?faT;rk2|YxTz|jQdDdd?6c}Uxin@qG<5EE=|1(hrk zp&+HD(bOMcBpbvR@o~SKDAX}8+NF+yU9bI~uSXG`(H&>vf9UQCBo1|VfG@vo;+R;I zjNUR4+>8Jh7=hxbscaZfigdwjSR@Fdru(z~%z;PN>c5HP&DfdQ$^5KMbJBOXqvhlo z;%OrSbvtGBn@D*mK(OXeD35juQ$xdcV>`uimj-cWy`(vk1B3Wl(-^86C%D3x@#-vn zE^+!qS(WqT4#Z^fV$UB4mKe$UpufBpojx~G=>kT-O<$%Ft<7&@Wg7sG;C{Cw+QwY- zx`+7WS+V|hc<&URC)hqUZOfUzZ*PlF-#nD68-1jN$u(u7uHivS$RinCBsG9YUZ4=l zCRr4Rsgqw@g@C)*-C=rpLocYY)hV8SnMF|*BTKP>Pem2^vEO5l4#k^c;lCj)IN-QZ z=Aai99288-x8YJnbJzt$3Xlt1cQ!w&^L+sTAFkWghqSlSo{H#n z=pys65(oPk^;G@uwj+-Z2c=9y3x-KQgtzE%46&xhd2of8E%)+T6Qh>>OIby&;GhUr zdfnoXW9eDDim|rL!JtSPL4!RGL9EKBhT*J559CUY3lpz^XmbIePdkb6aFbWHXJi97 z|9knP)leiRr)BaX!G-EKUP6Z7qQZdLQG)0_`2bSE`4tg}?=aS@@%|qAq{9@(us<2YE_GC3H;_B zLZ_wa#a18pZBEpnIyWum1y&iJCARKKnsQNl){NpdKGUjV_)gpxyHBIyEl{$x8^xSs zfWuO}33rwKtOcXk(~}UHT&|jGtoCprjp)kOXFc{sEr_*gre*r*Bzkj%jBbupgenxi zm>GWgY{NX9y^i;JggN{{3>I_xM%UA%XUo6T^EH*DcXb|}qr^j)!V7lu0$$-Dq+6TE z{Ozo|=GURjuJ{gH!n_%z;F?Cg$s6Ktu?lE2JPWLucZy+_I!;}xxq-^2wwL`zd$#c`pqKIGpyy}4l5JA$1p#zxNzrRH^`TUmw6sXAqMqQ4~;gO886yCzbEs& z9LC)W8$t7-O;&v4+Qi0&r`uw>-5N!!VSF$lK!}E-q7WWn4GmSJyz^9f8Sy@yAp1kc z;`f*w!>%AYrER2(`nJ(J0;*QaHzrI}wyEmE6OeK;_Ywb5YHZm6A)-f2DiD+MAh2kw zb~+!pU-BcBu2yKLBHq;LvZ(t9ynpO7cZ-OVyh_GFGJ}x?4ZSh=xl?mde04I$S7hs^ zk2xuQs2ubjz9=-HOLUo+u|LmMG*ne>h=K3$sVTF9<`O8STp%PKAn#S>SSr&BFOhoL z3kWT63?*X6fpfiR%SNm9gftD}dcFD9MI+UCp7>~PSM~FWk*S4!%rAzi?)E8R>F=qPn#N5(ChJ38AbA`5*+rU&&Nv z-un+5BO&mGEmnjfaRTZ5&ThTap7Jtnta{)<*d&?q3Rp;Wavw+V_~kEEQ~DhLwC}W0 z)FZ6wh@R3p2k$r(F%!D==el6=QkE z*dXFc0?aZqT~kYVT_AFTAi!4Fdkor}kZ+|ZG-(k=Wq;h9dt-qY0B=6Hsp%Ud3s@#NickovN zkPR^?Iv&+PB+<2oPrCM;_JtRC2eM9|JS>nI%2WX8Rqbw^tCu)fZk6+Cbk3;V zX+3j@F(z#Kzk2%fts{+nc{M2o1}g&?<}iiKMpq~8X4<=}?IQ4POshxlwcmXVN+yqc z5`7g{Cm;y|Ns~%%8G{Sl|MT~f=T?oGGJP`QJ8)(|BRPFqi?L#<>zJ*2eA#=Jaq!;W ztt3_O_UR*ca|(M#$|N~?ZKbiaEq4}Xpr7Hh!{T3F7yqf?@mz`*FVv{L>DWurEInO3 zaTjqlxb08ZkJ~$zzlV@?sXF^w)3huD@Kqm@Dsj%9je_KXUj(;6dEr(w!K7 zTYr6)f3PF!8-h-IS~1Rsnc83DzMghPuQ2z={Os{`I|N(fpo*B!?*kdTHcCdWkb$JjEh42{13b)MJg>!y?aWN|JHq3nH_#d^ zE2I?;Nu-pm%Kws!-|^%C2zFH3xzlIhM-3tYrUIa<#G7M`s6d_JCdt9Rk?euNV?N4R z84D093|m4=a$H;vKJ-rbpTXAT31Wl&qJ&L$1R~7PW~IzVf-J<+T zyyX8Zi};CKS0LYhoLm-pi&oKF3E>FHoMX2YMfuu4%Y=Ubg_UY>%gC?m}E* z3d2P6YksAyUq(_Zn@$6VT~Zm~s{eG7J4fi*QkulP-eXKOwdMUibqPTl(T+eVjr9dm zne6VQa;HJ$&25f?AdcjMM#k7TG~~uVXo~Og&?Pyt50x+hDt9}7F^SLAt3~ChZSs0B zHwBUBI#s0lvx5p<>agsx8b6@?s}u)idAMTML35&}R( zamz%wtR|TQTPG?M>O%j?F)^~miUgv@zrw>Fkd;5Q@j)ej`&wtD zmp3f+Ja8N?+Z$Qpof$?T>*_9V)~g7~HT9E<2JSp=f+n?8ip z-dHT7&RIq1hf14BFTtkWf>OZ@0ni4Q@!v9&N0O6C5|7<=2)xUZ*Uz2s(J&Gfo1T+^ zYC$=C+kP7F;__AvOta)CuF{b1Dw=ma(yIjr!*ljHVtjy&YRcGy!?sobUmeLX{q1_? zR?xLr>{@~Mle>Wq?Dy`8LC5r=YO;XAPe2Bzd2H3kPyq7fUGCd^tn*+FuQ;g5W`kpM zccS2Wv<0G$dn&(LFxNKlp8{S}ms1AhPFXupYduk%?q$t;@6rAAH8y&{bYYZm+?rUD zXCKb`4$AKKu$SVaKX9#b^1Mfsdb473s2vt&(9$P~L+LeXP1u`K!u;V)Ecytv$4sYL zesVKMkFa8ENhBBXOYX^Ld^~M9i1y9e^^&KG zuDbVC7O8(BX^?bD|DlM9)|W{!q6@Z|^d+E3)qmv%f!(#DaLzM+ZTb1$IfitAEu^FQ z4YEUcGAqs?YN>l)4K?gj-~mkxb!bhdC7KEqqa*3kMC~1@p4B?Xlf{5Yg)5n>ye>m1 zm&M@$Y@3m6G$|%)n1CYY>)JkF&)-vpcN?lw$AqTBTd387EW`LG%7QA0(5or3pLs7a z|9C?|A_R?rv?Zz~Z^cc+#Jofeb4gsNSn75ucy_P!nydK9c=M$U{DyIK|6ppd>b@<8Qxglb*xH$kVMqSfJ~(^Bm~F+`^v zR%KU0ZA+Ho2}00|In&aUVi4Jzml2UJDo zhg_*x^0iSv0$!hK61Wc9u|j$jC@E*{q17B=N1ID3>K+I$ag4#xpf(TkyT&OX{sNk5 zj=Y7S`)ng;8$pE`lqpa-%yJGsB7bVQa5(aMcv}_d?So(M$&PHU?7=2c(idF6|PYMtnx?3(=zxyra(H40vnZdeKpoiiXx5Q3LuhoSmyu_X+ zYWWszdBUa&vBwnXo=ew!hv2UyJaKkioAP7dizbkOctN+0c@z!B4#wVN@t7hBE&iA{ zU(7^wA(yZ1nd%E%#(XHn)J|ezkiW0BdxGUr`OXdIth-5?2BrI*D~{#S(@}=KD|PE! zFDfM4!09t)Nx9m}>K1cM>fq=q&M~$)=j0+g`RDhGa8kCt=Lf;XCzD| z3NFI6s7)n!iqs+Lamq6fvSKVoGE>>uiwo;v{fyxItY z^>b<IGCR#57*)?&p%m3utz7MIERa%Xi&F zruFZG$6Bs4w!g|JJjq9l;M+oc2{ z-{u=Xpvme-t>duP3*9d!_Bx&sm@H+=pm> zOB&tVGX$Sj|Ls}-n}_iv7S^;Xj&buV7m0q7cVKRL*RM7Pk#)Pg{^O@{^C1r8n7f_! zq*gEg^7bUl1D5m|Gg$+uy?lQ-Y538we}C7#>hWjkBM)Jl&gq~4{=ZE(>qr1kS_sEFH~2y(YWJ%;4fc z>Y7;*mB+AVW^Ta6A(WDiBVYI>Bd+`|TXbxqRsp0`GO~5uAQ5a}f}3>$WZb+anvC)K z5!wu@Zc#764jnWmh(lhgfS;(v`JS4qt{oc`7~8JOHFi^r18r!u1;=gcP@?ppf15ph z-LsN&Q{NNV#*aU5k6uWaV6CKvrOEq?e*Q7``+i+J+|-8K@NFKXU{6K8008m6dmE zAX%LBc51BGeygSK?m4A)yGMo%=zNk)8n+O8KU9#>UFF`AIBwG0M9gVv(7WylVIGFZ zMYS3+m`&p#?j7gf!~I~){n*=$Uyx+cR^q8%!3C{!iT%V;XA*QsC|81QYTCY{O=IX8 zU#qh|%prrF10Fvm1NXQg`#+HO)BPh{D81H`Y)mla~hWig3}Eem8?R+8|+ z0JTN0M<4?D|0A6JLj})45k@$2d2H@DQS8cAwpQ{1y2%n4@l2zY36GQQ*_Ik@y#Sm9Qb$#{EueXMiqdF;Wcd+$Z*< zk(Fh?06Wm?{}2SlT05NjrSdJnCI}THyPxr4H^T7y(%g;;8ZH_!gX6J2z)h8`EOW3a)XYqwD+)S8|>q*}nS%JpHhI#41(4dTt zhz&T}oxE`#CCO_2=?hd)xsn(0A9$@g44@R=eJwB`Px;P@Lf`;kWynqNIo$8MQP?ZIyxjfrKY@n6B5BSHca*}C=tt34E zM-lh4rZ(O{21AH~Dxvi%LYwZ+Fc0uPz=!4c1y0-GysYE+QuNt!zcgWNK_h3N zO0s|@S%_2JXy6A9Jn5?|Ed(#*Q3+>chu? zX>tmr+Nj}l3|l?^PU+E#;HxZ(Ktk29pn_=0&5BphfArJ#nk$(wTE*ukOzSqxnn;HO zOaU-BYQbj5PeTiLS^GZXwikZgXAt%}5x@p^)T|P0FaXlCVjA@*kT8xdGUa*gaglrm>ZVc_{=8P|U15c2JGMFimsqdb5gUXEJ7)mLPV?*WRk8OtM1BMLrq7&mC6h3! zIXc$UUI6x=S(5jChDr7A<`~xC7YI6fo^p>tdk{eb!vM28e=^nSPk~296ywf!hTy;o zR{g;ZMP;us){4yT(vdllW*&;J88YkZfkm_LW19375`=F7vwtYGqL(xBGM?)pRB-*X zo(^}Hh~=moPys(kPF>4IQ6W4er$?TlvN)p$9%Fj_H&1bqi#`MP<}lw7nrw}?hFVlq zBI0cA*9mj-4HK}pNnI%L7{u_G4%BB9_#@F=&;b*(&?s9G4+~FtZICI?j{!`ABgWR@ z!FaEKD~iY#OME;_%;<+?dg)YRTlnU6{3Nq~U4yteI4BQ}R_BSn%;8P)f|&gOD)s1k zj$|F7+-_4?M0B%OK{$MI6Z5`}yl8ME@8w80d8-2{r#PL;phR2Rk09z`!UX^NdU@-5sMy5|Dubmwh-+r`?vgudM|+x&x#p z)ZKKS5Sr|sjpo|ypW+j0CmN3i4&YcVo)pm@%$l*@!6wD28l+;;fV6fiWb^7-+T&p` z6IPBI+^Dx1hyf`6bXSbbK|zKrE=Y1qjs+rq*v)aZ7>q`fj>N+{ z2=>cUUPtUF)ZRJj`zif=l$ZA$QHz4GBhaMcf}obcd9mun z(6xfYi;Z9PS)!et| z;yOU~JBla)+&#jVX(^S;7wfoqrmI<77`B^*5a$@V3(CIN+U5lN2F_}_? zIT*PT22%2X@nXs72nf&ROiJVJmy3r$hzZ|{GDWkwkT!1(nSrJKx5-9}zWQ{H z6thUo4jh7Eg%VG7DCr=Bczcj+R^lo(qo&RsD5{t0WW>~YMM}CjTQe9X3Nw|+W$jQ7 zSaU-uWmQUj1=uQSd+DN~FB%gd)C7AYEsp^GYhmwM9CR4$C_EiK$8QVZ{kNW{-_@Qs zTCpkvKp?shUP`Q33xt}%Rj>(r_GL6_6LOH37^VD<=KS__b{q3Xc8JBnzfYG{?$>xy zMd}P{Fi@HnX|!qf<~3BQaus;V|9sHEB@Bg06(bQY_Ji7VGpoa7L0H%owmfM-HsJT-Pc?BVc81qeMcjalw!bOWb~5L)Lqgqs#t!r zLJ|Xt;%R0g3GDyiA+@-;c*ad%pk%g(M|CMVp(7m~roQ07!}6yH{!dW~wT%T60?ulA z%7t0YLw|g_(eB(>(yg0Qt|E%dcY-;TW;N;b`_Bn~!+=v2MRS=x)rdd9k1^(cB-u;f zah8f3)pPsTMh-E<^1e5f?-xQ^_AfFbnY7=uD&ITFguDO|=SOR5a8rJiuJ)dL53640FrIHTu&6`>M z9=TcDrhed}7Dl~eWX{eoVZUai)E3g< z?RMcva+|g`h}-+-;!sj9^EJ#^R<0X-Y{xybl4P}?`K|zdM;x@=HzhQ=wgl)t4LIwa zPF*>o#Hz|<8_Yi4{IP)x7Q>kQiDwm4?>>kKi+HmdE;%nrtKroNC47@fF@Ib4Tih|# z_%rcADHUPwsMb-j!71|VYPPc;3QdoH?7Vhi@~95?^mr1L2Gpe?8CKf=xVJc>L%+>+tH5kfQH%6%7em4IG+m3?&#bTK{uty?G zrba-G>O-^rNv<;m{eH_6Xi>JF(6TSDq}2JS|Hswv*F2ppeebJnhF8JF?oApcJD^+N zGZ$n2tBIPuBzGI(n@U7aJK|)rjR&0By}9#&tC}yW6eaKiI3N=+ztROcpE1{Gl8R=y zvqeQaJ0Bb3oeZ5Y^Di|+ZBKHjSOmO!+y+9%qWDeQDJ@>-?z4&=d`8=kV>KBVR83JNmHOc=Yzn%H{<=J88cZ!P`1Pixh1bA zVo%ey#4lIH2x;q0{6Han)J1MRP>vr=-e%eK<#%}UwwP$8lOd0rOb5;WGKKB~oOGbGj`F?YA$a~ene zw|Byl{!vg*RC8C;GGmfV_h1kUFyOBTAwX7ZClqL){lg^xI2gn?~2x@)Rw4c9fQ4X4EOcSO$?=KGY4 z0eW4jKmta!RtI!0_PBG(q$yV#lVWxYY#2+31`#jhqszYzEBMHGd@31`{ladv251>+ z0$6RR$G~I=wG?7S+F=DSh?Qn^C$bwZqOk~ZuvxZX0Dy;UGO@3kYh~gr$jSdzdXtsW zWa7$dJY0OPNNpH2$Oz|8I3i1%%P&B~Gk-8th3imk z!t=1{0yqJ{HwMpPz1%{t4%@2Vn2}9}Q*s!E;dD_$tx#%G$+P#wyR{3}2$l|}zm3BS zpPQ_4IuU`5!+@wKIGht3@S2zI&1U%Np&8QHl~ie1|W+A})$*nY*qtgprxW zI8L$pskX#uAqVG4fz&|v@^m(>jLX~CrK_JVr!tKH(GhZobm~O0m#4cseJYB;ale40 zzhVT`TKG0+PS%{AWzT;NGu1mK-AVVAZ4cO6^8RJX z@vL&MflO+F5foZT zsAPHga}dW&HnHj%X&pP_4pf!jNo0LrJvc{FGy9fb)k!yWEVv`cQ{h=3Mi?A^biS30 zZ=oDYf{C8ZH0_+D$Ly+@LRSWL32neyeRfdPzuw<<(>Y8JBCpU;iIW_L|9;#RQL3R9|&QUgW^x?VR|VZ4^ryK6P}bVZK&0m5j|; zCgUVa%7l6lp4YrK58k7WHJ^fq+Uy)J3w8+Zr;09^^3M~*k+FTOoU22^wJ@W`r2~Rc z^!bc9n1}24H9i@Zw*L(c2)&4vb{|@>jyBv%8J`gRpd{r{OS6IUYppP{XH^ zkDol-J}?Q!bkT{=w0rs%Sx*8_;OLN=&nltVpTl8;#kPf{%S50g1rfGo48gHI)+^Dn zFpDr>HT12r&4Mc8BAU59D1wuWKjwZ>=#IE#a$e{8b}s>PVd=f)-P$#AuP5$b+|QR> z;tk&~6U|WLYzJ<8A}*+OySFsXA{10&!;2z*ud;kRW&dudOYpJ5okw#fOM-4hpdaL< zp=G@R>OX%Qm~ud3JQUiR(m{D2^{B%9c-#JRaXPe)T`zqopMjcLe;gFIl{Jsq+&Ss9 zZcC4^#&-e-^)c{ng(Y}fLG&N8vMy9EjsbWwGzJ!jd&pa9j8Z@TZqRH4pxtUTFWGop ziJPHZv;g*~@(7HP`}@*4IIaO0;!>FQz+v!FJ)wyvVugmKDyS(Q3~u26vf7-D`LAkh zBg}`E|0+4@NPJMev^+cY`t03RN0QR$f#Uf{tE=g+=ci!eG7^Z>5+9!@{WiP+0M49y zTTIU|>J-F+QNCt?3t#Ujz4#{LZ&tH0`a4@)<(|*lTh6 zGp6I9Gc`KSM;fe_OHyQ|$nW~Su7|^vZe+N<*AljR8WfhjjOfW@5q0-hF9~tu`wGFm zAcW545~g=3&IMs^gE-0a2*E^JM$XC(MBhU66{oj2eRz&+z$_%_?%Cwku!VJGqE`Uk zyiSt@zWG4T#i)tg>;(Oi!hpplr_`;lA3xdhoC;R-V#a;bms3cT$u_R$xe3Us~Wt zvjHAfA!A_c6)R0r4y?br;cP*QAhHWg7;7R9LeL*4HpH;*$-Re_9F)%*LS+xnKB<1# zG^2KoFd;n9ZZ#&fvBkolhfDCLx{Tv?i)3HVA1A5&-88n$;OO{J)=Y==$_!;wowGT3 zdU|!EQbVVSD;I4)Y!n3u*9DbOD=%btCLYLSJDZ49UURD}6@=lQN5V+}zdH4s0I6G0 zysLV`!wuVEB`>+7k1>}sjWQyC9<+8dM+^0i_*i4}_CTo`Za)V-=DB+S0%^?@eJO@K zH1L4e?#(Xsz5z75pFTiIn>iqSbB=Kj4ks^UL~qrMt?9@!cwqW&rOFsfTHj$*Q6sDh z=u653>EwH~gOA#qNa|X4ua?Oi7=t${FxzA^V8sT44xp4n&RDciruitMT1+x-iC-QSO3DcSXku z`z-+vz?2*3sR`DJ=3xg47Z7I|W0!HiK8#wn_R(iW^MuF8N`>%B5iB6r*eYDO>aqfL zJC)j`iF!I;5rqV^+nCKuc>HdpwSpq)r(6-E{l?h%joqA1}m^LboYOr7tl zn0%NJsP~B$(#==A=fWePkO-Q8rg(S#Yzv5?uD+0^Ms>#H_4Y@hJGlUAg!ioz>ZQ6qjkP=(MU12xamm`KqxGABw@3c2r_amYj{I+ZD zMR|PhRMnrkae;+=PS&?VA<+n%?rNeFdNp=+u5mnsrtX@lcb9PF$)nZ=fO_mXjmjMl zk^K|pHt1Y)stKqWT1tVQ-2zTBmi6uBjIT0gv+I{NYfv+*y?^UR_)? zu=-6wp$TE|HngbEgghj=!SNgqq&U9DtYbTIz?g|*i<@Fcn)+>7V}|VXnZ;oRW&H9p(WBaFq%isOvRKy}@EK8WUGmcmg03hWOdD9V~N`8I+Cmm=^QUI1&)F zA`q<*Nj2_wBd4SV4m;g3deA$G_#V=Y>g|KX0o?$0Tz15)*g{Hm zQn+>>?q}M9Y~x;hh}eZ*7OSYlbta88ugJ&KM46RJWAO;%0g{e-{E4ntv`ppxdc=Ne zg%@e1iq!-b+ul)A+5f`cF&34#X7$$+Qc^J*5H_<6pMnS3Rw0KFe%x?E|mJtsFi zz}e+iviT4w`!Tmpy9*i7Thk1Q-xOXUFq`_pyljM@Y~gz7q7cRcM@%8Itr$DFimV(6VWw90R~xp*2HQjHclnn1Kq z*>nuCv&!>0ib_DeJB;+;8sg`$nsP_0Iw-%hzaKYd%!{h+w-fhv;(TyP)nfxU%-&`WzWI(_I#WMLu`SO{m8>K1;;+#+|2Sc)+xJo|2c;2EwjPQNFQ{ z4=5ScP&2z&P;JF;5Qrn9)(&kL>@=NEkv>MR#jHW}{w1=-G7fDPd8GW(eIYI0OcHM8 z*X&GWEi_iN!kRwUie;5}G9WUKEmRv;enJG>PQ8 z>bH2*_j|Gm@bud~h$ox3kka74!0b-zU~`>(6p=ur#%Z0)%Trz8JQi|f^!dP>lyzG| zo_!nXEh4e6ID1+}dwr|n<=t)<6D%=r@IybAQrPN=r=iA_QdY8?QPsCbHDxephew8cJE zhD0@EvdgWZuiE131Y)-Nbrk^HBU|l-0gbClc-X@49cTb|)oW|J)C~r2+~;%z5W9)9 zD|^hWHcXk2>fV(SGp6bRJmRxDmSoH45#R<$$p4joliT$hrFhYH6YeRh>{|M(zUEs* zr}wcu`%AgX*K|60*qh&z1IUqRL3g}x?M^dEMO#nc+*ch%lez6EeH^}q zNF0b!^kjw=x#ca?UOoJySVNv4NNlWNC!uLYvJ-Z?8KH5MQSV?x-TO0C?ZcF{?b^-&Qa$8lp%xGdfRP^3;fq7}WQmWr;}!2cY=Tw37llFDa^a zW1u}Io-$lX$IZy%WajyWdYqbgr#4iUK8DG+LfR_ zjANrj^_9t!JvPmWGSC9AKoBcgi0kurm<~}IKO~x5sotBo^UBr~a8}K|=LO`~rlm;Y z*U1ZaKg2tgwp(!JBxUxoTfN+QY>omL29@m@AnN-(BH^aoK96#13$C@2(aKJd)!HFM z{#KQN68}n-PS+wNL6-x3xIzeL3zRnpu*(=KjZd%BEWcEj@hR+D?g~$L2(}VxZc2)W z)jKelrL1GLtbg1UMTJAeUzy!6%Xou_`FB`@HyNK10~ViH5o3Z+W^s_<1#WfE8HKCs|cUL{woi%F8K<KcUHOYp?ih(!t2ZiBPQ`rL}2{$5F2#iIS_?EpEu z8lcQ?OK$x=DATlB0cBK~vjPiifxL_3MFEK_viWeL*ila!24pIp8P&*HHEQEE7FJyzd9aUOG)Ss2r;2 zveaQ34kB8Racr$0nI@nMuM3bwZIe*z<*$BiFe${qI3~kJA!n~c#Ou`$pt&_rC1P$7D-RYY{s>^SjF`kuxowB>JILQolP36FL1akc zb4|`1XZG6SwqAI-wM+p-q_bSDw=V(l7n)ka7jnkg-fAkqP+Gf2f47!i{Q%19)Ri?* zl?#_kM5_HAYWe*lcw=epMV6L$5U>h=@F&%$8)6lgZsu@Dulxaz_-uAKzVP+WNtve_ zjUbueHVm04wLgX?)R|xW7c<4ZpAJMo7%o2!9%aN;oKSIGEFWuqTj5g-i;WXlywHTy z9Jaw8pcp*Zk@NUzBo(F|8NBq{2r_h1D3v@y;_2d4?9PQU)3pY*4X;%8{c9`thr*cx z?}CSuBU%}94aUu?=huUocSc7x8in0GNN*5+5A9~iDNYu@v>d`x=iXUVtP4DpD92VE`_eI0g;xcc0P^@fF0Syj zr%#t&YOKb$oM0JjUgA>2I;AR#$&OW_&%RJd($W+R2`>pjJm#+v+7@zhgvAcc$pKnJ z6}p<)Xoga7huIJ#2N5EfRNN*B*TDs$5*b8k?}CZ$mW~Aicy<5+gT;pIYHTMU_hvV*N&}^rB<%w z%sweo_j-y8_3)AG%FNqL*n1Aus-X7#he$~=TkiC8eK+=NRF=wuY`1K&ogsO}kU`@X zZpK^ZO}k4CECI2HmueTFyt2%ulFJrTh?08tIi{srN0EgRlw$fxeAR~wLJY}`{tnuW z7Z$Xr1ws_J<$l++_WDOeW)Cf1 zk=h88nd;(km^a2<53q<3KkQofY{M3KLReT~n3McNrv&GG!=nPk%M6X=^{Aw#&!hU! zqUe0ydY5&4txH)L7hC&z1c=G7)P65C5+QLrc_L_6@pg28ga1$@ zRf_ci-=pPHKwUMY-;snArVHgLS7^lR66IUYWKFoDJtmDvehAfk0?zuw`^2oIvbvb= zbw&Ue@hgs424=%pz*QAoNz7%jrZfTtYw`9-$4_yLW~??9S){3(kge+v*^?C`nS!Aa zDj%@%WY;3@&&nm_xKQk*vOJ9E=HzTF_T^Pd$TX32wo7TFKAsBs*S#ACe#fBUviMEp7g;Pi zqQa*dJi~X)QH84E4-2y)f6da~O>J2whJ0HuDPRdhufyD>dRtN?;GyyAKV?dU@=P^R z@|T50razTBLmL*LP`FUAyo9On?zvF$%8EAS`v}7}&n06Ttd~1^CLG zhnXgH0(j0@vpmIrVsBplr0p52#{Mb^Ig^6jCb3gd7jw79R;PS^XgINNLKBYX6$QFl z3qK^06b55t3TfP^@~5bp~E=W!^j-fdZ_&fH0Ru2Rax<>l%5MA2%auBydkvL9mB_e7zZI==Az=_mHY z-A%eB_sEYHJU7LDo8rj37m6Yq?qdRT;K*$g5lGV#BUI%CUV>Bc5HaA&69H zOIIKMHgJC3E~zFvsSo1{`%wm?bBcIjWou0x~9$k1ndoj8ozd^~{MDd~-gwbdS3FtzSkB6(Q&ws$e zsZ(@1eXOgW?{vFE*O*84c?$!SrwsGghh)CRs0@S`V9fSdv@r)X-a z>`oZSQjO%k=0vW7mUjW+G-Gk2Z>(!jQ8j7K)DC@<1bEyEK#)4pA`Sa;RY%}*?JX(P zp8b*HYs>nXu!>@gCk(>x_ZaA41a}Fss2j3()sMdd-M3SiX}lANFwTR1!j!6ra!1eVqgW8k;w9`1KG(dE4vSFdo(WbdxHrZ81J3T*Gw#8^D?cyHfKJY9$G><{} zL_2fDG!AQ41qIYUA%}4cuqIk!PXEVZTixff!83p!H=@$Hc+Pm>U1(CKq-@7Tq}1$7 zQKS8ZW^u{$D)fFH=M=#Nyou_*8$3@)f_4EaFBA@j?w*wp|b+XW}@6my+e zxCPMm=jdV@JQ$)I=-PyE^I346P1keP#iE%_i)ZWd_yFRpFC5FHrmD=}A?!}VzVZ75 zdQ>|ss}7^#MiqtfFhsVzE`HQhPQzkyWXyTsokRC5+CkBnIWiyW-oM*i;dR}i=s zM;Rc&{wa9AogfbW&X}5|KzdK%k#qCkaL7&xTYw%6@cm{<^pyAJy;VTz+}QK{!stTN zLIw-3V{f*$|KA(GG?_^E+z3CK{+3SvsYJ#s5Ys?iIhrB+!l0JXdLT<|9mtDp&y``c zO&S$QK?FGShsT*b5OQ%!>Df|GF*$|S1s8JkW%`^Y?F$*X6p%jkXW|paR@{XShUIh3 zzie$SyW-i;I7XKyL14c2sx|cV2k!S3BZ2ql1WrWf=n!m~%wg4$^I1%iYAQe?{TFrE zQ8Yl1;gKJ6*K14Vh>bG@YHY<-$%P$cS};x@E}`1_RqUSdxzhiyPRT9ln~vi{l7;Iu!X*Aop4yRPPw8Dh?c=4kA8=oz=q9xbEUAGcRW-lN#UPxS)F zy{=l?xc6Z~jJ8QN(1qc89PS^NF%5%Cayvm+UX*tCaTr%X*=*cIzu!54?)ekVf=Wn~ zMpux>mj}(3uMZ6ylFks?K@Hyl$d%OY4#UU4U*qP}I{+#ABysSqMHS=Y-uxPyopQlq z*YT>LJ7-`M_{r&;V7@m_L2_P#p60Cg)w%Ea)-^DiM6OjaQOYG7j1-GJRLyK2JC#+a zw9j2RM7*eG>h&jNz@zaWOuNpCWn4XA#kE#eqy-Bb!6F$x_85N-WM$Np_xCH8i(=gX;>vH!?l@+PtVTx#tFBp8psN;PmB>~Z@Dx74OA3V>;2mr zC0jq)`@=J6DASx{z2{rs9SJliBYDDnvRa{HpVP3HQQ7c0uUKgs}@wJ40)-0;rQlKv2;+KRcR+>a!P4kNp@{HHG;kzo;8zA?fa)#i#> z|K5c%G$|P-<)yRobxMxmiKucwHnk|5`KCq%9>ZItJuVH|#{|somu(q)Dv6QTK0iB~ z?Crzj2?g$PsGl@K)TXxsj@j7^LS?FqJZ$;EZT_hTJ0A$_@2iWFev-y{yvgVMXcu)< zr2Vk$^M=G5sv@O0W~yo$pE)Z8`rx|fg!t9*iEu6t z2SpOmI;E52xN?-=$~@0$eP!}WL3+O& zs-I4qrSJc_XW%L(>zVBM$$7bUj5&+pW3#rAGExOUbeL;iy7KnSsMI-`?!YYtt9_4i zPr3k-q%EEBUG4^0xWmwic9^~@i&ERnz+E)BD}esK>3Y3oc-l_u!|AY?Bo_j%E21&? zsuq&Rg%M<2stfEdQ$emc#)=}qK6I9kzNiNd8zHgt{EV`qU?&#wtk-8xq#j8P)$x1s zS1?}q6n*&mE0fd zhL7=Q@i{Vh($B-BUl$Q=|fcHEa}eX@Q#I(ZsTv&F*y5^>u%W;0I}>&h(YzGnIxYtr?1ue zW+MtMquruM5dq!6|AG<_*!E5NUYo2!H~e(;6ilrKPn%6*pKda5wjP8fGaRy>b32^>JOQRmCMQPn2z>J+*{mWWKpAbb-Y4^#s8>^vUiZ!qXl1ZCy2Xax;w^Z$;xgO09c#roI@3%+$iDD4 zHw`Vt^TAE!6+Y@8PW5XQz=puowJa6soV7K-3B2@0}#1 z5_kUpnX{geB>Te(bwisJNGYN+`9o*o-A6M>Vgg`tKCPTZweX60fJE(^`n8;7`>ibW zM|N__b2Py~iWP`(6ie2kFr%4k1x*6*KxEeeDy)lf_#=(}F2PDvi~0D?0*NfZHRp#V zf92;lT6l0FnZvMEcBI@4GS~ej3}Ap9nK97aMgtw|Fjl^d8I35 zcA)ADO6554eFwM_2wURImp8Sy`-JsE&!(6AITIvGz9oq;;3ka{am&%OO;Ws1|0Nee zY(=og6!~B1lW@P=JYEC}>(>&jj5}$9#%p59#>vHD z*7k6`5#t;h%P%fkNKJ+TLAd_9%2W>aoH(g)8#HlyCxv+*1Z*wMX2@d$O>FF#)q_R} z2eoYYJo~`Hoc?A*^Un$o;A*>w@Or@2!TvXvi4K$P>|fz7DqN){*qyIw?bFuFx=#0u z8`*4QeZ-ZKDdQ1FMJoT&-=!Fg&CmnR_Dx7ap=!a^UMwfFV#np7S|GnTpnQgC)6Hc*GC ztx!Mz4*{|A^JL@IOYA#H2$2&SAzgBONy#1&-DIB)r-az9O7!pTu^0N&O_(x z`d>XtA1zPAmeH!)R@<0>>ga6?KD^A9!|tMx18!9)L3lzFj}kcPcXokP6eunohB2av zuq2@kt*m9W{aWOK!}IoGM)C(=iCm5t2|noVm-RXu%ZXZkz3Cvu_>j7SEF3O^I0^#H zjQl1uZgrSDUBrLPkM5cpG0q#na;+{T;}(d$Oe*VIt3p9vEV9zlu`bNhqZSclhYA@l zDR3*9FbTvZNM@{L(p$%+A?*d{SX^)3P!0Gc*H-Cl+YorDe~A)%k8rfSUMK}N3}(&y zVs1H$p~(@{p*;KH0E+0)@1#%IE(Qh32QjUzFEy|Hn0!VPMGsATIc4Gc zT0gajG{`1Z2XSdXwSog6uUln^C)owwGkui{lkEnjbkhC)+>a1joYl$L__XmPGz=|2 z>ayr)Q>?1U!&I`0=OK%PJXv%CB1WCS4Zj4BJypz?bxp|?vp9Wr-C_iA^&B#2F?W%1 z8)41_kwkDWQ^*9izJ~WemUpda%A$F!dsp1_9XoxTT5%ZfU@;qG(ez}^FUa?_ow3hw zP(l@@x1X<%Vsxr>yO$ICkt>7Iy}YR4t5CgwO6_i%T$)ZmrLLfeh;IyYJQq0Qo<82T$nY_zYrXe|DM*XL z09ab?w-Av@J5;OUZwuU62qNVTV(vv1c`)ioHqR1;MwdE^!{fG?9{F`UY?w-nd%DB0 zJGs}f4=v$Er_M{J&FKwZU${#v#R}*p;bn-#V94>{Bea-~Fs)YWG5xp+?gg&^E1N9( zSIb*A0i(I>D(P-%EtNV~sXxzhont^S_mPyDkCAO@PWLk`E5>#v-=Dt#J(2dJjPCVR(0kkEHSL{f*Gi84As+-XQr$&mmHGhi5D>SHs zf|mhc0Q93b{y-Fhy>)R=HfYWkCL{dM$BkcI& zH0>k5&6@5P>_PtFS4nQ|*S@Sq8oM)U3j?_U@$J&n;o2k#%J7r8)DI|BHUIAm(PrMo;QZG^Gb7N5359=VnOXn7Tt<1@cQMO2K5^Y$3%jK!3i2D zx{q9c3#}pLMl$+FOz5L5ID^JgXkITh12gG5bOXot-oDimv!(ptccna z>4GaiJ@d%sfWm`jFDZ7tc#=xZ`jgr_mGHX2trULS^BO#R@Y0o-1H21seHa{R} z+hXK?X&)eC@kN_YIcy>%#!+_5yC?5%x!w^!EQ#QTf6%LVvE7j-lU z2`6kcy*&}kg>fs4=}=p`)Z5DU0T$h{!@4sa#FP)WI@-zPdHklPjERh`^Kr6&f{JuqdJ#_9FQ58jkl+}?YK9=r*e5!O#G(~`zQSZ?6VOZPY;4Gap7yvPX!s$qL6!Y! z9uO!tE+nnJfy!m)uPxp~ea2>RN?{_gUQVAj%Db5RRs@JnXc#=SA|Xzy;UF>dnFtvA z$VCk)6By2OkA=_p?JBH}_aofnv`))9ilwd_@D%-g5*>Bdj7OEjltcMQ?nR%e(5s}s zg1}!a9(5{pxyNoySGx%kKA<{I7jpbK*=p=$rl8hNLRJkR^;c0cizjH9lO17~>V z`$VG9E`(lOGL4l2PQ2SL(LP5PmzL>~bg9K#WC~EZL0gM%x`qu!gTlV;vYViS0gL^LC>Mu@IV0_j~6mZ9P zHzlG>86i`&7sVR@n;&&j)!+dw%xv0<4_fA~;NI|SoeNfIhG^pN0F`Rr=~Gj>O(T4% z&Z|E%=JGWi7mysd;|P0iF0jwuyj%DhmEs@3HFNd2gSHHknQu=OCOtd{MN?3|l*nI|769l5$_Zg%!@eVrE)p?R9S#Jscr-DO># z*g_H8f0I{CQP5={ZCBpHajqYV`0>}R0{c%6v2u?~LP13dDg7mCldO5&KmgpT6f`?7 zA5@0|+&8bW?#S00;htMfS!Jvhs86F_)M4OQlzQ3FXnG-Ou=Zg=Rfk{@x;nmlXwGkK zfKdgVgZTUB2vb!kvN-ZWAXjXi@lMaI19!(tH5wuWXB@{<(P~j1v4O?C=^R}@B8UOIR>o>mZP;Mj}!@O=9XAjd@otYH{CulCMu%LaH zFFOvv*;7ZXfF`5Z73c8({#>KPGm)D?s`PMrqk>O8uV&{oqV1$AXn zV2KguBsj)z42?suM*5&$8h(!2v#(O<)il;I#9&jD^N{8KCL7`AHa7&shCvU}?N73HTr>+3%C_8T#*2@!{!OT7PMES~ z0qycgU|qPacKo=C!Yw2Uu>?l?{q&m>(KoHbioT03;J3B%%XUmIUK^gcdxPL}oaYdZ_(iXsbrv}twS{XvsjeiWPm`wvg+MFAe!n`QE>!Kz7jCoB)eA?MJduP_>M 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 1492/1786] 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 1493/1786] 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 1494/1786] 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 1495/1786] 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 1496/1786] 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 1497/1786] 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 1498/1786] 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 1499/1786] 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 1500/1786] 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 1501/1786] 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 1502/1786] 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 1503/1786] 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 1504/1786] 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 1505/1786] 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 1506/1786] 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 1507/1786] 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 1508/1786] 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 1509/1786] 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 1510/1786] 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 1511/1786] 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 1512/1786] 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 1513/1786] 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 1514/1786] 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 1515/1786] 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 1516/1786] 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 1517/1786] 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 1518/1786] 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 1519/1786] 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 1520/1786] 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 1521/1786] 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 1522/1786] 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 1523/1786] 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 1524/1786] 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 1525/1786] 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 1526/1786] 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 1527/1786] 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 1528/1786] 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 1529/1786] 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 1530/1786] 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 1531/1786] 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 1532/1786] 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 1533/1786] 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 1534/1786] 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 1535/1786] 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 1536/1786] 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 1537/1786] 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 1538/1786] 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 1539/1786] 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 1540/1786] 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 1541/1786] 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 1542/1786] 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 1543/1786] 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 1544/1786] 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 1545/1786] 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 1546/1786] 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 1547/1786] 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 1548/1786] 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 1549/1786] 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 1550/1786] 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 1551/1786] 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 1552/1786] 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 1553/1786] 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 1554/1786] 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 1555/1786] 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 1556/1786] 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 1557/1786] 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 1558/1786] 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 1559/1786] 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 1560/1786] 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 1561/1786] 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 1562/1786] 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 1563/1786] 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 1564/1786] 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 1565/1786] 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 1566/1786] 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 1567/1786] 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 1568/1786] 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 1569/1786] 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 1570/1786] 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 1571/1786] =?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 1572/1786] 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 1573/1786] 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 1574/1786] 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 1575/1786] 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 1576/1786] 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 1577/1786] 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 1578/1786] 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 1579/1786] 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 1580/1786] 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 1581/1786] 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 1582/1786] 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 1583/1786] 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 1584/1786] 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 1585/1786] 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 1586/1786] 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 1587/1786] 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 1588/1786] 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 1589/1786] 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 1590/1786] 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 1591/1786] 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 1592/1786] 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 1593/1786] 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 1594/1786] 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 1595/1786] 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 1596/1786] 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 1597/1786] 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 1598/1786] 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 1599/1786] 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 1600/1786] 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 1601/1786] 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 1602/1786] 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 1603/1786] 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 1604/1786] 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 1605/1786] 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 1606/1786] 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 1607/1786] 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 1608/1786] 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 1609/1786] 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 1610/1786] 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 1611/1786] 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 1612/1786] 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 1613/1786] 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 1614/1786] 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 1615/1786] 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 1616/1786] 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 1617/1786] 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 1618/1786] 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 1619/1786] 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 1620/1786] 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 1621/1786] 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 1622/1786] 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 1623/1786] 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 1624/1786] 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 1625/1786] 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 1626/1786] 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 1627/1786] 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 1628/1786] 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 1629/1786] 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 1630/1786] 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 1631/1786] 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 1632/1786] 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 1633/1786] 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 1634/1786] 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 1635/1786] 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 1636/1786] 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 1637/1786] 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 1638/1786] 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 1639/1786] 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 1640/1786] 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 1641/1786] 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 1642/1786] 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 1643/1786] 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 1644/1786] 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 1645/1786] 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 1646/1786] 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 1647/1786] 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 1648/1786] 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 1649/1786] 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 1650/1786] 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 1651/1786] 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 1652/1786] 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 1653/1786] 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 1654/1786] 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 1655/1786] 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 1656/1786] 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 1657/1786] 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 1658/1786] 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 1659/1786] 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 1660/1786] 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 1661/1786] 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 1662/1786] 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 1663/1786] 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 1664/1786] 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 1665/1786] 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 1666/1786] 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 1667/1786] 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 1668/1786] 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 1669/1786] 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 1670/1786] 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 1671/1786] 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 1672/1786] 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 1673/1786] 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 1674/1786] 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 1675/1786] 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 1676/1786] 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 1677/1786] 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 1678/1786] 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 1679/1786] 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 1680/1786] 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 1681/1786] 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 1682/1786] 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 1683/1786] 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 1684/1786] 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 1685/1786] 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 1686/1786] 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 1687/1786] 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 1688/1786] 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 1689/1786] 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 1690/1786] 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 1691/1786] 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 1692/1786] 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 1693/1786] 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 1694/1786] 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 1695/1786] 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 1696/1786] 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 1697/1786] 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 1698/1786] 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 1699/1786] 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 1700/1786] 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 1701/1786] 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 1702/1786] 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 1703/1786] 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 1704/1786] 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 1705/1786] 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 1706/1786] 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 1707/1786] 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 1708/1786] 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 1709/1786] 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 1710/1786] 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 1711/1786] 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 1712/1786] 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 1713/1786] 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 1714/1786] 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 1715/1786] 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 1716/1786] 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 1717/1786] 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 1718/1786] 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 1719/1786] 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 1720/1786] 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 1721/1786] 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 1722/1786] 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 1723/1786] 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 1724/1786] 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 1725/1786] 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 1726/1786] 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 1727/1786] 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 1728/1786] 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 1729/1786] 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 1730/1786] 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 1731/1786] 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 1732/1786] 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 1733/1786] 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 1734/1786] 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 1735/1786] 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 1736/1786] 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 1737/1786] 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 1738/1786] 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 1739/1786] 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 1740/1786] 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 1741/1786] 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 1742/1786] 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 1743/1786] 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 1744/1786] 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 1745/1786] 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 1746/1786] 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 1747/1786] 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 1748/1786] 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 1749/1786] 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 1750/1786] 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 1751/1786] 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 1752/1786] 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 1753/1786] 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 1754/1786] 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 1755/1786] 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 1756/1786] 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 1757/1786] 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 1758/1786] 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 1759/1786] 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 1760/1786] 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 1761/1786] 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 1762/1786] 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 1763/1786] 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 1764/1786] 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 1765/1786] 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 1766/1786] 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 1767/1786] 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 1768/1786] 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 1769/1786] 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 1770/1786] 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 1771/1786] 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 1772/1786] 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 1773/1786] 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 1774/1786] 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 1775/1786] 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 1776/1786] 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 1777/1786] 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 1778/1786] 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 1779/1786] 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 1780/1786] 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 1781/1786] 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 1782/1786] 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 1783/1786] 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 1784/1786] 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 1785/1786] 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 1786/1786] 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"); } }

    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 zcmV-24bAeu8=oAIegX{zk${wc4GnE%VRRAz3JEwRry6V^A)wMS^%+cL0^4q)X`9)j zSeicDKRP3ys7?xHLV;r4K(a-IvM>dFf>$=vX2BEd9&I#J^)xDc*MKa-G>k$&xh5hN zL9jVN+|O(`3^6e~jV;8Up^5{Hwlh>r!q;GyWf7h`De!e<8C!56jf^Xce+;sIN7QDtAOE^*wEM zM{o{u!NAUIRI0O6*rXhz+#3g$w}=_8CWPm2lA9Tg#G}DNvWZ7Cr`F0O8ztC>Z(eJx zWMD}aLvU&HPW&%_5<&9nuMMm$Ef;D%5bY@f&BT466mxrmZ`kpdj>+F>7}ajM3Ik@t zPqC1F5p!@kIKJJ^c&fY`e&!)`fU-?X92{4gn=Gwz(91O^6%GY4VEZ-MDi$JORI1R^ zf&~s&^P&?c8ow;TE^u@HBZ7u<_wk&3xq74huT!Kc^00D$%)G?hjXXma3&zp5;bRGU zd*m&Mp1!NofLwFuc{}Z=haO$uS}7Lh%oAjYK4g=XM#7FMh)O1OJyDCG!;ct3OzLoH zp$6Aws?uZxRv+dGx|``E@y8PxQQvQ4q-EW-VR!gt)1l3&CZFR`Mr>BW7GbbKl$iN` zF7QUtm_J#6S0Lfg`|Dt6&F_5Ru2ft0AfsEu>qG{=#?u|${%vx@iF@vfs6T@#>3n1o zl1Ik@J}BwNRfwt^)ChCj5w|y_e}r`Vh@&_neUlx%%EFcc=g37cn^B?jNFpw`?oU!& zXr#+{bYo5tNt#M$b{QxK)B=sAN{rAMZU(2tIxVYz!MWgBO}J&7xy|o+f~sk2!62;} zJk@p&Vk&!)MoF;Ty8Jqn*Hh#@urr>zYei?OS-#(6y1@jetq$5sM}V;Z-;o}pR%3TC zKMjk9Ewi!UW?&v!lG@Mt!$LHv2v}xE!UuS(fl*Fz-4!hHrD05qA8Jy08!WPC0fP0@ z88Ih+Sz9{LJj;9Fafj689;kv-{n+{)IDnirtMb!_hg(i3aE_fT92W z1yU2ibDp8ID^nS(lz;%qrG!0VVNn=x1j!|`<_6Y?8#3pLoV2dvLp@fiP{?)?Z8@6p zG8;9~J|_!Zl12K5Uz4#D*62x}6>y}RTibicehS?oc-?h2+c=!|uj~{4qgwlHeh^|& zR9l54q99l?a{sAweS^)6{~(ap!bV4b4T4f<>EU<`SH(3r(u1HgFKr5NB8f7es`JR9 zbrN(%d)lGwK2~`V_-$uspLYU=zhMTqepnvq9q{dA=&*rQ}j!cvW8{Fv%blHaI>O2 zhiMihUCO#4pkeZY(h-3~X&>bd9Nx4GS^S*qj!7R4cY@k5*2vSid3;KGu{26ZR0Mp` zIOC9@sRHN!4c@4vbA*Ac)NCKU^jBN_!9g?THz8J<(K(fXJc03!pa=7ICW!n#2Av^V z&jY$VL1d>soMM$NSE~ByqVtu1@&u7p6%Sq%k=I_Llj{3QD|?d)r&Db!C>Zw-k8`NO zLT}(SDx?0VR@xQ(5M2-CL-sM4rb~r+S+M4>(+eYUn6Jo8<@ELZ{9A{Wy&KkR~8-+irm>S ziR592YtCH=)r9KxsJT6@t3Lx&B%#V-8SmRym7OU`y5ttQ@7tcc9B2&he`KMkfl_Sjtu z<(7599u37WBr{R!{V-*>9JTU7V=V}3gC)&Byi>~kl2<|EPrX7&M_67H8sqI*=hW$+ z+DD>Hk54HqW%4V+`9|x4J}8Nxb4w{lVr#qD7%z^r|8CSJ*9?JwUtjzF@>E_Jhksue z1+7saqs9Bgm*{y>@Fu?E7%=hP>`?&!dy-0GuC3926B}&VgNbXVc0$T829b~Fd=F8R`aeuQdOH6|TbC`jtn zE6k+V=K}Eum;~S{5kdKYbM3B2ZZ}|d#M!XA(#&5DCw_G|Bf^d3EG0IGf~!n~VmG_` z+=Cgv)<=P5NsyY8vhg&qfVZwuplCETa=-sS8rMcU=$tk=N1Q?{t5H2ApN!Y)N7p|LEZ3Pk(?C2%QA{iB zmF0{YEmi?z$M4Q&XoBZ1ZhEV}NlN#lw=cW}-_lmJ;V-SW#LFeNxczsvO6P@So*5qu z?+V&=a&R1f<)A4z%o!mIY6X2tN6ToS*CAr~Q(qLYR#AS%n&Oi4fJ!$~3+*AY^RnDt zC)uzNEc7= zGah|9u@yT7Wd|9TAg?32vnI4DMyt@a+Qcg!?ph*$t5@wm|4idmi<<9)GE3pxH;A_? zhro7>{+e#=VY(lSQ)Xm+rH`jPRB86{e;!`E#a%?)8Kfe**xf%P$oIu%3D@@y-?7<4 zbvZ~`o8TB5hy5oY)4nal$#G$(_#0~LF89WM*u9%j8TE*T{#wL@SiQL5OqSZu9X{h6 z&%SAY(_RR0KelxdIdfM0k{|Oe*A`U<6^hS^ey}Pjhk>!Io+%|@VBAW4tJ!Kd8{!SB zD0-ly6^a}PsMRv#|DhRZ1XAcfauAr?c(Q7{@c-aiA}hR9SN-#}F^niOQXUWnozfBfzoj;GF3XYrJ;{RSb0ph zfy3lao5IZp!Q?;bwKB~O0; zRcs_CT)<%`=;aQ9(@?H^~wASz$>BM_dEpUdrc!_NQ8}H1t#RVTs zii2=qGm7WZf+LQOH!fP1^f0z9>ewK72M7T^)d<^ajyFvwTGr^p*@?5cCvDV!CI?TP zZVJ$Rq)vKv15vPphSzuRU6i^lwq0se&zg^FurjGTT4>|0+;`xY1=6$cL}1vZ1{nZ! zLSzx80Nw(?RlR3@1J_)kdn^Xc&38gegL&?9HMXvAgve8SIA&2OA7#Fv&u)fFaFQrk zjPx20wj^)O<3J9Xj-}cqVq8Eaz4yDu{lQ|iclMBqRTCsDWTK^>(dCTjLJMnVP$cCd 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 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 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 zcmV;RGhfWxXu@cae*q|wfR%qRZDe6|5&#MbIA!M_HV_cdX)>5*5s(3f7-2x&PfBkR z@#oOhVNA-Nk@%X@DSOg*uc}F8k&0oAtllZ*J3?p8WAgE-BE!4`1E=s>*Wa<)vNAbqZ6L{Bd4dZ6m0E>6`molg+`o;jtYaA^Y!0jyaI3DOt47|Ny1Rt`PE%H*l3 zUa_ID%08Hp&Rf|={+fTpxkmF6`?I<865y4NmN_c}Ci6z#o#ZM;x@hFg2B#3UNCqk3 ze}iJi;-W(KtPUa&PBl(HSInE{V{Nx3$+Fyy$m0Ra-!W=~!i@UmHJF5c_KEQExK6Vmc_f0k zS}@LF*g4@(u>^nlI2FhSh$+H{bGV)YxuR^n1rmS*&TK60Lo5zYYmMwz)~S7ZsOOb4 z1)$-UjK730WkNe#H6t~FyK1lbyw_L0qmB5vY2_W40{s1=G2W5tE8Rh{geFSX;*li4 z_B3Pt;s^h41^Q#4c2V2>pF;u(0<;aE0%svx4M`_Ofh~V$*BYPh%uy&`c!k(qF)MZg z=atMvK&Xf>?k^Sr%Jto5zARj41)B@Z-sB>eeLNQlZ9GeFqIBO=d;I?~r9 zf;U2Hrndvuwn;J#|DPRx=1Q~@N?Z)2mXsygMK*tuo6HptXoeMxnRa-r`?KKdWt*$$ zLdw3qd7G1Z^WS;Vis2>M^2%r)x$$CMWF;XHAoah>mt%LciM0?R9tM!SPq2Pr$PD7E zazuY+AG~a;HUnwYw&k378y3acQ<#z7Oeup<{&9!~*DphO zvmZT{j0Fy7W_{$aG~5faqu5aQm7gvSxCbxG3h+gY(cw4TgbtUIxdU-ofi_zjnSz`} z5xIoh(4!UKoDE|9a>;fLOB;EC>ABsFyRCmoTxeuoA=1A*ADTR0mzj-&{r$EYabJQc zUO$`;a5tN47KQYXD_WDq?84y*P1BTZHcE*IR3XnJ+fERu{kqLiEcd{ttB~Xh-L3<0)1E#&T>1NC;p4ys*l%TFT|n)-uWGTukL@_ zxych1C)YLfff2`|8Mr&0Lu_l})v#5H=7D)_jlZn&uzU9?_UK7MQiGq?7@?B#x(5eJ z_647Kt$1mIM|;inS4BH;i*iVUt#f_gszcec6ys);2W`#-KOC1=)U z#v@Sqonw9X)CmPW^f3H zs2cKlXbb9yttZ|@dF40IksMN|km-ean2R+$$YlP}g~WgBOQXsV$VmtGjxpe3jEA>lI(x|;S}hZ)Tm)ofyxp-7h`dKIH!G+h)qe^Jr)$sV(f3!vV825*b0;fQJGS|uWQFXb#nW-@v zW_FGW!>DChCHh=2(cs;gzWB;w=syhhOnuy~-BzJJYeh^|bWVkID15=?a?unq2lZUn zTb9oTEepA-Xkg~uzoLJ^_>Z6Oyf{a&7mH~QSZNo!)g?NAhev`~&5M%c$hP1c1~LLX z#Zt|j-QXV*aS&th8v+y~L>Nubs;{`!O*6ZWJPi^ud4UoJS_mwhJ6`_DnW7}tjhP>v z87On5r1qwW63wq4u$S`j*H`Wo!UrEDKTsl)Iz_`jlVu$@=^TGP@TIs>AeDeIeI%Lv zfpBhI`z>c9(ol)ItX`JoYBtc&vHOS}iz9+vF~`U)Sk#wf-#kvAG5|6W#@VtDdkrCp zLpxdk7j3^%<-B3hGrvxBue0fr9F^j#)sKy!e>~mATD9P5-ghsSZsGfRf z&+!T91tz^r8AI3RC5;PT%6Rb(Xo-U-`;ci`@RkdpMu+$#IH{Tn34nb7XfAH8VZsv- zLu(5eSp=X4Yv41o1jkTULEeyv$89_(C+l7B()o)IYu0~eYwNry2LcGIp*Yz0Gg4@b z{2|=KMpvbXHC4QyeazwV!I*YKHiG6ETQs3MesH$OBM89o&Zt@hTS%MNT$Kd3Jb)*Q zdVr&!UVXS4RZwSM$5_fjKxXL;MhbHfATbwDfi;!@AL#8RimM!Tf5U}UhdkO9UF7Jb z)!Iq9Cko24fBHnl;__pvTkr{6=dEjKGwbwHdU(;{zBc zaMu{285=)#6Q0YQoX(vW?cA;JKj&rJwHHpvYVv;=D1zXl`CSW@#mK^(xgQm-7a%7p zq==6Jh1hGO3jrTAJoEwW7Y7((o|me6yJfqWs)JfM1sOswjM*ptoq11QH!*Hh82;>b#!`u-m zCWB=EcRV3gdTUfk@{DmYbnfO<7NO-0_!WN#u~9+Zk0G8z1)Fr{BuNLQq|Ezjbg+Hj zQP%<50y@?|C(H1hRjp@Is+yA3@syJZpW}0GYFo$SA0eklUh10Y17JnK$2J(@W%Ep* z2z7%H+^l)cyOgG@X0HKgX8YRcwh*MVtDx@t0_+nKm^&EU>iW(J$=2qCfd`~uar=Mf zu(&&Ui+Pjc)uvIIzy7R6YXg0P{~Uzt1A)yFCF%a>2|+whcOD%TSOU(27xywFa0H6? z_e4K5!n;Te4ArWR=n*Ak8UCZs(L2xrK=-0X9d4@OOgD&)8;@uX!I9O~9klAaOtABq_ld2b239+m6FVz z)qn$=8SgN!@Ss94wSK`ZMbN6@d%Hxhf&8#5eVpudnYPU=#x5hoMNUTMX0xB&ceJ$& zpZT?RvN2D=FsZfY!mWt?2y0Q8XwSQkQrykGh`@MhnpkEEDEtl>ybGfAp>Z=qjp!1n zQKmY|cF-Qnn^3N3YR#kCT=;*Lgz5VidT-E1Afp5E=RQ)XcIZJ{mplhO83_qAE`DSM zGUB(c+Y)mzBY7RP@g<$Bp0=525woK-kQpA-+skzmGy^!o*PuWW!uk)6jNVTDB) z>qh+#>pLr35zw7hXM?{~v1Kg1(eEO8zDlA!A`E8^(ggO}D}!Rdw;TU7|G6 z)0UD%B#(YhCWTxI>qZi-_73@aA>yvaCs8zz*J|Dwd~TZMd^LY8dh=*;Csm(W!?pFd zx!xoO)$H;syWVr?RC5O>A^rxM_UH(~JyrUW*bvSe4_O`bLT&Nu-EcBjQJiKSnueZy z_FX0N;lB#hEMhwi#EmFdZg4!ojh*aK%gr-!e2rbSMn$!MWBoA%4QJcx6x7}A4I|KJ z!BKz?T~5UFrDA`=+oHcn*Ngm9Kq;BUdNC^W&a_Tm+*IA z@GsSa2WVq`+N)&tf!w!t5K)6BiRiP>z@R2Q5tjpuu4|w7sOTyUT>qurm`2J<;|9$tJ>EuTAi;{j8UuD)+?$^4DwAdQNG@&>K@-V5ae^6r8z#Xy& zMi_txgHM0ve3XhlM?e!i?C)ccU>7*XTM;&J|@} zWy~ICb8(XKQG2~tNE=P;+SAiwxEj41mFT1DjmH+GC!VT_Oxl8joTbM*>`}dbjO5|ORcbS%bJ|$qW1Zru!d(HQKf(3sh;Bfp=UydeXGJ zr~MMI8VNndvQEXjaz^1cnb04pTKm7h(@Yo+*bhDK{N=C z*OGq^@@(KwjIj$sK$O=7+`cOW194W;KX(JDyaqOs#V4sQk9(DzxzMifq3@I46|CCz z^l%y<;aKJE4~9M>MpNwH@Y;o|U&`5QAEc%!Ts8_!uBvfW7bJgs5{o6%dm(TUdFtxm zPv?y}3y0WvAgoyW0@VRTE>*hsN;#F$;nP#MN#8f(Rj z)5o`vE5veA7%?Xl3Wdsj8~u5wezJEt<^l!hBkE)v5Q4H3d(FQBVR=L4Pps**j8D^K*KfoUutx_3-BCB!dW@@^(U*-VF#zoP{ z4J(0!eqD zYDxVhAsW(WqJ?va*DDi!;7y7}!w3-x^)(*FpWaQ>7ckxaz%^VSNLN$QEk&Idoq0f@ z_gtZBoO-fo=XpCeq#VAP^N!s6^m4SDW8y|irrVghh7XGlfID(h6&Ry~P|SaGjhHd} znI8!9qmsqW_&5J6SF(Q|4~OlJ3HjIl1nELD2DF56VxDRQVgIasLkQaqd&Vd@wLLMl zM!C9jsbqjS<4$!C=LVm(g9Tvw(X+?O?0MjozQERdsu#cP`e8b#eLMBcu7+seLR*`1 z$ebPDu)zKln8xh$-udwrFK2(AQyYY>pv-Vmk3LkQTNsD^b)j0R{WI4Il6M3)8J7Kv zf^H0Nc0u$xn9s(jV}VQDh9{^j{h(l^$g3>mv+%D{gV*c6ykBR^fU z{{^zAysu>HkGmOz0o#%lwKipokm>vZP@kcNHqRx%0}{IQS2lcseCvR-$fZba%o^ae zb)~MWZg-x0nJ`Nu#H;!1jE+OZjWk-EMq|-SK6AxBa-BgbuFGhtm;?oMmQ?0s{H2n` zz!JTfX}|9r-{CARO7wpn8CVXB9_XIwK|(17^n!`H+zm`X;bx#+<(9;HBWQ(%YU4UQ z0+K_g>xl3)A#hJ1PIILky2*SU z)Q6Lw&tR|j@aruY-`g#QUWHrb6Zf^8c9RttSq<)ioz0@G;##F>*)*#%R-?DAyoC zg|E3;e=Q^g_8IaJFHCMIb>Jw#pO-X_gts>7h>l#ITr;J^QbN9m8X*o*B%#ACvF}j? zIp3*JzGbX9`xAfNe8bE_L~X5+jZ}q25~Gk78mHsjXw;d@y?wpq<6PWhUB7%5mh~<3Fy0b7tGdy@Y@8&@4b4nXgZWFK#@zd< zg%IkftDB?%{^W+I?Gl4%*@M!YjytNT$1rAc^ZV;`I8=X=eS|m1@4y!cxFKj=0oeKD z&LApRf#J&-pVM)|Agg71G&EWiqqw}zPNBfs@vdz#t3gS5i~yfkK2#~$ypk@H*l4=h)o=>0+L~{( zXLlcL`0an9p=u(UwQ8ZeL;u%MeyvLWF39yR-2Tw0AR%SCHWYS)+H{z}wok>Exf10z zoiFx?UH6Ze%djn4r6l93mkHmav+3>)51;|v1oeUn3{O;0=N}jny$3gcZG=u!go|$ z=K5G`WqXY{t8oS!Bs_S4y<~Q~))H^j^t8ODVLi-u%eephaMy+D)^IPVh5-|r56j%N z9Yuc_Oqdc&mJ&o-|I=pV+-4E#Wl_(XIT_qaf`Bm3C}%LB{5ErCIw(9iR=E7{sHD5P!c&nNYXyI?YQm1O#S3Nr+a)5h;_dXE6+n9PUl+-= z;ln30##?O(Y%PU3laxV@FW+Nx(H4TI+!YpbSqEU`-u+D~Um(2MF2qSW*>7t^iQCYl zC1VjLmgKk-w3%|*CiY~SkS66TGUy4(lS%0x7D3%mqAiWlxOE4k6?`sVV&}TSFvow> zB6*J4_73EnhhRnr$jKWnWMi9RPnh{zZiCvuR~Yzu9BBm7NwFgiN09NqI)9&1Mm%1N z@Ij^qsI{)_p=B2BJ@ks?UUm_Ef6P38E9<3)Kl(Emy-G9G)j%L+=aiWIMZi5o;8(y{ zk|`D6Fv0ZEg3J?dGUH|HjXHb;N(6txgJpZw*9Yws<#=`lQP3k6rH_dAr+l5K8gvSd z#78cU*o*i-X>*Oe#ymJiUKe2C)lj zhgNXX3wtYP9xCC1Jb;nxZ?!8$KjX;P&Hme4JfFfjv$F9>qAWaBeBbkASk~1eRBL*Q zyH%KsYar?piNBsL(-1B!s8yVj&4Jd0t?VSfBbs`ee++)N@p7cQf!~>choILsl3(i9 zYDP}UHYDXm)E+WJBy_n!-$Q?ef5CFm^3C2xFAek#fxBI}=)4THn4#^doLogv_ZTIsZ<2kTEPlDP1&Hc z(Wf3vVnBJpPNb0zLPinmHB*kBeMnE;-?Dn9`d*N> z32>N1=%H0dcbfUbEqj*j(&|SMYcq&60c++2hVH|Z^|$OFCp^+AHt#1=egnhFr@(xO5!{tZ9}*?oa@_mhq1dgSY^N$+i`~5v*tWG#<$*z&Yi&G6es_ zD9|kJSR-4l0d<;rrK=RrQO8X(`jHDE#!3*%Ve<~dxKi;ozBwP0mc0quXkgk8;`d7!Yy3|?A*HQ=4y z1!lq=iFP&JNUCu0YrqkWMuaHLUVH?&hdRuQ63i z^5qx1Kg@q_)A9gA)D)Edk&4fW-x{qXXi-ALv9R|Rn|TSZ5^*PTwdI|;wk~uf&9c^d z+CBxtTAc=Gmn4?vF+fIKIZa#x76?Ql79JD9>%lsxUPDfFQRNmXLkTFtAY?PBCO{@X z>;S(!2kcTu9w3yZqoP;V?$>&bzc2inxJYQjRquasbv1y$;a5S@KC`8);HP_!MG&&d z_JZra-GvPs?y^FTo7ukGcKKHiIuXQBI3LWe$SafCLdNgYYXI5}fDLNHG9a|Y9_Q)u z(|1+iXXasT-bk;r@1rvJKYy6S*O8JF2JH6rN<6-Bor&WyEkW4D3tA-+edtY08ZqH) z{a=3&bNN6n108-|un?X6I+Lz0)rBGEUU5d2%0s@RpxR0tc1n?MhYaiB{<%-6Tf*ZB zA9aSkXBKL@1KOuUG)88SFuCm2p-Hp@) z^!uC2U9E1B?=DHCWV=Bpg#PUrL9rx$Z}fi^hTkh-+?X|+atY?n#1}JfrPp|dEFA=! z=`QgL=Q@k(G$l{l;cjtIxHSMCc|1t-lInb2y2p<*97FsG0#%hqNJy_fv}D3mLZ=}1 zvR>Bb3^KWw_~qUmO|eCCOaFZ$>jVHVPtmiy01wlT%Z!`rLp&(;!EGkMYS4U8%*uc0 zG6UGVT$$%RwV{R^Nm9t%ct})79UYZU`$VRQyO%LOK$VwgNpL9oHik%uVVUFqpheAB zI2NA{a%{ITEV3^9j?vBJhht&s@|LPvp0YQ)E7k` zIJ;q$WyFNgKa)6B$2TXGUAJ@>e6YbiIJel9RZqMt@{6B0O_IUT@2!W^v{WXXy_k^} zq|7^V%-8HrfRj^sdzIFT=I#u!1BWi620_~`zx#rh_BgXo((Zp)F*^Nle%;Vkug zbmtC&Ks;vv<)kv>+`s18m-U-GU}x1c5hwX}(Tt zMzx5n8$R6;F7xAS1JhE0OmvN~MS{gZri-NTU$Km=QZe{4OX=SxzYTvdPZRbF;gIiU zHRx<5s~lS3lfQWnaal6G|D)mP&%{I~eVxRPlGxYfS^FsM`B|OQElf`WA%mWRCou}S z=D?%Cab<-puePJIPSM}haYX~Kov75fpjraN1ZYSb#z;cuqwcuWh-XQ3p6cW`|8sp9 z|Lb{W4lF>wz=6Wh7%hM6cwrKWF_%#|strcK#Y?5exyW%}@tmT3dlVQG|0-obgfC{e zC(3CrL_HWMnY%L_M$UG}i^IiL)9xZ>(CSx7jAl|c@(HKjN znZ=&-pS&tsRm@;-GO)ono!~DE7bKFpiNKFOXA-jB>^xL1{|7WGHwKQL$wx$SHn^u# zyx(fNs(12kn9dR7s>_#(OrU?r43`dD-WXSAWE%_Iz3AV?NCxYsDTk`afgt#e05pEP z1D(8dERl{=tYUu$e9u{qSbfx-AXALbo%*3_qmm^>hpyvHj_YkQMl8s>5LM#7FppXiR z0kQ}Z7Pj%(N0dbfa`TY9)&M7Y;%7V&LGWqJW}7Bx?G>2l{B)-iZ>1<1MvWruMlV7n ztZu*Y?P)3EZr!566pC~<{O|ff!?bcge+Ok$@9;+3buYdenTHA7%g&|e+;v6RigW`o z5q*EAW_OFbf&e#c_lKc|K=J*_6$Q@e&Z|TZ)7ql{gc=rc)Pe-?Nj_6T%f$ts1pG61 z19K}hFx4$t*j`NgvoRn-xnOCcCAxD*tjX1F>#|sguP|rMP&7sFcFtRU52tacVKTSz zQ2hVZ7o7KtnLfp(J;GsSib|I5-R(E8{JnqR1JQxH#T5)-67#Uv%)-A={4*g5K`Nad zDS|-p0zd<$5NoT0D)aoD&YNXb_C!F@wKYC!9Mm;L;YZ!S*x=Scp*7xDyL(5)az!~) z#pvI4)SwO{U8`7lwD?{!OneUOM9#9ATPi8Kh{AC@Cl9Oi9WJ{N|x>O+8UY#d6A-uMSkX4kLhB zb>Z%G0FVja)hqI~hGRBAKqBKW(7}JHxHfL=p`UmsC4!FQlFl!pR{u#4vk@)STZl_t z2-w9aged;5H4L)m%~evc^1_S%$jHE9laR|J4u}i~66DDc=qo+mWR#_WM3;-Mk4c$K zXFZ}^mt*EpW8HQp&;Huife#hmOMnaYq&B<+>0S)EAR%Up-RfPg{`)_MDPVu~djWDx zkH1mC0>O0UK0NU4{j8`V!SUiF6bxTw| zT{mzJ$~uY~iJ8Hw+D-CzA^zX4l$yC|JU9zE+dh={%MKB1$dAo|tz8fL)+iKhzh?k` zv4mw&rn+g_woD%(Ak$EJGDeRCJ7n~X|0y0$!Ud=HI;?T+UtLc~{5*fd;4V(2CSxcp zU;8OJlyl$Uh_T*IRgh1fF%O(QvT3Dop#Gf(QHat;lMPTp6^{!|)w zFTwX^VAaE~fMj7fBMPmt58&M`Hzgvv$Kmnj$QxK=7l1|AM378gN~*J9flq88 zSju(YLuo{-{WIg%6qA2HAA~4~3_W*mYvqTNd~xxY$Vq`5HJ9L3J?hk^x03j)xrR)2 z=?POU+&z}*gWmtnEkQ6Ps;e2!DFCXo0AAZ}-JT)dD-JG6C#v(g@N1;~`j z0JJvtg3bqRjoH}Vuw?pIk}j48zQn;j8lKyAWQlH+OT}xfynBBxRLXXAzvswwcwL+r zh`72TqGQ`wC4ONnedDnrH9!+UZL0@Ug|{!bXoS)6>$!u#>Y;xPU?jTBe5iG{)U#RQ z9De;DuT3WvtUDXEYJ2>t=X2L&ceN)%>@F@%&cxS_`~yO+)gsdM9()+q(Ch$rDmW-x zsDu2mbRn&uiwJ+q$`yivCKql;cV$;MKO5%F80UM7NG%f-Av?grrX-@)dmq<2BVPao z0e*e^lo2n8n|s-64@}2;1~omev33qX^zwbS&8fYP_Q^tD5h*lq&sB-yURQz}NC}N5 zs1xVbj=d^Z*p@^DB~`g+OUeaKNq*~Gn@i4iZYOj-@XaOVJgx|L}@1oH7i{)nkz_*>41sl7l@ML8P zqLV^^9Y-wrF3E2iSH8ne{Z9fN1s92GJ86Jj#H>VR9eY3c11UF$RDYYNi(9k0bFuxO zLyt*HtjMC`kTCO)y;apWufYG^NY|jMR0G`!Pa%JyNg_PaSJ#Q~{tPEaVIDgtvO+#L z4C{)2mvIPag=nJt1ds5xo_I)U~`p29#ihn?_}r1%=tk^|3~DQ< zD;8r;;ZykBI>G$jEZG8zWU*vJ$Z+1;dy;UyZLtRF@uQ26d+KOTeuB2w z5>J21_|Oa?&(lJH*`yB`Aon+6rKG)=zyE7V27=Lv5h<@t;^3T6AbWC3Tc@h7^g;yf zx@(m5a!jE-*&WFkHD`=kq(S?%7;o{DdHw=rDPy^TfNK_`HH0@s4@1oqZNxR$g#ome zzllA{o`rgaORyGtIs zT|$*0A(7ftGbI-aa+?DP(%tQ3bra0t#q~C!1IK6C{?f}l;1u&KIE!{K+Zp`FdyQoEKY~FE$M*!V^}kT>WC{8*_V6+X z?uwvDV%YsoUT3&{3@OE@x<=0ny4et8$??#6p};znyhesg3R(i+?IG$hiCdML=skO( zW!Mb_K9xMRud~r2bQc72=-I&7;K_d$DO5FtUHb2jw3YOBm?Uk^m3dx#&SAl2YC{uy zy0NRH4j#aL0JhBYxCFNoD!33AEf@QJNPtIpO8gGHD6I~%TCTu0|Fy@jGCdSlUOFGw z7u^A$u5{pS@hX>yUTzork9$^OL>uTL5`WrR5px+9LG&Ot=}2{urAIpkApn06x8N?> zCoQsX{Ah$yWEJ-obnP>&$=Gd~1%2=vcVCM}KHGv2tvHrLYTdif^!|ci4%Rh_@<*N2 zXG?l6Og??MIxA=a5jOAPM#)2uT{m;ay3ZXrJ3sP#WgZDN6XW@tIs+72zsrPnB+MdG zHQ(;}dgtvw8s8EcuW_vRrtyDL7Gk=_K>nHH%p#%MlwSbXS~*vb1IzZWO>3sUhy|M! zSSgW79K*w}Zccjt7BM=ZQnO6u|GZF3J0Qf)&wd|1a5KJ+1C*I=w+?|#CE}}#5{VWm zCzU`7PeqkR;I9H6W9*DBCurwj*Cy;$oecHyrxlEciC}+&M6=b&vQd%I)WMnI znN;_;*0F9Vjp*Ddx*VJ_mME&7?`ET!c4;?O^#@b-;w&I5z*Xt_ZaA%_g^q;G0N`7r z#^)hgs`Xru_gp7vTU&qFjxj1kRriLkePkO%2wW`$dgr8EuKkP?Fm0!EWL`ij?{&El zaXa{1jh_JqN1+P-6=;g5wy+oC``e{+ii6$NfZR+V9KXg~t72u%Wsg`$E>}5hmWABh zYJdWATKxRSkkGwS*eaz5Hkq;5%OG;j!@7d3tl>nrXSK>wfS!LXaiGQ(nnryJ_P}QF z{Ym06L&qRO3EG_J)KhF%?m~H_5{7KX_NrExUVLTrUEqM?-ztM&M!f^J62gLO6-x{p zZDr6Dm6_@U?oe21*Ftdc2VLtP$)r4@(1)N^x!U~?c}QYD*;4`5(b4Rq~FoyHZLp7n$u6A4gMO@3UK+FZw0d)IlnCk&!ZK+TqS zvrWx-$Hxvl?FhIk-j4_K+%lEd!Exk2Jdd)uO56+3~$77E_&%?e@>)5 zY|Qzfonai;V9IAbA3%)B@eXN|?fXFGq#@Hlyt@jnJ4$~wlbW0!cX^*az-AOe6nDm`oIn0fk)N|?^v`KsZ+d@x4v(#3<*6P1qKKsUjSMe zXl{jjuha~(V1n=FJC$esM0oO@>DRc&OCBP={$JEqulO2JxpE#-PYp@q7+*0BM_&L% z+be%KRPH@=C$>~}3R7i>)k2ZeNkcP(f#RE)QLq%h5PFLU8LfwE$3VnT$W8)VQcQXGw%25fq3_k1iast7D)@OlMQs90BlTc&#Z_O zkL^rb66o0(KxX^s{Y*KMwU+b`OYY44uX!ybQ& zD1VDZ4q|@%0&xRv<$0mXMmamTBo{%7Vl{s)lO4pe)7T0STNd$e)qW)G5Ap({fPzWs z7nzndr~#^PO_^@$5ep+`V_lAL`@@@7-DeK79eUCVVUKIBRuSd9Whuip4-h)7E;PcS zIDP-1t?>o5YYzq5@W@mpfhi{vj_iN6f-njzlR`S9Iz8G^qzku<>O1rejLds#YTSk$ zL%Nf-hN%xLvplI{>QGBZX%%$Ut$Ta`81biGPCWkUXCrqrCUyiL$NGnWA0K~VfZ)YN zAU=YQ1Sfp13C%zG=OgFbPJtb-7Le 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 0543/1786] 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 0544/1786] 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 0545/1786] 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 0546/1786] 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 0547/1786] 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 0548/1786] 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 0549/1786] 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 0550/1786] 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 0551/1786] 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 0552/1786] 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 0553/1786] 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 0554/1786] 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 0555/1786] 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 0556/1786] 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 0557/1786] 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 0558/1786] 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 0559/1786] 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 0560/1786] 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 0561/1786] 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 0562/1786] 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 0563/1786] 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 0564/1786] 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 0565/1786] 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 0566/1786] 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 0567/1786] 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 0568/1786] 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 0569/1786] 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 0570/1786] 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 0571/1786] 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 0572/1786] 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 0573/1786] 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 0574/1786] 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 0575/1786] 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 0576/1786] 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 0577/1786] 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 0578/1786] 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 0579/1786] 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 0580/1786] 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 0581/1786] 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 0582/1786] 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 0583/1786] 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 0584/1786] 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 0585/1786] 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 0586/1786] 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 0587/1786] 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 0588/1786] 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 0589/1786] 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 0590/1786] 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 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 AGynhq From 11093045f30eb289c17c9d08a80de69798ad942d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 6 Apr 2023 14:56:36 +0200 Subject: [PATCH 0591/1786] 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 0592/1786] 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 0593/1786] 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 0594/1786] 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 0595/1786] 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 0596/1786] 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 0597/1786] 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 0598/1786] 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 0599/1786] 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 0600/1786] 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 0601/1786] 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 zcmV<64IlD~CG8`SdK3!%000K?00IC2009610b2k738ImX#{v+VlUD(N0T;8_0eu30 zr-~Pj8Q;TKxr#VYuz;#%5d#tc0Pbv(PEX7#WVC|P_vi4f?2y3zYamkNA1_uJ$l&pu zb6a*-IvQzE+)d+4)x`p3;6WiRvT*%7teWPB#9i; zBxNxkMo&4;IXx=5-K=2n@p9(7``KTAQq#WEsn0U_YG@%5qwI|B2au<34hhRB+Ps6G zLsgc-b-B|20OCbImk}al@(Yuy#CVPx@T>g_DTK8y=En;>rBXDo5YP);i~8#|gPB-^=@r_W`7pvZYwCU+ZB{3TM=@EJm&^?8?X{GuftDlXCpjGCaf(}Q zA3&DE-K6m%!z7?Iu^V!HwhNqR>PV`(c9)~v*~u-|w6@ZzAVgv$w;%)g5`PR;Me>TJ zD9!UW_O|AnI_HJpx!e7OWVH%^(Ust{f@37^Vn{zL;DeF6qdLEZ0=h?_Ose=Tx>Cdu z(+4>K_vfE#g5OBcX0?)b)ucs=W>(yTb1nwb2W;WHp5Kiov(i&gR5$L{q)bbw`EUv9|GZxFSJ<7A?Bu)A9 z!W^g=v=P+W$cq@j$8@a|haY_BJ;n=QiYuR7<4B9<$)(czLwBuAD2pCT%{9lY_#R~&K3&Uviu zKJ&v+CNFfWo2D+uaG0jm#{d9(A74{gG*Aak{ioqiKmI^}6L~~GA8CESlDmJ4u-)~@ zra`HAZap9Da_KWmIRyQnxDC6U9uGhW`Fe4h=O~~Ky5Cmtq>VMr){a(XV9_EIgMx6o zK?{s+&PQX^nx=J)5c#ZhRAzK^3!SRG$jaOhbCVWue(JCs8s})B4yG+z!m&bepvq@4 z%A1-}$~Pf@P;gIGCpr9h;-YO&!sk$CUk}JE{Gt^N!aV~l#&H$?z%MStPZ zbvK)%NY>d?5LwtixMRBq@B*ya>Yf=FH*wr(+ifI-2=L5YI;lA%u_G;xgmKq3%uzrc z1^%a?PZKq+iesE?3A#qvfT2!6VUxyl$0wZEKi-OeCgQBYO zw#F_sd9I|b>Hh!(^n3kRSJUnxvKnTQCB#swOCUyV;N?d-2X5R0p6m3gBU;uz)oT&5 z(sy5f#?Z!|Qin30U*jPy0bQCX!c>dQ)3cX}Rz&~b9jy1B= z;DoO+1P0ybFUZ;W!R&RfZYQ4)UmW0t|Cp3t^QKjW&5Uh!<71eJIHcZ zLN*L(On)!f|Ha6sSiTZ)2xe@S*VImF|CR2KXyEpHJ*=ec-U+r9o?#yaOELj2wQG z_)zQF0+t|Cn2~eiAEQAM=5q{xm6&^2Y-^I%j<7(s&$h5K%nXa35}n^}nMyp3{&o2BH9si}d{SSZA_t!aFJ<+2wM-iU~9 z!m^`qB5@#}n9j;H^S}rQ8!7z;p2KnZMhhm06$~SU4>GFgocMMn?m_%`cZLBN~XXE?7I%o<9TTO2hl8>vNM{*0d@iJcg zLU`JzLUR=(alEN+r(LNM(#4cWPLmAyL%>D-iTX=S$z^d;eEE2$Q#fSuF`;#40};2v z;9mfzWnWB~2884zURxuY%|HaI$84Sad#Ojf3|K$sGu;9Z>-q|RaW9-9L>`#xIsAPL z1a$}uWz`xk&eIb9`7hTe`5vU4@J_BfHn^C#?;+vmBrajBrymo?oqN)!73lq%Lq)~( zBh?8J2}AT^^1*4q2jLQ57#9Sc07CXc(0drh23Cm{lXnspo82Euws<<55|X9y_Bt$( z#PGX8ZjasACSljbD<`sUvXC>`s6B$8PZ8-t(AbB%5Cmfd9Y z6KtNu?=qE-i)q>@`5Wo(kTg`R`ebtoid1jS#9?+oz7M&A@fpYL;`*(d@A&YTs;~H}L0yom;h`MuxP@6@9DEjj~@T#7#1XIb$naA%(OY)_&OGrstwh zxix-!PIFj)V)rT~n^$}Tyb^qr#HFdNa5ew&WssAdds(TOFSmV2G-?NXjb0=5wE8HF zIAX)=w;aCir}tpuCTW!M47^350y9|eQ1l-lRZ*P5eYcbE`mw0jCm${wji(!@c?gWj zC7C>f1c#!fj@Dj#vaq{H3&mzroTj-FRcn$vf3sbGvwX%@ulr=Uv)`|9JN-=$N8Q1L zC9N-;`Bgi)CUyPt`ijYr+#E`7Upze!A;)Bvmt9E6qn9tFgdh$zTG|YWrYaExDN)_@!&1KScIV;kMAZ#B#9T z@_!S5G~0NkFIYCEj){BX{al^Y4M@Bux0ARMhV~M2!23Q$2G68OqwY|Xco~#=8J`sa z!m0D%m7+#5#oGR@MARe<;!cfylFvnAnUxapdPX5gtd&Ew#tzRecwikp*xybNxFPD% z`9=w)(Y%0vgNe7b;@QQzkmZ+)*Gs3KZ>d#(Nf^s{zbb1hy6yZ$vibV5<6a|;@_UFT584|OlCS52qW8F3cPS$zk76dV~* zvZaOW(mpm$*z+nI2c1l%51(z=BGLle-J6$qF(!+E4=}LC@A|yaO`u(r^AtL7Rm+Omi^=L(g7n`I_frZ z6EG$8p0UDGmCDJOjfk}QYwKBDU$})@`tX!{^855DZPllB-DfPx$A`Xp& zEzNBO;s$B#FX zPg93Zd+g`6NjA6Or8kjB;ptr^n6gMDBjp6+9OZaD20Le_Dxzrq7LIU|>(4Ti9$qvk z06VvJ2ROq1ee=a(q-X~5p*|oX1bf84W;;pUjlFZ6bJOvo+A%yNFMGeekGs}9Jo<%| z)vktO*>)$nR(zz1zdl%hLzM#@ejPcaI=6?SmM6B+SuhvO5ZUz7& z9A~JhZu*8URPg-w zhG;Z)NJL8%a2CKAWhIGH32nQFC%83JQNGf*+exHY$!jD}xs0vmZaK*6Nc7_$on%o! z9Z}Z&HFb$^^hqRtx@eJPc%<^wuuvI-sQ_exdUxqm&Y|J&wnL2-#j2nZgF6`+y+Pf8 zD+Y=H=@VMeP)MKH3S;|OmK72ZRz3oTW0KuD9S&;6wzJ`vonpDsM0WBJvNH0@3&zYr z&U!0>j)Af24<|(cZ_Rz-wz-Aj(rzP(SQ!(|Ew}~;0F%alKqJ3ey=$#_blar&dQ4wv zg|ZSf{{UE6g2a!zf%53*5Bx>2fgpG;ypEzQhtLs4tLn$prrZ zz`bhJ+Mk5Cp@YNog$%pH+_}o`1+j+eS0H=WF+~7$_L`@K?XGU*eHM9Qm<5hElRi@5 zhQTMPI63NnF~vI5Qt-U9Lj~TH$!>-IeZ&wLu^B3Iag_r(;C9J1%TYibJT!cOLo8bM#OL zM4GRM;JCDSbW&9d8NAmnSQP<41&Z~_9+d+0Ew*h+e>IHG;fy9IAgpK zN#@3q+o~ztPu>c^@CXb|XI@9HYWn@P!s(hlmBd#n>XztHHz{0algA)+&lSPZRe0ND z7aF{O*HTvW{{Vt|J^rh!>Gu%X4KqlR;wV)mkRvwma-*Dsw{8K?b^28it!p1@wTRhi zJFnwtV^1l{s1iS5a4^hB#&O1a8sVs{(v|gPr7OF=4?$=J=Y}QmWH4Ap+GBl^TR{iz zz)*x4B&g!%L(OQhWe}` zR}nSRl7WuWb02EuDvLI?4-w0L8b7hxM;0AWDjcY7x$lhppy$+@n$yMCc5ufU*=h1L zZ4pUigqL3|C{PZ1e7X9QjB$>BiU8la@onARs>3Cgo=UFOk)YndZqM-&J$rXF`;QoZ zT+L}T38m>U8Gq%ZR^Kx7leZ*+`FG}CD)BE?|hFxPt%-3GEa{!@a(w*cg@cS zA52wAd`UdoWR_A{STU3DPvqiG{V;Zpy@z4xSkzDfMHEm0MHEm0MHEm0MHEm0MHEm0 zMHEm0MHEm0MHEm0MHEm0MHEm6|JeY45&#MbI3=<=Y#jBbT3{K4&8GkU%`M*ksMhx z+#<_BnLY^7e^j#*Yb^&veKI(?i$TD27{_RVkdz$oiuhiJGiZxg?OS54xLQ4C(8R`( zqj8dLSbbcVBu}JJ>b-$7Y6#9GJesq3jZ68ER?Y74Dx=y*>U$fs1$alMP7nNFncrW(tgA??Z z08i}mNfz$3G+vWdb%}{E($u0~9h*dDAyqC`AO@|%)7|{*>w!~Rob#g6wM!E~962h4 z0a1@F*HN*I;K}mLIF6~vXAlxQgIk2xyWPy2p#4JsnCI!25gP`3tebfaw4^mIaOynv zSWOrg0csQ!kU{Q+Z0&S^3~hSR;#TiFO~j1m>yKS?ab}$QBh;|y|G#uedMRyx(Y+r7 zb74Ivi%b{v7z8P&zVm2+u8DXnkJCi9lG~Z+^=JLOl&{(f3MLdB|LiNV4+~8G8;e=1 zpb2N9G~H%hJKf{)w_&wgg+*BRyBu0Wc@Z&MQHS>uwfn~NG{5wJSMz%iJq?AY01vvW z=(W^QVFi7O?%lh`Y{^a;J#OB|dcmvR0~&I@mS1203@rXqgW|7U2*>VV`vQ-ahXh`stFy?N{^MQj zx5EjsmRhZXv2C|2fw&;v=R+8nIcKdm1QV6_#YS;_08Na#B{%;V(N3jv*9CeF_CtsE z^)RBi);5@HlgXk$}~v1q^+ zCx$PSf=I*Y(@LFw`VpJNoUF3{&!u45IbEk~!&vV-luLlaz>!+mq3 zb4Vq^#k(GOb4{Xx?NLUPvO_QTr|(7^9|Xa|TpgXejlOV`IP=bfQbw+kEXP1=N)6_f z(j&3>djXCPQ=F!W=5^_gF%y)uKwdym# z>9SZsKXblR@Aa3d_N^^ZDHN{~*Twcbz)tpm8I|8|?E69;{%L;&x1$0pxxR9_7X{9O zauXSQd*6WQN}9MrdPPtix=j9n72X-L@>TNKwBAeH9?Y|290F`12Ai{N*FQj5PN~rk zD(>h>L(Y@8qre|rY#(Y(@H6!6m%n0k>`Z!UsDt4>s<_lec-O{BH|x!XUT%6V&9`lT zZ{!0>te_)-*UC0h$=#h7jM{u<=|rxcDV=EhjE&7uB$Bet>yKlFjK>X|8j{v``*)IW ziIE*4)}_JEgNLWdm4+F1-I}z-)I)4p2KeUt>04j_z#%6{Smaak<~in%gdg&C%Kd{n z&M8`fMCb?e`&l1!$#!Sa%xH4$C7u+~tX?8{(!5O(T zSi1x!^3u82R=p}YpQfY=?#BV)q4WfWEmn?ui^vl?f@UvE-U{`4wwQYf Date: Wed, 19 Apr 2023 22:02:27 +0200 Subject: [PATCH 0602/1786] 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 0603/1786] 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 0604/1786] 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 0605/1786] 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 0606/1786] 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 0607/1786] 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 0608/1786] 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 0609/1786] 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 0610/1786] 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 0611/1786] 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 0612/1786] 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 0613/1786] 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 0614/1786] 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 0615/1786] 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 0616/1786] 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 0617/1786] 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 0618/1786] 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 0619/1786] 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 0620/1786] 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 0621/1786] 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 0622/1786] 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 0623/1786] 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 0624/1786] 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 0625/1786] 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 0626/1786] 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 0627/1786] 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 0628/1786] 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 0629/1786] 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 0630/1786] 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 0631/1786] 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 0632/1786] 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 0633/1786] 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 0634/1786] 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 0635/1786] 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 0636/1786] 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 0637/1786] 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 0638/1786] 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 0639/1786] 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 0640/1786] 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 0641/1786] 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 0642/1786] 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 0643/1786] 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 0644/1786] 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 zcmbTdby(dovoLs&7K*zScXzkb;ts{#U5dB(!6{zcp}4!ddnxYj1&TWy4tv`7-uvyh z&-cgfh9_hunM`Jq{4$dX0001TOE*s^lP@-w0BHJKI@nlpIM|q2Dt_en2mruvIas)v z{B46KdTVogm;ZnOfRl}x+keAwWabDhaco?jETAPc{T%}KFAav1 zjfc(O8aPBmL}-Cx@`Xb@fZ}fr0Nc#b-sQ8Iy$4hnRKQz*XcfMVlY`0MHfVwYz`(=6 z2EhXWNpue8CjX{JR+bU)mkm@DXnqHP0O0>>@-IWl|CO(Q@&AJVR=~o*0pOr@{?H5u zh5ypO{hR-9Fz$cBf9YUg|HCH~3d8;vT+RYTpb7Ec&+F3b763y|N>&Ow&_6)|fY()k zH~{hOTZFf75D^d%-n~OaLcu{rK}JR)#KK0$At53oB_SdvCZ}elBd27hA||HiV_;_I z;O6EgqZ1I}=M-k;;^zFz1m@klcPPjx1gNM4oD{?qod2KGYYzYu5h~Uz91JA@783>z z6XtaQKn9ib4a~pvA65P;3J3q@Edt^@BxEQ-BgWsEf`f&Jd-Db!I_WUJ&~^Yk<{K;u zj*oA#KbasMC+6qk^c zl9rK`Q&ZQ_)Y8_`H8Z!cw6eCbb#-(9^3}uBD=0W5H0)b=M0`SGQgTXaT6$i7L19sG zNoiSKeM4hYb4zPmU;n`1(D2CU*v#zQ{KDeW^2+wk?%w{v;qRm4%d6{~+q?UR$EUw~ z!9W-Fztev-`+w+#3DpZ09v%)J;jdmWuwVZwjtT#Ug5xdL$4>|*&e)Wk0f;zaak;g< z@2I#`FK|s=rjhWdxwmO9|El&+v;TLB1^)li?0*#dUwW+oP~c#oiwB1Z00Qox=qv8q zbDkx0@vai1U0@R*uQ%iQabR*~ewGxb`sc^X9*M<|yi+ZRZF7!$)Z*E7kmX({mgfrg z$C|-jgUR&s0GH*G+GvN5C$r>po)2GrtTbGev_jTh?i#X84092^d&|!83+5!^G+0b;?`&;Uzro;=F z%%Q|-+$s`nYGS_IOA_wb9VfQ}syIIw&%17yi?`n|lJS1r_d7!2ec8z2IIQlJl?v!? zz&xYAZeb{7VTX;A>Dw|N?l0#N{^0}0;4YHJWM{T4rvMd3sS4ie7I^oP z{fo}1cG-9*jYtb^)PZC=Vb}X;fMNH%{mm*N8!PQ66d$Z&I?Y^>o>SwEI!&u!N)Gj}Pk4Ya3GK z%g-WyR7w%_Wt>R#dH({ke?rib~5fmymgVADV8Bt-;{Pwf_Z^gguipjn?YKE zz=s#@u$|a%`WB}*+phrooLI15OINqVt)X&+0se+Js;j8L#h+}NDZgRT_x6EOvBjwX zVXKp%^C)M1Hz1b#az>;#AgDX>5%_Rxq)dAJ%-5m$QTm0;5yBW-J?*Q*#yB8(oU&o* zfz|i?VTvbO@NP(ZFL_6@*&sT~-c&GZx5*|4*@tfjaA9c2J2bYkgo&fjVuLQcTS9W8 z=mV+{GBK_{EHZ<#tB~ETRHA;&Z&?3L1x1TbZUmdqSq3VZ8?S}RQ!V1A^Nb5%Ib{i6 z0Yoy!S(aLH_W;D9-NnUMK&7GACWgB^A^S3Dv*{JEQ;NNVSGRdJG){Iq(fv?nw4#o$ zb&qhTL|6AbshHQX?c-VA46dzz1#~;S0tPiw!8YYUa9zWH;p(pd+wJ!57G=f()=kgN zPx`74^{OIfO_R^jf2qHLWlOr%n_mH4=nr$R0K4s`_UEV#BOOPx%DmQq>P@n(Ajku7 zR~fR=0r^9AKMEDM`cxnI^`7uWsdVO(e!oZHjhi;`JORS<-Xs3OO$K-#1mVth3^g!X z;|VDHRTZ(jImmZ1&GHI>Ht=9xelC0k2%mPJhyK+JWN+f#-O`w%;y>nd?5x zs(!iH1Z(g?uwImfrR`n;K76kLT=jZ=q4Rs(mkguvbD;>PNM&5xcy^75rFbWR6qHlB zgstEu;3a$Y>J{*(+}g}$?m-PiC9q{HzGLI_D<8V&l68f z8Gc;kuI4P7mSyqz=OE&rs0!vI8DW%|XIlWy%f2ELlC8x~9K#kj_dL#DR*RHb zt?dWfz2Z@uMzgDIE9!O+T_;TxlO0;W0{Kid__!;Rk91^{2yV@L(%#b*>O>2nzXCKQ ziLTGVWjB~s#LoKHaf(aH1ogU@^n66AMkTS{8Va8%0)rn5FlQ9bATEyDF}#nx=d5lQ79hEMu}y z!WD{8mZ}0jYGN^K=~F5cn>_h=f8Kcoc(v*5Uzx4pJ5vL?8bdzAtLDe`2vp{}!UbHz z-Qu1Z(-8C)O)}xF6{Kk&myh6GJ|C$ zbq0$mKv3lk}T*=!N$ zdkJf!2-1P#l`a2K-^hoN^V?w@FH~s*`IU<4$?X@}e1|cXeZqSryS^%m-oErZ?^p~E zFTHp6zw%)vE>mlY3E)jT)KtSA&S^pg;@#8&sI4f%N-D`iv#K0=iTshBf+Fq+I*{`! zFbirLqVkhj<`!ecsM}hiF=c7|C2-I0zjqEMUJN~xN-$RbmN_vrgw3>=aCe=WD4Q!D z9cMCp1>{C$qfX6%lZS!l>1tc+I8BQ6*pSE49J#jZ4G-#=^%WY$+S=8ggw^>(2o7&n zDfTOX%oqjJ|1jX%c{aOz(kQu;%tZcCYt7>opj!!^JZEeUxWN~&(*#~{$q8frC?#kl zhaOV4fAG9A{k&z}vALw1cpjTVdrme95w1)2X5HVhR1UAG=u02?U2yC=3pt+z#Gn_F z_N81^w}>_xJ#KD@b)in<7uG_#OvrWN%-|QcLcwVHw>cguk=%DrSY&;Z$_bl2KT zgX@9!^K5rKDd1~hmS%m!9HyZx9W}v-I`tkYXtI)*1^9`*H2x61!6(~f*gnuX$LLpV z*%UZHpme^!sUvAaiML3bQ7i2yX zZw0z)<+rzSm2s95_FAZgKB?VmtbY!ADI3QOD=3vM$(PeOb}g@mrFU_$bqyxK*$pAU zMXmuP7%G^4Y1$i-S%RM@ByQ~~rTO04Q-Fl|m9%jh*G!^Sr6-SPZQVBWDur&QAlu<^ zr5rOML2pQ8?Alzyd~Xh$|AS}gzEl22-5CwD4DK}ITJqQ;X9_i(4!#;plF_fqbwz&- z<+%mn^Mn8c=kVY?jjSst#^B1PN`+o2#-Qlo^r_yFGw$-c>9gcB{=8(3=R6H&nA>B4 zszAr^^a0HM-TL*TeW-24)mL9+f^~Gg{z96Rc-?T`8at&mAyz5FB)Lo`E{IbmY8!Fr zBg%O46Evs2+kCeA3Wz98*zs!{CRI%KhMYo;{ub3QC&5<$V>hg7Hf!CAL zCBB|ttqyeE|N04KGalDkBC4~%Tj)-Rc8>FDxh=n7m8r5Zt0kcwWF{r?4R*iu7}rQB z(?fr@1PxWvMKsbL|CeF@DaQUrKQUa+hL3jH}ZY) zT43WCbjx5cVfYWJXzqWQCP1)!#b?l;x1i#hT5-2d@b6w4{Th2JB-@u-1XDkS3nTvZ zCU|VzeJv8nD22(MpifG~C&ixG8x;ldy0u^vx*(soXDhSqLukMx5p(tfxeZiQ?`XQ zX5X><^}2cTUiqmH*L1)|+Pr%Od}+?m@W)xH>V2t=$?iT!N@jYnOrumBs7pq$8F~vG zs#Ftqw_4gQo^{9P$4fAKS($8^zEx#U#?J9=JYqf$V(vl9objAKW$AR{r{l@f7jeR~S9p8?2B`{#!dj<3`t!PTPh}BTL2FU%piTyB7SZO%4bZGKGy$^Gb z4MDX+U=LeuPB>GZYx?clqc(NEO0pb0ypf8V>L=yS+~7F2v)N&fgPq1IMD zG+Xhf>u*L0I(`yRl13y=U(hwFXwn%T=pFaBN;AF4@C}E2Z-$=9Mh~2et8#a=uueT( zBwp8JPi|!0PbPki$95Opl1lOVpiK=*FwgX20n`KDRF`M1cqW9pyeikiD{n?|ivd-) zqGU%lGdkUZi5_H1hVhDz3r5TC;Be0*gteXBQGQ%={*M6*?QbsJ15w`5fR8}i7*G?D z9S?EO7^_8Z-cY^^LFf9eIl+){Rn-r{WFiJtq+Az3Pd=$(h?o51f->zu*Cy0xHPCy$ z43l&(M6X{P#DXb#f!8xezfzzb$R3Z_4pr;)l~XpzR=9;ByRitgg&z%!FABdy1b~7b z7ZZ6moN6lN zJ84AD&r}4JcCT5oKN*B9ShwOiWXLM$vw1kB%KYSGPiPS$^ZTn7y0AYi!l8~@*KUBW zq&{`!+)a6TBvWeNOC8P0uPv`YV5JzDve-kX|L0-&o8etUJ+5GQv_{DQ*92WgOC?Q_ z&=qgwuc$A%*jt$6DA!SkS49RBW^TiRWz0S#0im2sgT)D-KY88rWHA9my0d_0&Wu&8 zzwgUS8%l37qD9z@CDQRDg@!L-xt8zp$Jt~)ZI6yex1|4u}t>pt{9yunr zhM{*3O}6|wqK`az{s)x2?a^gRz_ed)oIZhdS`r{8nCQ>;puXbRo#=t+Mz@mg^UGHN z(vims@~I!njy8()6@>nePp3J#&|K3W+>vc3FYiN~{pPt~jJy%`=>4mn%oKRgZflhS zST251C1Zq}Pebddst40U?omFL1m67%+ggO(tFeA0D7rJ?ISzDd&`# z?b;6=9QKkC4lx=eQJnLtLe^{hj9CKHhSxg^(Lnih5_rIJjvp6yU=CiIyy*d-WRYQ5 z051&?v4;77%FG!rDzf(yl#ogIon;y zjUU%Yn~`!Ml;Surb|*Y~Sde?z`SJ=#fnKoBp^*ZlBp(YQ(0C^3ei@43nT0}CO?b)q zW@L3KRR^*YH>1l6O<}~KK!~u_J9(F~fh_=f(`21%se}FHK7LJj1z`2w9)cOl;;;*;JT16% z2oZbfJ*v6d5)quxT@82^!`W64B1D99sowjW#m=<8+iG`lcI11xu#uZ-jAqz)w^qy@ z67%L$S|2QeZYN9ON)$^4)VM5isjn(`noU4Y)%!mSwGv}r>G_#mYzwX&#;Oeu8mwx& z;B0mDvAiD@A-H0STq?bT(bKPhCYH$~-2w}Sw7MEN@U?n@08c4x(%*Xp`E&R4)#kPe zZ**zSW0(PS+M%%qq*-w~Dw>cFkaat`6Q!=Es8ODz0onBpS`{D`6VFQt#fXm;wPr}m z>@^A|*57KxBy>=Yl&rT5fW|&Y0IijP#xVQ@mXnh5+rE?lo*wdL>J* ztG`Ftj6Oa;3Bz=hi(L^0?ZSM*5MXbnAtVMtF1Xb!U?#f*-F97KOqF>hgij@q6S-u# zn&&s*4FJYpNGnH|>}CY&Gh|1CPo~PN0;jXTFs%Q`ix|12t$HF269GFjSK_fpIib20 z?9E71ebKTcixhTb3v;JGrL2$foj#|@tOCkSU8Hu-MOGCH!&?{>%Ro<$9B(Mn?)PW zuRj;df4$`0L0-;{RSKEmV5h}RK1!b# zaW(m2_|lwXa+}1&LehzO-x%>1qS#09$^L=vQ_8^R6{8*5?Jgh0-){eqkf)O+EyT() zl!94|#!wogYJNW!`W&!;yV6m6Y%B9iNwzvIUUcZqLyWRfrSieyzm39XGW$3eNn=Kz zQHsBytQ%)uhD@U!-JU+tQ)PPNur^=v%Tt6gSXwwc$(f8tIM9VnYMIBvd>FQbId#j= z-Imm|l1ky18e1RNXn6#555Xr8BV`fOk5+wC6DVX#N$NvM50xFygd0@%4jcwtD#y+( zDlnuqJLr4{swr>iZ@HCiM-rnYaT=pvPkhcbdpF0-23vs8T7q-W{jyxPFJPh4XuaGS z1ZiWtu9mFkZcM;m*aA&zKukMX+ZdRr;w!59N{;!KQ>Il!`E8aL~|ZTZo(=xEYpP(xi&!j*}1L-rtX6A1#amO8`v zR{x2l;=S(25b{;@beQjLY0EbDj9U)%o$%uA-0ft21@t)->QeVfNh;KB8H1k6*9V5m z)pwB}vlS5(1;#Y51W3^4Y>C#B@?GM8284Q5dA@KN_Je*bS$E;io7R5I8^!zre@KlE zX@ojzq3-W}nFe^jE`CfWAgF&s2y_d0O20eF822^mi(d=JBVetRXBuk2)$%bZ5EuWoUjF*6z$%?Sr zD|&txrGijqE9ko&@h~RROk~i~;u|Tqyt(gB^m!e-4da(=;E1;27f;1kzz?FwkcaBx z4*6FAWmWYnz)%hJ`)!wT;**vnN!n<*S6-BrFr<+$BQD?`l%;mf-*W^$8oRx&qFXA( zm&k#XC7G8|%4NNWqpf#hQRs+{QPlZ%Ch&Lfe5DJ}oW7nZ9Prt{@wq8SdI_;A$O_T@ zc932qpXNtudo23)jaB}Zu}10=ePzDFm>M^gQ+~QsYHiPvdekyMF0Z*RieiVtW%$f{>!rG}Pxd)KwJNk?wSi!TQ-l{@6IT>#7vvmE=l0 z^MWAZvf!AWY~}s*;|{Z}7GWkk2S!6#E`@!ux_~JywOk)QBGGOeZ`MkbF7f26U~k#2 zSR=2E%bZ|~ORZ%w!^*bagiyt0x=Y*>_2FV&;ktXTY#;X6W%)Gk;S>*{eyTzI*`9k; zq<#X^F-}>!*gd$iM~2&5o5;P}0**wAO32}? zuu&+iQ?2*+)i@6+#gqA9i8)6{3itXhitQHUMA7BjY9Qx;T)j`MQdoJyR3TE0M*Ouv zaBXAq+J_6)Uu!N*v!bXTk?LWC^&X}NXY%FP_Ey1T%hn@|963sMlg+(2hOTmfz;nxX zjPR5Tb*lnV&aoJPO;bOf< zCg8=Ys4opYy7J8mwWDiwhtkk29#&xsu3dY|J{}Kfbl9YgePJ1#&=u1Q(4eBuL~00z ziTE9brkf-$^MRlo(L1NFOv*dGrl>q|KTB+^k$*Iz%Dks!MPYVdV4u@6frrpX-J%p` zQn&CuftCLAWYWhNk|LXp|&XIRD!|cZgVPG zeO?;Pu#=D<&)HN6TWRT>p4~&Xug=`lcogX#DZY2)Cce#%&Aze4#$e_v0Fh;KU#mlJ zSMNphNzYq$1DV?N2Su;XSK3ZfGBg|BZl1=F4o-N+syP1-R3vtNw^^LK^7EfrKC6_M z$G;?I=hVnz>yX^LLPqVAD4`^%q}%AqbEYXQ`3txkQQWu75_;7im)Ke+5#@qONjQHjd{fk$V<+vrmlCQ|Kh2>Jb@FZBZd7}lF{jKB zvcRk&12^cpMU$2rtS=KS-pC9g7WKkwPBW|I71*+u6sotOFj_o9zxqa$;W^iTT z0{(B-c>(v9?0?(MvA>ywMSn)=-N*eZ9i}Z*&PbT~@iALjE|u5g^vIAWHeZ#Q$qMeO zG^wmCJzLZ-u~qJXMH=d~?M4)Z;aYM<%&=ppIioRJe4f`()QM?|LUgUQWo!tegDs;N z?J1}KK!7_7o=+l(Y6#}iJ4tAl(^yQQI_umPO-GnV)27UasdIG0l| z=P&8?U>I-Qu!t?2RK|(-;w?AuTe0)b4~wNI>2I29^WVRH59@DgEV@m?G|Xdw@M+r0 zyuI07Ls;%dqUd9lK8db-%{e-qrDJ%ppnH;emG}5aT<%wQ4LF+c9-Jksm>t|?I<4qX zjl?}nLxAHs>nE0pxw>je#l6FeYQ+cNx7Btg%v#^Mzj&eo5<=l`cWa&&NvU9ei>Hkm z)y_)epIVLO{fhkGHse+6lhzz5&0*h4_kWxI)Jm(+kasIgPelBZdp}u%-&cU5D|f8E%8Ic$y`LrrJt5#i?59Fm8vj>#tlJr8mlC)I{ZE zJT|Ddd9Gs?1w4X{nrZ>csOet>3ORiri-S~xRDawSnh`1_NqhO(_|FcL=_cTFtcx~m zG2nbHwt`{|3e82CwoQIrUZCG%omCy8LmFW!O-Yku@#P$M@I-gq^Eb;>T6)j+nAsMe zUTkT<8dFy?r63}d;JktRF{lBVpY1+`EJ9uZY!A~frNys+$(QOEh|y(<&|`|rI!~Ow zPY+p1+2%^ySMV!f1$rmjhrT2$pE?LZ0`a=O z;wLeG95#_$5neaQ-Hcr(K#=#0He$NXDg^D z^&{y&Sl&<8@Z<$}Q%xLI?+{%6zc0=8YL&PbL9VNN{ z8=*QG@~rI4!-Ml*(w!oUTCD9fjO|y;5{@avXq&M|8m0n!&Ouu_VZ-3=W6=E?2rMb= zLokH^#f<)8?q%uyf)()`3Q?JinQ)7-<76@3>XlX{zEz(2?e3`Lh-oA5t`39ZvfuwW zv#lCf6@a;L6(eD5BzryuK14V@0CQs>{pLXD(7!R*u`A?lYnaI&XImo?{gk{bf}qrL zE{}DB*Jd%CLHno*pj7{$w3VNG=9-_T1{rL!r zZC>%jG1oJ%)rF`#biO@PCh;VlJ7?2D)0P{+U>8*qy>EVQEuLiE*^4!UgW!IS0q#Rz z`yo%t5ZX*p{3AGs5nJ~;G={Kam)q^DDl!C+3;Cr2>l)O9u!##FcVa2C=}hz0?9B&4 zc$CZ0qf_~8gTX&Po(OiglfMJ^&+h**%7I1-R^`a9?!8|DzHF}mY~69vHXJ|jTb6h^ zCbUenCBkw|S)XuVPHTamdMz=r_m})^u{-Wfaexp1Oc=P+5VQ&1eFHPGVS?Jw;8XeJ z^AYGFef3$i5UVA^=gfZJ-`?#g=dxHg^0tkE3Y&mD{zLD`;U;(M(gt2qwYe#JSi155 z>ZkmmbGNr=eTq!mu0Il2|;iP6L%`4Sc)YoJ(eS5DDN`9}qci)(qZ zt6R_il3pJa&TTQxLsnl^@&nZ-NM3tkpBh7ZD_8I&v_;okZYzNp|2-J?c!L$8hF61{S}({0)Xi*ENHC6CjYB zi)yvdNyU~B+R&BdUFTLEGXlzFc@aU}b(+pHwsOh<-BRh=k-7G4!*0R@$H$<5-BqiH z2xGy0Dxg(02<}l{-+;elVJku|W`xn7XSTg%7<3TPUg&u#S_3^{VPmZC=$7Xppq?$zw&mZ*?C-y^ z&|>s(SF*=2Y3Qkn`ZdP{`VHr3gU$n_mmGkHD`d}GsvX|Q%L~w6+rVw}|LIjoh6N4G zqA5Q=*tI>Q7K5Lm>*j-GRI>t_YyjT(6nfm@*Fi6@KpyJ-#{pp$zLkf$~~<+wf_)hG_teWL8qw( z`lvct0lfe7>3=4+@Y@yHo!)=QyfGL#?T(cHLq&G~M;%MDaA2QQNW)|fm)O^rF_~_} zjtO!PjXT3X*2%K7GnO~m9RvS7Q%x?DL-)FA?EmZuknRIqR8r^lyaq-9-`K^3^kzownxqce^^2adLI+Ba|(p5P~CBxe46)ITU^v3uyM_1!C8#Ae1e z)=5`RCM>D;*U;WhXGS?+n``|5^;OS8_bTM%%IKoh0YYf=Nuio&{^tmq92Nkmk2E-y zF*9sBJRQ?<3XbeX?|>RINy_W`SdI=T_!S!dO`mCJo|WZ2TnRJHPUSz$?!OfgZFB0! zZFq-5UrK~pR>lvT?qI^@S;WyTFxg!t;(JoZl*~X%qVp^l<2&+)%Hy=lx!LtIa+I;J z&{trz=;5!GE@f3GB|-1G8x6w5<_&_;6_{bgPUr*rZJA{9u6;h`zZsTk}nlg2!>0E3^q- zt;LP%n8Eu0{P&NT^$n-bOFQ+(N%3za*skBa0+NMlmLHpmZ=ZHAD+NR4g*^4!`=W+R zsj3$j{0Yrs>$AF#@0(K~XCA}N#f^$w4NmQ4_>5c)?%Wsb?DRiStUsslmPB?=#r30S z2s=L>t`aXyNYxC*ca-@H?KFk{QR7xSV@%lTSCbu4vWgCs39_+GzrjlbzX5?io`fnday?tUWZ5 zJaK0fV4H%4&^@CKVtwiZDtV%>LY04*m&M02E=b^UoJeK`;bEAKEW7SEAxp@UP9urj z>$v#4$qMOyUkvjIGh2M<3N)9bF!J`ctU|e*tq9g&;I3=S)*+4&-M8_lk>dz$cI_o& z);|;9`2KAd?QO1-E4ejAZ~f#RxR;01O`(juW1)*C1{@Q|!^gL;(rd=-1R3GSyCfEl zE;0f?mUNP6VG|+6Kbz_Ez&{as!{ccX6YLkjei^oZJN5qT=*`bS=1(sH=lWjal4;)b zZvNwr1E=;LojDw`!w{+vdh=_FMQ0flPP!r3HB0VBkeco{?!t&$3`IupV2lqf3 zeXM7;2c!1^-vGG`H7HV$@VU=&;(IaaPIHBb1jgGWtl<&WCt)oDx1pD-5$?^5C~AL; z)0QOcU+7>!7k~FrUwMtvsWbBZY)lLxL(KwMsMK@qf{+XDieG@Jw>L148(SRJR2?OO z%DuV?W8^8jd;sapGU-{bqa<)2IX~_T;mzP}3#Wg$YcdHZZM0l9>*i>aoGJd0;H8gk zr|B1yk3kaR<9AmI(!Fs(45gQIiH8HaA5CIDy-i3Km1=HNT`HC5OIcfGM^IB&l@)I_ zzm;vO_$pTM92&06DBKr-FYQTS=VZbK_Llz{*Fcr6>HHN%Fbum={d{O+8}pkqir4}w zLxjp`^O*~3(dhjUPqntdMsm^3D57oQeuRAI$BNRQjf0d))L&M0-f!@kTa&KQz7_iL z!cIigjQ6s5C<^Di8t!%?-(gy8KP*d}kws60VdG<#XDQgF5_3e`q@UJ6&46{A`NDF! z5qpSVCPKqMqq!dzZ(^2V`jEW11_v6`h%yFbSH0oiV7^LVWvV#gx!FLDY3p zTyrJXCZx)ZY2V=j+e~eWe5J|(E?Fi!!=LyM(gi++MhXuvyJ-WCWVdC+g{9^23Q+=&>uRIeqa*&B_vW~= zVaQ6L5(H^V$Mzv$T3fb$ZFqkRy>(>;aau~mS}Ye~-fH}G)2D4a0--(8tUlF!1FgQn z<%Kux1vxl}rhJcxA0aDI7X<|Vx(kb@i9$MT*0kC_xxXFYf%_US>`}1_G|@y8Oh^}~ zZ|>L%m!Asf4Fobc_DUyO_pjy0qQ9dz3nr#{r}Bsvjrzac2LR0?I^b34kpwq1lsCTw zV9B05rZXTSGiN3I!s*QLbeaX`?NGgWs$!PB0kI`~J&xKaeTy*W0qUF0j_O<9lO8P8 zeS+{nq^VFg+OI7oDn zF^4YA4z=+yIOMl?hK%g47whj@LkTF}D#>4evTZ!SK#yk_C&6z_0EVm)N)Gyf=8%)cS=<&;VrQ5#6;nn3JgS$5BxYCeO ziQ(|*!Ep&FnYC;hVb32z>lMJxB%w?t0*8f4{SGhOV$tKaQ{(_<&MXrb>72@cFQ&pw z;#la|lF!_!Qr~^E_u)4mo@3I`gkC7fNe9b^GGb|4CnI!&R@%j?2!OsSk`@;l^dI*yweB! zTzx2qFoAgQYEdjEl-NiTQ$U)M;-^cRv6RfwK-|6;rMle7(Hdoo+wkK+pZ-y8l^(nu&=Fb~)_@F$wD)2EKF z*mcD~FaeAmSWupf;}knY@;LErFS6k4Q`RGp4dN_N^N%AB*sK zWtVLXY&72d{qP7Y=_OsXC+uxx6VKVlS$xZdU30|@AG2;vb$g?Had%0L3XLDz6bx(e z3|kLlnp5Uz1(uW}QtE3nW4}YdmkKVx)?JIH*yDoh@u{HG4)hRQA>QPopJ_=yf2aRW z}yU=j{P+j%c;q+eFGhO6~q&YF=*qQFI);&93H;mfC@o@H8e zecfLEjPLxfOUAZ@JWqIy_6e{0Xg3ve=vJ9K7Y*#Frm;>AzR2R_448R4blB`QI_)wk zwYDpx#fy*E{LK6>FZ>h!FTDrII>!O-bh~3cr;JW>@5B?>dj`Tk1~=TEoOlI^WZL1aGAU^@md0eA z?RM9kgg@MfM=v<)9=FHErVStd& z(c(#U(U{5810rV(gF`(y!Vi=Ai*XHhod|0EGFNxa_YD0nm6_p~e;R{EG}Xr4K4Vcy z;m9S@VV4SevwxtU7qyE{2toMvOlqs_7+@r3Vy+~0)&?NHV3??A%q&FnjbnF`!R)({ zf|V`bDxI-fJr|fcuO7UzKc>=OWGFkQ5+_lTAPsD={vqTh>1aVr4-m*J&nv2-B&+?f zH6_sON^Kw}R7V~!JD0-|@{yPaCw_QQZ|(jk9(pF43mwy)u}OQj739fu6!>Du7UYZZ~5>9wH9;z?d_H`-mkkvErnx=I?-5s zEeaP2OakA`Lh>tyU!+7qF3~=DA<3Ka@uFX@_`H>(U8y?i3GhC2MjF?_hy`}rKjGsHo`*pAI^FjIC89ls3c zNjgYsgIoN6Dxk)0%V)lL!(rC#eb_z47|xd(OcDzM{5Y4>@@0WLz!~zesizB;wpB>S zkWy&{Kpyg`vniD__vjOj1t0V>wtjZAA$Qz$AEN0VN2!D~&5FMDeD%|6+xOI! z@z67h%Z;3(jNv7TUJkp_ZmObJ?(`y{lWqxR56fxJrdG2BY;IoNSNPUrVP*=X%Y``1 z?QuoN%6+?|hClNTvC3tM?N*v@J>)Qmmx<}!BdR^K?Eh6LZcOK6uP>Iax_9Mmd5U^~ zul9-%Wu(9>*_OSHH7-DvHI-$DT36!k-qJ-B{+s43i>L9V2*ee$c~gUu7Xy&=|B(bs zUkn2i4bg)sbgi3)&&%LbL-+6sRFK?fe`~bpc(J3@CZb0EBl(_4k-a~&>P&(zZ%nAG zJ`b^T^?jSEK`K#qVMbv~K)fD#L1hVhI(^)_wEj8=+y zL$3;T(b0v?U_$&es*x=@HIZx#W(qnM^B~rfCQsvPhE_5PA6&*^&6NEpRXVfBTF35L zU#H`8i?Y$ecef+Lh)*b2pFKm}*Q=A0UbeH{NE^xM+6m(klFPpe-kjyAns_cKT$XNr zGGCMrd#&`y$XJf?)2h%Q;xBuQZ~Ji^jze^2A*q>>|5?am~-1ZmqtSEO&HLW29l&8khe1SPD&6ILR^u8EdP&kEG4=JYm*7ps|@P>P^ zp;V`}UtwK_%%1``t8y#Wuf1nS{}ab^_cvpMhQU9!Y5KY)^w>gHeU)TRhRpb1+vnK= z4S*@wdb)g6#N1wG%5OvK@LXlwioZwE9rYV~VUgOR*Z6(I`>Z8xaYh2k&SF<~j;cE^ zyu6UN2i@!kHY^pJ$?HFG@BRwaj+{}3?R8N6!2_6;eL6;0fgG=ld2AahHExc4Nc?C> z{|Wa6N#|T^<SlkjJ5}`UB%a5 zZ7W*2uBj<8np1?GBOT3_An4aU8fSc(T4aWGqXXYq!uamjCNQ6~MR)T%|MnhT6m#ku zeQs$a z@rswv`2yt6A(gj=fqtFGnyFs5gd`D{_kuEB<7w&qRgqs={q)^w-!ZLiZJobTTL5}2$t@8&=7QPp|6iE{H}bdT>PE>gjiX%V7*U)RE|7K zWiDqul^Q>s!6dS@JOYc_ ztkS=$KV!Tj%RjZQnn{Vh>QOlnoY1-=31qb!9=z^AqXvQHmHfYcgL9EZQ_m0?Ox@JU zeY;&&7Tzbxb}`NY>^uqfmz(rVE0yGT31s`!{GP6g2E9*vy&h2~Sk>~z%n-5cV@GlH zvRME5(uO94d|6}sB4f2~=wykvHrAmIxSYP^1P2eZ8cU}A;L*-(%Qmg+2ppc9(V4V` zIPqJr>A+x76LLamTx-!d;KuK8n_w`4Gy5yXdx-T4_QHT%7wt!2( zk`_P+^)11A%+fA_kQpXU7t9AV?YuML0~3MC>TNZ;fvze6aq*w!>BR_&q6SGLTz`^d zjPze{TrHcbnXNTEB5efQRha?fn&>kOu^Y>VVs9c}e9fs%&m$rs&t3g-_KQS1qKQrm zw@;131dQX6{uwS+Z3I0qmcPfQ#IDuE%v*5rxVYZ(KoF$1q!;GmqRQhtV|y~1kSZvg zTN*IZ0h(h<$I4b80?V<_>a7fBr}C1_g5jr)yasZK$*A0Qb_1qT4>5V~p4aN7Fi*4TMY(0QY3mUk zle55YB~ujiLhvALTpUF;chtoxLq7AR84vVcjUfCQH@)rhbT}w#Bj2RH)pzd9euM11 zOxJb#{NT#=Ef(AXm~?%SH{}wpzhG)r$NW7BnU2C}e&2Hpv(1iR1!s1`&g!}S_0VuG zI;b*YdK(WFb>r5DiNrxFWPh9OP|s_Py6y3XFsF>Ehx5|4%zXSN&HZS=f+wqNd%ZkC zfvRdHKVcaY;r^RfCeu#vfuIh1KpT)->wtS1yPUOj*wcYV+YwVOnRx4L=|G>k&9-*IzBp147*00S%@OUTxy} zTO^sX6T9>HlN9IN^KeaQns|^zoIy-IKlJieXGLOM{T9d)*8xV)!&+}`28r54an=fp zCLmM0DGCkX(jaAf%U-6k`@wpE7g3D!bmxZOd%m5ic1@gi=?nTtJd5Jm_l+&u5W_&k zIeG(2OdgM63(2{_s3c6jWOwrhvWW(#MqHg~0?lPXdcPv_d=lx_|bJvT+jLZPMfjpZQv>qehiiwF0s%CY)d|isqw4$nDK~# z{m4qIt+Wly8&Oz0=2<);J;uwQHT4kWy2;$VT0{)urVI>H0{^j@e5FF1{l4@_k0z`+WpKVBGTrtOS#H5#&e zc;?EVT@N+LEp~R{?HGBKqfDTpiH`OU4t+$JlYeunJ=|&xF=0%-l5=^SYPTRnjPlL} z)oRxijvvMWYCe{P9p7qvvj5l5VPkN480C4+=o(S-?I+&|5wCx#N3qwy-7%FS8$YEm3^k)SW1 zA_XbEkVFdkB|pi>Rp<@)OKlhhm$?Vd(17If%h23W#ch+jyyZ3cDP_cl_1fkDxU>l$ z9qd^a+kN5VuAy@kGh4=*TcElV;CJ=oFEU&0Y~g$&IzB(F0sstc$EIf$ugR2N*Qw-Z zLc)yer8>@T?|vuOxD2kj%`4C+Zy#^DE_C)FV<>Ze09Cn=3-e4~hWfdYdlKH#e7z}l z%}+NG=jal7GbkYPX1PA+zYw_|&mH+DzW9%r)C2UDXqQzPTm>?HLB4QQ?JqE+P^L~u z<;Ud$*W#_r{A`DiHta8pS)1hQKjhsrv|M6LD3R|$c!l#VssSQWgh?g! zD&f4v_`!9xA#aXny9K@56h($` zpGmVW@1WV9HYDK2_^D65acs?Jv48DrmQIoXYlHFtGib1~NA7d>BkW(yg^9l@@lfFU zsUpmF5cl(YdYct6Q`Aeausr66<{+qH*}u$5z&zs z=;}re*p>dlcZ0#8H6kE9DC{o-n%;m@>CX9v0z56aJX#pL^GW>?YLCMo;n{sm^lI^k z415s4il*(9x|(q1S#X=>p}WxpBqD(!z-~a(6H7<8G~~!Zm&66+)$C1^dm9AcX(4;I z;IL8%XVUfyzN@rF@I1=+Q6P7sjPz`@6`cSF2{^gWzmHBT!G z>QkQfXpMQY6+snrvJ4zxnn6heL2}ue3ZF)gzKLQW-GuyFBvCcWyx`4&^!cggJr20) z4>&~;_tz%D>p(<@EI;6_jALjNx-8DQo|Z4p)WI7_hVr6J(Rn5cioV$1!bPV%a5!3d$0yrx%L0)4my= zpSlF0I%7hSwVgn-H1%dy`{s=mR|FXj96ji%ZDxDbN)YH_^;ElBVHBT*>isRy5-s$* z5hRqfCe~@IdU1LWZdbE=)i!XQ0$`H(Z*~&} z`g2BvuY8Wl$9^%Qqwz|3SUMc4%5%=bE{J#>GgFhTz0a|C96yx|_ z93#%QO^mZhNYYi^yI=GYeQkw@1KBQm^p#AX^Gzn3o=;H~zOqT7cL289>XB(iY}C?n z;bR;6a*5!%=(`pXTb!)!)5$BMWwwp@c-n#-=BoM278EyygISXbB)>F~3qi7M2y?*p zY3j`k7`|Fj3eDUX!-PIM# z7x1Zt!sDSNvgW=`I~*AJZ(EbUuCK0ldbWGT*TY*n?|>39F53$o$HN=io!_W=I zQy0_QQq_%ElpAF6A8?nrtBKQPnM%ZXQec7O4Vf~9#_qia&Eq)*! z;t2BOP`Ju(|6b~Wc7=GOzXRe@5E^B!&NZLu^q!oKmFU(LjwfL{QtE!Tw-?T}s-mQl zwKbaIG;|MH-A>P{z_du?b6(#OR?ZQtxdc)o$6AN&tQev}vhx=NCur%E>v4&V=~)8G z{Pyiop+a$mv>aw^?#*RkbC9;@fr2d^q%ZG=Yg>4x94{VE2M9M**b)*2fe3J6GZx=s zjwmMv37cEZ$#7MfOa~}xaHca58=yDp^|bRrj3Ug|or>h5fjP>3FbdL(gX46yQEHP^W|$BUOMQ8-2|ouNzh z^;WdHO6TxfCbSr!r^2yZ#jbfAaqb+H;#zsi ziktkrcpLdc5OwPw_ce5-J@`qf*h4xqgVyO+!SLS*vitv~Bw{{+lUL@!V!DU+k$>Lroz1jUw1oQ5gddy(RMh z${ibdplO6qW&HAB2xf$y&U%HBugFqu7a1m9#62lN;5 zrChimI>a$nS4_pL=Ty0p5sK%=RU5EAe&3-67)Wh{DuN2QY#4tf@a9Xy?W8IUDU9eU)F>~m@%s(C5C$nRrgp% zm9|9^8ErIYfr)bA6N1T6;*v)u(vBq61c!{6g;gPTdK)9&eAEN(Yl5%GxVUE4_Qf)gj3DT$wOtSKmph=~}vvf2m z0v>SaA^L-W(1Fwvt%8p0vc{Nbeo!T7^ZeYJ$t z%ToM>CfIRQn+ZFm38Q*cwbAc^?#H0$RDC<0bHl7$zQO_ib&BOdME`KR5p_%uSP0u{7yKSj*Z~ zc7oDe%lK;elt!Yi#UT~Eos=L7Up0TNda2Xa4vkq(3IZ$YY_nFpmHuMqfp20T+@HdB z0T1QEaQjt|;ge(M6#oc4o(e&31|9HR7Ye!+^9JlbOoB>hc9R83{T|MMsTc6I<*zw8 zME@UzM~K4#Ayy8qk^f&14Nu;i9I)Md`vHMARqv*Hz`RZ5pY%(P8U%8`IdvS%rxA;i zr>=hTdsO9q@m>F{aY5ljes>#W)tp)NYTI8;6!A)7OXPfIh|Q-ch_24$$EU&)q>_ek zVI>`M_V7sMd~oc)#d~qR6$XrNvF?G!V&Q+CseY$q8pVP>vnFr2>ZTp(_$@d%u36_$ zua08E%jxH3PBHFPtUIW79f60kMmE_-(@yuGG)WhMv)Ibxx;v$PG@}f%Oo8YaNLkw9 zXCeWb+8t{A@P8k~O+?&HVp|GBi`qiYBcey@Z8)JgdexaPwlBB$aZH5X}86 zf;vb!C0%n@`MX~PD@rNIc6^A|hBR%t@+D&&P=r*E-Eka9dWDM`fZm+mN+e>pwN+jU ztRt(=m_etwW12Q7Z#rHcz=5#MfIW|vT=4_#4<5aeQi>fTWBdnGYJdH*?4Bf7m-=<@ zazyGp@sM@@(g-1kKqiVB57jh+d5J_5PP46b-eW=WX9Og2SA&vvXc*7AOi<_cowkGz zO5F`&DSvkDh04!c@ftaB9DYz<5=K(oq&afD76oP}+_q9I4YeXvJr>gG=MjSQd{{Jk zER#tHuHuPtI&}t3FoPWEG zIe;#2mV!706krc~!<5diW1+SqsKK|=M3gnx5FM6`IAm|>7Rys((D>k)zE2pGN1S8v ziy5QLj(v>ZKh*(QY&!G5;-kMRa1L4I%bFwj$9F+*9hMfTBt&B030NCp?<$T6ZVVK7 ze=hno(+Ip_3mc#(Dyemk!B;3c2J)-myYeFXrB9sJ(nbid(fb2LcI{UkOxH~i*_SE= z>;KZmlF-Pm{7X))1I|koe9A^NQ71)kW zr2H%}$1VJYIGJ7hcw2q-0oH^9)h+h`J`pY6OS{49Xp$NTTv%j*r(d&ql%bpcH|TDD zZrwm()hC1`SG0YSi7_&5y3k5UZ)R&M!=P?g2LMcH`Mz&P0ypp>1!PG$v(GWqtw#BB z?jV=q+1e&qKv_JVDwZ}gzEwj5(Re6b3Cw|U_3elkfFs|0Dk3RAHyxIFnIS>iS&anF2#p;0K|T*<2ksdcv)~Mal-v3knfJ=A4(1@zYgv#Zi;po$H^QyBnhOU$b?pM4ECzyd=d<_MssK z3-q@Wmzz`a6AW;WFWea`u4+|d?6}yhZlP}v#o3^dQ~jk$0fMW1$TU4di6ktx+Qat( zBHVKqqVB>cHE-66m5Dl8{HGOhC}ql+@lJV3L7yHIqQLBNCU*VrGg?!BmB2|2K3CTs zCvG`-+llyAQxrem4JCm@>PT9-_mJ(O&CFV_e54bP3D#I1=;arG#P|;!2KbBnN4mip zBGK?bLL|ghD>U0I?glER_s>{7Q2jBzGO9^FTG0Zs_*UiVpXWfYgNwo>RsE0I?K{l( z;HIS(aWwALAu;nfK;Pbi`ZQL#G*#&YfdVQ%=ATsy@`GN)ooGO)#M1Id+%5JXJQBkhl7Z=>!a z>rqwuZX>g)SbXf9SrJ|p{ghLM!vqrX+R}`^Lj#Ker;TsbEeJ)H6eOP+<*W}vssNo? zw?z1?&wj#`U9+zcz64<9D{tHX>{+SQM0+~Ld_1Eai4mE&%u|yOjp3*dWOrY2;KS(y zkSF057Pcrjsu#yEV0Scf1yTD9H1!PT0gj!#AQ*27bxApJQxf(e9=XgY;Aw5JC0PCioJp z=B54onadk+On815BCsk!2KDD!e%R|KunV-&@IM$i`1SF`DBN(rs6D=ZEs0Njn`c93 zmbXofOG<78pfsiK=NQWJ^?l&^g$d<1i|Dx`zOf6{r}xry8v+QFsW~U=!3$VK?P14N zE7X{Ge|V;r!=AuHH!{{8gc}-VfbQ8cT33kXE~&etn!cBFcP@4y2UZ~1VEJSr}Qu{Lh1Gcj<3<4@vIwWdV=kHuTh14TYtfDYg+ z;+NF`)}nPPo>J`+|A?wi$Wsf8+2Xo5ZISvSFI$F_QnBlH>I~~bG_8oLg>9TsQY!p_ z?Q3~~)ETD&n8bOjxiq8q7+1WTlwQs|%@2o7<|~cOntX7gK3|aP@RB38bq*nW!?5iZ z#Xo~L{fd}_FGYI81**jxyi;+A@Q$hAH3U6i*;BQAmc6hCHt&}|dBddCaS)!VkM1oY z%Wrs~+G7pm@p_t+_zFJLx6tCn?$A_OY*JM8W9<{l2u!;O=hrW=*emk$lr@TcapkC_ z=gS<3*czA6NQJFw5?f$iJb&BITgAthz==$mTn?KMe9e5=Q?rB@2b9=i&5PwXzPK_xxs4cf6KCd6TLbhlYuvv6L|SA%k#4syI*_ zY;@pmn6Y@N6#8*k zNza)W&?6#?PTiotFI1ZmhNT_Y^yK;empp9O0tXSqD7cZgmp*yMXW2Pkt3}&p3FJD4e6I1r;@ZBMjq1^v>gqw%LV`->l2{%@9l& z{i|>fX*XKQe>H`|8C|tc0uH4!$Km&4(;$#>5om&2s(4nBC)tOme=W-y;z(Ossq$)m zw}+rg*-ghTQnrN;baKwlieLIBYdqrjWvEjJlcqbi!fP@ra5+PMHK#^nbJ$t6pqkvbt;L_4 zPgKyAmuFK4xdM^q^A}=6`~8f8ymyvBK!{VYU?AAlNM}a8;ur^9X@25E`NAF-H?={s z=g=lT5>3Q46IPLZcq8k_CZDNB2WfMEsQtJKjGl(SW(wW;$$Uth^UV%vXJFu1W8JI` zT{xP9ve(VObp;QKHDSj^&Q@eq6r5=s!Ju~PH5@8}Q_~6hWU`B&>`e;nF&5$jo1V|& zk#A~#AV9ZJ_`tU~C9ST=ridCSHTv_BGnKy#f*s9X<4ZF9dsnh5k>AZ!pLL!UYF&9D z^eO@NhY=#IBANI+MP&+e>k`HkMEHorOkx~B!A&pS-i;OBMvw=C3cdYq@tZbXEGBS& zW|eonnsvP+7i2#zjGS}#8Z~hrQ}E$IhR9l(VY4D+29Z^C8$_L9G@UvDg0|mobj4kd z6rudwHK?6cx9^GaI{V}&EJCDyKtVf3SU#*>2Zr>DH%5JBe#2+a`-3&_kPksBC~U^> z=UQ<=WvdD@$!cHNm)vFEw+ag)VM_K#=bjCTz5idpCah?8Ry5nGvg4AHSRfU<=$jYrEDc@M1F)7D(!UBn=mi>{7M7L+qjUR2?_sjOJ zxOIRy?lMVm&sHejrIG$4A+iLleF%S=#hm~ro@^?2L*(lRJ!J~xC3jatR$PwAK1w#)E>tOZ;tE>BPvjna!6 zNE64gEf7l%P{JX?ch~@L)CBHks995NRMPc}ZeeEnLb629@{SFTu)IKphAdmfrmLm8 z?Y#}0EGpP?!G+N2#AGbej#jg7!iGX{)rmD!)0A1aBWc@a+)CHs?J0TXkE$`w<&ROS zjV+;dZQ?&V)~}B%FzSr~)r|62`K!4|omhF@$q!we4cFB`mbc*QG~7mi~&I=ejxqs*2f&NeT? zoN#d6qWa9SrQNTnlvow`V_SfWtz!MzKCBDZSkYM+hsC$L_6JyjJ*Kk%$jvd{9y{i0U`SH$zk4TJ*dXqeYLp^Rph> zw4c&XQ5NQW%vTKPonYF&?mCw9qL8SI7t%BMb^>RI5V9x4?Y7o>rc$BR1aOfH7@!HA z>DjDeF*xk<1fBha&PAEh<5KBcC3^S^c29S@sUjyU6f*a`6eM0m&j&;eoHfyK8c7+v zlf__q%dOd%1(@&?cjcWE!Av*3@&F;Zcq$Gxzx7h-u^V*>rtaV9k#pTGXkDZk_2(L0 z22+Y!2}MVP#VuF_xtDV|Y~BrLCj(u*0s$1uVcI1cNfhZMU<~Ow~g4ASaRgCKhs#o^eP`e7uDZfd6&6O{vrUb%j{& z%5r|7t!=|-;LOoBf;locL6;Bn zv5O*_?)!v98$MT{Oej%q)<_ZuOlgbi{3-|4Z@FGEB^kCBRidk5CBUV^biw%;uZ1$; z(`(%Fdu!D2u1~_kqhn}FywdJM$6@?Jd-ws96GtXrfldfhxhKEpyWyd$lMW*Q_ietu zuP5{Uvcyr;%8= z6z%F7{7|1YhTyil(j=|nl`b8m%k?TelSr>}h#s|{-Klw9h*Jg2%C2Ivo66U>Eh?l` zqvFp5*_ed|4xuLz1VACta~beFnu<0H0G(g|Ih$t=6koZP5U-ptP?zB!CD!m7D;U={&9O@7JIUSaqD&k2E8 z*YWY^%ie$XN(pf~DgM}-U#D;lmZ^xs4Krind)0z{r%{~oY5i=S1ngJkUH(KorpY6C z=K*c=1;a~?sG^jnX5w_#s5VS()SU|OA%=~4$U>ZDv2FpdGKeRwQ!C?_jx;7w6=eA) zD+KN>!gRG-KUm?(oN@exBmpkTLU4 znrUg$6F)3UBeA;xB>XdOH;FQKxPMU-uh!(ZY27RlHf$^SL8K!eA@2|VeQ6(`4z-NEW^yEL<>*06YS$Aj8pUU!~FjL^-|m$VhU!gw%M z2H5DZ@8y@7@3ZvCf(%M^?W$R8U3Gu*tzPUIxYW#Tu;ot9n z!PG=-7!B0MfaKCUB0RLv10+%F%r(t4RF*3L$fq-aSJkdxkApOe0Di85b}QO}xc0=+ z--~ng>|+aKSI@AY_FTZ7-E~Vm6TH5-z3dkxEKmq|DId568uy4x+GhZy$bxkavK`U` z=wUdKcRGDa^;Xp3A>2ACB-ZMXGz!Y+FewXv8^=GpJ8lam2fAC+g2+1*%j7wEl zPu#2c^7=CP!Dl9u@XUPvIRC@lV?MsQ57uY^ex*l0LH)!+WlE{-`(Igtsqx&B{{^&K z;qBg}UmbK1OvuEII{OXp_>7X%)^}x_6tV?50iCWbSjr-ydUJmb!`5+BTu9eH;+KPj9z5Fw zc8Z@E`uOP^{<}!`9Z0basIZH{##_suw_!6}r@vl3ce+B}*wjP(4C`&QNap$DN$mI^ zw3aT*8uP7wS5&!2@wI|9w7(+Fm?A z;z0WU8>YTXe)n%5@H8e2fcp_*6E}Q+4WZI{vEE-mBQHe}AL4UA^Svb={MKP=L%&}_BwG_3@diTI`$5l%PXPE~L z*3uZT4CN-G53Ncei9gIuub#5C?qb)fCpdoXe~GXG21@Chb!K9GoN*y>uK!Kt zc`@RcNv|-IoWvm}q(!e$A6&+(*<`UITtKkk9z6{&;z842u zSEG?!mn+c2l?hM@{GKFw9O0G;2@0gBM+@uM+Ra@1u|i)hF^a(zz7S$W!{yK>n1o?g z6rj1e0jR1A?m=TKv;J$6h8I+hKz4ih>>OmFMKG4>(KX&qO;Q0M-@y0QzqOouI=V!|fEy z{at|F#>h;6*#1jxDZaxNx1%v9t$Eis{Jm}Eu*kRsZ_}`}0r3=hFtzepZ`7>^@$zkB z&YhOc?ODz;18(7%8+CQhV(~ZnJAQrOjt5*4aH#+*3n7u$5L-hO@rNR3K)14LXz8cO zR6jKdfF1duIt!xBu}7Jk8K7t{O4_(XoU6tw@tBHQcAM^=Z+9#&Nw32P2KD@PN!k@v z)3cUc(ENSbC&~A4@=?W1QWTRO=DGHZpA?pg<5gfrnWXDy4HAtBnlzTF=+bMxwd z%QVS-@e{v*t*?0Fbw$DnA7%c=lxrvB5yOwBg@6Qg_;NkxRId;`fQC4!AH?ZoKXEmv z(MT3Il)8_^P-vZ%9_UM=b34=s^iZ)+`0|v|4<9lZ?OWZ@@dB77<=t3(UH~8rB)U%GsS1L2Z}m% z`;sPfYIReB2_`X#VB~HI{;S@jZIazTxx|@~Yf{2$>v}=HJE52BRX$l)etVlZLQ@g~ z-qcHjJw27dfjA}WGi*HkeijQ{iOSK2ZQWUfA!z7t>w!FyTHpeZv{URU7YvC5UWb^H zVD~apKhQ5=E6u|^Z~e4wa*MbbJS28Iqy9rIN~>LkB?Bw4@k_lbSwJ@O zF>`B?x95TPmL*7F9ITQ%fW0E+amiW8y=WoT8z7FtAg6IXHtu0;kyS?garUv3`xK#d zsdxc867drL1$#7kJ@d7B3(elP&bI7+k)P=CEt{l`^nZ#5I1CK@7uCvP9NnS{$a+|F zm(jRq4n)&{s5loZ`DF@7229Vl1LsD^gorV|BK8{J(0MfQw6#E?Z7m?k&!0P%Hrf&R ze1`4qhAiUB7&*P#O@H+`kFp`ScshQwD{3-ngFQD5Ner_TgVhjP8>20K1Kfo0Ye zW;hf8(K9T>tBN2DBL}qipJ)fa+e_WpzPgDhH!fkz{avLYbVNY4pgw~q1wPn+9evFE zg{^4^ae>it;tmzu5xCv zkuy+qKa(sT0SopLEp4NM>$#v>Q2D=h%y8iqXJYG{<_cT8<%cf8QaSQW1sa^Sd2{az z7`uIR8|%x=Zs0gjTn#KldT*rzEks-=6=Ysa9trcE@W^@`u6NE%9-xcXadL>T(eh(B z{w3A_dA7zbF0|aEq+eiFCVQJDCG@q1ou2>!aXqrhCTITb^6*!q=HV%i5Z|AU=dkhbgtOW4yh$=3S)ZXdriTL=MCY{Hq|4oXPFm5AKjewJyBSi^X z=8bWL)g|tge6&+VsKo=BE~@2i5l%_ryFo#=3?=mMN^xvicd5K0v9PFbPhze?_Ye=F#iRs*6U<5h>F5@WVs%3ooCv~YC46X|P7c3pd zZF*d@=U;!dYIC43W8QSjkxfS8iIIB=<#KdXWF6LfgV-oRJDngha~`c zaf1bX7m+sbc5L_+9c9+VU1fd_5t7DXSXK&A>xpOmAk|6u)PNB^PB^7&5CLI6Pbwd; z4au54VZUFY5vpO_WQ4|?%-zO4G5&q!>tYWbd9+8d%iO5_s0QyBSS#ERH5peTT-GvA z*!hMV#9}OQ1%`^;KN35;rnU2jk6D=mv!rki6K0 zy7)66+~yq1|LrDtMUHJ+CQoSh}b_c1ReQLXV;r3gl)TBq`F2kf|JQJ zO`2CjOi^UX@XGDfViM(%KitolxqdAMW;h@E0SPkgIdGpS&4rKNCBktfFQ$g)G z@9|2>P85RtlX#l{En9C5lqM|G+9E>TGgxu+$W37hf% zq8p8oWlmJB8xEsa0E0ZS6}jQN9&~u#B&AcZIl?imnP{-ZHeG_x_Q)aC&~A zJ?7(D@iafs)+W`rfxcL{FWXF<#=~2OuC_E5_dGl}J*!bZ`@lD|RfJ}pI(#e(G66_D z)J=LEZRsBc;%g%4!z^8DZe^uASefYNHes*Q89Z;A7>ecCPfj^sJ z#|&3C{k{`Qf!gz-nSL6`7<~I;_qWbUQMu3ZxH5`R!Lv? zCC%J^4{=dpcDqJVRC_^SrPFZ&HxSdi=;LmexJgK9#m#2?09q5dJD}$SEIGh+46?l# zM-Z47P0|*20l)FL#0v^r%MMNj^Q)5Tm04nSj;9swQ}u5aag#!YX!_ZgVxTpso|7EP zG#l(i9T)_zcm&NqomHR1(vA(Ay8nPgxnMQUCzGz?mZ&|imEvtjqyF?QGh+k(WTX+) zqOjcIsV|y_Rd)-bY8g}lrAg~W?-X?voGjaag*Fj*YDgRu_;1WlP6qA6@3xqkK2%E= z>%V)Hi7?y1#u$PXlIBwjai_Usps-umCsjYb*H3K}ocg|{fR2aG70$^a)Gca2asuG6 z5D_t%v1WL)w!3UrtL%m-w-s=giAF~u5YK^J$Ict*5H2)_+C?I0{7wb8slV0yTsuwK zy@pVpj`ZKGk{uy2S$-=t&43y%WY+g}2f_N%g}Dtn+m9|;S!-F(M^&xBl0l+3sY%i(;|s9i!p4y|_WjCpEu`XQcZ(E9 zmYJI|9Yf^0lHXm|mgC7=`U^bAz+28ay9GDwzdm@c0USVL%#{89m8fwiW2b+)@|h+zP1fDp7aWta zl*`;V2diwO6ewCuex>C5c2`Gdbe>^ULDb@fXh3vjJ0dJ6b=4kd*DGI*g>jRpdKYPQqwc{RUvZT+kuHn>cJcAjN(o~TVI`)|4b<2kfxGH z_fGLPm{6{T`mk6eM4dQDO5CFN%Ou=bqZj*kR)Z~aVr5NrMk2DC;zrOAerM@iTkAG)?Q~#nm4g(w&l#mCUgM$QXQX(t?-2apj8mXai+9Pzh zK0t)HpO}}=l4Z%2f2thS07L6{)Iv82UD&s*CmtbT)lUuVUyXNs%@{%!6uuhV84?q5 zV*(jwT^#{1J$?W)jM_g;W4UcdQ-f8~vYV}%#ebIu=+s!;6}0-NyR9?Ux^iZ)U*%+2 zkQt@6+Uc26-+V#rq&RYq zHnr3&J%Qd7q}+C4<{$z z&dZ9UU@Q0U1)lo;dcbEyEHxhjd`QK!KEf5a9WL*gu(J>#)3ONSU}{lc(+}LG`Vp01 zqGoH4x_i-!$xeIrbxMa7WMuT>QLo<8W2fF#82xuyIy|pjeo)m@2BgwAjbFSA{yp1f zc$K3I35WPA$LMi`F2eljnF(#OtPAAL`|7jaM3_iFd}mR65Sk^Pqvll54k+h4TvWA| zNi8xYco15qMmaxS>!1+1gm5)p{V!UDPJ2?WXYRuk6aBpvU9jFK0YFKE3)CG zWf?>3#$T=vp$?2HrSlS9pxy$ytoCZpU`(dYW=w|nSClZUSRTyHtFURYqqNvN)5<)W zDm0316V^JLrJ6~bMRha~jv`+*_&WcTc>BiMZiL304|EZ52gIa9UX8yysNVz!q_ENA z&xKM&46Oyd=iD(Gyn{Tm34nZ1_KrkK>kgKop0f31&mmn|nL z&f}a1BNPV{-Tlj^G_<*oIqfKQjhqwNjg@8aG9dXHYMN?7oN0mZkhT_~%HQ`56| zDnD8lja~R~6MLgLr}MN)GQ{04vNQ!}pJ&mZ=!B8_AM@8ooQ0*!FQp)%1P0HD1)vjh zqnnx;o*4k35wgl_9+@|-g?EHg34xA?GRp5NoP&t|&S#h!k`lROws3o?FHmKi37(S( zQn2iqen_(OEv=0+vNPdkFaWGEJE<0*j_pet8GUBV$a-}xj-+-LApWXiIUV)GA>Iy5 z4HLZm4789qT=4dVJ1F+dedL0GW1|}Z-LbB}Asv_b%r!5qoXMW_B$DgWBD6p2ezAY2 zzy?|bv}{?eWg&=$@P6LY$l{jXoMdrv$I}M)>m-fUdfioD>bRy@&xzIpJy=1#$x?9w zR*eao!;KhXH!ZVoUQ;Us0~Zy-U@(5;^V25Ta|b9ZA!g`}Bj<6NfyRi0ElheRS@8%jqA|>hqm+DkiF$BxeJmNBoDIKBEZ*xC) z=An(Bu$bOD%3bX#DjUol)kPVfX8)nZ?=J@$VAuy9dqY?LRzrJF8(kY#jQnqcO4!X? zD4(Hr9~9mWiJn=Um(HkUO5~=>tS)!?7k*{fkX6$-AIHx%Vh>$QRSQ>_aQ@LSM-K1| zPXvOVqCjsXApCwgE?UM}F_D97v}y66BHO$3TLC$OngJ`b1 zH{uB;5v5jNUDq!h%^e*D+V%qjIUl5m6?obR_0%|(lMFPS-phHxjrVi7!KL2)c02Dh zC|p`jw_ZmbHTS_>BI8=`x}dz7CvZs2Uua?HL%Ye3skTbctP#i=?Gq6lR3lz=HrbI` z1Q))7-Hezqe|PG_4r4Zj;nLN(xLy+g>Bq~-L__lgQUnzN3Up?ZRNC9bwTQ&a%MQe_ znpsu-+f!n1VbE0vXahZyF)(#0kZwY`WMTqXu+18hQ$WM1`~4SVPv*|1Of*40AyhV2 z;REOVZd8?f?b&d3t9#Cb+b3t2Lc6Dt56o_6G~2q8Ykg@HRAT`FpP6^>GiUdTfq9l8 z0~gX*MAja~(gG&+dvn&GaxX}D)Wq7Vyi-(Il^@S9vBbSgY{29pG45hp%K&Je=W-GI zbWG%?X(4HqlYt~c7GZa#^?_$hm9X#I&z1{@kF$%?HI5fA)R@O85A^X8hJ<1JyM@RV zC=)p@q4*?H&Ac_QhcVY8Xj=pnkvN0x{PJouTVM$aPT4t?Hpzkic0YhwWwA!I7}>u7 z(43&Kftk@DH5j0(TvTuv&l)3OEW9eAM#e6m7yD}?Z@4%ISDseKT=_f0n)WT4{8CG+ zrE4t1eoxRq_(l-ZwkChZ;_F1XrSo|l4tU=2E!j2|{#Xfw*yG$r(@F$1^g7BgE{}vr&I3_-#F?AwYM6W?DBcW; zpXeXl)6#006NQuGO9n{d$>(W6L0L}A-^klQF+Y> zL*W^syv4=VH?pld{Eq2z+^%rcqmtVu@w`ccG@~c`-V+9R6kC6IbGB`ohN%GEFkrs# z+d3#H{;h2cn{@3zs*JooGctGt(oFDMF&+x3K8ZI!p-H@$Qb%b=QV^mU6~(ok1Fj6) z8Go9W{{olve{Q5mU>%U|GgX(WZXfGZq?A2N#<`gk1)oXMw6QIpS#pZcNlb`WfGG_IZM79Z0c8VYN@{6d-mE3}XyPnBC^0@$P~qx=o!M)xVn9rMOT0cH)FAoO7Q$}`ho9>)V3{N&vI(TyWs^r< ze9GkkZ>hx#^gzuo=R5xI1^p(6GW3e<|8!$|_p2qwmcR9P_#$M#o(c(WBuMYfu|kO< zCU)ioiL!zs_pays>5w~Xfg(5}{|l~$zd)ZvQb!x|5SB8{x-(#I4Ve%Ue&#Aluk^>% z3W4&}dtWO8ACzOGI~)A=7unX3{81Taixa|29dp^#c0D&lC{%e|xT50yAIS zN2A#%;J9w#bcS_%)X&#gty%QMvk({w=K!H8WR!R+TQYBJ|C4`KmM7R8m zF%;}#c(PA}wi0EOMn#g{N)=2Djpajul-zjBBKrY|wIY0{*-K>#4Ua<}w&N)7*YPIc z9i8GF|5#lyjshaLUwqCu8ZleOEORt&7XU&NnKMpq3}j?m&D6SOc_sphR0(2QJsgUD?aSR0KrI4%d-?<9vzVFJPKl zwd`9xyOm1m)c{<1lmtVUR^v7aEa_w1nc{9R4QKb49%oY3ZV+Tj&Yjh8Wa3;ua&CLg zkHg3dOgDje z>VC3%g`K7cvFN1U{JMO2aB6K0r6ZCtQHr+1&jbUW5$TL3?FZ!2BdhG9hTZ!$8l*AfzgKQfWz@C%;-KVJUxC zrzqiU->958x7DMpJ#XWO*jc(Xj1V+z7Jm}X+@tAC%tWV8U8OP| z>m>MAvgdMO{^bH(K`984a9vcw+VZ$6td+Rr+^xn4;BQfO<*! zs>npdJ)8=Ku@T<}C?KkW=bUNnr$0>OWujsqzlsvIuJ_-F4@ zyThjVUeo9=L<%-bNN{;57qSQ)M(d+-g>n#%X%@D5h&e(LM$%gHkF1rMm##I;w6e-< zq%GtR815`*Qegvw8sPBc2NdhRTStu)N3*45vw=j(k4++#=l^FL(`;}*%5f|^>s%Sh ztz=-a>PE3 zfy>5{00i=AZnCG{n*%X3L#BA)*Oram43ZUgXGk7o)fap3!q1J_D-|@(Zv=FLuX~b_8q@h>GNz&yUiT&MAZj~m;hq)hp&-oMiwiY>l89Yeqnw5osV(6Oa|A2%|U%YMFK>05b(D4^qVH z*Fe(qISZ!)4NTS7g;#snu}?t??oeUAEG9AoCn!F}mSQE?F2CLJa-ZUOX|AWYcEX<*Qzr~zNU=b52N#0o@!6IAI?8Ia z=u-tXcNL5M2*bvv6Lj0{Fozl^xk~*HfLs(1@aGM4(l9*@6CjW%P0&!~cesoh6FQIQ zGLuQnVI`t~4+%O$q?#(&M!a{_k=^l8xHJ$m$x|cslS%GQW>ofx%+DtN{4)yBYW5UG z2zdf-b(kSIDR(_KardHA6#Z3X@-1>Zw1LXjj#QlSkt5|*a);_f6qbCH?&})zr@B3n zOyV}TOPHOU2c_yVbnI3NMI5D}s{5ex~W>z>T{h43b!$w?Vk(&4Xg?@-#o7O&D@ zNZ#w{pT3{P0%Hv&MTHmTk#E^H6SN{r1m-1~+l5++h}`0G#!XQGzuciR{|6N0B>Z-p zR=^X252eiqqe4De-R$2z%|ebum-1o2Gy=nUr1wSxpXjw#s&jr14v-4sVA6>R*uJd zb5m`oA>r+JJqwW&!0jY3l2p2g|dv75bfJk`jj5ykr@sPGED1_Y48d0 z&x?7p3YoZ^A(6VE$UH3nJ6T2_1bcmZpF+wA^zi!pe*!BE-q=ic3SsWTx_jO6$0Yd_ zJsZO<#cm*A55SdS77h$S_618NK zB05ntS)X7|fSmHiwh38-D-h=#xDwc5Kr24}DyjSKf10MWj4KIL>g#P1_$}9=b}z1f z5=$E(#&3bP2bb`&HKW0-{{UMq)es$e?#6YI`F9Eu@G;rb5VlH_4sK?dm3MHabOZAkE;%(dsv+#x~}DD_3918sn)IljE$CY{ne8m46LX&ZY{ zYXG@7t72fPR@(+1Lh`l@Zm6h+v~CtrPt+m4aXsfnts~Hvaw_zgs?06`xu@3qLxd~$ zbuJ%LO4R$P)uezCCwyX|RB8qRi;0#xS9Q@NvGe%SwtE4PZ0Cr8(Bq9>-Dsy8|+2(}OM4dshMs-GVk;!06W zsIzW{KC?)LbCH@Fg**_t0#4rs;u{qCM=gD3tD60_e7**TKo<;6m&azqxFi1|^%zXq zo>rmJ2f8cOm=*{l7$$FXs^Pmrwa}L1ntB=`>;-xo>1{-4Sd`M4h$346~}8IR4gq z>KIM6NA#7DP^ZAJ^YFOUIfb<&VVvo~Cf4c>-OeJ2Q5A8BI9lsI+JlS9(u=$?=*z?Y zQ$=l9PRxcnerP&NZqUXO`6rs0Y3)#N?qdXh+L+K!qmKgKC#Ej(uLq@Tfj|@C zI0CKet`L!9wa#;%IUwpK{ojYF7@7-TTDC$Wjt?S&pgJFA(8dQOu1P}f=-luZeS$`= z%*%J&6Saf4vI9Ql#!{f@EV znNcO_cc_x~Bkik1e_tJhwt&w3P!bw_SJ5@IvCH~y<;iyIfjS8mziSE&g zrjSY`#=D?-UB24{B#aeBEmZZB=JmYHg`Kc*((U{z3ljDD)x5_~&`*V`g8Ym%5Wzn4 z7l%eE2b5WeOPixn22o2j8@)BH#RbCYaiqE67xJA6cgh)6C%VAsO(O9*W}YhWTm7tpb} z*MDr{%vDc>=#~p~;3utVu%mX;i=Nz@>Ab?JXDb1p2$7?e)n@9EoKirY_q=X<<3*$@ z)x80^&1(G7Y=#D*Jd}OU=9U#>uMnm{0a?KI@(YEJ`sTy zJB|^8-{6PPm)~Xn&XN*&v8e=v=QmyIYnlw`gpTnIR{AE@6Sa&R8~@RkF^c_NbEObI zs+GdDV|ebd+C?QP@h`|md*ypFa8>CAX>}=BCl-IEGboSAI#|9cg%Gdte@Km^PL6uy zh~JC6V`QFU=Gm7fAAQr5G_LMgoEF+4%9V(Glq&pR9)_(xA}3wm{Bo~Jx8OE(2nI{& zgZ{P}wReY@6K1XzRI3w$PmNgvtY}#;?_@(V)lZelK7rUp;ca>>!HvJQE(YU;pde+U zCqz%OR|hXEZ~8p&pY)XyOfa^vzu|*h@GVMPvqc=sU~I~kljK(=C9C799LABid)0EH zWbFBb&{H)*B1{I-hjF$ex)4Z)JR5a3X7R;XoNu0vEv1tk>1Kqw#8!9jj;i9sy2QL4 z5;`H_?0dEV$vt`Xk*W; zJ1IazZb?D@CdXyXm~PywMU2XLfv_0JQ)_)?0wYBJ5Pg!i3wpO^A?2~NIifmdUnq&!G2x3L{_(_`N|YPXbjZa zE#7k|W=t)aM5izQv?lBFw;J~?|ImtV(6<3hMHWV+i?A3)C|3L_-d^Yi!_NbR-{$Z6 z$xiQdWeTkvA2j*rj-fIHqqvU(m~jE3I9A;gYmQj@{vf4ZS(yWF=5eaBSFoK?#cp7 za}G0t%+ypBi9LjLzZR5(Y2L5v?9U5KpvJ-S`~S?B^GGM~mx0yUi&K zagFwH;md`<+l*?)rF&k<{)NM!+eXzs$sI-#%s23^HpQ(^++jrLYuDdZ%Kw^v+5+Rau_TmbeO%S4n;0Gp!I-14SJp zRA+&EypkT~P%i)uD1|T`Ssx*120?|p>KxHF@v7F+dFx_OeFb>yT@p=%WK9&4v)$hd0uM8W<#<8wvpX|scsAQ-s)jc*yP$Xmay|{9lyV#U1(;lPh_CNIo**#`b zaRJLlI=ZMLk^j~!8gb$z$Htc0Atwg>3?9DW#~3#M+F{=j)f>ef)t1VGa*H>?Uv^CM ztRkl73+Uw}8;-PBqM>w3)H|Z>zDR$Km3J*oL%w+z0fOO}!r`DMXJU7GHzkZQdEqJ` z$+Z&eTD|f+`$5e`D)NLgH_}})N*gS;@>b6%xl6g@>cfMWEZ}~tc&6aG*TF?P6h;fv z9yXSN3V2A#v94&xhO$zHB3DyGknov(zNJf+?5rwSa4rs<}%64iUo>mHmv0D&m_n`1jJh1=Xwv53e|rI8}t39jcB# znR0KPZhCmv4q4`&n@Y}5&?~X9rS!g>eUo(3H~tGwU*^iO6^a>bR9lgVT@W0QZ-UxM zh5B_aAU@gtbsn^+i!3K(AB>;CYtEZG=51;zVv4wa-lw5Ask|HQwhfga@><#c%uLn3 zE`910&@b8P3`P^PI>hi@i}3(hZWV7TsDV%WrRp>;fYTJ6UqEuP`U(uvt4iWERct$J zr1hL`l+dls8mEoZX5YmVK^)AM;QAuNVwyOX#G-A3%|!vT$aLdg$%bB_BDfc#+Xgb( zhEN?xZ$J9%4#x>;dUr40qjB%aE4}c&vX!2G!%L+ZWC8bT+0A1CbD>fw)0NLGC1l|_ z*u-@k3T_LTuWJWehhQ^`3JH4}Wa;RouW&pM&G1rneWE4OyE5d|E z#!hgc&-rI*qq*OBCoULVvK5#S4^&=q*>(QuRI5j26(WiBb{IW}DXAD?>Y3fbg{aaK>uDISVQ|R#g!0Q$$>>FN00~;IW=q^effyfQcs0|+iOp2lb`qYDDL?RV# zx76s$65DTO%wprx4MQAV$8LQ8+6CUzup$RmRB71$6V5dmG&@&9)gEbO`;eBs5MoK0 z;g<$v5FMl}z=xj}y3pdx0NC{P$ij!&{{MeM$K7FND=z-xFAEC?#bX!EHhPXxraZtn z9PiiJ^{@C?Z^PUGkChOm?nQ-8qR;sP<@kJP>t%)o7hwNZ{2MIXdZmCzq7>R1Ev!|G qHGOVznkr+ojusJM@r=OQp?xVsxxST@$9gf^*?jRgsg}e~L~ocL?S Date: Thu, 25 May 2023 10:26:14 +0200 Subject: [PATCH 0645/1786] 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 0646/1786] 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 0647/1786] 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 0648/1786] 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 0649/1786] 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 0650/1786] 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 0651/1786] 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 0652/1786] 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 0653/1786] 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 0654/1786] 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 0655/1786] 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 0656/1786] 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 0657/1786] 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 0658/1786] 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 0659/1786] 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 0660/1786] 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 0661/1786] 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 0662/1786] 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 0663/1786] 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 0664/1786] 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 0665/1786] 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 0666/1786] 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 0667/1786] 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 0668/1786] 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 0669/1786] 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 0670/1786] 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 0671/1786] 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 0672/1786] 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 0673/1786] 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 0674/1786] 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 0675/1786] 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 0676/1786] 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 0677/1786] 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 0678/1786] 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 0679/1786] 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 0680/1786] 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 0681/1786] 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 0682/1786] 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 0683/1786] 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 0684/1786] 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 0685/1786] 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 0686/1786] 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 0687/1786] 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 0688/1786] 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 0689/1786] 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 0690/1786] 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 0691/1786] 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 0692/1786] 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 0693/1786] 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 0694/1786] 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 0695/1786] 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 0696/1786] 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 0697/1786] 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 0698/1786] 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 0699/1786] 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 0700/1786] 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 0701/1786] 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 0702/1786] 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 0703/1786] 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 0704/1786] 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 0705/1786] 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 0706/1786] 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 0707/1786] 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 0708/1786] 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 0709/1786] 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 0710/1786] 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 0711/1786] 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 0712/1786] 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 0713/1786] 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 0714/1786] 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 0715/1786] 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 0716/1786] 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 0717/1786] 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 0718/1786] 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 0719/1786] 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 0720/1786] 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 0721/1786] 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 0722/1786] 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 0723/1786] 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 0724/1786] 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 0725/1786] 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 0726/1786] 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 0727/1786] 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 0728/1786] 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 0729/1786] 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 0730/1786] 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 0731/1786] 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 0732/1786] 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 0733/1786] 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 0734/1786] 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 0735/1786] 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 0736/1786] 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 0737/1786] 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 0738/1786] 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 0739/1786] 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 0740/1786] 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 0741/1786] 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 0742/1786] 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 0743/1786] 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 0744/1786] 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 0745/1786] 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 0746/1786] 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 0747/1786] 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 0748/1786] 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 0749/1786] 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 0750/1786] 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 0751/1786] 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 0752/1786] 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 0753/1786] 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 0754/1786] 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 0755/1786] 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 0756/1786] 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 0757/1786] 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 0758/1786] 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 0759/1786] 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 0760/1786] 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 0761/1786] 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 0762/1786] 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 0763/1786] 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 0764/1786] 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 0765/1786] 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 0766/1786] 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 0767/1786] 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 0768/1786] 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 0769/1786] 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 0770/1786] 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 0771/1786] 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 0772/1786] 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 0773/1786] 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 0774/1786] 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 0775/1786] 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 0776/1786] 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 0777/1786] 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 0778/1786] 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 0779/1786] 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 0780/1786] 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 0781/1786] 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 0782/1786] 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 0783/1786] 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 0784/1786] 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 0785/1786] 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 0786/1786] 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 0787/1786] 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 0788/1786] 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 0789/1786] 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 0790/1786] 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 0791/1786] 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 0792/1786] 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 0793/1786] 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 0794/1786] 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 0795/1786] 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 0796/1786] 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 0797/1786] 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 0798/1786] 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 0799/1786] 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 0800/1786] 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 0801/1786] 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 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 Date: Tue, 10 Oct 2023 13:16:58 +0200 Subject: [PATCH 0802/1786] 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 0803/1786] 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 0804/1786] 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 0805/1786] 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 0806/1786] 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 0807/1786] 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 0808/1786] 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 0809/1786] 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 0810/1786] 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 0811/1786] 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 0812/1786] 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 0813/1786] 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 0814/1786] 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 0815/1786] 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 0816/1786] 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 0817/1786] 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 0818/1786] 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 0819/1786] 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 0820/1786] 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 0821/1786] 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 0822/1786] 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 0823/1786] 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 0824/1786] 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 0825/1786] 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 0826/1786] 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 0827/1786] 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 0828/1786] 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 0829/1786] 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 0830/1786] 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 0831/1786] 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 0832/1786] 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 0833/1786] 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 0834/1786] =?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 0835/1786] 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 0836/1786] 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 0837/1786] 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 0838/1786] 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 0839/1786] 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 0840/1786] 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 0841/1786] 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 0842/1786] 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 0843/1786] 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 0844/1786] 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 0845/1786] 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 0846/1786] 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 0847/1786] 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 0848/1786] 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 0849/1786] 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 0850/1786] 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 0851/1786] 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 0852/1786] 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 0853/1786] 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 0854/1786] 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 0855/1786] 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 0856/1786] 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 0857/1786] 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 0858/1786] 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 0859/1786] 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 0860/1786] 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 0861/1786] 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 0862/1786] 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 0863/1786] 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 0864/1786] 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 0865/1786] 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 0866/1786] 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 0867/1786] 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 0868/1786] 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 0869/1786] 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 0870/1786] 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 0871/1786] 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 0872/1786] 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 0873/1786] 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 0874/1786] 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 0875/1786] 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 0876/1786] 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 0877/1786] 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 0878/1786] 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 0879/1786] 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 0880/1786] 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 0881/1786] 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 0882/1786] 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 0883/1786] 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 0884/1786] 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 0885/1786] 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 0886/1786] 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 0887/1786] 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 0888/1786] 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 0889/1786] 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 0890/1786] 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 0891/1786] 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 0892/1786] 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 0893/1786] 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 0894/1786] 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 0895/1786] 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 0896/1786] 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 0897/1786] 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 0898/1786] 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 0899/1786] 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 0900/1786] 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 0901/1786] 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 0902/1786] 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 0903/1786] 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 0904/1786] 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 0905/1786] 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 0906/1786] 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 0907/1786] 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 0908/1786] 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 0909/1786] 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 0910/1786] 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 0911/1786] 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 0912/1786] 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 0913/1786] 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 0914/1786] 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 0915/1786] 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 0916/1786] 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 0917/1786] 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 0918/1786] 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 0919/1786] 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 0920/1786] 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 0921/1786] =?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 0922/1786] 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 0923/1786] 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 0924/1786] 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 0925/1786] 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 0926/1786] 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 0927/1786] 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 0928/1786] 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 0929/1786] 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 0930/1786] 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 0931/1786] 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 0932/1786] 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 0933/1786] 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 0934/1786] 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 0935/1786] 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 0936/1786] 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 0937/1786] 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 0938/1786] 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 0939/1786] 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 0940/1786] 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 0941/1786] 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 0942/1786] 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 0943/1786] 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 0944/1786] 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 0945/1786] 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 0946/1786] 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 0947/1786] 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 0948/1786] 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 0949/1786] 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 0950/1786] 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 0951/1786] 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 0952/1786] 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 0953/1786] 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 0954/1786] 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 0955/1786] 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 0956/1786] 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 0957/1786] 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 0958/1786] 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 0959/1786] 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 0960/1786] 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 0961/1786] 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 0962/1786] 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 0963/1786] 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 0964/1786] 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 0965/1786] 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 0966/1786] 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 0967/1786] 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 0968/1786] 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 0969/1786] 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 0970/1786] 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 0971/1786] 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 0972/1786] 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 0973/1786] 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 0974/1786] 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 0975/1786] 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 0976/1786] 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 0977/1786] 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 0978/1786] 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 0979/1786] 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 0980/1786] 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 0981/1786] 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 0982/1786] 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 0983/1786] 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 0984/1786] 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 0985/1786] 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 0986/1786] 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 0987/1786] 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 0988/1786] 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 0989/1786] 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 0990/1786] 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 0991/1786] 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 0992/1786] 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 0993/1786] 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 0994/1786] 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 0995/1786] 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 0996/1786] 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 0997/1786] 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 0998/1786] 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 0999/1786] 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 1000/1786] 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 1001/1786] 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 1002/1786] 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 1003/1786] 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 1004/1786] 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 1005/1786] 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 1006/1786] 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 1007/1786] 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 1008/1786] 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 1009/1786] 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 1010/1786] 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 1011/1786] 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 1012/1786] 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 1013/1786] 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 1014/1786] 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 1015/1786] 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 1016/1786] 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 1017/1786] 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 1018/1786] 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 1019/1786] 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 1020/1786] 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 1021/1786] 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 1022/1786] 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 1023/1786] 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 1024/1786] 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 1025/1786] 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 1026/1786] 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 1027/1786] 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 1028/1786] 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 1029/1786] 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 1030/1786] 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 1031/1786] 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 1032/1786] 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 1033/1786] 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 1034/1786] 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 1035/1786] 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 1036/1786] 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 1037/1786] 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 1038/1786] 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 1039/1786] 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 1040/1786] 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 1041/1786] 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 1042/1786] 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 1043/1786] =?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 1044/1786] 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 1045/1786] 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 1046/1786] 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 1047/1786] 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 1048/1786] 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 1049/1786] 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 1050/1786] 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 1051/1786] 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 1052/1786] 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 1053/1786] 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 1054/1786] 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 1055/1786] 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 1056/1786] 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 1057/1786] 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 1058/1786] 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 1059/1786] 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 1060/1786] 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 1061/1786] 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 1062/1786] 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 1063/1786] 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 1064/1786] 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 1065/1786] 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 1066/1786] 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 1067/1786] 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 1068/1786] 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 1069/1786] 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 1070/1786] 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 1071/1786] 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 1072/1786] 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 1073/1786] 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 1074/1786] 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 1075/1786] 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 1076/1786] 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 1077/1786] 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 1078/1786] 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 1079/1786] 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 1080/1786] 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 1081/1786] 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 1082/1786] 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 1083/1786] 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 1084/1786] 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 1085/1786] 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 1086/1786] 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 1087/1786] 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 1088/1786] 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 1089/1786] 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 1090/1786] 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 1091/1786] 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 1092/1786] 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 1093/1786] 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 1094/1786] 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 1095/1786] 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 1096/1786] 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 1097/1786] 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 1098/1786] 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 1099/1786] 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 1100/1786] 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 1101/1786] 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 1102/1786] 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 1103/1786] 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 1104/1786] 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 1105/1786] 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 1106/1786] 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 1107/1786] 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 1108/1786] 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 1109/1786] 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 1110/1786] 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 1111/1786] 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 1112/1786] 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 1113/1786] 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 1114/1786] 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 1115/1786] 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 1116/1786] 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 1117/1786] 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 1118/1786] 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 1119/1786] 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 1120/1786] 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 1121/1786] 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 1122/1786] 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 1123/1786] 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 1124/1786] 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 1125/1786] 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 1126/1786] 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 1127/1786] 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 1128/1786] 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 1129/1786] 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 1130/1786] 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 1131/1786] 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 1132/1786] 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 1133/1786] 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 1134/1786] 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 1135/1786] 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 1136/1786] 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 1137/1786] 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 1138/1786] 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 1139/1786] 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 1140/1786] 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 1141/1786] 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 1142/1786] 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 1143/1786] 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 1144/1786] 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 1145/1786] 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 1146/1786] 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 1147/1786] 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 1148/1786] 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 1149/1786] 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 1150/1786] 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 1151/1786] 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 1152/1786] 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 1153/1786] 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 1154/1786] 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 1155/1786] 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 1156/1786] 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 1157/1786] 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 1158/1786] 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 1159/1786] 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 1160/1786] 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 1161/1786] 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 1162/1786] 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 1163/1786] 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 1164/1786] 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 1165/1786] 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 1166/1786] 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 1167/1786] 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 1168/1786] 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 1169/1786] 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 1170/1786] 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 1171/1786] 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 1172/1786] 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 1173/1786] 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 1174/1786] 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 1175/1786] 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 1176/1786] 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 1177/1786] 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 1178/1786] 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 1179/1786] 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 1180/1786] 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 1181/1786] 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 1182/1786] 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 1183/1786] 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 1184/1786] 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 1185/1786] 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 1186/1786] 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 1187/1786] 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 1188/1786] 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 1189/1786] 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 1190/1786] 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 1191/1786] 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 1192/1786] 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 1193/1786] 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 1194/1786] 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 1195/1786] 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 1196/1786] 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 1197/1786] 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 1198/1786] 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 1199/1786] 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 1200/1786] 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 1201/1786] 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 1202/1786] 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 1203/1786] 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 1204/1786] 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 1205/1786] 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 1206/1786] 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 1207/1786] 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 1208/1786] 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 1209/1786] 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 1210/1786] 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 1211/1786] 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 1212/1786] 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 1213/1786] 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 1214/1786] 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 1215/1786] 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 1216/1786] 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 1217/1786] 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 1218/1786] 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 1219/1786] 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 1220/1786] 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 1221/1786] 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 1222/1786] 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 1223/1786] 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 1224/1786] 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 1225/1786] 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 1226/1786] 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 1227/1786] 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 1228/1786] 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 1229/1786] 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 1230/1786] 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 1231/1786] 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 1232/1786] 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 1233/1786] 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 1234/1786] 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 1235/1786] 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 1236/1786] 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 1237/1786] 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 1238/1786] 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 1239/1786] 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 1240/1786] 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 1241/1786] 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 1242/1786] 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 1243/1786] 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 1244/1786] 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 1245/1786] 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 1246/1786] 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 1247/1786] 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 1248/1786] 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 1249/1786] 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 1250/1786] 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 1251/1786] 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 1252/1786] 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 1253/1786] 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 1254/1786] 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 1255/1786] 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 1256/1786] 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 1257/1786] 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 1258/1786] 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 1259/1786] 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 1260/1786] 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 1261/1786] 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 1262/1786] 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 1263/1786] 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 1264/1786] 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 1265/1786] 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 1266/1786] 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 1267/1786] 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 1268/1786] 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 1269/1786] 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 1270/1786] 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 1271/1786] 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 1272/1786] 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 1273/1786] 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 1274/1786] 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 1275/1786] 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 1276/1786] 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 1277/1786] 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 1278/1786] 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 1279/1786] 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 1280/1786] 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 1281/1786] 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 1282/1786] 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 1283/1786] 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 1284/1786] 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 1285/1786] 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 1286/1786] 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 1287/1786] 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 1288/1786] 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 1289/1786] 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 1290/1786] 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 1291/1786] 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 1292/1786] 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 1293/1786] 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 1294/1786] 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 1295/1786] 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 1296/1786] 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 1297/1786] 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 1298/1786] =?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 1299/1786] 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 1300/1786] 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 1301/1786] 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 1302/1786] 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 1303/1786] 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 1304/1786] 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 1305/1786] 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 1306/1786] 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 1307/1786] 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 1308/1786] 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 1309/1786] 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 1310/1786] 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 1311/1786] 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 1312/1786] 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 1313/1786] 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 1314/1786] 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 1315/1786] 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 1316/1786] 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 1317/1786] 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 1318/1786] 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 1319/1786] 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 1320/1786] 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 1321/1786] 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 1322/1786] 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 1323/1786] 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 1324/1786] 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 1325/1786] 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 1326/1786] 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 1327/1786] 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 1328/1786] 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 1329/1786] 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 1330/1786] 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 1331/1786] 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 1332/1786] 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 1333/1786] 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 1334/1786] 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 1335/1786] 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 1336/1786] 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 1337/1786] 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 1338/1786] 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 1339/1786] 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 1340/1786] 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 1341/1786] 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 1342/1786] 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")) ] . "