Merge branch 'main-function' into next

This commit is contained in:
Christian Hesse 2024-03-04 17:53:35 +01:00
commit 771ca341b0
64 changed files with 3865 additions and 3547 deletions

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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 ];

View file

@ -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";

View file

@ -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;

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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;

View file

@ -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;

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];

View file

@ -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 ];