From 8fc88c73f8cb99774727e7b96f9b85a8bf216c2c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 15 Nov 2021 20:22:56 +0100 Subject: shorten modules directory name (global-functions.d -> mod) --- README.md | 4 +- doc/global-functions.d/bridge-port-to.md | 79 -------------- doc/global-functions.d/bridge-port-vlan.md | 83 --------------- doc/mod/bridge-port-to.md | 79 ++++++++++++++ doc/mod/bridge-port-vlan.md | 83 +++++++++++++++ global-config | 8 +- global-config-overlay | 2 +- global-config.changes | 6 +- global-functions | 6 +- global-functions.d/bridge-port-to | 54 ---------- global-functions.d/bridge-port-vlan | 62 ----------- global-functions.d/inspectvar | 40 ------- global-functions.d/ipcalc | 35 ------ global-functions.d/notification-matrix | 157 --------------------------- global-functions.d/notification-telegram | 164 ----------------------------- global-functions.d/scriptrunonce | 46 -------- mod/bridge-port-to | 54 ++++++++++ mod/bridge-port-vlan | 62 +++++++++++ mod/inspectvar | 40 +++++++ mod/ipcalc | 35 ++++++ mod/notification-matrix | 157 +++++++++++++++++++++++++++ mod/notification-telegram | 164 +++++++++++++++++++++++++++++ mod/scriptrunonce | 46 ++++++++ 23 files changed, 734 insertions(+), 732 deletions(-) delete mode 100644 doc/global-functions.d/bridge-port-to.md delete mode 100644 doc/global-functions.d/bridge-port-vlan.md create mode 100644 doc/mod/bridge-port-to.md create mode 100644 doc/mod/bridge-port-vlan.md delete mode 100644 global-functions.d/bridge-port-to delete mode 100644 global-functions.d/bridge-port-vlan delete mode 100644 global-functions.d/inspectvar delete mode 100644 global-functions.d/ipcalc delete mode 100644 global-functions.d/notification-matrix delete mode 100644 global-functions.d/notification-telegram delete mode 100644 global-functions.d/scriptrunonce create mode 100644 mod/bridge-port-to create mode 100644 mod/bridge-port-vlan create mode 100644 mod/inspectvar create mode 100644 mod/ipcalc create mode 100644 mod/notification-matrix create mode 100644 mod/notification-telegram create mode 100644 mod/scriptrunonce diff --git a/README.md b/README.md index 7eb646d..d252deb 100644 --- a/README.md +++ b/README.md @@ -203,8 +203,8 @@ Available Scripts Available modules ----------------- -* [Manage ports in bridge](doc/global-functions.d/bridge-port-to.md) -* [Manage VLANs on bridge ports](doc/global-functions.d/bridge-port-vlan.md) +* [Manage ports in bridge](doc/mod/bridge-port-to.md) +* [Manage VLANs on bridge ports](doc/mod/bridge-port-vlan.md) Contact ------- diff --git a/doc/global-functions.d/bridge-port-to.md b/doc/global-functions.d/bridge-port-to.md deleted file mode 100644 index e0eba1e..0000000 --- a/doc/global-functions.d/bridge-port-to.md +++ /dev/null @@ -1,79 +0,0 @@ -Manage ports in bridge -====================== - -[◀ Go back to main README](../README.md) - -🛈 This module can not be used on its own but requires the base installation. -See [main README](../README.md) for details. - -Description ------------ - -This module and its functio are are supposed to handle interfaces and -switching them from one bridge to another. - -Requirements and installation ------------------------------ - -Just install the module: - - $ScriptInstallUpdate global-functions.d/bridge-port-to; - -Configuration -------------- - -The configuration goes to ports' comments (`/ interface bridge port`). - - / interface bridge port add bridge=br-guest comment="default=dhcp-client, alt=br-guest" disabled=yes interface=en1; - / interface bridge port add bridge=br-intern comment="default=br-intern, alt=br-guest" interface=en2; - / interface bridge port add bridge=br-guest comment="default=br-guest, extra=br-extra" interface=en3; - -Also dhcp client can be handled: - - / ip dhcp-client add comment="toggle with bridge port" disabled=no interface=en1; - -Add a scheduler to start with default setup on system startup: - - / system scheduler add name=bridge-port-to on-event=":global GlobalFunctionsReady; :while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }; :global BridgePortTo; \$BridgePortTo default;" start-time=startup; - -Usage and invocation --------------------- - -The usage examples show what happens with the configuration from above. - -Running the function `$BridgePortTo` with parameter `default` applies all -configuration given with `default=`: - - $BridgePortTo default; - -For the three interfaces we get this configuration: - -* The special value `dhcp-client` enables the dhcp client for interface `en1`. The bridge port entry is disabled. -* Interface `en2` is put in bridge `br-intern`. -* Interface `en3` is put in bridge `br-guest`. - -Running the function `$BridgePortTo` with parameter `alt` applies all -configuration given with `alt=`: - - $BridgePortTo alt; - -* Interface `en1` is put in bridge `br-guest`, dhcp client for the interface is disabled. -* Interface `en2` is put in bridge `br-guest`. -* Interface `en3` is unchanged, stays in bridge `br-guest`. - -Running the function `$BridgePortTo` with parameter `extra` applies another -configuration: - - $BridgePortTo extra; - -* Interfaces `en1` and `en2` are unchanged. -* Interface `en3` is put in bridge `br-intern`. - -See also --------- - -* [Manage VLANs on bridge ports](bridge-port-vlan.md) - ---- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) diff --git a/doc/global-functions.d/bridge-port-vlan.md b/doc/global-functions.d/bridge-port-vlan.md deleted file mode 100644 index 9df46b0..0000000 --- a/doc/global-functions.d/bridge-port-vlan.md +++ /dev/null @@ -1,83 +0,0 @@ -Manage VLANs on bridge ports -============================ - -[◀ Go back to main README](../../README.md) - -🛈 This module can not be used on its own but requires the base installation. -See [main README](../../README.md) for details. - -Description ------------ - -This module and its function are supposed to handle VLANs on bridge ports. - -Requirements and installation ------------------------------ - -Just install the module: - - $ScriptInstallUpdate global-functions.d/bridge-port-vlan; - -Configuration -------------- - -Using named VLANs you have to add comments in bridge vlan menu: - - / interface bridge vlan add bridge=bridge comment=intern tagged=br-local vlan-ids=10; - / interface bridge vlan add bridge=bridge comment=geust tagged=br-local vlan-ids=20; - / interface bridge vlan add bridge=bridge comment=extra tagged=br-local vlan-ids=30; - -The configuration goes to ports' comments (`/ interface bridge port`). - - / interface bridge port add bridge=bridge comment="default=dhcp-client, alt=guest" disabled=yes interface=en1; - / interface bridge port add bridge=bridge comment="default=intern, alt=guest, extra=30" interface=en2; - / interface bridge port add bridge=bridge comment="default=guest, extra=extra" interface=en3; - -Also dhcp client can be handled: - - / ip dhcp-client add comment="toggle with bridge port" disabled=no interface=en1; - -Add a scheduler to start with default setup on system startup: - - / system scheduler add name=bridge-port-vlan on-event=":global GlobalFunctionsReady; :while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }; :global BridgePortVlan; \$BridgePortVlan default;" start-time=startup; - -Usage and invocation --------------------- - -The usage examples show what happens with the configuration from above. - -Running the function `$BridgePortVlan` with parameter `default` applies all -configuration given with `default=`: - - $BridgePortVlan default; - -For the three interfaces we get this configuration: - -* The special value `dhcp-client` enables the dhcp client for interface `en1`. The bridge port entry is disabled. -* Primary VLAN `intern` (ID `10`) is configured on `en2`. -* Primary VLAN `guest` (ID `20`) is configured on `en3`. - -Running the function `$BridgePortVlan` with parameter `alt` applies all -configuration given with `alt=`: - - $BridgePortVlan alt; - -* Primary VLAN `guest` (ID `20`) is configured on `en1`, dhcp client for the interface is disabled. -* Primary VLAN `guest` (ID `20`) is configured on `en2`. -* Interface `en3` is unchanged, primary VLAN `guest` (ID `20`) is unchanged. - -Running the function `$BridgePortVlan` with parameter `extra` applies another -configuration: - -* Interface `en1` is unchanged. -* Primary VLAN `extra` (via its ID `30`) is configured on `en2`. -* Primary VLAN `extra` (ID `30`) is configured on `en3`. - -See also --------- - -* [Manage ports in bridge](bridge-port-to.md) - ---- -[◀ Go back to main README](../../README.md) -[▲ Go back to top](#top) diff --git a/doc/mod/bridge-port-to.md b/doc/mod/bridge-port-to.md new file mode 100644 index 0000000..89ee5d0 --- /dev/null +++ b/doc/mod/bridge-port-to.md @@ -0,0 +1,79 @@ +Manage ports in bridge +====================== + +[◀ Go back to main README](../README.md) + +🛈 This module can not be used on its own but requires the base installation. +See [main README](../README.md) for details. + +Description +----------- + +This module and its functio are are supposed to handle interfaces and +switching them from one bridge to another. + +Requirements and installation +----------------------------- + +Just install the module: + + $ScriptInstallUpdate mod/bridge-port-to; + +Configuration +------------- + +The configuration goes to ports' comments (`/ interface bridge port`). + + / interface bridge port add bridge=br-guest comment="default=dhcp-client, alt=br-guest" disabled=yes interface=en1; + / interface bridge port add bridge=br-intern comment="default=br-intern, alt=br-guest" interface=en2; + / interface bridge port add bridge=br-guest comment="default=br-guest, extra=br-extra" interface=en3; + +Also dhcp client can be handled: + + / ip dhcp-client add comment="toggle with bridge port" disabled=no interface=en1; + +Add a scheduler to start with default setup on system startup: + + / system scheduler add name=bridge-port-to on-event=":global GlobalFunctionsReady; :while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }; :global BridgePortTo; \$BridgePortTo default;" start-time=startup; + +Usage and invocation +-------------------- + +The usage examples show what happens with the configuration from above. + +Running the function `$BridgePortTo` with parameter `default` applies all +configuration given with `default=`: + + $BridgePortTo default; + +For the three interfaces we get this configuration: + +* The special value `dhcp-client` enables the dhcp client for interface `en1`. The bridge port entry is disabled. +* Interface `en2` is put in bridge `br-intern`. +* Interface `en3` is put in bridge `br-guest`. + +Running the function `$BridgePortTo` with parameter `alt` applies all +configuration given with `alt=`: + + $BridgePortTo alt; + +* Interface `en1` is put in bridge `br-guest`, dhcp client for the interface is disabled. +* Interface `en2` is put in bridge `br-guest`. +* Interface `en3` is unchanged, stays in bridge `br-guest`. + +Running the function `$BridgePortTo` with parameter `extra` applies another +configuration: + + $BridgePortTo extra; + +* Interfaces `en1` and `en2` are unchanged. +* Interface `en3` is put in bridge `br-intern`. + +See also +-------- + +* [Manage VLANs on bridge ports](bridge-port-vlan.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/mod/bridge-port-vlan.md b/doc/mod/bridge-port-vlan.md new file mode 100644 index 0000000..8b88777 --- /dev/null +++ b/doc/mod/bridge-port-vlan.md @@ -0,0 +1,83 @@ +Manage VLANs on bridge ports +============================ + +[◀ Go back to main README](../../README.md) + +🛈 This module can not be used on its own but requires the base installation. +See [main README](../../README.md) for details. + +Description +----------- + +This module and its function are supposed to handle VLANs on bridge ports. + +Requirements and installation +----------------------------- + +Just install the module: + + $ScriptInstallUpdate mod/bridge-port-vlan; + +Configuration +------------- + +Using named VLANs you have to add comments in bridge vlan menu: + + / interface bridge vlan add bridge=bridge comment=intern tagged=br-local vlan-ids=10; + / interface bridge vlan add bridge=bridge comment=geust tagged=br-local vlan-ids=20; + / interface bridge vlan add bridge=bridge comment=extra tagged=br-local vlan-ids=30; + +The configuration goes to ports' comments (`/ interface bridge port`). + + / interface bridge port add bridge=bridge comment="default=dhcp-client, alt=guest" disabled=yes interface=en1; + / interface bridge port add bridge=bridge comment="default=intern, alt=guest, extra=30" interface=en2; + / interface bridge port add bridge=bridge comment="default=guest, extra=extra" interface=en3; + +Also dhcp client can be handled: + + / ip dhcp-client add comment="toggle with bridge port" disabled=no interface=en1; + +Add a scheduler to start with default setup on system startup: + + / system scheduler add name=bridge-port-vlan on-event=":global GlobalFunctionsReady; :while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }; :global BridgePortVlan; \$BridgePortVlan default;" start-time=startup; + +Usage and invocation +-------------------- + +The usage examples show what happens with the configuration from above. + +Running the function `$BridgePortVlan` with parameter `default` applies all +configuration given with `default=`: + + $BridgePortVlan default; + +For the three interfaces we get this configuration: + +* The special value `dhcp-client` enables the dhcp client for interface `en1`. The bridge port entry is disabled. +* Primary VLAN `intern` (ID `10`) is configured on `en2`. +* Primary VLAN `guest` (ID `20`) is configured on `en3`. + +Running the function `$BridgePortVlan` with parameter `alt` applies all +configuration given with `alt=`: + + $BridgePortVlan alt; + +* Primary VLAN `guest` (ID `20`) is configured on `en1`, dhcp client for the interface is disabled. +* Primary VLAN `guest` (ID `20`) is configured on `en2`. +* Interface `en3` is unchanged, primary VLAN `guest` (ID `20`) is unchanged. + +Running the function `$BridgePortVlan` with parameter `extra` applies another +configuration: + +* Interface `en1` is unchanged. +* Primary VLAN `extra` (via its ID `30`) is configured on `en2`. +* Primary VLAN `extra` (ID `30`) is configured on `en3`. + +See also +-------- + +* [Manage ports in bridge](bridge-port-to.md) + +--- +[◀ Go back to main README](../../README.md) +[▲ Go back to top](#top) diff --git a/global-config b/global-config index 3905c8e..2ad80d7 100644 --- a/global-config +++ b/global-config @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! -:global GlobalConfigVersion 66; +:global GlobalConfigVersion 67; # This is used for DNS and backup file. :global Domain "example.com"; @@ -26,7 +26,7 @@ # You can send Telegram notifications. Register a bot # and add the token and chat ids here, then install the module: -# $ScriptInstallUpdate global-functions.d/notification-telegram +# $ScriptInstallUpdate mod/notification-telegram :global TelegramTokenId ""; :global TelegramChatId ""; #:global TelegramTokenId "123456:ABCDEF-GHI"; @@ -36,7 +36,7 @@ # You can send Matrix notifications. Configure these settings and # install the module: -# $ScriptInstallUpdate global-functions.d/notification-matrix +# $ScriptInstallUpdate mod/notification-matrix :global MatrixHomeServer ""; :global MatrixAccessToken ""; :global MatrixRoom ""; @@ -166,7 +166,7 @@ # Use this for defaults with $ScriptRunOnce # Install module with: -# $ScriptInstallUpdate global-functions.d/scriptrunonce +# $ScriptInstallUpdate mod/scriptrunonce :global ScriptRunOnceBaseUrl ""; :global ScriptRunOnceUrlSuffix ""; diff --git a/global-config-overlay b/global-config-overlay index 1570461..07280cd 100644 --- a/global-config-overlay +++ b/global-config-overlay @@ -8,7 +8,7 @@ # Make sure all configuration properties are up to date and this # value is in sync with value in script 'global-functions'! # Comment or remove to disable news and change notifications. -:global GlobalConfigVersion 66; +:global GlobalConfigVersion 67; # Copy configuration from global-config here and modify it. diff --git a/global-config.changes b/global-config.changes index 2561506..2f30563 100644 --- a/global-config.changes +++ b/global-config.changes @@ -70,6 +70,7 @@ 64="Implemented '\$InspectVar' in module to inspect variables."; 65="Added module to manage VLANs on bridge ports."; 66="Moved script 'bridge-port-to-default' to new module."; + 67="Moved modules to directory with shorter name."; }; # Migration steps to be applied on script updates @@ -77,7 +78,8 @@ 41=":global SendNotification; \$SendNotification (\"Migration mechanism\") (\"Congratulations!\nSuccessfully tested the new migration mechanism.\");"; 47="/ certificate remove [ find where fingerprint=\"731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568\" or fingerprint=\"25847d668eb4f04fdd40b12b6b0740c567da7d024308eb6c2c96fe41d9de218d\" ];"; 52=":global CertificateDownload; :if ([ :len [ / certificate find where fingerprint=\"67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd\" or fingerprint=\"96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6\" ] ] < 2) do={ \$CertificateDownload \"R3\"; }; / certificate remove [ find where fingerprint=\"0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739\" ];"; - 54=":global ScriptInstallUpdate; :global TelegramTokenId; :global TelegramChatId; :if ([ :len \$TelegramTokenId ] > 0 && [ :len \$TelegramChatId ] > 0) do={ \$ScriptInstallUpdate global-functions.d/notification-telegram; }"; + 54=":global ScriptInstallUpdate; :global TelegramTokenId; :global TelegramChatId; :if ([ :len \$TelegramTokenId ] > 0 && [ :len \$TelegramChatId ] > 0) do={ \$ScriptInstallUpdate mod/notification-telegram; }"; 61="/ system script remove [ find where name~\"^(early-errors|global-wait|mode-button-(event|scheduler)|script-updates)\\\$\" source~\"^#!rsc by RouterOS\\n\" ];"; - 66=":global ScriptInstallUpdate; :if ([ :len [ / system script find where name=\"bridge-port-to-default\" ] ] > 0) do={ / system script remove [ find where name~\"^bridge-port-to(-default|ggle)\\\$\" ]; \$ScriptInstallUpdate global-functions.d/bridge-port-to; }"; + 66=":global ScriptInstallUpdate; :if ([ :len [ / system script find where name=\"bridge-port-to-default\" ] ] > 0) do={ / system script remove [ find where name~\"^bridge-port-to(-default|ggle)\\\$\" ]; \$ScriptInstallUpdate mod/bridge-port-to; }"; + 67=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Script in=[ / system script find where name~\"^global-functions.d/\" ] do={ / system script set name=[ \$CharacterReplace [ / system script get \$Script name ] \"global-functions.d/\" \"mod/\" ] \$Script; }; \$ScriptInstallUpdate;"; }; diff --git a/global-functions b/global-functions index 813e4b4..85fdf40 100644 --- a/global-functions +++ b/global-functions @@ -8,7 +8,7 @@ # https://git.eworm.de/cgit/routeros-scripts/about/ # expected configuration version -:global ExpectedConfigVersion 66; +:global ExpectedConfigVersion 67; # global variables not to be changed by user :global GlobalFunctionsReady false; @@ -755,7 +755,7 @@ :if ($ScriptVal->"name" = "global-config") do={ :set ReloadGlobalConfig true; } - :if ($ScriptVal->"name" ~ ("^global-functions(\$|\\.d/.)")) do={ + :if ($ScriptVal->"name" = "global-functions" || $ScriptVal->"name" ~ ("^mod/.")) do={ :set ReloadGlobalFunctions true; } } else={ @@ -1242,7 +1242,7 @@ } # load modules -:foreach Script in=[ / system script find where name ~ "^global-functions\\.d/." ] do={ +:foreach Script in=[ / system script find where name ~ "^mod/." ] do={ / system script run $Script; } diff --git a/global-functions.d/bridge-port-to b/global-functions.d/bridge-port-to deleted file mode 100644 index 437cba7..0000000 --- a/global-functions.d/bridge-port-to +++ /dev/null @@ -1,54 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: global-functions.d/bridge-port-to -# Copyright (c) 2013-2021 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# reset bridge ports to default bridge -# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-functions.d/bridge-port-to.md - -:global BridgePortTo; - -:set BridgePortTo do={ - :local BridgePortTo [ :tostr $1 ]; - - :global IfThenElse; - :global LogPrintExit2; - :global ParseKeyValueStore; - - :foreach BridgePort in=[ / interface bridge port find where !(comment=[]) ] do={ - :local BridgePortVal [ / interface bridge port get $BridgePort ]; - :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ - :if ($Config = $BridgePortTo) do={ - :local DHCPClient [ / ip dhcp-client find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; - - :if ($BridgeDefault = "dhcp-client") do={ - :if ([ :len $DHCPClient ] != 1) do={ - $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ - " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; - } - :local DHCPClientDisabled [ / ip dhcp-client get $DHCPClient disabled ]; - - :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ - $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; - / interface bridge port disable $BridgePort; - :delay 200ms; - / ip dhcp-client enable $DHCPClient; - } - } else={ - :if ($BridgePortVal->"disabled" = true || $BridgeDefault != $BridgePortVal->"bridge") do={ - $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ - " bridge " . $BridgeDefault . ", disabling dhcp client.") false; - :if ([ :len $DHCPClient ] = 1) do={ - / ip dhcp-client disable $DHCPClient; - :delay 200ms; - } - / interface bridge port set disabled=no bridge=$BridgeDefault $BridgePort; - } else={ - $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ - " bridge " . $BridgeDefault . ".") false; - } - } - } - } - } -} diff --git a/global-functions.d/bridge-port-vlan b/global-functions.d/bridge-port-vlan deleted file mode 100644 index 754579a..0000000 --- a/global-functions.d/bridge-port-vlan +++ /dev/null @@ -1,62 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: global-functions.d/bridge-port-vlan -# Copyright (c) 2013-2021 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# manage VLANs on bridge ports -# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-functions.d/bridge-port-vlan.md - -:global BridgePortVlan; - -# TODO -:global BridgePortVlan do={ - :local ConfigTo [ :tostr $1 ]; - - :global IfThenElse; - :global LogPrintExit2; - :global ParseKeyValueStore; - - :foreach BridgePort in=[ / interface bridge port find where !(comment=[]) ] do={ - :local BridgePortVal [ / interface bridge port get $BridgePort ]; - :foreach Config,Vlan in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ - :if ($Config = $ConfigTo) do={ - :local DHCPClient [ / ip dhcp-client find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; - - :if ($Vlan = "dhcp-client") do={ - :if ([ :len $DHCPClient ] != 1) do={ - $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ - " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; - } - :local DHCPClientDisabled [ / ip dhcp-client get $DHCPClient disabled ]; - - :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ - $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; - / interface bridge port disable $BridgePort; - :delay 200ms; - / ip dhcp-client enable $DHCPClient; - } - } else={ - :if ($Vlan != [ :tostr [ :tonum $Vlan ] ]) do={ - :do { - :set $Vlan ([ / interface bridge vlan get [ find where comment=$Vlan ] vlan-ids ]->0); - } on-error={ - $LogPrintExit2 warning $0 ("Could not find VLAN '" . $Vlan . "' for interface " . $BridgePortVal->"interface" . "!") true; - } - } - :if ($BridgePortVal->"disabled" = true || $Vlan != $BridgePortVal->"pvid") do={ - $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $ConfigTo . \ - " vlan " . $Vlan . ", disabling dhcp client.") false; - :if ([ :len $DHCPClient ] = 1) do={ - / ip dhcp-client disable $DHCPClient; - :delay 200ms; - } - / interface bridge port set disabled=no pvid=$Vlan $BridgePort; - } else={ - $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \ - " vlan " . $Vlan . ".") false; - } - } - } - } - } -} diff --git a/global-functions.d/inspectvar b/global-functions.d/inspectvar deleted file mode 100644 index 15da04a..0000000 --- a/global-functions.d/inspectvar +++ /dev/null @@ -1,40 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: global-functions.d/inspectvar -# Copyright (c) 2020-2021 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md - -:global InspectVar; - -# inspect variable -:set InspectVar do={ - :local Input $1; - :local Level (0 + [ :tonum $2 ]); - - :global InspectVar; - - :local PutIndent do={ - :local Prefix [ :tostr $1 ]; - :local Value [ :tostr $2 ]; - :local Level [ :tonum $3 ]; - - :local Indent ""; - :for I from=1 to=$Level step=1 do={ - :set Indent ($Indent . " "); - } - :put ($Indent . "-" . $Prefix . "-> " . $Value); - } - - :local TypeOf [ :typeof $Input ]; - $PutIndent "type" $TypeOf $Level; - - :if ($TypeOf = "array") do={ - :foreach Key,Value in=$Input do={ - $PutIndent "key" $Key ($Level + 1); - $InspectVar $Value ($Level + 2); - } - } else={ - :if ($TypeOf != "nothing") do={ - $PutIndent "value" $Input $Level; - } - } -} diff --git a/global-functions.d/ipcalc b/global-functions.d/ipcalc deleted file mode 100644 index f146fbe..0000000 --- a/global-functions.d/ipcalc +++ /dev/null @@ -1,35 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: global-functions.d/ipcalc -# Copyright (c) 2020-2021 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md - -:global IPCalc; - -# calculate and print netmask, network, min host, max host and broadcast -:set IPCalc do={ - :local Input [ :tostr $1 ]; - :local Address [ :toip [ :pick $Input 0 [ :find $Input "/" ] ] ]; - :local Bits [ :tonum [ :pick $Input ([ :find $Input "/" ] + 1) [ :len $Input ] ] ]; - :local Mask ((255.255.255.255 << (32 - $Bits)) & 255.255.255.255); - - :local Return { - "address"=$Address; - "netmask"=$Mask; - "networkaddress"=($Address & $Mask); - "networkbits"=$Bits; - "network"=(($Address & $Mask) . "/" . $Bits); - "hostmin"=(($Address & $Mask) | 0.0.0.1); - "hostmax"=(($Address | ~$Mask) ^ 0.0.0.1); - "broadcast"=($Address | ~$Mask); - } - - :put ( \ - "Address: " . $Return->"address" . "\n\r" . \ - "Netmask: " . $Return->"netmask" . "\n\r" . \ - "Network: " . $Return->"network" . "\n\r" . \ - "HostMin: " . $Return->"hostmin" . "\n\r" . \ - "HostMax: " . $Return->"hostmax" . "\n\r" . \ - "Broadcast: " . $Return->"broadcast"); - - :return $Return; -} diff --git a/global-functions.d/notification-matrix b/global-functions.d/notification-matrix deleted file mode 100644 index a2f7af0..0000000 --- a/global-functions.d/notification-matrix +++ /dev/null @@ -1,157 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: global-functions.d/notification-matrix -# Copyright (c) 2013-2021 Michael Gisbers -# Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md - -:global FlushMatrixQueue; -:global NotificationFunctions; -:global SendMatrix; -:global SendMatrix2; - -# flush Matrix queue -:set FlushMatrixQueue do={ - :global MatrixQueue; - - :global LogPrintExit2; - - :local AllDone true; - :local QueueLen [ :len $MatrixQueue ]; - - :if ([ :len [ / system scheduler find where name="FlushMatrixQueue" ] ] > 0 && $QueueLen = 0) do={ - $LogPrintExit2 warning $0 ("Flushing Matrix messages from scheduler, but queue is empty.") false; - } - - :foreach Id,Message in=$MatrixQueue do={ - :if ([ :typeof $Message ] = "array" ) do={ - :do { - / tool fetch check-certificate=yes-without-crl output=none http-method=post \ - ("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \ - "/send/m.room.message?access_token=" . $Message->"accesstoken") \ - http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Message->"plain" . "\"," . \ - "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ - $Message->"formatted" . "\" }") as-value; - :set ($MatrixQueue->$Id); - } on-error={ - $LogPrintExit2 debug $0 ("Sending queued Matrix message failed.") false; - :set AllDone false; - } - } - } - - :if ($AllDone = true && $QueueLen = [ :len $MatrixQueue ]) do={ - / system scheduler remove [ find where name="FlushMatrixQueue" ]; - :set MatrixQueue; - } -} - -# send notification via Matrix - expects one array argument -:set ($NotificationFunctions->"matrix") do={ - :local Notification $1; - - :global Identity; - :global MatrixAccessToken; - :global MatrixAccessTokenOverride; - :global MatrixHomeServer; - :global MatrixHomeServerOverride; - :global MatrixQueue; - :global MatrixRoom; - :global MatrixRoomOverride; - - :global EitherOr; - :global LogPrintExit2; - :global SymbolForNotification; - - :local PrepareText do={ - :local Input [ :tostr $1 ]; - - :if ([ :len $Input ] = 0) do={ - :return ""; - } - - :local Return ""; - :local Chars { - "plain"={ "\\"; "\""; "\n" }; - "format"={ "\\"; "\""; "\n"; "&"; "<"; ">" }; - } - :local Subs { - "plain"={ "\\\\"; "\\\""; "\\n" }; - "format"={ "\\\\"; """; "
"; "&"; "<"; ">" }; - } - - :for I from=0 to=([ :len $Input ] - 1) do={ - :local Char [ :pick $Input $I ]; - :local Replace [ :find ($Chars->$2) $Char ]; - - :if ([ :typeof $Replace ] = "num") do={ - :set Char ($Subs->$2->$Replace); - } - :set Return ($Return . $Char); - } - - :return $Return; - } - - :local AccessToken [ $EitherOr ($MatrixAccessTokenOverride->($Notification->"origin")) $MatrixAccessToken ]; - :local HomeServer [ $EitherOr ($MatrixHomeServerOverride->($Notification->"origin")) $MatrixHomeServer ]; - :local Room [ $EitherOr ($MatrixRoomOverride->($Notification->"origin")) $MatrixRoom ]; - - :if ([ :len $AccessToken ] = 0 || [ :len $HomeServer ] = 0 || [ :len $Room ] = 0) do={ - :return false; - } - - :local Plain [ $PrepareText ("## [" . $Identity . "] " . ($Notification->"subject") . "\n```\n" . \ - ($Notification->"message") . "\n```") "plain" ]; - :local Formatted ("

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

" . \ - "
" . [ $PrepareText ($Notification->"message") "format" ] . "
"); - :if ([ :len ($Notification->"link") ] > 0) do={ - :set Plain ($Plain . "\\n" . [ $SymbolForNotification "link" ] . \ - [ $PrepareText ("[" . $Notification->"link" . "](" . $Notification->"link" . ")") "plain" ]); - :set Formatted ($Formatted . "
" . [ $SymbolForNotification "link" ] . \ - ""link") "format" ] . "\\\">" . \ - [ $PrepareText ($Notification->"link") "format" ] . ""); - } - - :do { - / tool fetch check-certificate=yes-without-crl output=none http-method=post \ - ("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \ - "/send/m.room.message?access_token=" . $AccessToken) \ - http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Plain . "\"," . \ - "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ - $Formatted . "\" }") as-value; - } on-error={ - $LogPrintExit2 info $0 ("Failed sending Matrix notification! Queuing...") false; - - :if ([ :typeof $MatrixQueue ] = "nothing") do={ - :set MatrixQueue [ :toarray "" ]; - } - :local Text ([ $SymbolForNotification "alarm-clock" ] . \ - "This message was queued since " . [ / system clock get date ] . \ - " " . [ / system clock get time ] . " and may be obsolete."); - :set Plain ($Plain . "\\n" . $Text); - :set Formatted ($Formatted . "
" . $Text); - :set ($MatrixQueue->[ :len $MatrixQueue ]) { room=$Room; \ - accesstoken=$AccessToken; homeserver=$HomeServer; \ - plain=$Plain; formatted=$Formatted }; - :if ([ :len [ / system scheduler find where name="FlushMatrixQueue" ] ] = 0) do={ - / system scheduler add name=FlushMatrixQueue interval=1m start-time=startup \ - on-event=(":global FlushMatrixQueue; \$FlushMatrixQueue;"); - } - } -} - -# send notification via Matrix - expects at lease two string arguments -:set SendMatrix do={ - :global SendMatrix2; - - $SendMatrix2 ({ subject=$1; message=$2; link=$3 }); -} - -# send notification via Matrix - expects one array argument -:set SendMatrix2 do={ - :local Notification $1; - - :global NotificationFunctions; - - ($NotificationFunctions->"matrix") ("\$NotificationFunctions->\"matrix\"") $Notification; -} diff --git a/global-functions.d/notification-telegram b/global-functions.d/notification-telegram deleted file mode 100644 index faf02d7..0000000 --- a/global-functions.d/notification-telegram +++ /dev/null @@ -1,164 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: global-functions.d/notification-telegram -# Copyright (c) 2013-2021 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md - -:global FlushTelegramQueue; -:global NotificationFunctions; -:global SendTelegram; -:global SendTelegram2; - -# flush telegram queue -:set FlushTelegramQueue do={ - :global TelegramQueue; - - :global LogPrintExit2; - - :local AllDone true; - :local QueueLen [ :len $TelegramQueue ]; - - :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] > 0 && $QueueLen = 0) do={ - $LogPrintExit2 warning $0 ("Flushing Telegram messages from scheduler, but queue is empty.") false; - } - - :foreach Id,Message in=$TelegramQueue do={ - :if ([ :typeof $Message ] = "array" ) do={ - :do { - / tool fetch check-certificate=yes-without-crl output=none http-method=post \ - ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ - http-data=("chat_id=" . ($Message->"chatid") . \ - "&disable_notification=" . ($Message->"silent") . \ - "&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \ - "&text=" . ($Message->"text")) as-value; - :set ($TelegramQueue->$Id); - } on-error={ - $LogPrintExit2 debug $0 ("Sending queued Telegram message failed.") false; - :set AllDone false; - } - } - } - - :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ - / system scheduler remove [ find where name="FlushTelegramQueue" ]; - :set TelegramQueue; - } -} - -# send notification via telegram - expects one array argument -:set ($NotificationFunctions->"telegram") do={ - :local Notification $1; - - :global Identity; - :global TelegramChatId; - :global TelegramChatIdOverride; - :global TelegramFixedWidthFont; - :global TelegramQueue; - :global TelegramTokenId; - :global TelegramTokenIdOverride; - - :global CertificateAvailable; - :global CharacterReplace; - :global EitherOr; - :global IfThenElse; - :global LogPrintExit2; - :global SymbolForNotification; - :global UrlEncode; - - :local EscapeMD do={ - :global TelegramFixedWidthFont; - - :global CharacterReplace; - :global IfThenElse; - - :if ($TelegramFixedWidthFont != true) do={ - :return ($1 . [ $IfThenElse ($2 = "body") ("\n") "" ]); - } - - :local Return $1; - :local Chars { - "body"={ "\\"; "`" }; - "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 ($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 ("[" . $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 Telegram 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") . \ - "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; - } on-error={ - $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; - - :if ([ :typeof $TelegramQueue ] = "nothing") do={ - :set TelegramQueue [ :toarray "" ]; - } - :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ - [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ - " " . [ / system clock get time ] . " and may be obsolete.") "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 \ - on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;"); - } - } -} - -# send notification via telegram - expects at lease two string arguments -:set SendTelegram do={ - :global SendTelegram2; - - $SendTelegram2 ({ subject=$1; message=$2; link=$3; silent=$4 }); -} - -# send notification via telegram - expects one array argument -:set SendTelegram2 do={ - :local Notification $1; - - :global NotificationFunctions; - - ($NotificationFunctions->"telegram") ("\$NotificationFunctions->\"telegram\"") $Notification; -} diff --git a/global-functions.d/scriptrunonce b/global-functions.d/scriptrunonce deleted file mode 100644 index ce9425b..0000000 --- a/global-functions.d/scriptrunonce +++ /dev/null @@ -1,46 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: global-functions.d/scriptrunonece -# Copyright (c) 2020-2021 Christian Hesse -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md - -:global ScriptRunOnce; - -# fetch and run script(s) once -:set ScriptRunOnce do={ - :local Scripts [ :toarray $1 ]; - - :global ScriptRunOnceBaseUrl; - :global ScriptRunOnceUrlSuffix; - - :global LogPrintExit2; - :global ValidateSyntax; - - :foreach Script in=$Scripts do={ - :if (!($Script ~ "^(ftp|https\?|sftp)://")) do={ - :if ([ :len $ScriptRunOnceBaseUrl ] = 0) do={ - $LogPrintExit2 warning $0 ("Script '" . $Script . "' is not an url and base url is not available.") true; - } - :set Script ($ScriptRunOnceBaseUrl . $Script . $ScriptRunOnceUrlSuffix); - } - - :local Source; - :do { - :set Source ([ / tool fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data"); - } on-error={ - $LogPrintExit2 warning $0 ("Failed fetching script '" . $Script . "'!") false; - } - - :if ([ :len $Source ] > 0) do={ - :if ([ $ValidateSyntax $Source ] = true) do={ - :do { - $LogPrintExit2 info $0 ("Running script '" . $Script . "' now.") false; - [ :parse $Source ]; - } on-error={ - $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed to run!") false; - } - } else={ - $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed syntax validation!") false; - } - } - } -} diff --git a/mod/bridge-port-to b/mod/bridge-port-to new file mode 100644 index 0000000..40b216c --- /dev/null +++ b/mod/bridge-port-to @@ -0,0 +1,54 @@ +#!rsc by RouterOS +# RouterOS script: mod/bridge-port-to +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# reset bridge ports to default bridge +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-to.md + +:global BridgePortTo; + +:set BridgePortTo do={ + :local BridgePortTo [ :tostr $1 ]; + + :global IfThenElse; + :global LogPrintExit2; + :global ParseKeyValueStore; + + :foreach BridgePort in=[ / interface bridge port find where !(comment=[]) ] do={ + :local BridgePortVal [ / interface bridge port get $BridgePort ]; + :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ + :if ($Config = $BridgePortTo) do={ + :local DHCPClient [ / ip dhcp-client find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; + + :if ($BridgeDefault = "dhcp-client") do={ + :if ([ :len $DHCPClient ] != 1) do={ + $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ + " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; + } + :local DHCPClientDisabled [ / ip dhcp-client get $DHCPClient disabled ]; + + :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ + $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; + / interface bridge port disable $BridgePort; + :delay 200ms; + / ip dhcp-client enable $DHCPClient; + } + } else={ + :if ($BridgePortVal->"disabled" = true || $BridgeDefault != $BridgePortVal->"bridge") do={ + $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ + " bridge " . $BridgeDefault . ", disabling dhcp client.") false; + :if ([ :len $DHCPClient ] = 1) do={ + / ip dhcp-client disable $DHCPClient; + :delay 200ms; + } + / interface bridge port set disabled=no bridge=$BridgeDefault $BridgePort; + } else={ + $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ + " bridge " . $BridgeDefault . ".") false; + } + } + } + } + } +} diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan new file mode 100644 index 0000000..bfe00e9 --- /dev/null +++ b/mod/bridge-port-vlan @@ -0,0 +1,62 @@ +#!rsc by RouterOS +# RouterOS script: mod/bridge-port-vlan +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# manage VLANs on bridge ports +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-vlan.md + +:global BridgePortVlan; + +# TODO +:global BridgePortVlan do={ + :local ConfigTo [ :tostr $1 ]; + + :global IfThenElse; + :global LogPrintExit2; + :global ParseKeyValueStore; + + :foreach BridgePort in=[ / interface bridge port find where !(comment=[]) ] do={ + :local BridgePortVal [ / interface bridge port get $BridgePort ]; + :foreach Config,Vlan in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ + :if ($Config = $ConfigTo) do={ + :local DHCPClient [ / ip dhcp-client find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; + + :if ($Vlan = "dhcp-client") do={ + :if ([ :len $DHCPClient ] != 1) do={ + $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ + " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; + } + :local DHCPClientDisabled [ / ip dhcp-client get $DHCPClient disabled ]; + + :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ + $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; + / interface bridge port disable $BridgePort; + :delay 200ms; + / ip dhcp-client enable $DHCPClient; + } + } else={ + :if ($Vlan != [ :tostr [ :tonum $Vlan ] ]) do={ + :do { + :set $Vlan ([ / interface bridge vlan get [ find where comment=$Vlan ] vlan-ids ]->0); + } on-error={ + $LogPrintExit2 warning $0 ("Could not find VLAN '" . $Vlan . "' for interface " . $BridgePortVal->"interface" . "!") true; + } + } + :if ($BridgePortVal->"disabled" = true || $Vlan != $BridgePortVal->"pvid") do={ + $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $ConfigTo . \ + " vlan " . $Vlan . ", disabling dhcp client.") false; + :if ([ :len $DHCPClient ] = 1) do={ + / ip dhcp-client disable $DHCPClient; + :delay 200ms; + } + / interface bridge port set disabled=no pvid=$Vlan $BridgePort; + } else={ + $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \ + " vlan " . $Vlan . ".") false; + } + } + } + } + } +} diff --git a/mod/inspectvar b/mod/inspectvar new file mode 100644 index 0000000..4e10fd6 --- /dev/null +++ b/mod/inspectvar @@ -0,0 +1,40 @@ +#!rsc by RouterOS +# RouterOS script: mod/inspectvar +# Copyright (c) 2020-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global InspectVar; + +# inspect variable +:set InspectVar do={ + :local Input $1; + :local Level (0 + [ :tonum $2 ]); + + :global InspectVar; + + :local PutIndent do={ + :local Prefix [ :tostr $1 ]; + :local Value [ :tostr $2 ]; + :local Level [ :tonum $3 ]; + + :local Indent ""; + :for I from=1 to=$Level step=1 do={ + :set Indent ($Indent . " "); + } + :put ($Indent . "-" . $Prefix . "-> " . $Value); + } + + :local TypeOf [ :typeof $Input ]; + $PutIndent "type" $TypeOf $Level; + + :if ($TypeOf = "array") do={ + :foreach Key,Value in=$Input do={ + $PutIndent "key" $Key ($Level + 1); + $InspectVar $Value ($Level + 2); + } + } else={ + :if ($TypeOf != "nothing") do={ + $PutIndent "value" $Input $Level; + } + } +} diff --git a/mod/ipcalc b/mod/ipcalc new file mode 100644 index 0000000..64a03a9 --- /dev/null +++ b/mod/ipcalc @@ -0,0 +1,35 @@ +#!rsc by RouterOS +# RouterOS script: mod/ipcalc +# Copyright (c) 2020-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global IPCalc; + +# calculate and print netmask, network, min host, max host and broadcast +:set IPCalc do={ + :local Input [ :tostr $1 ]; + :local Address [ :toip [ :pick $Input 0 [ :find $Input "/" ] ] ]; + :local Bits [ :tonum [ :pick $Input ([ :find $Input "/" ] + 1) [ :len $Input ] ] ]; + :local Mask ((255.255.255.255 << (32 - $Bits)) & 255.255.255.255); + + :local Return { + "address"=$Address; + "netmask"=$Mask; + "networkaddress"=($Address & $Mask); + "networkbits"=$Bits; + "network"=(($Address & $Mask) . "/" . $Bits); + "hostmin"=(($Address & $Mask) | 0.0.0.1); + "hostmax"=(($Address | ~$Mask) ^ 0.0.0.1); + "broadcast"=($Address | ~$Mask); + } + + :put ( \ + "Address: " . $Return->"address" . "\n\r" . \ + "Netmask: " . $Return->"netmask" . "\n\r" . \ + "Network: " . $Return->"network" . "\n\r" . \ + "HostMin: " . $Return->"hostmin" . "\n\r" . \ + "HostMax: " . $Return->"hostmax" . "\n\r" . \ + "Broadcast: " . $Return->"broadcast"); + + :return $Return; +} diff --git a/mod/notification-matrix b/mod/notification-matrix new file mode 100644 index 0000000..a78539f --- /dev/null +++ b/mod/notification-matrix @@ -0,0 +1,157 @@ +#!rsc by RouterOS +# RouterOS script: mod/notification-matrix +# Copyright (c) 2013-2021 Michael Gisbers +# Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global FlushMatrixQueue; +:global NotificationFunctions; +:global SendMatrix; +:global SendMatrix2; + +# flush Matrix queue +:set FlushMatrixQueue do={ + :global MatrixQueue; + + :global LogPrintExit2; + + :local AllDone true; + :local QueueLen [ :len $MatrixQueue ]; + + :if ([ :len [ / system scheduler find where name="FlushMatrixQueue" ] ] > 0 && $QueueLen = 0) do={ + $LogPrintExit2 warning $0 ("Flushing Matrix messages from scheduler, but queue is empty.") false; + } + + :foreach Id,Message in=$MatrixQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :do { + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \ + "/send/m.room.message?access_token=" . $Message->"accesstoken") \ + http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Message->"plain" . "\"," . \ + "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ + $Message->"formatted" . "\" }") as-value; + :set ($MatrixQueue->$Id); + } on-error={ + $LogPrintExit2 debug $0 ("Sending queued Matrix message failed.") false; + :set AllDone false; + } + } + } + + :if ($AllDone = true && $QueueLen = [ :len $MatrixQueue ]) do={ + / system scheduler remove [ find where name="FlushMatrixQueue" ]; + :set MatrixQueue; + } +} + +# send notification via Matrix - expects one array argument +:set ($NotificationFunctions->"matrix") do={ + :local Notification $1; + + :global Identity; + :global MatrixAccessToken; + :global MatrixAccessTokenOverride; + :global MatrixHomeServer; + :global MatrixHomeServerOverride; + :global MatrixQueue; + :global MatrixRoom; + :global MatrixRoomOverride; + + :global EitherOr; + :global LogPrintExit2; + :global SymbolForNotification; + + :local PrepareText do={ + :local Input [ :tostr $1 ]; + + :if ([ :len $Input ] = 0) do={ + :return ""; + } + + :local Return ""; + :local Chars { + "plain"={ "\\"; "\""; "\n" }; + "format"={ "\\"; "\""; "\n"; "&"; "<"; ">" }; + } + :local Subs { + "plain"={ "\\\\"; "\\\""; "\\n" }; + "format"={ "\\\\"; """; "
"; "&"; "<"; ">" }; + } + + :for I from=0 to=([ :len $Input ] - 1) do={ + :local Char [ :pick $Input $I ]; + :local Replace [ :find ($Chars->$2) $Char ]; + + :if ([ :typeof $Replace ] = "num") do={ + :set Char ($Subs->$2->$Replace); + } + :set Return ($Return . $Char); + } + + :return $Return; + } + + :local AccessToken [ $EitherOr ($MatrixAccessTokenOverride->($Notification->"origin")) $MatrixAccessToken ]; + :local HomeServer [ $EitherOr ($MatrixHomeServerOverride->($Notification->"origin")) $MatrixHomeServer ]; + :local Room [ $EitherOr ($MatrixRoomOverride->($Notification->"origin")) $MatrixRoom ]; + + :if ([ :len $AccessToken ] = 0 || [ :len $HomeServer ] = 0 || [ :len $Room ] = 0) do={ + :return false; + } + + :local Plain [ $PrepareText ("## [" . $Identity . "] " . ($Notification->"subject") . "\n```\n" . \ + ($Notification->"message") . "\n```") "plain" ]; + :local Formatted ("

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

" . \ + "
" . [ $PrepareText ($Notification->"message") "format" ] . "
"); + :if ([ :len ($Notification->"link") ] > 0) do={ + :set Plain ($Plain . "\\n" . [ $SymbolForNotification "link" ] . \ + [ $PrepareText ("[" . $Notification->"link" . "](" . $Notification->"link" . ")") "plain" ]); + :set Formatted ($Formatted . "
" . [ $SymbolForNotification "link" ] . \ + ""link") "format" ] . "\\\">" . \ + [ $PrepareText ($Notification->"link") "format" ] . ""); + } + + :do { + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \ + "/send/m.room.message?access_token=" . $AccessToken) \ + http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Plain . "\"," . \ + "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ + $Formatted . "\" }") as-value; + } on-error={ + $LogPrintExit2 info $0 ("Failed sending Matrix notification! Queuing...") false; + + :if ([ :typeof $MatrixQueue ] = "nothing") do={ + :set MatrixQueue [ :toarray "" ]; + } + :local Text ([ $SymbolForNotification "alarm-clock" ] . \ + "This message was queued since " . [ / system clock get date ] . \ + " " . [ / system clock get time ] . " and may be obsolete."); + :set Plain ($Plain . "\\n" . $Text); + :set Formatted ($Formatted . "
" . $Text); + :set ($MatrixQueue->[ :len $MatrixQueue ]) { room=$Room; \ + accesstoken=$AccessToken; homeserver=$HomeServer; \ + plain=$Plain; formatted=$Formatted }; + :if ([ :len [ / system scheduler find where name="FlushMatrixQueue" ] ] = 0) do={ + / system scheduler add name=FlushMatrixQueue interval=1m start-time=startup \ + on-event=(":global FlushMatrixQueue; \$FlushMatrixQueue;"); + } + } +} + +# send notification via Matrix - expects at lease two string arguments +:set SendMatrix do={ + :global SendMatrix2; + + $SendMatrix2 ({ subject=$1; message=$2; link=$3 }); +} + +# send notification via Matrix - expects one array argument +:set SendMatrix2 do={ + :local Notification $1; + + :global NotificationFunctions; + + ($NotificationFunctions->"matrix") ("\$NotificationFunctions->\"matrix\"") $Notification; +} diff --git a/mod/notification-telegram b/mod/notification-telegram new file mode 100644 index 0000000..d575103 --- /dev/null +++ b/mod/notification-telegram @@ -0,0 +1,164 @@ +#!rsc by RouterOS +# RouterOS script: mod/notification-telegram +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global FlushTelegramQueue; +:global NotificationFunctions; +:global SendTelegram; +:global SendTelegram2; + +# flush telegram queue +:set FlushTelegramQueue do={ + :global TelegramQueue; + + :global LogPrintExit2; + + :local AllDone true; + :local QueueLen [ :len $TelegramQueue ]; + + :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] > 0 && $QueueLen = 0) do={ + $LogPrintExit2 warning $0 ("Flushing Telegram messages from scheduler, but queue is empty.") false; + } + + :foreach Id,Message in=$TelegramQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :do { + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ + http-data=("chat_id=" . ($Message->"chatid") . \ + "&disable_notification=" . ($Message->"silent") . \ + "&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \ + "&text=" . ($Message->"text")) as-value; + :set ($TelegramQueue->$Id); + } on-error={ + $LogPrintExit2 debug $0 ("Sending queued Telegram message failed.") false; + :set AllDone false; + } + } + } + + :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ + / system scheduler remove [ find where name="FlushTelegramQueue" ]; + :set TelegramQueue; + } +} + +# send notification via telegram - expects one array argument +:set ($NotificationFunctions->"telegram") do={ + :local Notification $1; + + :global Identity; + :global TelegramChatId; + :global TelegramChatIdOverride; + :global TelegramFixedWidthFont; + :global TelegramQueue; + :global TelegramTokenId; + :global TelegramTokenIdOverride; + + :global CertificateAvailable; + :global CharacterReplace; + :global EitherOr; + :global IfThenElse; + :global LogPrintExit2; + :global SymbolForNotification; + :global UrlEncode; + + :local EscapeMD do={ + :global TelegramFixedWidthFont; + + :global CharacterReplace; + :global IfThenElse; + + :if ($TelegramFixedWidthFont != true) do={ + :return ($1 . [ $IfThenElse ($2 = "body") ("\n") "" ]); + } + + :local Return $1; + :local Chars { + "body"={ "\\"; "`" }; + "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 ($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 ("[" . $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 Telegram 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") . \ + "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; + } on-error={ + $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; + + :if ([ :typeof $TelegramQueue ] = "nothing") do={ + :set TelegramQueue [ :toarray "" ]; + } + :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ + [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ + " " . [ / system clock get time ] . " and may be obsolete.") "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 \ + on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;"); + } + } +} + +# send notification via telegram - expects at lease two string arguments +:set SendTelegram do={ + :global SendTelegram2; + + $SendTelegram2 ({ subject=$1; message=$2; link=$3; silent=$4 }); +} + +# send notification via telegram - expects one array argument +:set SendTelegram2 do={ + :local Notification $1; + + :global NotificationFunctions; + + ($NotificationFunctions->"telegram") ("\$NotificationFunctions->\"telegram\"") $Notification; +} diff --git a/mod/scriptrunonce b/mod/scriptrunonce new file mode 100644 index 0000000..0b519c3 --- /dev/null +++ b/mod/scriptrunonce @@ -0,0 +1,46 @@ +#!rsc by RouterOS +# RouterOS script: mod/scriptrunonece +# Copyright (c) 2020-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +:global ScriptRunOnce; + +# fetch and run script(s) once +:set ScriptRunOnce do={ + :local Scripts [ :toarray $1 ]; + + :global ScriptRunOnceBaseUrl; + :global ScriptRunOnceUrlSuffix; + + :global LogPrintExit2; + :global ValidateSyntax; + + :foreach Script in=$Scripts do={ + :if (!($Script ~ "^(ftp|https\?|sftp)://")) do={ + :if ([ :len $ScriptRunOnceBaseUrl ] = 0) do={ + $LogPrintExit2 warning $0 ("Script '" . $Script . "' is not an url and base url is not available.") true; + } + :set Script ($ScriptRunOnceBaseUrl . $Script . $ScriptRunOnceUrlSuffix); + } + + :local Source; + :do { + :set Source ([ / tool fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data"); + } on-error={ + $LogPrintExit2 warning $0 ("Failed fetching script '" . $Script . "'!") false; + } + + :if ([ :len $Source ] > 0) do={ + :if ([ $ValidateSyntax $Source ] = true) do={ + :do { + $LogPrintExit2 info $0 ("Running script '" . $Script . "' now.") false; + [ :parse $Source ]; + } on-error={ + $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed to run!") false; + } + } else={ + $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed syntax validation!") false; + } + } + } +} -- cgit v1.2.3-70-g09d2