global: variable names are CamelCase

___  _         ___     __
           / _ )(_)__ _   / _/__ _/ /_
          / _  / / _ `/  / _/ _ `/ __/
         /____/_/\_, /  /_/ \_,_/\__/
 _       __     /___/       _             __
| |     / /___ __________  (_)___  ____ _/ /
| | /| / / __ `/ ___/ __ \/ / __ \/ __ `/ /
| |/ |/ / /_/ / /  / / / / / / / / /_/ /_/
|__/|__/\__,_/_/  /_/ /_/_/_/ /_/\__, (_)
                                /____/

RouterOS has some odd behavior when it comes to variable names. Let's
have a look at the interfaces:

[admin@MikroTik] > / interface print where name=en1
Flags: D - dynamic, X - disabled, R - running, S - slave
 #     NAME                                TYPE       ACTUAL-MTU L2MTU
 0  RS en1                                 ether            1500  1598

That looks ok. Now we use a script:

{ :local interface "en1";
  / interface print where name=$interface; }

And the result...

[admin@MikroTik] > { :local interface "en1";
{...   / interface print where name=$interface; }
Flags: D - dynamic, X - disabled, R - running, S - slave
 #     NAME                                TYPE       ACTUAL-MTU L2MTU
 0  RS en1                                 ether            1500  1598

... still looks ok.
We make a little modification to the script:

{ :local name "en1";
  / interface print where name=$name; }

And the result:

[admin@MikroTik] > { :local name "en1";
{...   / interface print where name=$name; }
Flags: D - dynamic, X - disabled, R - running, S - slave
 #     NAME                                TYPE       ACTUAL-MTU L2MTU
 0  RS en1                                 ether            1500  1598
 1   S en2                                 ether            1500  1598
 2   S en3                                 ether            1500  1598
 3   S en4                                 ether            1500  1598
 4   S en5                                 ether            1500  1598
 5  R  br-local                            bridge           1500  1598

Ups! The filter has no effect!
That happens whenever the variable name ($name) matches the property
name (name=).

And another modification:

{ :local type "en1";
  / interface print where name=$type; }

And the result:

[admin@MikroTik] > { :local type "en1";
{...   / interface print where name=$type; }
Flags: D - dynamic, X - disabled, R - running, S - slave
 #     NAME                                TYPE       ACTUAL-MTU L2MTU

Ups! Nothing?
Even if the variable name ($type) matches whatever property name (type=)
things go wrong.

The answer from MikroTik support (in Ticket#2019010222000454):

> This is how scripting works in RouterOS and we will not fix it.

To get around this we use variable names in CamelCase. Let's hope
Mikrotik never ever introduces property names in CamelCase...

*fingers crossed*
This commit is contained in:
Christian Hesse 2019-01-03 17:45:43 +01:00
parent 7d06a7e8c2
commit 870f00bb36
41 changed files with 770 additions and 777 deletions

View file

@ -78,7 +78,7 @@ crap and a good example how to *not* do it.
Now let's download the main scripts and add them in configuration on the fly. Now let's download the main scripts and add them in configuration on the fly.
[admin@MikroTik] > :foreach script in={ "global-config"; "global-functions"; "script-updates" } do={ / system script add name=$script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit.cgi/routeros-scripts/plain/" . $script) output=user as-value]->"data"); } [admin@MikroTik] > :foreach Script in={ "global-config"; "global-functions"; "script-updates" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit.cgi/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); }
The configuration needs to be tweaked for your needs. Make sure not to send The configuration needs to be tweaked for your needs. Make sure not to send
your mails to `mail@example.com`! your mails to `mail@example.com`!

View file

@ -6,31 +6,31 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local seen [ :toarray "" ];
:local shown [ :toarray "" ];
:global Read; :global Read;
:foreach acclist in=[ / caps-man access-list find where mac-address!="00:00:00:00:00:00" ] do={ :local Seen [ :toarray "" ];
:local mac [ / caps-man access-list get $acclist mac-address ]; :local Shown [ :toarray "" ];
:foreach "seen-mac" in=$seen do={
:if ($"seen-mac" = $mac) do={ :foreach AccList in=[ / caps-man access-list find where mac-address!="00:00:00:00:00:00" ] do={
:local skip 0; :local Mac [ / caps-man access-list get $AccList mac-address ];
:foreach "shown-mac" in=$shown do={ :foreach SeenMac in=$Seen do={
:if ($"shown-mac" = $mac) do={ :set skip 1; } :if ($SeenMac = $Mac) do={
:local Skip 0;
:foreach ShownMac in=$Shown do={
:if ($ShownMac = $Mac) do={ :set Skip 1; }
} }
:if ($skip = 0) do={ :if ($Skip = 0) do={
/ caps-man access-list print where mac-address=$mac; / caps-man access-list print where mac-address=$Mac;
:set shown ( $shown , $mac ); :set Shown ($Shown, $Mac);
:put "\nEnter to skip, numeric id to remove!"; :put "\nEnter to skip, numeric id to remove!";
:local remove [ $Read ]; :local Remove [ $Read ];
:if ($remove != "") do={ :if ($Remove != "") do={
:put ("Removing numeric id " . $remove . "...\n"); :put ("Removing numeric id " . $Remove . "...\n");
/ caps-man access-list remove $remove; / caps-man access-list remove $Remove;
} }
} }
} }
} }
:set seen ( $seen , $mac ); :set Seen ($Seen, $Mac);
} }

View file

@ -6,31 +6,31 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local seen [ :toarray "" ];
:local shown [ :toarray "" ];
:global Read; :global Read;
:foreach acclist in=[ / interface wireless access-list find where mac-address!="00:00:00:00:00:00" ] do={ :local Seen [ :toarray "" ];
:local mac [ / interface wireless access-list get $acclist mac-address ]; :local Shown [ :toarray "" ];
:foreach "seen-mac" in=$seen do={
:if ($"seen-mac" = $mac) do={ :foreach AccList in=[ / interface wireless access-list find where mac-address!="00:00:00:00:00:00" ] do={
:local skip 0; :local Mac [ / interface wireless access-list get $AccList mac-address ];
:foreach "shown-mac" in=$shown do={ :foreach SeenMac in=$Seen do={
:if ($"shown-mac" = $mac) do={ :set skip 1; } :if ($SeenMac = $Mac) do={
:local Skip 0;
:foreach ShownMac in=$Shown do={
:if ($ShownMac = $Mac) do={ :set Skip 1; }
} }
:if ($skip = 0) do={ :if ($Skip = 0) do={
/ interface wireless access-list print where mac-address=$mac; / interface wireless access-list print where mac-address=$Mac;
:set shown ( $shown , $mac ); :set Shown ($Shown, $Mac);
:put "\nEnter to skip, numeric id to remove!"; :put "\nEnter to skip, numeric id to remove!";
:local remove [ $Read ]; :local Remove [ $Read ];
:if ($remove != "") do={ :if ($Remove != "") do={
:put ("Removing numeric id " . $remove . "...\n"); :put ("Removing numeric id " . $Remove . "...\n");
/ interface wireless access-list remove $remove; / interface wireless access-list remove $Remove;
} }
} }
} }
} }
:set seen ( $seen , $mac ); :set Seen ($Seen, $Mac);
} }

View file

@ -7,31 +7,31 @@
# !! This is just a template! Replace '%PATH%' with 'caps-man' # !! This is just a template! Replace '%PATH%' with 'caps-man'
# !! or 'interface wireless'! # !! or 'interface wireless'!
:local seen [ :toarray "" ];
:local shown [ :toarray "" ];
:global Read; :global Read;
:foreach acclist in=[ / %PATH% access-list find where mac-address!="00:00:00:00:00:00" ] do={ :local Seen [ :toarray "" ];
:local mac [ / %PATH% access-list get $acclist mac-address ]; :local Shown [ :toarray "" ];
:foreach "seen-mac" in=$seen do={
:if ($"seen-mac" = $mac) do={ :foreach AccList in=[ / %PATH% access-list find where mac-address!="00:00:00:00:00:00" ] do={
:local skip 0; :local Mac [ / %PATH% access-list get $AccList mac-address ];
:foreach "shown-mac" in=$shown do={ :foreach SeenMac in=$Seen do={
:if ($"shown-mac" = $mac) do={ :set skip 1; } :if ($SeenMac = $Mac) do={
:local Skip 0;
:foreach ShownMac in=$Shown do={
:if ($ShownMac = $Mac) do={ :set Skip 1; }
} }
:if ($skip = 0) do={ :if ($Skip = 0) do={
/ %PATH% access-list print where mac-address=$mac; / %PATH% access-list print where mac-address=$Mac;
:set shown ( $shown , $mac ); :set Shown ($Shown, $Mac);
:put "\nEnter to skip, numeric id to remove!"; :put "\nEnter to skip, numeric id to remove!";
:local remove [ $Read ]; :local Remove [ $Read ];
:if ($remove != "") do={ :if ($Remove != "") do={
:put ("Removing numeric id " . $remove . "...\n"); :put ("Removing numeric id " . $Remove . "...\n");
/ %PATH% access-list remove $remove; / %PATH% access-list remove $Remove;
} }
} }
} }
} }
:set seen ( $seen , $mac ); :set Seen ($Seen, $Mac);
} }

View file

@ -4,27 +4,27 @@
# #
# reset bridge ports to default bridge # reset bridge ports to default bridge
:global "bridge-port-to"; :global BridgePortTo;
:local "len" ([ :len $"bridge-port-to" ] + 1); :local Len ([ :len $BridgePortTo ] + 1);
:if ($"len" = 1) do={ :if ($Len = 1) do={
:delay 1s; :delay 1s;
:set "len" ([ :len $"bridge-port-to" ] + 1); :set Len ([ :len $BridgePortTo ] + 1);
} }
:foreach interface in=[ / interface bridge port find where comment!="" ] do={ :foreach Interface in=[ / interface bridge port find where comment!="" ] do={
:foreach comment in=[ :toarray [ / interface bridge port get $interface comment ] ] do={ :foreach Comment in=[ :toarray [ / interface bridge port get $Interface comment ] ] do={
:if ([ :pick $comment 0 $len ] = ($"bridge-port-to" . ":")) do={ :if ([ :pick $Comment 0 $Len ] = ($BridgePortTo . ":")) do={
:local "interface-name" [ / interface bridge port get $interface interface ]; :local InterfaceName [ / interface bridge port get $Interface interface ];
:local "bridge-default" [ :pick $comment $len [ :len $comment ] ]; :local BridgeDefault [ :pick $Comment $Len [ :len $Comment ] ];
:local "bridge-current" [ / interface bridge port get $interface bridge ]; :local BridgeCurrent [ / interface bridge port get $Interface bridge ];
:if ($"bridge-default" != $"bridge-current") do={ :if ($BridgeDefault != $BridgeCurrent) do={
:log info ("Changing interface " . $"interface-name" . " to " . $"bridge-port-to" . " bridge " . $"bridge-default"); :log info ("Changing interface " . $InterfaceName . " to " . $BridgePortTo . " bridge " . $BridgeDefault);
/ interface bridge port set bridge=$"bridge-default" $interface; / interface bridge port set bridge=$BridgeDefault $Interface;
/ ip dhcp-client renew [ find where interface=$"bridge-default" ]; / ip dhcp-client renew [ find where interface=$BridgeDefault ];
} else={ } else={
:log debug ("Interface " . $"interface-name" . " already connected to " . $"bridge-port-to" . " bridge " . $"bridge-default"); :log debug ("Interface " . $InterfaceName . " already connected to " . $BridgePortTo . " bridge " . $BridgeDefault);
} }
} }
} }

View file

@ -4,12 +4,12 @@
# #
# toggle bridge ports between default and alt bridge # toggle bridge ports between default and alt bridge
:global "bridge-port-to"; :global BridgePortTo;
:if ($"bridge-port-to" != "default") do={ :if ($BridgePortTo != "default") do={
:set "bridge-port-to" "default"; :set BridgePortTo "default";
} else={ } else={
:set "bridge-port-to" "alt"; :set BridgePortTo "alt";
} }
/ system script run bridge-port-to-default; / system script run bridge-port-to-default;

View file

@ -9,29 +9,29 @@
:global DownloadPackage; :global DownloadPackage;
:local "package-path" [ / caps-man manager get package-path ]; :local PackagePath [ / caps-man manager get package-path ];
:if ([ :pick $"package-path" 0 ] = "/") do={ :if ([ :pick $PackagePath 0 ] = "/") do={
:set "package-path" [ :pick $"package-path" 1 [ :len $"package-path" ] ]; :set PackagePath [ :pick $PackagePath 1 [ :len $PackagePath ] ];
} }
:local "installed-version" [ / system package update get installed-version ]; :local InstalledVersion [ / system package update get installed-version ];
:local updated false; :local Updated false;
:foreach package in=[ / file find where type=package \ :foreach Package in=[ / file find where type=package \
package-version!=$"installed-version" name~("^" . $"package-path") ] do={ package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={
:local "package-name" [ / file get $package package-name ]; :local PackageName [ / file get $Package package-name ];
:local "package-architecture" [ / file get $package package-architecture ]; :local PackageArchitecture [ / file get $Package package-architecture ];
:if ($"package-architecture" = "mips") do={ :if ($PackageArchitecture = "mips") do={
:set "package-architecture" "mipsbe"; :set PackageArchitecture "mipsbe";
} }
:if ($"package-name" = "wireless@") do={ :if ($PackageName = "wireless@") do={
:set "package-name" "wireless"; :set PackageName "wireless";
} }
:if ([ $DownloadPackage $"package-name" $"installed-version" $"package-architecture" $"package-path" ] = true) do={ :if ([ $DownloadPackage $PackageName $InstalledVersion $PackageArchitecture $PackagePath ] = true) do={
:set updated true; :set Updated true;
/ file remove $package; / file remove $Package;
} }
} }
:if ($updated = true) do={ :if ($Updated = true) do={
/ caps-man remote-cap upgrade [ find where version!=$"installed-version" ]; / caps-man remote-cap upgrade [ find where version!=$InstalledVersion ];
} }

View file

@ -4,83 +4,82 @@
# #
# check for certificate validity # check for certificate validity
:global "identity"; :global Identity;
:global "cert-renew-url"; :global CertRenewUrl;
:global "cert-renew-pass"; :global CertRenewPass;
:global SendNotification; :global SendNotification;
:local months ("jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"); :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun";
"jul"; "aug"; "sep"; "oct"; "nov"; "dec" };
:local currentdate [ / system clock get date ]; :local CurrentDate [ / system clock get date ];
:local currentmonthstr [ :pick $currentdate 0 3 ]; :local CurrentDay [ :pick $CurrentDate 4 6 ];
:local currentday [ :pick $currentdate 4 6 ]; :local CurrentYear [ :pick $CurrentDate 7 11 ];
:local currentyear [ :pick $currentdate 7 11 ]; :local CurrentMonth ([ :find $Months [ :pick $CurrentDate 0 3 ] ] + 1);
:local currentmonth ([ :find $months $currentmonthstr -1 ] + 1); :local CurrentStamp ($CurrentYear * 365 + $CurrentMonth * 30 + $CurrentDay);
:local currentstamp ($currentyear * 365 + $currentmonth * 30 + $currentday);
:foreach cert in=[ / certificate find where !revoked ] do={ :foreach Cert in=[ / certificate find where !revoked ] do={
:local certname [ / certificate get $cert name ]; :local CertName [ / certificate get $Cert name ];
:local invaliddate [ / certificate get $cert invalid-after ]; :local InvalidDate [ / certificate get $Cert invalid-after ];
:if ([ :len $invaliddate ] > 0) do={ :if ([ :len $InvalidDate ] > 0) do={
:local invalidmonthstr [ :pick $invaliddate 0 3 ]; :local InvalidDay [ :pick $InvalidDate 4 6 ];
:local invalidday [ :pick $invaliddate 4 6 ]; :local InvalidYear [ :pick $InvalidDate 7 11 ];
:local invalidyear [ :pick $invaliddate 7 11 ]; :local InvalidMonth ([ :find $Months [ :pick $InvalidDate 0 3 ] ] + 1);
:local invalidmonth ([ :find $months $invalidmonthstr -1 ] + 1); :local InvalidStamp ($InvalidYear * 365 + $InvalidMonth * 30 + $InvalidDay);
:local invalidstamp ($invalidyear * 365 + invalidmonth * 30 + invalidday);
:local remaining ($invalidstamp - $currentstamp); :local Remaining ($InvalidStamp - $CurrentStamp);
:if ($remaining < 15) do={ :if ($Remaining < 15) do={
:local commonname [ / certificate get $cert common-name ]; :local CommonName [ / certificate get $Cert common-name ];
:local fprint [ / certificate get $cert fingerprint ]; :local FingerPrint [ / certificate get $Cert fingerprint ];
:do { :do {
:if ([ :len $"cert-renew-url" ] = 0) do={ :if ([ :len $CertRenewUrl ] = 0) do={
:error "No renew-url given."; :error "No CertRenewUrl given.";
} }
/ tool fetch mode=https check-certificate=yes-without-crl url=($"cert-renew-url" . $commonname . ".pem"); / tool fetch mode=https check-certificate=yes-without-crl url=($CertRenewUrl . $CommonName . ".pem");
/ certificate import file-name=($commonname . ".pem") passphrase=$"cert-renew-pass"; / certificate import file-name=($CommonName . ".pem") passphrase=$CertRenewPass;
/ file remove [ find where name=($commonname . ".pem") ]; / file remove [ find where name=($CommonName . ".pem") ];
:local certnew [ / certificate find where common-name=$commonname fingerprint!=$fprint ]; :local CertNew [ / certificate find where common-name=$CommonName fingerprint!=$FingerPrint ];
:local certnamenew [ / certificate get $certnew name ]; :local CertNameNew [ / certificate get $CertNew name ];
:foreach ipservice in=[ / ip service find where certificate=$certname ] do={ :foreach IpService in=[ / ip service find where certificate=$CertName ] do={
/ ip service set $ipservice certificate=$certnamenew; / ip service set $IpService certificate=$CertNameNew;
} }
:do { :do {
:foreach hotspot in=[ / ip hotspot profile find where ssl-certificate=$certname ] do={ :foreach Hotspot in=[ / ip hotspot profile find where ssl-certificate=$CertName ] do={
/ ip hotspot profile set $hotspot ssl-certificate=$certnamenew; / ip hotspot profile set $Hotspot ssl-certificate=$CertNameNew;
} }
} on-error={ } on-error={
:log debug ("Setting hotspot certificates failed. Hotspot package not installed?"); :log debug ("Setting hotspot certificates failed. Hotspot package not installed?");
} }
/ certificate remove $cert; / certificate remove $Cert;
/ certificate set $certnew name=$certname; / certificate set $CertNew name=$CertName;
} on-error={ } on-error={
:log warning ("Failed to auto-update certificate " . $certname); :log warning ("Failed to auto-update certificate " . $CertName);
:local invalidbefore [ / certificate get $cert invalid-before ]; :local InvalidBefore [ / certificate get $Cert invalid-before ];
:local invalidafter [ / certificate get $cert invalid-after ]; :local InvalidAfter [ / certificate get $Cert invalid-after ];
$SendNotification ("Certificate warning!") \ $SendNotification ("Certificate warning!") \
("A certificate on " . $identity . " is about to expire.\n\n" . \ ("A certificate on " . $Identity . " is about to expire.\n\n" . \
"Certificate Name: " . $certname . "\n" . \ "Certificate Name: " . $CertName . "\n" . \
"Common Name: " . $commonname . "\n" . \ "Common Name: " . $CommonName . "\n" . \
"Fingerprint: " . $fprint . "\n" . \ "Fingerprint: " . $FingerPrint . "\n" . \
"Validity: " . $invalidbefore . " to " . $invalidafter); "Validity: " . $InvalidBefore . " to " . $InvalidAfter);
:log warning ("A certificate is about to expire within " . $remaining . " days: " . $certname); :log warning ("A certificate is about to expire within " . $Remaining . " days: " . $CertName);
} }
} else={ } else={
:log debug ("The certificate " . $certname . " expires in " . $remaining . " days."); :log debug ("The certificate " . $CertName . " expires in " . $Remaining . " days.");
} }
} else={ } else={
:log debug ("The certificate " . $certname . " is just a template."); :log debug ("The certificate " . $CertName . " is just a template.");
} }
} }

View file

@ -4,31 +4,31 @@
# #
# check for LTE firmware upgrade, send notification e-mails # check for LTE firmware upgrade, send notification e-mails
:global "identity"; :global Identity;
:global "sent-lte-firmware-upgrade-notification"; :global SentLteFirmwareUpgradeNotification;
:global SendNotification; :global SendNotification;
:foreach interface in=[ / interface lte find ] do={ :foreach Interface in=[ / interface lte find ] do={
:local intname [ / interface lte get $interface name ]; :local IntName [ / interface lte get $Interface name ];
:do { :do {
:local firmware [ / interface lte firmware-upgrade $interface once as-value ]; :local Firmware [ / interface lte firmware-upgrade $Interface once as-value ];
# strip the extra line break (TODO: remove when fixed upstream) # strip the extra line break (TODO: remove when fixed upstream)
:set ($firmware->"latest") [ :pick ($firmware->"latest") 0 [ :find ($firmware->"latest") "\n" ] ]; :set ($Firmware->"latest") [ :pick ($Firmware->"latest") 0 [ :find ($Firmware->"latest") "\n" ] ];
:if ($"sent-lte-firmware-upgrade-notification" = ($firmware->"latest")) do={ :if ($SentLteFirmwareUpgradeNotification = ($Firmware->"latest")) do={
:log debug ("Already sent the LTE firmware upgrade notification for version " . \ :log debug ("Already sent the LTE firmware upgrade notification for version " . \
($firmware->"latest") . "."); ($Firmware->"latest") . ".");
} else={ } else={
:if (($firmware->"installed") != ($firmware->"latest")) do={ :if (($Firmware->"installed") != ($Firmware->"latest")) do={
$SendNotification ("LTE firmware upgrade notification") \ $SendNotification ("LTE firmware upgrade notification") \
("A new firmware version " . ($firmware->"latest") . " is available for " . \ ("A new firmware version " . ($Firmware->"latest") . " is available for " . \
"LTE interface " . $intname . " on " . $identity . "."); "LTE interface " . $IntName . " on " . $Identity . ".");
:set "sent-lte-firmware-upgrade-notification" ($firmware->"latest"); :set SentLteFirmwareUpgradeNotification ($Firmware->"latest");
} }
} }
} on-error={ } on-error={
:log debug ("Could not get latest LTE firmware version for interface " . \ :log debug ("Could not get latest LTE firmware version for interface " . \
$intname . "."); $IntName . ".");
} }
} }

View file

@ -4,9 +4,9 @@
# #
# check for RouterOS update, send notification e-mails # check for RouterOS update, send notification e-mails
:global "identity"; :global Identity;
:global "safe-update-url"; :global SafeUpdateUrl;
:global "sent-routeros-update-notification"; :global SentRouterosUpdateNotification;
:global SendNotification; :global SendNotification;
@ -18,45 +18,45 @@
} }
/ system package update check-for-updates without-paging; / system package update check-for-updates without-paging;
:local installedversion [ / system package update get installed-version ]; :local InstalledVersion [ / system package update get installed-version ];
:local latestversion [ / system package update get latest-version ]; :local LatestVersion [ / system package update get latest-version ];
:if ($installedversion != $latestversion) do={ :if ($InstalledVersion != $LatestVersion) do={
:local channel [ / system package update get channel ]; :local Channel [ / system package update get channel ];
:local model [ / system routerboard get model ]; :local Model [ / system routerboard get model ];
:local serialnumber [ / system routerboard get serial-number ]; :local SerialNumber [ / system routerboard get serial-number ];
:if ([ :len $"safe-update-url" ] > 0) do={ :if ([ :len $SafeUpdateUrl ] > 0) do={
:local result; :local Result;
:do { :do {
:set result [ / tool fetch check-certificate=yes-without-crl \ :set Result [ / tool fetch check-certificate=yes-without-crl \
($"safe-update-url" . $channel . "?installed=" . $installedversion . \ ($SafeUpdateUrl . $Channel . "?installed=" . $InstalledVersion . \
"&latest=" . $latestversion) output=user as-value ]; "&latest=" . $LatestVersion) output=user as-value ];
} on-error={ } on-error={
:log warning ("Failed receiving safe version for " . $channel . "."); :log warning ("Failed receiving safe version for " . $Channel . ".");
} }
:if ($result->"status" = "finished" && $result->"data" = $latestversion) do={ :if ($Result->"status" = "finished" && $Result->"data" = $LatestVersion) do={
:log info ("Version " . $latestversion . " is assumed safe, updating..."); :log info ("Version " . $LatestVersion . " is considered safe, updating...");
$SendNotification ("RouterOS update notification") \ $SendNotification ("RouterOS update notification") \
("Version " . $latestversion . " is assumed safe for " . $channel . \ ("Version " . $LatestVersion . " is considered safe for " . $Channel . \
", updating on " . $identity . "..."); ", updating on " . $Identity . "...");
/ system package update install; / system package update install;
:error "Waiting for system to reboot."; :error "Waiting for system to reboot.";
} }
} }
:if ($"sent-routeros-update-notification" = $latestversion) do={ :if ($SentRouterosUpdateNotification = $LatestVersion) do={
:error ("Already sent the RouterOS update notification for version " . \ :error ("Already sent the RouterOS update notification for version " . \
$latestversion . "."); $LatestVersion . ".");
} }
$SendNotification ("RouterOS update notification") \ $SendNotification ("RouterOS update notification") \
("There is a RouterOS update available\n\n" . \ ("There is a RouterOS update available\n\n" . \
"Routerboard: " . $model . "\n" . \ "Routerboard: " . $Model . "\n" . \
"Serial number: " . $serialnumber . "\n" . \ "Serial number: " . $SerialNumber . "\n" . \
"Hostname: " . $identity . "\n" . \ "Hostname: " . $Identity . "\n" . \
"Channel: " . $channel . "\n" . \ "Channel: " . $Channel . "\n" . \
"Installed: " . $installedversion . "\n" . \ "Installed: " . $InstalledVersion . "\n" . \
"Available: " . $latestversion); "Available: " . $LatestVersion);
:set "sent-routeros-update-notification" $latestversion; :set SentRouterosUpdateNotification $LatestVersion;
} }

View file

@ -6,54 +6,54 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:global "identity"; :global Identity;
:global GetMacVendor; :global GetMacVendor;
:global SendNotification; :global SendNotification;
:local "place-before" [ / caps-man access-list find where comment="--- collected above ---" disabled ]; :local PlaceBefore [ / caps-man access-list find where comment="--- collected above ---" disabled ];
:if ([ :len $"place-before" ] = 0) do={ :if ([ :len $PlaceBefore ] = 0) do={
:error "Missing disabled access-list entry with comment '--- collected above ---'"; :error "Missing disabled access-list entry with comment '--- collected above ---'";
} }
:foreach regtbl in=[ / caps-man registration-table find ] do={ :foreach RegTbl in=[ / caps-man registration-table find ] do={
:local mac [ / caps-man registration-table get $regtbl mac-address ]; :local Mac [ / caps-man registration-table get $RegTbl mac-address ];
:local acclst [ :pick [ / caps-man access-list find where mac-address=$mac ] 0 ]; :local AccessList [ :pick [ / caps-man access-list find where mac-address=$Mac ] 0 ];
:if ( [ :len $acclst ] = 0 ) do={ :if ([ :len $AccessList ] = 0) do={
:local hostname "no dhcp lease"; :local HostName "no dhcp lease";
:local address "no dhcp lease"; :local Address "no dhcp lease";
:local lease [ / ip dhcp-server lease find where mac-address=$mac ]; :local Lease [ / ip dhcp-server lease find where mac-address=$Mac ];
:if ( [ :len $lease ] > 0 ) do={ :if ([ :len $Lease ] > 0) do={
:set hostname [ / ip dhcp-server lease get $lease host-name ]; :set HostName [ / ip dhcp-server lease get $Lease host-name ];
:set address [ / ip dhcp-server lease get $lease address ]; :set Address [ / ip dhcp-server lease get $Lease address ];
} }
:if ( [ :len $hostname ] = 0 ) do={ :if ([ :len $HostName ] = 0) do={
:set hostname "no hostname"; :set HostName "no hostname";
} }
:if ( [ :len $address ] = 0 ) do={ :if ([ :len $Address ] = 0) do={
:set address "no address"; :set Address "no address";
} }
:local regentry [ / caps-man registration-table find where mac-address=$mac ]; :local RegEntry [ / caps-man registration-table find where mac-address=$Mac ];
:local interface [ / caps-man registration-table get $regentry interface ]; :local Interface [ / caps-man registration-table get $RegEntry interface ];
:local ssid [ / caps-man registration-table get $regentry ssid ]; :local Ssid [ / caps-man registration-table get $RegEntry ssid ];
:local datetime ([ / system clock get date ] . " " . [ / system clock get time ]); :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]);
:local vendor [ $GetMacVendor $mac ]; :local Vendor [ $GetMacVendor $Mac ];
:local message ("unknown MAC address " . $mac . " (" . $vendor . ", " . $hostname . ") " . \ :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \
"first seen on " . $datetime . " connected to SSID " . $ssid . ", interface " . $interface); "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface);
/ log info $message; / log info $Message;
/ caps-man access-list add place-before=$"place-before" comment=$message mac-address=$mac disabled=yes; / caps-man access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes;
$SendNotification ($mac . " connected to " . $ssid) \ $SendNotification ($Mac . " connected to " . $Ssid) \
("A device with unknown MAC address connected to " . $ssid . " on " . $identity . ".\n\n" . \ ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \
"Controller: " . $identity . "\n" . \ "Controller: " . $Identity . "\n" . \
"Interface: " . $interface . "\n" . \ "Interface: " . $Interface . "\n" . \
"SSID: " . $ssid . "\n" . \ "SSID: " . $Ssid . "\n" . \
"MAC: " . $mac . "\n" . \ "MAC: " . $Mac . "\n" . \
"Vendor: " . $vendor . "\n" . \ "Vendor: " . $Vendor . "\n" . \
"Hostname: " . $hostname . "\n" . \ "Hostname: " . $HostName . "\n" . \
"Address: " . $address . "\n" . \ "Address: " . $Address . "\n" . \
"Date: " . $datetime); "Date: " . $DateTime);
} else={ } else={
:local comment [ / caps-man access-list get $acclst comment ]; :local Comment [ / caps-man access-list get $AccessList comment ];
:log debug ("MAC address " . $mac . " already known: " . $comment); :log debug ("MAC address " . $Mac . " already known: " . $Comment);
} }
} }

View file

@ -6,54 +6,54 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:global "identity"; :global Identity;
:global GetMacVendor; :global GetMacVendor;
:global SendNotification; :global SendNotification;
:local "place-before" [ / interface wireless access-list find where comment="--- collected above ---" disabled ]; :local PlaceBefore [ / interface wireless access-list find where comment="--- collected above ---" disabled ];
:if ([ :len $"place-before" ] = 0) do={ :if ([ :len $PlaceBefore ] = 0) do={
:error "Missing disabled access-list entry with comment '--- collected above ---'"; :error "Missing disabled access-list entry with comment '--- collected above ---'";
} }
:foreach regtbl in=[ / interface wireless registration-table find ] do={ :foreach RegTbl in=[ / interface wireless registration-table find ] do={
:local mac [ / interface wireless registration-table get $regtbl mac-address ]; :local Mac [ / interface wireless registration-table get $RegTbl mac-address ];
:local acclst [ :pick [ / interface wireless access-list find where mac-address=$mac ] 0 ]; :local AccessList [ :pick [ / interface wireless access-list find where mac-address=$Mac ] 0 ];
:if ( [ :len $acclst ] = 0 ) do={ :if ([ :len $AccessList ] = 0) do={
:local hostname "no dhcp lease"; :local HostName "no dhcp lease";
:local address "no dhcp lease"; :local Address "no dhcp lease";
:local lease [ / ip dhcp-server lease find where mac-address=$mac ]; :local Lease [ / ip dhcp-server lease find where mac-address=$Mac ];
:if ( [ :len $lease ] > 0 ) do={ :if ([ :len $Lease ] > 0) do={
:set hostname [ / ip dhcp-server lease get $lease host-name ]; :set HostName [ / ip dhcp-server lease get $Lease host-name ];
:set address [ / ip dhcp-server lease get $lease address ]; :set Address [ / ip dhcp-server lease get $Lease address ];
} }
:if ( [ :len $hostname ] = 0 ) do={ :if ([ :len $HostName ] = 0) do={
:set hostname "no hostname"; :set HostName "no hostname";
} }
:if ( [ :len $address ] = 0 ) do={ :if ([ :len $Address ] = 0) do={
:set address "no address"; :set Address "no address";
} }
:local regentry [ / interface wireless registration-table find where mac-address=$mac ]; :local RegEntry [ / interface wireless registration-table find where mac-address=$Mac ];
:local interface [ / interface wireless registration-table get $regentry interface ]; :local Interface [ / interface wireless registration-table get $RegEntry interface ];
:local ssid [ / interface wireless get [ find where name=$interface ] ssid ]; :local Ssid [ / interface wireless get [ find where name=$Interface ] ssid ];
:local datetime ([ / system clock get date ] . " " . [ / system clock get time ]); :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]);
:local vendor [ $GetMacVendor $mac ]; :local Vendor [ $GetMacVendor $Mac ];
:local message ("unknown MAC address " . $mac . " (" . $vendor . ", " . $hostname . ") " . \ :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \
"first seen on " . $datetime . " connected to SSID " . $ssid . ", interface " . $interface); "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface);
/ log info $message; / log info $Message;
/ interface wireless access-list add place-before=$"place-before" comment=$message mac-address=$mac disabled=yes; / interface wireless access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes;
$SendNotification ($mac . " connected to " . $ssid) \ $SendNotification ($Mac . " connected to " . $Ssid) \
("A device with unknown MAC address connected to " . $ssid . " on " . $identity . ".\n\n" . \ ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \
"Controller: " . $identity . "\n" . \ "Controller: " . $Identity . "\n" . \
"Interface: " . $interface . "\n" . \ "Interface: " . $Interface . "\n" . \
"SSID: " . $ssid . "\n" . \ "SSID: " . $Ssid . "\n" . \
"MAC: " . $mac . "\n" . \ "MAC: " . $Mac . "\n" . \
"Vendor: " . $vendor . "\n" . \ "Vendor: " . $Vendor . "\n" . \
"Hostname: " . $hostname . "\n" . \ "Hostname: " . $HostName . "\n" . \
"Address: " . $address . "\n" . \ "Address: " . $Address . "\n" . \
"Date: " . $datetime); "Date: " . $DateTime);
} else={ } else={
:local comment [ / interface wireless access-list get $acclst comment ]; :local Comment [ / interface wireless access-list get $AccessList comment ];
:log debug ("MAC address " . $mac . " already known: " . $comment); :log debug ("MAC address " . $Mac . " already known: " . $Comment);
} }
} }

View file

@ -7,55 +7,55 @@
# !! This is just a template! Replace '%PATH%' with 'caps-man' # !! This is just a template! Replace '%PATH%' with 'caps-man'
# !! or 'interface wireless'! # !! or 'interface wireless'!
:global "identity"; :global Identity;
:global GetMacVendor; :global GetMacVendor;
:global SendNotification; :global SendNotification;
:local "place-before" [ / %PATH% access-list find where comment="--- collected above ---" disabled ]; :local PlaceBefore [ / %PATH% access-list find where comment="--- collected above ---" disabled ];
:if ([ :len $"place-before" ] = 0) do={ :if ([ :len $PlaceBefore ] = 0) do={
:error "Missing disabled access-list entry with comment '--- collected above ---'"; :error "Missing disabled access-list entry with comment '--- collected above ---'";
} }
:foreach regtbl in=[ / %PATH% registration-table find ] do={ :foreach RegTbl in=[ / %PATH% registration-table find ] do={
:local mac [ / %PATH% registration-table get $regtbl mac-address ]; :local Mac [ / %PATH% registration-table get $RegTbl mac-address ];
:local acclst [ :pick [ / %PATH% access-list find where mac-address=$mac ] 0 ]; :local AccessList [ :pick [ / %PATH% access-list find where mac-address=$Mac ] 0 ];
:if ( [ :len $acclst ] = 0 ) do={ :if ([ :len $AccessList ] = 0) do={
:local hostname "no dhcp lease"; :local HostName "no dhcp lease";
:local address "no dhcp lease"; :local Address "no dhcp lease";
:local lease [ / ip dhcp-server lease find where mac-address=$mac ]; :local Lease [ / ip dhcp-server lease find where mac-address=$Mac ];
:if ( [ :len $lease ] > 0 ) do={ :if ([ :len $Lease ] > 0) do={
:set hostname [ / ip dhcp-server lease get $lease host-name ]; :set HostName [ / ip dhcp-server lease get $Lease host-name ];
:set address [ / ip dhcp-server lease get $lease address ]; :set Address [ / ip dhcp-server lease get $Lease address ];
} }
:if ( [ :len $hostname ] = 0 ) do={ :if ([ :len $HostName ] = 0) do={
:set hostname "no hostname"; :set HostName "no hostname";
} }
:if ( [ :len $address ] = 0 ) do={ :if ([ :len $Address ] = 0) do={
:set address "no address"; :set Address "no address";
} }
:local regentry [ / %PATH% registration-table find where mac-address=$mac ]; :local RegEntry [ / %PATH% registration-table find where mac-address=$Mac ];
:local interface [ / %PATH% registration-table get $regentry interface ]; :local Interface [ / %PATH% registration-table get $RegEntry interface ];
:local ssid [ / caps-man registration-table get $regentry ssid ]; :local Ssid [ / caps-man registration-table get $RegEntry ssid ];
:local ssid [ / interface wireless get [ find where name=$interface ] ssid ]; :local Ssid [ / interface wireless get [ find where name=$Interface ] ssid ];
:local datetime ([ / system clock get date ] . " " . [ / system clock get time ]); :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]);
:local vendor [ $GetMacVendor $mac ]; :local Vendor [ $GetMacVendor $Mac ];
:local message ("unknown MAC address " . $mac . " (" . $vendor . ", " . $hostname . ") " . \ :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \
"first seen on " . $datetime . " connected to SSID " . $ssid . ", interface " . $interface); "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface);
/ log info $message; / log info $Message;
/ %PATH% access-list add place-before=$"place-before" comment=$message mac-address=$mac disabled=yes; / %PATH% access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes;
$SendNotification ($mac . " connected to " . $ssid) \ $SendNotification ($Mac . " connected to " . $Ssid) \
("A device with unknown MAC address connected to " . $ssid . " on " . $identity . ".\n\n" . \ ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \
"Controller: " . $identity . "\n" . \ "Controller: " . $Identity . "\n" . \
"Interface: " . $interface . "\n" . \ "Interface: " . $Interface . "\n" . \
"SSID: " . $ssid . "\n" . \ "SSID: " . $Ssid . "\n" . \
"MAC: " . $mac . "\n" . \ "MAC: " . $Mac . "\n" . \
"Vendor: " . $vendor . "\n" . \ "Vendor: " . $Vendor . "\n" . \
"Hostname: " . $hostname . "\n" . \ "Hostname: " . $HostName . "\n" . \
"Address: " . $address . "\n" . \ "Address: " . $Address . "\n" . \
"Date: " . $datetime); "Date: " . $DateTime);
} else={ } else={
:local comment [ / %PATH% access-list get $acclst comment ]; :local Comment [ / %PATH% access-list get $AccessList comment ];
:log debug ("MAC address " . $mac . " already known: " . $comment); :log debug ("MAC address " . $Mac . " already known: " . $Comment);
} }
} }

123
daily-psk
View file

@ -4,105 +4,96 @@
# #
# update daily PSK (pre shared key) # update daily PSK (pre shared key)
:global "identity"; :global Identity;
:global "daily-psk-match-comment"; :global DailyPskMatchComment;
:global SendNotification; :global SendNotification;
:local seen [ :toarray "" ]; :local Seen [ :toarray "" ];
# return pseudo-random string for PSK # return pseudo-random string for PSK
:local GeneratePSK do={ :local GeneratePSK do={
:local date [ :tostr $1 ]; :local Date [ :tostr $1 ];
:global "daily-psk-secrets"; :global DailyPskSecrets;
:local months { :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun";
"jan"; "feb"; "mar"; "apr"; "may"; "jun"; "jul"; "aug"; "sep"; "oct"; "nov"; "dec" };
"jul"; "aug"; "sep"; "oct"; "nov"; "dec" :local MonthTbl { 0; 3; 3; 6; 1; 4; 6; 2; 5; 0; 3; 5 };
}
:local monthtbl {
0; 3; 3; 6; 1; 4; 6; 2; 5; 0; 3; 5
}
:local monthstr [ :pick $date 0 3 ]; :local MonthStr [ :pick $Date 0 3 ];
:local month; :local Month;
:local day [ :pick $date 4 6 ]; :local Day [ :pick $Date 4 6 ];
:local century [ :pick $date 7 9 ]; :local Century [ :pick $Date 7 9 ];
:local year [ :pick $date 9 11 ]; :local Year [ :pick $Date 9 11 ];
# get numeric value for month # get numeric value for month
:for mindex from=0 to=[ :len $months ] do={ :for MIndex from=0 to=[ :len $Months ] do={
:if ([ :pick $months $mindex ] = $monthstr) do={ :if ([ :pick $Months $MIndex ] = $MonthStr) do={
:set month $mindex; :set Month $MIndex;
} }
} }
# calculate day of week # calculate day of week
:local sum 0; :local Sum 0;
:set sum ($sum + (2 * (3 - ($century - (($century / 4) * 4))))); :set Sum ($Sum + (2 * (3 - ($Century - (($Century / 4) * 4)))));
:set sum ($sum + ($year / 4)); :set Sum ($Sum + ($Year / 4));
:set sum ($sum + $year + $day); :set Sum ($Sum + $Year + $Day);
:set sum ($sum + $month); :set Sum ($Sum + $Month);
:set sum ($sum - (($sum / 7) * 7)); :set Sum ($Sum - (($Sum / 7) * 7));
:local return ([ :pick [ :pick $"daily-psk-secrets" 0 ] ($day - 1) ] . \ :local Return ([ :pick [ :pick $DailyPskSecrets 0 ] ($Day - 1) ] . \
[ :pick [ :pick $"daily-psk-secrets" 1 ] $month ] . \ [ :pick [ :pick $DailyPskSecrets 1 ] $Month ] . \
[ :pick [ :pick $"daily-psk-secrets" 2 ] $sum ]); [ :pick [ :pick $DailyPskSecrets 2 ] $Sum ]);
:return $return; :return $Return;
} }
:local date [ / system clock get date ]; :local Date [ / system clock get date ];
:local newpsk [ $GeneratePSK $date ]; :local NewPsk [ $GeneratePSK $Date ];
:foreach acclist in=[ / interface wireless access-list find where comment~$"daily-psk-match-comment" ] do={ :foreach AccList in=[ / interface wireless access-list find where comment~$DailyPskMatchComment ] do={
:local intname [ / interface wireless access-list get $acclist interface ]; :local IntName [ / interface wireless access-list get $AccList interface ];
:local interface [ / interface wireless find where name=$intname disabled=no ]; :local Interface [ / interface wireless find where name=$IntName disabled=no ];
:local ssid [ / interface wireless get $intname ssid ]; :local Ssid [ / interface wireless get $IntName ssid ];
:local oldpsk [ / interface wireless access-list get $acclist private-pre-shared-key ]; :local OldPsk [ / interface wireless access-list get $AccList private-pre-shared-key ];
:local skip 0; :local Skip 0;
:if ($newpsk != $oldpsk) do={ :if ($NewPsk != $OldPsk) do={
:log info ("Updating daily PSK for " . $intname . " to " . $newpsk . " (was " . $oldpsk . ")"); :log info ("Updating daily PSK for " . $IntName . " to " . $NewPsk . " (was " . $OldPsk . ")");
/ interface wireless access-list set $acclist private-pre-shared-key=$newpsk; / interface wireless access-list set $AccList private-pre-shared-key=$NewPsk;
:if ([ :len $interface ] = 1) do={ :if ([ :len $Interface ] = 1) do={
:foreach "seen-ssid" in=$seen do={ :foreach SeenSsid in=$Seen do={
:if ($"seen-ssid" = $ssid) do={ :if ($SeenSsid = $Ssid) do={
:log debug ("Already sent a mail for SSID " . $ssid . ", skipping."); :log debug ("Already sent a mail for SSID " . $Ssid . ", skipping.");
:set skip 1; :set Skip 1;
} }
} }
:if ($skip = 0) do={ :if ($Skip = 0) do={
:set seen ( $seen, $ssid ); :set Seen ($Seen, $Ssid);
:local host "www.eworm.de" :local Url ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \
:local srcpath ("/cgi-bin/cqrlogo-wifi.cgi" . \ "?scale=8&level=1&ssid=" . $Ssid . "&pass=" . $NewPsk);
"?scale=8" . \ :local Attach "qrcode-daily.png";
"&level=1" . \
"&ssid=" . $ssid . \
"&pass=" . $newpsk);
:local attach "qrcode-daily.png";
:do { :do {
/ tool fetch mode=https check-certificate=yes-without-crl address=$host \ / tool fetch mode=https check-certificate=yes-without-crl \
host=$host src-path=$srcpath dst-path=$attach; $Url dst-path=$Attach;
} on-error={ } on-error={
:set attach ""; :set Attach "";
} }
$SendNotification ("daily PSK " . $ssid) \ $SendNotification ("daily PSK " . $Ssid) \
("This is the daily PSK on " . $identity . ":\n\n" . \ ("This is the daily PSK on " . $Identity . ":\n\n" . \
"SSID: " . $ssid . "\n" . \ "SSID: " . $Ssid . "\n" . \
"PSK: " . $newpsk . "\n" . \ "PSK: " . $NewPsk . "\n" . \
"Date: " . [ / system clock get date ] . "\n\n" . \ "Date: " . $Date . "\n\n" . \
"https://" . $host . $srcpath) \ $Url) $Attach;
$attach;
} }
} else={ } else={
:log debug ("Missing active interface " . $intname . " for access list entry."); :log debug ("Missing active interface " . $IntName . " for access list entry.");
} }
} }
} }

View file

@ -4,12 +4,12 @@
# #
# schedule daily-psk on startup # schedule daily-psk on startup
:local scheduler [ / system scheduler find where name=daily-psk-schedule ]; :local Scheduler [ / system scheduler find where name="daily-psk-schedule" ];
:if ([ / system scheduler get $scheduler interval ] = 0s) do={ :if ([ / system scheduler get $Scheduler interval ] = 0s) do={
/ system scheduler set interval=15s $scheduler; / system scheduler set interval=15s $Scheduler;
} else={ } else={
:if ([ / tool netwatch get [ find where comment=[ / tool e-mail get address ] ] status ] != "up" ) do={ :if ([ / tool netwatch get [ find where comment=[ / tool e-mail get address ] ] status ] != "up") do={
:error "Mail server is not up."; :error "Mail server is not up.";
} }
@ -19,5 +19,5 @@
/ system script run daily-psk; / system script run daily-psk;
/ system scheduler set interval=0s $scheduler; / system scheduler set interval=0s $Scheduler;
} }

View file

@ -6,16 +6,16 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:foreach lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={ :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={
:local macaddress [ / ip dhcp-server lease get $lease mac-address ]; :local MacAddress [ / ip dhcp-server lease get $Lease mac-address ];
:local oldcomment [ / ip dhcp-server lease get $lease comment ]; :local OldComment [ / ip dhcp-server lease get $Lease comment ];
:local newcomment; :local NewComment;
:local accesslst [ :pick [ / caps-man access-list find where mac-address=$macaddress ] 0 ]; :local AccessList [ :pick [ / caps-man access-list find where mac-address=$MacAddress ] 0 ];
:if ( [ :len $accesslst ] > 0 ) do={ :if ([ :len $AccessList ] > 0) do={
:set newcomment [ / caps-man access-list get $accesslst comment ]; :set NewComment [ / caps-man access-list get $AccessList comment ];
} }
:if ([ :len $newcomment ] != 0 && $oldcomment != $newcomment) do={ :if ([ :len $NewComment ] != 0 && $OldComment != $NewComment) do={
:log info ("Updating comment for DHCP lease " . $macaddress . ": " . $newcomment); :log info ("Updating comment for DHCP lease " . $MacAddress . ": " . $NewComment);
/ ip dhcp-server lease set comment=$newcomment $lease; / ip dhcp-server lease set comment=$NewComment $Lease;
} }
} }

View file

@ -6,16 +6,16 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:foreach lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={ :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={
:local macaddress [ / ip dhcp-server lease get $lease mac-address ]; :local MacAddress [ / ip dhcp-server lease get $Lease mac-address ];
:local oldcomment [ / ip dhcp-server lease get $lease comment ]; :local OldComment [ / ip dhcp-server lease get $Lease comment ];
:local newcomment; :local NewComment;
:local accesslst [ :pick [ / interface wireless access-list find where mac-address=$macaddress ] 0 ]; :local AccessList [ :pick [ / interface wireless access-list find where mac-address=$MacAddress ] 0 ];
:if ( [ :len $accesslst ] > 0 ) do={ :if ([ :len $AccessList ] > 0) do={
:set newcomment [ / interface wireless access-list get $accesslst comment ]; :set NewComment [ / interface wireless access-list get $AccessList comment ];
} }
:if ([ :len $newcomment ] != 0 && $oldcomment != $newcomment) do={ :if ([ :len $NewComment ] != 0 && $OldComment != $NewComment) do={
:log info ("Updating comment for DHCP lease " . $macaddress . ": " . $newcomment); :log info ("Updating comment for DHCP lease " . $MacAddress . ": " . $NewComment);
/ ip dhcp-server lease set comment=$newcomment $lease; / ip dhcp-server lease set comment=$NewComment $Lease;
} }
} }

View file

@ -7,16 +7,16 @@
# !! This is just a template! Replace '%PATH%' with 'caps-man' # !! This is just a template! Replace '%PATH%' with 'caps-man'
# !! or 'interface wireless'! # !! or 'interface wireless'!
:foreach lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={ :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={
:local macaddress [ / ip dhcp-server lease get $lease mac-address ]; :local MacAddress [ / ip dhcp-server lease get $Lease mac-address ];
:local oldcomment [ / ip dhcp-server lease get $lease comment ]; :local OldComment [ / ip dhcp-server lease get $Lease comment ];
:local newcomment; :local NewComment;
:local accesslst [ :pick [ / %PATH% access-list find where mac-address=$macaddress ] 0 ]; :local AccessList [ :pick [ / %PATH% access-list find where mac-address=$MacAddress ] 0 ];
:if ( [ :len $accesslst ] > 0 ) do={ :if ([ :len $AccessList ] > 0) do={
:set newcomment [ / %PATH% access-list get $accesslst comment ]; :set NewComment [ / %PATH% access-list get $AccessList comment ];
} }
:if ([ :len $newcomment ] != 0 && $oldcomment != $newcomment) do={ :if ([ :len $NewComment ] != 0 && $OldComment != $NewComment) do={
:log info ("Updating comment for DHCP lease " . $macaddress . ": " . $newcomment); :log info ("Updating comment for DHCP lease " . $MacAddress . ": " . $NewComment);
/ ip dhcp-server lease set comment=$newcomment $lease; / ip dhcp-server lease set comment=$NewComment $Lease;
} }
} }

View file

@ -4,73 +4,73 @@
# #
# check DHCP leases and add/remove/update DNS entries # check DHCP leases and add/remove/update DNS entries
:global "identity"; :global Identity;
:global "domain"; :global Domain;
:global "hostname-in-zone"; :global HostNameInZone;
:local zone; :local Zone;
:if ($"hostname-in-zone" = true) do={ :if ($HostNameInZone = true) do={
:set zone ("dhcp." . $identity . "." . $domain); :set Zone ("dhcp." . $Identity . "." . $Domain);
} else={ } else={
:set zone ("dhcp." . $domain); :set Zone ("dhcp." . $Domain);
} }
:local ttl 5m; :local Ttl 5m;
:local hostname; :local HostName;
:local fqdn; :local Fqdn;
:local dnsip; :local DnsIp;
:local dhcpip; :local DhcpIp;
:local dnsnode; :local DnsNode;
:local dhcpnode; :local DhcpNode;
:foreach static in=[ / ip dns static find where name ~ (".*\\." . $zone) ] do={ :foreach Static in=[ / ip dns static find where name ~ (".*\\." . $Zone) ] do={
:set fqdn [ / ip dns static get $static name ]; :set Fqdn [ / ip dns static get $Static name ];
:set hostname [ :pick $fqdn 0 ( [ :len $fqdn ] - ( [ :len $zone ] + 1 ) ) ]; :set HostName [ :pick $Fqdn 0 ([ :len $Fqdn ] - ([ :len $Zone ] + 1)) ];
:set dhcpnode [ / ip dhcp-server lease find where host-name=$hostname dynamic=yes ]; :set DhcpNode [ / ip dhcp-server lease find where host-name=$HostName dynamic=yes ];
:if ( [ :len $dhcpnode ] > 0) do={ :if ([ :len $DhcpNode ] > 0) do={
:log debug ("Lease for " . $hostname . " still exists. Not deleting."); :log debug ("Lease for " . $HostName . " still exists. Not deleting.");
} else={ } else={
:local found false; :local Found false;
:log info ("Lease expired for " . $hostname . ", deleting DNS entry."); :log info ("Lease expired for " . $HostName . ", deleting DNS entry.");
/ ip dns static remove $static; / ip dns static remove $Static;
} }
} }
:foreach lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={ :foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes ] do={
:local mac [ / ip dhcp-server lease get $lease mac-address ]; :local Mac [ / ip dhcp-server lease get $Lease mac-address ];
:set dhcpip [ / ip dhcp-server lease get $lease address ]; :set DhcpIp [ / ip dhcp-server lease get $Lease address ];
:local comment ("managed by dhcp-to-dns for " . $mac); :local Comment ("managed by dhcp-to-dns for " . $Mac);
:set hostname [ / ip dhcp-server lease get $lease host-name ]; :set HostName [ / ip dhcp-server lease get $Lease host-name ];
:while ($hostname ~ " ") do={ :while ($HostName ~ " ") do={
:local pos [ :find $hostname " " ]; :local Pos [ :find $HostName " " ];
:set hostname ( [ :pick $hostname 0 $pos ] . [ :pick $hostname ($pos + 1) 999 ] ); :set HostName ([ :pick $HostName 0 $Pos ] . [ :pick $HostName ($Pos + 1) 999 ]);
}; };
:if ( [ :len $hostname ] > 0) do={ :if ([ :len $HostName ] > 0) do={
:set fqdn ( $hostname . "." . $zone ); :set Fqdn ($HostName . "." . $Zone);
:set dnsnode [ / ip dns static find where name=$fqdn ]; :set DnsNode [ / ip dns static find where name=$Fqdn ];
:if ( [ :len $dnsnode ] > 0 ) do={ :if ([ :len $DnsNode ] > 0) do={
:set dnsip [ / ip dns static get $dnsnode address ]; :set DnsIp [ / ip dns static get $DnsNode address ];
:local leases [ / ip dhcp-server lease find where host-name=$hostname dynamic=yes ]; :local Leases [ / ip dhcp-server lease find where host-name=$HostName dynamic=yes ];
:local hostnamecount [ / ip dhcp-server lease print count-only where host-name=$hostname dynamic=yes ]; :local HostNameCount [ / ip dhcp-server lease print count-only where host-name=$HostName dynamic=yes ];
:if ( $hostnamecount > 1) do={ :if ($HostNameCount > 1) do={
:foreach j,lease in=$leases do={ :foreach J,Lease in=$Leases do={
:if ($j + 1 = $hostnamecount) do={ :if ($J + 1 = $HostNameCount) do={
:set dhcpip [ / ip dhcp-server lease get $lease address ]; :set DhcpIp [ / ip dhcp-server lease get $Lease address ];
} }
} }
} }
:if ( $dnsip = $dhcpip ) do={ :if ($DnsIp = $DhcpIp) do={
:log debug ("DNS entry for " . $fqdn . " does not need updating."); :log debug ("DNS entry for " . $Fqdn . " does not need updating.");
} else={ } else={
:log info ("Replacing DNS entry for " . $fqdn . ", new address is " . $dhcpip . "."); :log info ("Replacing DNS entry for " . $Fqdn . ", new address is " . $DhcpIp . ".");
/ ip dns static set name=$fqdn address=$dhcpip ttl=$ttl comment=$comment $dnsnode; / ip dns static set name=$Fqdn address=$DhcpIp ttl=$Ttl comment=$Comment $DnsNode;
} }
} else={ } else={
:log info ("Adding new DNS entry for " . $fqdn . ", address is " . $dhcpip . "."); :log info ("Adding new DNS entry for " . $Fqdn . ", address is " . $DhcpIp . ".");
/ ip dns static add name=$fqdn address=$dhcpip ttl=$ttl comment=$comment; / ip dns static add name=$Fqdn address=$DhcpIp ttl=$Ttl comment=$Comment;
} }
} }
} }

View file

@ -4,72 +4,72 @@
# #
# create and email backup and config file # create and email backup and config file
:global "identity"; :global Identity;
:global "domain"; :global Domain;
:global "email-backup-to"; :global EmailBackupTo;
:global "email-backup-cc"; :global EmailBackupCc;
:global "backup-send-binary"; :global BackupSendBinary;
:global "backup-send-export"; :global BackupSendExport;
:global "backup-cloud"; :global BackupCloud;
:global "backup-password"; :global BackupPassword;
:if ($"backup-send-binary" != true && \ :if ($BackupSendBinary != true && \
$"backup-send-export" != true && \ $BackupSendExport != true && \
$"backup-cloud" != true) do={ $BackupCloud != true) do={
:error ("Configured to send neither backup nor config export."); :error ("Configured to send neither backup nor config export.");
} }
# filename based on identity # filename based on identity
:local filename ($identity . "." . $domain); :local FileName ($Identity . "." . $Domain);
:local cloudstatus $"backup-cloud"; :local CloudStatus $BackupCloud;
:local attach [ :toarray "" ]; :local Attach [ :toarray "" ];
# get some system information # get some system information
:local model [ / system routerboard get model ]; :local Model [ / system routerboard get model ];
:local serialnumber [ / system routerboard get serial-number ]; :local SerialNumber [ / system routerboard get serial-number ];
:local channel [ / system package update get channel ]; :local Channel [ / system package update get channel ];
:local installedversion [ / system package update get installed-version ]; :local InstalledVersion [ / system package update get installed-version ];
# binary backup # binary backup
:if ($"backup-send-binary" = true || \ :if ($BackupSendBinary = true || \
$"backup-cloud" = true) do={ $BackupCloud = true) do={
/ system backup save encryption=aes-sha256 name=$filename password=$"backup-password"; / system backup save encryption=aes-sha256 name=$FileName password=$BackupPassword;
# attach to mail # attach to mail
:if ($"backup-send-binary" = true) do={ :if ($BackupSendBinary = true) do={
:set attach ( $attach, ($filename . ".backup") ); :set Attach ($Attach, ($FileName . ".backup"));
} }
# upload to cloud # upload to cloud
:if ($"backup-cloud" = true) do={ :if ($BackupCloud = true) do={
:do { :do {
:if ([ / system backup cloud print count-only ] > 0) do={ :if ([ / system backup cloud print count-only ] > 0) do={
/ system backup cloud remove-file [ find ]; / system backup cloud remove-file [ find ];
} }
/ system backup cloud upload-file action=upload src-file=($filename . ".backup"); / system backup cloud upload-file action=upload src-file=($FileName . ".backup");
} on-error={ } on-error={
:set cloudstatus "failed"; :set CloudStatus "failed";
} }
} }
} }
# create configuration export # create configuration export
:if ($"backup-send-export" = true) do={ :if ($BackupSendExport = true) do={
/ export terse file=$filename; / export terse file=$FileName;
:set attach ( $attach, ($filename . ".rsc") ); :set Attach ($Attach, ($FileName . ".rsc"));
} }
# send email with status and files # send email with status and files
/ tool e-mail send to=$"email-backup-to" cc=$"email-backup-cc" \ / tool e-mail send to=$EmailBackupTo cc=$EmailBackupCc \
subject=("[" . $identity . "] Backup & Config") \ subject=("[" . $Identity . "] Backup & Config") \
body=("Backup and config export for " . $identity . ".\n\n" . \ body=("Backup and config export for " . $Identity . ".\n\n" . \
"Routerboard: " . $model . "\n" . \ "Routerboard: " . $Model . "\n" . \
"Serial number: " . $serialnumber . "\n" . \ "Serial number: " . $SerialNumber . "\n" . \
"Hostname: " . $identity . "\n" . \ "Hostname: " . $Identity . "\n" . \
"Channel: " . $channel . "\n" . \ "Channel: " . $Channel . "\n" . \
"RouterOS: " . $installedversion . "\n\n" . \ "RouterOS: " . $InstalledVersion . "\n\n" . \
"Backup attached: " . $"backup-send-binary" . "\n" . \ "Backup attached: " . $BackupSendBinary . "\n" . \
"Config attached: " . $"backup-send-export" . "\n" . \ "Config attached: " . $BackupSendExport . "\n" . \
"Cloud backup: " . $cloudstatus) \ "Cloud backup: " . $CloudStatus) \
file=$attach; file=$Attach;
} }

View file

@ -6,45 +6,45 @@
# Make sure all configuration properties are up to date and this # Make sure all configuration properties are up to date and this
# value is in sync with value in script 'global-functions'! # value is in sync with value in script 'global-functions'!
:global GlobalConfigVersion 1; :global GlobalConfigVersion 2;
# This is used for DNS and backup file. # This is used for DNS and backup file.
:global "domain" "example.com"; :global Domain "example.com";
:global "hostname-in-zone" true; :global HostNameInZone true;
# These addresses are used to send e-mails to. The to-addresses need # These addresses are used to send e-mails to. The to-addresses need
# to be filled, cc-addresses can be empty, one address or a comma # to be filled, cc-addresses can be empty, one address or a comma
# separated list of addresses. # separated list of addresses.
:global "email-general-to" "mail@example.com"; :global EmailGeneralTo "mail@example.com";
:global "email-general-cc" "another@example.com"; :global EmailGeneralCc "another@example.com";
:global "email-backup-to" "mail@example.com"; :global EmailBackupTo "mail@example.com";
:global "email-backup-cc" ""; :global EmailBackupCc "";
# You can send Telegram notifications. Register a bot # You can send Telegram notifications. Register a bot
# and add the token and chat ids here. # and add the token and chat ids here.
:global "telegram-tokenid" ""; :global TelegramTokenId "";
:global "telegram-chatid" ""; :global TelegramChatId "";
#:global "telegram-tokenid" "123456:ABCDEF-GHI"; #:global TelegramTokenId "123456:ABCDEF-GHI";
#:global "telegram-chatid" "12345678"; #:global TelegramChatId "12345678";
# This defines what backups to generate and what password to use. # This defines what backups to generate and what password to use.
:global "backup-send-binary" false; :global BackupSendBinary false;
:global "backup-send-export" true; :global BackupSendExport true;
:global "backup-cloud" false; :global BackupCloud false;
:global "backup-password" "v3ry-s3cr3t"; :global BackupPassword "v3ry-s3cr3t";
# Specify an address to enable auto update to version assumed safe. # Specify an address to enable auto update to version assumed safe.
# The configured channel (bugfix, current, release-candidate) is appended. # The configured channel (bugfix, current, release-candidate) is appended.
:global "safe-update-url" ""; :global SafeUpdateUrl "";
#:global "safe-update-url" "https://example.com/ros/safe-update/"; #:global SafeUpdateUrl "https://example.com/ros/safe-update/";
# This controls what configuration is activated by bridge-port-to-default. # This controls what configuration is activated by bridge-port-to-default.
:global "bridge-port-to" "default"; :global BridgePortTo "default";
# Access-list entries matching this comment are updated # Access-list entries matching this comment are updated
# with daily pseudo-random PSK. # with daily pseudo-random PSK.
:global "daily-psk-match-comment" "Daily PSK"; :global DailyPskMatchComment "Daily PSK";
:global "daily-psk-secrets" { :global DailyPskSecrets {
{ "Abusive"; "Aggressive"; "Bored"; "Chemical"; "Cold"; { "Abusive"; "Aggressive"; "Bored"; "Chemical"; "Cold";
"Cruel"; "Curved"; "Delightful"; "Discreet"; "Elite"; "Cruel"; "Curved"; "Delightful"; "Discreet"; "Elite";
"Evasive"; "Faded"; "Flat"; "Future"; "Grandiose"; "Evasive"; "Faded"; "Flat"; "Future"; "Grandiose";
@ -60,9 +60,9 @@
} }
# Run different commands with multiple mode-button presses. # Run different commands with multiple mode-button presses.
:global "mode-button" { :global ModeButton {
1="/ system script run leds-toggle-mode;"; 1="/ system script run leds-toggle-mode;";
2=":global SendNotification; :global identity; \$SendNotification (\"Hello...\") (\"Hello world, \" . \$identity . \" calling!\");"; 2=":global SendNotification; :global Identity; \$SendNotification (\"Hello...\") (\"Hello world, \" . \$Identity . \" calling!\");";
3="/ system shutdown;"; 3="/ system shutdown;";
4="/ system reboot;"; 4="/ system reboot;";
5="/ system script run bridge-port-toggle;"; 5="/ system script run bridge-port-toggle;";
@ -70,7 +70,7 @@
}; };
# Run commands on SMS action. # Run commands on SMS action.
:global "sms-action" { :global SmsAction {
bridge-port-toggle="/ system script run bridge-port-toggle;"; bridge-port-toggle="/ system script run bridge-port-toggle;";
reboot="/ system reboot;"; reboot="/ system reboot;";
shutdown="/ system shutdown;"; shutdown="/ system shutdown;";
@ -79,29 +79,29 @@
# This address should resolve ntp servers and is used to update # This address should resolve ntp servers and is used to update
# ntp settings. A pool can rotate servers. # ntp settings. A pool can rotate servers.
:global "ntp-pool" "pool.ntp.org"; :global NtpPool "pool.ntp.org";
# This is the address used to send gps data to. # This is the address used to send gps data to.
:global "gps-track-url" "https://example.com/index.php"; :global GpsTrackUrl "https://example.com/index.php";
# Enable this to fetch scripts from given url. # Enable this to fetch scripts from given url.
:global "script-updates-fetch" true; :global ScriptUpdatesFetch true;
:global "script-updates-baseurl" "https://git.eworm.de/cgit.cgi/routeros-scripts/plain/"; :global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit.cgi/routeros-scripts/plain/";
#:global "script-updates-baseurl" "https://raw.githubusercontent.com/eworm-de/routeros-scripts/master/"; #:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/master/";
#:global "script-updates-baseurl" "https://gitlab.com/eworm-de/routeros-scripts/raw/master/"; #:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/master/";
:global "script-updates-urlsuffix" ""; :global ScriptUpdatesUrlSuffix "";
:global "script-updates-ignore" { :global ScriptUpdatesIgnore {
"global-config" "global-config"
} }
# Use this for certificate auto-renew # Use this for certificate auto-renew
:global "cert-renew-url" ""; :global CertRenewUrl "";
#:global "cert-renew-url" "https://example.com/certificates/"; #:global CertRenewUrl "https://example.com/certificates/";
:global "cert-renew-pass" "v3ry-s3cr3t"; :global CertRenewPass "v3ry-s3cr3t";
# Configuration for update-tunnelbroker # Configuration for update-tunnelbroker
#:global tunnelurl "ipv4.tunnelbroker.net"; #:global TunnelUrl "ipv4.tunnelbroker.net";
#:global tunneluser "user"; #:global TunnelUser "user";
#:global tunnelpass "v3ry-s3cr3t"; #:global TunnelPass "v3ry-s3cr3t";
#:global tunnelid "user-XXX.tunnel.tserv6.fra1.ipv6.he.net"; #:global TunnelId "user-XXX.tunnel.tserv6.fra1.ipv6.he.net";
#:global tunnelint "tunnelbroker"; #:global TunnelInt "tunnelbroker";

View file

@ -5,12 +5,12 @@
# global functions # global functions
# expected configuration version # expected configuration version
:global ExpectedConfigVersion 1; :global ExpectedConfigVersion 2;
# global variables not to be changed by user # global variables not to be changed by user
:global "sent-routeros-update-notification" "-"; :global SentRouterosUpdateNotification "-";
:global "sent-lte-firmware-upgrade-notification" "-"; :global SentLteFirmwareUpgradeNotification "-";
:global "identity" [ / system identity get name ]; :global Identity [ / system identity get name ];
# read input from user # read input from user
:global Read do={ :global Read do={
@ -19,44 +19,44 @@
# url encoding # url encoding
:global UrlEncode do={ :global UrlEncode do={
:local input [ :tostr $1 ]; :local Input [ :tostr $1 ];
:local return ""; :local Return "";
:if ([ :len $input ] > 0) do={ :if ([ :len $Input ] > 0) do={
:local chars " %&"; :local Chars " %&";
:local subs { "%20"; "%25"; "%26" }; :local Subs { "%20"; "%25"; "%26" };
:for i from=0 to=([ :len $input ] - 1) do={ :for I from=0 to=([ :len $Input ] - 1) do={
:local char [ :pick $input $i ]; :local Char [ :pick $Input $I ];
:local replace [ :find $chars $char ]; :local Replace [ :find $Chars $Char ];
:if ([ :len $replace ] > 0) do={ :if ([ :len $Replace ] > 0) do={
:set char ($subs->$replace); :set Char ($Subs->$Replace);
} }
:set return ($return . $char); :set Return ($Return . $Char);
} }
} }
:return $return; :return $Return;
} }
# check and import required certificates # check and import required certificates
:global CertificateAvailable do={ :global CertificateAvailable do={
:local commonname [ :tostr $1 ]; :local CommonName [ :tostr $1 ];
:local filename ([ :tostr $2 ] . ".pem"); :local FileName ([ :tostr $2 ] . ".pem");
:global "script-updates-baseurl"; :global ScriptUpdatesBaseUrl;
:global "script-updates-urlsuffix"; :global ScriptUpdatesUrlSuffix;
:if ([ / certificate print count-only where common-name=$commonname ] = 0) do={ :if ([ / certificate print count-only where common-name=$CommonName ] = 0) do={
:log info ("Certificate with CommonName " . $commonname . \ :log info ("Certificate with CommonName " . $CommonName . \
" not available, downloading and importing."); " not available, downloading and importing.");
:do { :do {
/ tool fetch check-certificate=yes-without-crl \ / tool fetch check-certificate=yes-without-crl \
($"script-updates-baseurl" . "certs/" . \ ($ScriptUpdatesBaseUrl . "certs/" . \
$filename . $"script-updates-urlsuffix") \ $FileName . $ScriptUpdatesUrlSuffix) \
dst-path=$filename; dst-path=$FileName;
/ certificate import file-name=$filename passphrase=""; / certificate import file-name=$FileName passphrase="";
} on-error={ } on-error={
:log warning "Failed imprting certificate!"; :log warning "Failed imprting certificate!";
} }
@ -66,35 +66,35 @@
# send notification via e-mail and telegram # send notification via e-mail and telegram
# Note that attachment is ignored for telegram! # Note that attachment is ignored for telegram!
:global SendNotification do={ :global SendNotification do={
:local subject [ :tostr $1 ]; :local Subject [ :tostr $1 ];
:local message [ :tostr $2 ]; :local Message [ :tostr $2 ];
:local attach [ :tostr $3 ]; :local Attach [ :tostr $3 ];
:global "identity"; :global Identity;
:global "email-general-to"; :global EmailGeneralTo;
:global "email-general-cc"; :global EmailGeneralCc;
:global "telegram-tokenid"; :global TelegramTokenId;
:global "telegram-chatid"; :global TelegramChatId;
:global UrlEncode; :global UrlEncode;
:global CertificateAvailable; :global CertificateAvailable;
:if ([ :len $"email-general-to" ] > 0) do={ :if ([ :len $EmailGeneralTo ] > 0) do={
:do { :do {
/ tool e-mail send to=$"email-general-to" cc=$"email-general-cc" \ / tool e-mail send to=$EmailGeneralTo cc=$EmailGeneralCc \
subject=("[" . $"identity" . "] " . $subject) body=$message file=$attach; subject=("[" . $Identity . "] " . $Subject) body=$Message file=$Attach;
} on-error={ } on-error={
:log warning "Failed sending notification mail!"; :log warning "Failed sending notification mail!";
} }
} }
:if ([ :len $"telegram-tokenid" ] > 0 && [ :len $"telegram-chatid" ] > 0) do={ :if ([ :len $TelegramTokenId ] > 0 && [ :len $TelegramChatId ] > 0) do={
$CertificateAvailable "Go Daddy Secure Certificate Authority - G2" "godaddy"; $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" "godaddy";
:do { :do {
/ tool fetch check-certificate=yes-without-crl keep-result=no http-method=post \ / tool fetch check-certificate=yes-without-crl keep-result=no http-method=post \
("https://api.telegram.org/bot" . $"telegram-tokenid" . "/sendMessage") \ ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \
http-data=("chat_id=" . $"telegram-chatid" . "&text=" . \ http-data=("chat_id=" . $TelegramChatId . "&text=" . \
[ $UrlEncode ("[" . $"identity" . "] " . $subject . "\n\n" . $message) ]); [ $UrlEncode ("[" . $Identity . "] " . $Subject . "\n\n" . $Message) ]);
} on-error={ } on-error={
:log warning "Failed sending telegram notification!"; :log warning "Failed sending telegram notification!";
} }
@ -103,16 +103,16 @@
# get MAC vendor # get MAC vendor
:global GetMacVendor do={ :global GetMacVendor do={
:local mac [ :tostr $1 ]; :local Mac [ :tostr $1 ];
:global CertificateAvailable; :global CertificateAvailable;
:do { :do {
:local vendor; :local Vendor;
$CertificateAvailable "Let's Encrypt Authority X3" "letsencrypt"; $CertificateAvailable "Let's Encrypt Authority X3" "letsencrypt";
:set vendor ([ / tool fetch mode=https check-certificate=yes-without-crl \ :set Vendor ([ / tool fetch mode=https check-certificate=yes-without-crl \
url=("https://api.macvendors.com/" . [ :pick $mac 0 8 ]) output=user as-value ]->"data"); ("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data");
:return $vendor; :return $Vendor;
} on-error={ } on-error={
:return "unknown vendor"; :return "unknown vendor";
} }
@ -120,25 +120,25 @@
# download package from upgrade server # download package from upgrade server
:global DownloadPackage do={ :global DownloadPackage do={
:local pkgname [ :tostr $1 ]; :local PkgName [ :tostr $1 ];
:local pkgver [ :tostr $2 ]; :local PkgVer [ :tostr $2 ];
:local pkgarch [ :tostr $3 ]; :local PkgArch [ :tostr $3 ];
:local pkgdest [ :tostr $4 ]; :local PkgDest [ :tostr $4 ];
:global CertificateAvailable; :global CertificateAvailable;
:if ([ :len $pkgname ] = 0) do={ return false; } :if ([ :len $PkgName ] = 0) do={ return false; }
:if ([ :len $pkgver ] = 0) do={ :set pkgver [ / system package update get installed-version ]; } :if ([ :len $PkgVer ] = 0) do={ :set PkgVer [ / system package update get installed-version ]; }
:if ([ :len $pkgarch ] = 0) do={ :set pkgarch [ / system resource get architecture-name ]; } :if ([ :len $PkgArch ] = 0) do={ :set PkgArch [ / system resource get architecture-name ]; }
$CertificateAvailable "Let's Encrypt Authority X3" "letsencrypt"; $CertificateAvailable "Let's Encrypt Authority X3" "letsencrypt";
do { do {
:local pkgfile ($pkgname . "-" . $pkgver . "-" . $pkgarch . ".npk"); :local PkgFile ($PkgName . "-" . $PkgVer . "-" . $PkgArch . ".npk");
/ tool fetch mode=https check-certificate=yes-without-crl \ / tool fetch mode=https check-certificate=yes-without-crl \
("https://upgrade.mikrotik.com/routeros/" . $pkgver . "/" . $pkgfile) \ ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile) \
dst-path=($pkgdest . "/" . $pkgfile); dst-path=($PkgDest . "/" . $PkgFile);
return true; :return true;
} on-error={ } on-error={
return false; :return false;
} }
} }

View file

@ -4,26 +4,23 @@
# #
# track gps data by sending json data to http server # track gps data by sending json data to http server
:global "identity"; :global Identity;
:global "gps-track-url"; :global GpsTrackUrl;
:local gps [ / system gps monitor once as-value ]; :local Gps [ / system gps monitor once as-value ];
if ($gps->"valid" = true) do={ if ($Gps->"valid" = true) do={
:tool fetch mode=http \ :tool fetch mode=https check-certificate=yes-without-crl \
url=$"gps-track-url" \ $GpsTrackUrl keep-result=no \
check-certificate=yes-without-crl \ http-method=post http-content-type="application/json" \
keep-result=no \
http-method=post \
http-content-type="application/json" \
http-data=("{" . \ http-data=("{" . \
"\"lat\":\"" . ($gps->"latitude") . "\"," . \ "\"lat\":\"" . ($Gps->"latitude") . "\"," . \
"\"lon\":\"" . ($gps->"longitude") . "\"," . \ "\"lon\":\"" . ($Gps->"longitude") . "\"," . \
"\"identity\":\"" . $identity . "\"" . \ "\"identity\":\"" . $Identity . "\"" . \
"}"); "}");
:log debug ("Sending GPS data for tracking: " . \ :log debug ("Sending GPS data for tracking: " . \
"lat: " . ($gps->"latitude") . " " . \ "lat: " . ($Gps->"latitude") . " " . \
"lon: " . ($gps->"longitude")); "lon: " . ($Gps->"longitude"));
} else={ } else={
:log debug ("GPS data not valid."); :log debug ("GPS data not valid.");
} }

View file

@ -12,8 +12,8 @@
:if ([ / certificate print count-only where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] != 3) do={ :if ([ / certificate print count-only where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] != 3) do={
:error "Anything is wrong with your certificates!"; :error "Anything is wrong with your certificates!";
} }
:foreach script in={ "global-config"; "global-functions"; "script-updates" } do={ :foreach Script in={ "global-config"; "global-functions"; "script-updates" } do={
/ system script add name=$script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit.cgi/routeros-scripts/plain/" . $script) output=user as-value]->"data"); / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit.cgi/routeros-scripts/plain/" . $Script) output=user as-value]->"data");
} }
/ system script run global-config; / system script run global-config;
/ system script run global-functions; / system script run global-functions;

View file

@ -4,13 +4,13 @@
# #
# enable or disable ip addresses based on bridge port state # enable or disable ip addresses based on bridge port state
:foreach bridge in=[ / interface bridge find ] do={ :foreach Bridge in=[ / interface bridge find ] do={
:local brname [ / interface bridge get $bridge name ]; :local BrName [ / interface bridge get $Bridge name ];
:if ([ / interface bridge port print count-only where bridge=$brname ] > 0) do={ :if ([ / interface bridge port print count-only where bridge=$BrName ] > 0) do={
:if ([ / interface bridge port print count-only where bridge=$brname and inactive=no ] = 0) do={ :if ([ / interface bridge port print count-only where bridge=$BrName and inactive=no ] = 0) do={
/ ip address disable [ find where !dynamic interface=$brname ]; / ip address disable [ find where !dynamic interface=$BrName ];
} else={ } else={
/ ip address enable [ find where !dynamic interface=$brname ]; / ip address enable [ find where !dynamic interface=$BrName ];
} }
} }
} }

View file

@ -4,31 +4,33 @@
# #
# update firewall and dns settings on IPv6 prefix change # update firewall and dns settings on IPv6 prefix change
:local pool [ / ipv6 pool get [ find where prefix=$"pd-prefix" ] name ]; :local PdPrefix $"pd-prefix";
:local addrlist [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $pool) ];
:local oldprefix [ / ipv6 firewall address-list get $addrlist address ]; :local Pool [ / ipv6 pool get [ find where prefix=$PdPrefix ] name ];
:local AddrList [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ];
:local OldPrefix [ / ipv6 firewall address-list get $AddrList address ];
# give the interfaces a moment to receive their addresses # give the interfaces a moment to receive their addresses
:delay 2s; :delay 2s;
if ($oldprefix != $"pd-prefix") do={ if ($OldPrefix != $PdPrefix) do={
:log info ("Updating IPv6 address list with new IPv6 prefix " . $"pd-prefix"); :log info ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix);
/ ipv6 firewall address-list set address=$"pd-prefix" $addrlist; / ipv6 firewall address-list set address=$PdPrefix $AddrList;
:foreach record in=[ / ip dns static find where comment~("ipv6-pool-" . $pool) ] do={ :foreach Record in=[ / ip dns static find where comment~("ipv6-pool-" . $Pool) ] do={
:local comment [ :toarray [ / ip dns static get $record comment ] ]; :local Comment [ :toarray [ / ip dns static get $Record comment ] ];
:local intname [ :pick [ :pick $comment 1 ] 10 99 ]; :local IntName [ :pick [ :pick $Comment 1 ] 10 99 ];
:local suffix [ :pick [ :pick $comment 2 ] 7 99 ]; :local Suffix [ :pick [ :pick $Comment 2 ] 7 99 ];
:local prefix [ / ipv6 address get [ find where interface=$intname from-pool=$pool global ] address ]; :local Prefix [ / ipv6 address get [ find where interface=$IntName from-pool=$Pool global ] address ];
:local prefix64 [ :pick $prefix 0 [ :find $prefix "::/64" ] ]; :local Prefix64 [ :pick $Prefix 0 [ :find $Prefix "::/64" ] ];
:local name [ / ip dns static get $record name ]; :local Name [ / ip dns static get $Record name ];
:if ([ :len $name ] = 0) do={ :if ([ :len $Name ] = 0) do={
:set name [ / ip dns static get $record regex ]; :set Name [ / ip dns static get $Record regex ];
} }
:log info ("Updating DNS record for " . $name . " to " . $prefix64 . ":" . $suffix); :log info ("Updating DNS record for " . $Name . " to " . $Prefix64 . ":" . $Suffix);
/ ip dns static set address=($prefix64 . ":" . $suffix) $record; / ip dns static set address=($Prefix64 . ":" . $Suffix) $Record;
} }
} }

View file

@ -5,7 +5,7 @@
# run scripts on DHCP lease # run scripts on DHCP lease
# ( / ip dhcp-server set lease-script=lease-script [ find ] ) # ( / ip dhcp-server set lease-script=lease-script [ find ] )
:local scripts { :local Scripts {
"dhcp-to-dns"; "dhcp-to-dns";
"collect-wireless-mac.local"; "collect-wireless-mac.local";
"dhcp-lease-comment.local"; "dhcp-lease-comment.local";
@ -16,9 +16,9 @@
# delay a second to give time to update the lease table # delay a second to give time to update the lease table
:delay 1s; :delay 1s;
:foreach script in=$scripts do={ :foreach Script in=$Scripts do={
:if ([ / system script print count-only where name=$script ] > 0) do={ :if ([ / system script print count-only where name=$Script ] > 0) do={
:log debug ("Running script from lease-script: " . $script); :log debug ("Running script from lease-script: " . $Script);
/ system script run $script; / system script run $Script;
} }
} }

View file

@ -4,24 +4,25 @@
# #
# manage UMTS interface based on ethernet and wireless status # manage UMTS interface based on ethernet and wireless status
:local etherint "en1"; :local EtherInt "en1";
:local wlanint "wl-station"; :local WlanInt "wl-station";
:local umtsint "t-mobile"; :local UmtsInt "t-mobile";
:local etherstatus [ / interface ethernet get $etherint running ]; :local EtherStatus [ / interface ethernet get $EtherInt running ];
:local wlanstatus [ / interface wireless get $wlanint running ]; :local WlanStatus [ / interface wireless get $WlanInt running ];
:if ( $etherstatus = true || wlanstatus = true ) do={ :if ($EtherStatus = true || $WlanStatus = true) do={
:if ( [ / interface get $umtsint disabled ] = false ) do={ :if ([ / interface get $UmtsInt disabled ] = false) do={
:log info ("Ethernet (" . $etherint . " / " . $etherstatus . ") or " . \ :log info ("Ethernet (" . $EtherInt . " / " . $EtherStatus . ") or " . \
"wireless (" . $wlanint . " / " . $wlanstatus . ") is running, " . \ "wireless (" . $WlanInt . " / " . $WlanStatus . ") is running, " . \
"UMTS interface " . $umtsint . " is enabled. Disabling..."); "UMTS interface " . $UmtsInt . " is enabled. Disabling...");
/ interface set disabled=yes $umtsint; / interface set disabled=yes $UmtsInt;
}; }
} else={ } else={
:if ( [ / interface get $umtsint disabled ] = true ) do={ :if ([ / interface get $UmtsInt disabled ] = true) do={
:log info ("Neither ethernet (" . $etherint . ") nor wireless (" . $wlanint . ") interface is running, " . \ :log info ("Neither ethernet (" . $EtherInt . ") nor wireless (" . \
"UMTS interface " . $umtsint . " is disabled. Enabling..."); $WlanInt . ") interface is running, UMTS interface " . $UmtsInt . \
/ interface set disabled=no $umtsint; " is disabled. Enabling...");
}; / interface set disabled=no $UmtsInt;
}; }
}

View file

@ -4,16 +4,16 @@
# #
# run on mode-button event and count button presses # run on mode-button event and count button presses
:global "mode-button"; :global ModeButton;
:set ($"mode-button"->"count") ($"mode-button"->"count" + 1); :set ($ModeButton->"count") ($ModeButton->"count" + 1);
:local scheduler [ / system scheduler find where name="mode-button-scheduler" ]; :local Scheduler [ / system scheduler find where name="mode-button-scheduler" ];
:if ([ :len $scheduler ] = 0) do={ :if ([ :len $Scheduler ] = 0) do={
:log info "Creating mode-button scheduler, counting presses..."; :log info "Creating mode-button scheduler, counting presses...";
/ system scheduler add name=mode-button-scheduler on-event=mode-button-scheduler interval=3s; / system scheduler add name=mode-button-scheduler on-event=mode-button-scheduler interval=3s;
} else={ } else={
:log debug "Updating mode-button-scheduler..."; :log debug "Updating mode-button-scheduler...";
/ system scheduler set $scheduler start-time=[ /system clock get time ]; / system scheduler set $Scheduler start-time=[ /system clock get time ];
} }

View file

@ -4,15 +4,15 @@
# #
# act on multiple mode-botton presses from scheduler # act on multiple mode-botton presses from scheduler
:global "mode-button"; :global ModeButton;
:local count ($"mode-button"->"count"); :local Count ($ModeButton->"count");
:local code ($"mode-button"->[ :tostr $count ]); :local Code ($ModeButton->[ :tostr $Count ]);
:local parsed [ :parse $code ]; :local Parsed [ :parse $Code ];
:set ($"mode-button"->"count") 0; :set ($ModeButton->"count") 0;
/ system scheduler remove mode-button-scheduler; / system scheduler remove mode-button-scheduler;
:log info ("Acting on " . $count . " mode-button presses: " . $code); :log info ("Acting on " . $Count . " mode-button presses: " . $Code);
:delay 1s; :delay 1s;
$parsed; $Parsed;

View file

@ -6,9 +6,9 @@
# #
# manage remote logging facilities # manage remote logging facilities
:local remote [ /system logging action get [ :pick [ find where target=remote ] 0 ] remote ]; :local Remote [ /system logging action get [ :pick [ find where target=remote ] 0 ] remote ];
if ([ / tool netwatch get [ find where host=$remote ] status ] = "up") do={ if ([ / tool netwatch get [ find where host=$Remote ] status ] = "up") do={
/ system logging set disabled=no [ find where action=remote disabled=yes ]; / system logging set disabled=no [ find where action=remote disabled=yes ];
} else={ } else={
/ system logging set disabled=yes [ find where action=remote disabled=no ]; / system logging set disabled=yes [ find where action=remote disabled=no ];

View file

@ -5,10 +5,11 @@
# run scripts on ppp up # run scripts on ppp up
# variable $interface is available in ppp on-up script # variable $interface is available in ppp on-up script
:local dhcpclient [ / ipv6 dhcp-client find where interface=$interface ]; :local Interface $interface;
:local DhcpClient [ / ipv6 dhcp-client find where interface=$Interface ];
:if ( [ :len $dhcpclient ] > 0) do={ :if ([ :len $DhcpClient ] > 0) do={
/ ipv6 dhcp-client disable $dhcpclient; / ipv6 dhcp-client disable $DhcpClient;
:delay 1s; :delay 1s;
/ ipv6 dhcp-client enable $dhcpclient; / ipv6 dhcp-client enable $DhcpClient;
} }

View file

@ -4,14 +4,14 @@
# #
# rotate the ntp servers # rotate the ntp servers
:global "ntp-pool"; :global NtpPool;
:local ntp1 [ :resolve ("0." . $"ntp-pool") ]; :local Ntp1 [ :resolve ("0." . $NtpPool) ];
:local ntp2 [ :resolve ("1." . $"ntp-pool") ]; :local Ntp2 [ :resolve ("1." . $NtpPool) ];
:if ([ / system ntp client get enabled ] != true) do={ :if ([ / system ntp client get enabled ] != true) do={
:log warning "NTP client is not enabled!"; :log warning "NTP client is not enabled!";
} }
:log info ("Updating NTP servers to " . $ntp1 . " and " . $ntp2); :log info ("Updating NTP servers to " . $Ntp1 . " and " . $Ntp2);
/ system ntp client set primary-ntp=$ntp1 secondary-ntp=$ntp2; / system ntp client set primary-ntp=$Ntp1 secondary-ntp=$Ntp2;

View file

@ -6,80 +6,80 @@
:global GlobalConfigVersion; :global GlobalConfigVersion;
:global ExpectedConfigVersion; :global ExpectedConfigVersion;
:global "identity"; :global Identity;
:global "script-updates-fetch"; :global ScriptUpdatesFetch;
:global "script-updates-baseurl"; :global ScriptUpdatesBaseUrl;
:global "script-updates-urlsuffix"; :global ScriptUpdatesUrlSuffix;
:global "script-updates-ignore"; :global ScriptUpdatesIgnore;
:global SendNotification; :global SendNotification;
:foreach script in=[ / system script find ] do={ :foreach Script in=[ / system script find ] do={
:local ignore 0; :local Ignore 0;
:local scriptname [ / system script get $script name ]; :local ScriptName [ / system script get $Script name ];
:local scriptpolicy [ / system script get $script policy ]; :local ScriptPolicy [ / system script get $Script policy ];
:local scriptfile [ / file find where name=("script-updates/" . $scriptname) ]; :local ScriptFile [ / file find where name=("script-updates/" . $ScriptName) ];
:local sourcenew; :local SourceNew;
:if ([ :len $scriptfile ] > 0) do={ :if ([ :len $ScriptFile ] > 0) do={
:set sourcenew [ / file get $scriptfile content ]; :set SourceNew [ / file get $ScriptFile content ];
/ file remove $scriptfile; / file remove $ScriptFile;
} }
:foreach scheduler in=[ / system scheduler find where on-event=$scriptname ] do={ :foreach Scheduler in=[ / system scheduler find where on-event=$ScriptName ] do={
:local schedulername [ / system scheduler get $scheduler name ]; :local SchedulerName [ / system scheduler get $Scheduler name ];
:local schedulerpolicy [ / system scheduler get $scheduler policy ]; :local SchedulerPolicy [ / system scheduler get $Scheduler policy ];
:if ($scriptpolicy != schedulerpolicy) do={ :if ($ScriptPolicy != $SchedulerPolicy) do={
:log warning ("Policies differ for script " . $scriptname . \ :log warning ("Policies differ for script " . $ScriptName . \
" and its scheduler " . $schedulername . "!"); " and its scheduler " . $SchedulerName . "!");
} }
} }
:if ([ :len $sourcenew ] = 0 && $"script-updates-fetch" = true) do={ :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={
:foreach "ignore-loop" in=$"script-updates-ignore" do={ :foreach IgnoreLoop in=$ScriptUpdatesIgnore do={
:if ($"ignore-loop" = $scriptname) do={ :set ignore 1; } :if ($IgnoreLoop = $ScriptName) do={ :set Ignore 1; }
} }
:if ($ignore = 0) do={ :if ($Ignore = 0) do={
:log debug ("Fetching script from url: " . $scriptname); :log debug ("Fetching script from url: " . $ScriptName);
:do { :do {
:local result [ / tool fetch check-certificate=yes-without-crl \ :local Result [ / tool fetch check-certificate=yes-without-crl \
($"script-updates-baseurl" . $scriptname . $"script-updates-urlsuffix") \ ($ScriptUpdatesBaseUrl . $ScriptName . $ScriptUpdatesUrlSuffix) \
output=user as-value ]; output=user as-value ];
:if ($result->"status" = "finished") do={ :if ($Result->"status" = "finished") do={
:set sourcenew ($result->"data"); :set SourceNew ($Result->"data");
} }
} on-error={ } on-error={
:log info ("Failed fetching " . $scriptname); :log info ("Failed fetching " . $ScriptName);
} }
} }
} }
:if ([ :len $sourcenew ] > 0) do={ :if ([ :len $SourceNew ] > 0) do={
:if ([ :pick $sourcenew 0 5 ] = "#!rsc") do={ :if ([ :pick $SourceNew 0 5 ] = "#!rsc") do={
:local sourcecurrent [ / system script get $script source ]; :local SourceCurrent [ / system script get $Script source ];
:if ($sourcenew != $sourcecurrent) do={ :if ($SourceNew != $SourceCurrent) do={
:local "dont-require-permissions" \ :local DontRequirePermissions \
($sourcenew~"\n# requires: dont-require-permissions=yes\n"); ($SourceNew~"\n# requires: dont-require-permissions=yes\n");
:log info ("Updating script: " . $scriptname); :log info ("Updating script: " . $ScriptName);
/ system script set owner=$scriptname source=$sourcenew \ / system script set owner=$ScriptName source=$SourceNew \
dont-require-permissions=$"dont-require-permissions" $script; dont-require-permissions=$DontRequirePermissions $Script;
:if ($scriptname = "global-functions") do={ :if ($ScriptName = "global-functions") do={
/ system script run global-functions; / system script run global-functions;
} }
} else={ } else={
:log debug ("Script " . $scriptname . " did not change"); :log debug ("Script " . $ScriptName . " did not change.");
} }
} else={ } else={
:log warning ("Looks like new script " . $scriptname . " is not valid. Ignoring!"); :log warning ("Looks like new script " . $ScriptName . " is not valid. Ignoring!");
} }
} else={ } else={
:log debug ("No update for script " . $scriptname); :log debug ("No update for script " . $ScriptName . ".");
} }
} }
:if ($GlobalConfigVersion < $ExpectedConfigVersion) do={ :if ($GlobalConfigVersion < $ExpectedConfigVersion) do={
$SendNotification "Configuration warning!" \ $SendNotification "Configuration warning!" \
("Current configuration on " . $identity . " is out of date. " . \ ("Current configuration on " . $Identity . " is out of date. " . \
"Please update global-config, then increase variable " . \ "Please update global-config, then increase variable " . \
"GlobalConfigVersion (currently " . $GlobalConfigVersion . \ "GlobalConfigVersion (currently " . $GlobalConfigVersion . \
") to " . $ExpectedConfigVersion . " and re-run global-config."); ") to " . $ExpectedConfigVersion . " and re-run global-config.");

View file

@ -4,11 +4,13 @@
# #
# run action on received SMS # run action on received SMS
:global "sms-action"; :global SmsAction;
:local code ($"sms-action"->$action); :local Action $action;
:local parsed [ :parse $code ];
:log info ("Acting on SMS action '" . $action . "': " . $code); :local Code ($SmsAction->$Action);
:local Parsed [ :parse $Code ];
:log info ("Acting on SMS action '" . $Action . "': " . $Code);
:delay 1s; :delay 1s;
$parsed; $Parsed;

View file

@ -4,7 +4,7 @@
# #
# forward SMS to e-mail # forward SMS to e-mail
:global "identity"; :global Identity;
:global SendNotification; :global SendNotification;
@ -13,25 +13,25 @@
:error "Mail server is not up."; :error "Mail server is not up.";
} }
:local allowed [ / tool sms get allowed-number ]; :local Allowed [ / tool sms get allowed-number ];
:local secret [ / tool sms get secret ]; :local Secret [ / tool sms get secret ];
# forward SMS in a loop # forward SMS in a loop
:foreach sms in=[ / tool sms inbox find ] do={ :foreach Sms in=[ / tool sms inbox find ] do={
:local message [ / tool sms inbox get $sms message ]; :local Message [ / tool sms inbox get $Sms message ];
:local phone [ / tool sms inbox get $sms phone ]; :local Phone [ / tool sms inbox get $Sms phone ];
:local timestamp [ / tool sms inbox get $sms timestamp ]; :local TimeStamp [ / tool sms inbox get $Sms timestamp ];
:local type [ / tool sms inbox get $sms type ]; :local Type [ / tool sms inbox get $Sms type ];
:if ($phone = $allowed && message~("^:cmd " . $secret . " script ")) do={ :if ($Phone = $Allowed && $Message~("^:cmd " . $Secret . " script ")) do={
:log debug "Ignoring SMS, which starts a script."; :log debug "Ignoring SMS, which starts a script.";
} else={ } else={
$SendNotification ("SMS Forwarding") \ $SendNotification ("SMS Forwarding") \
("A message was received by " . $identity . ":\n\n" . \ ("A message was received by " . $Identity . ":\n\n" . \
"Phone: " . $phone . "\n" . \ "Phone: " . $Phone . "\n" . \
"Timestamp: " . $timestamp . "\n" . \ "Timestamp: " . $TimeStamp . "\n" . \
"Type: " . $type . "\n\n" . \ "Type: " . $Type . "\n\n" . \
"Message:\n" . $message); "Message:\n" . $Message);
/ tool sms inbox remove $sms; / tool sms inbox remove $Sms;
} }
} }

View file

@ -8,4 +8,4 @@
# while read type key name; do echo $type $key $name > $name.pub; done < keys.pub # while read type key name; do echo $type $key $name > $name.pub; done < keys.pub
# ... then transfer with scp/sftp. # ... then transfer with scp/sftp.
:foreach key in=[ / file find where type="ssh key" ] do={ / user ssh-key import user=admin public-key-file=[ / file get $key name ]; } :foreach Key in=[ / file find where type="ssh key" ] do={ / user ssh-key import user=admin public-key-file=[ / file get $Key name ]; }

View file

@ -4,7 +4,7 @@
# #
# play Super Mario theme # play Super Mario theme
:local beeps { :local Beeps {
{ 660; 100 }; 150; { 660; 100 }; 300; { 660; 100 }; 300; { 660; 100 }; 150; { 660; 100 }; 300; { 660; 100 }; 300;
{ 510; 100 }; 100; { 660; 100 }; 300; { 770; 100 }; 550; { 510; 100 }; 100; { 660; 100 }; 300; { 770; 100 }; 550;
{ 380; 100 }; 575; { 510; 100 }; 450; { 380; 100 }; 400; { 380; 100 }; 575; { 510; 100 }; 450; { 380; 100 }; 400;
@ -58,10 +58,10 @@
{ 660; 100 }; 300; { 660; 100 }; 300; { 510; 100 }; 100; { 660; 100 }; 300; { 660; 100 }; 300; { 510; 100 }; 100;
{ 660; 100 }; 300; { 770; 100 }; 550; { 380; 100 }; 575 }; { 660; 100 }; 300; { 770; 100 }; 550; { 380; 100 }; 575 };
:foreach beep in=$beeps do={ :foreach Beep in=$Beeps do={
:if ([ :len $beep ] = 2) do={ :if ([ :len $Beep ] = 2) do={
:beep frequency=[ :pick $beep 0 ] length=([ :pick $beep 1 ] . "ms"); :beep frequency=[ :pick $Beep 0 ] length=([ :pick $Beep 1 ] . "ms");
} else={ } else={
:delay ($beep . "ms"); :delay ($Beep . "ms");
} }
} }

View file

@ -4,26 +4,26 @@
# #
# schedule unattended lte firmware upgrade # schedule unattended lte firmware upgrade
:foreach interface in=[ / interface lte find ] do={ :foreach Interface in=[ / interface lte find ] do={
:local firmware; :local Firmware;
:local intname [ / interface lte get $interface name ]; :local IntName [ / interface lte get $Interface name ];
do { do {
:set firmware [ / interface lte firmware-upgrade $interface once as-value ]; :set Firmware [ / interface lte firmware-upgrade $Interface once as-value ];
# strip the extra line break (TODO: remove when fixed upstream) # strip the extra line break (TODO: remove when fixed upstream)
:set ($firmware->"latest") [ :pick ($firmware->"latest") 0 [ :find ($firmware->"latest") "\n" ] ]; :set ($Firmware->"latest") [ :pick ($Firmware->"latest") 0 [ :find ($Firmware->"latest") "\n" ] ];
} on-error={ } on-error={
:log debug ("Could not get latest LTE firmware version for interface " . $intname . "."); :log debug ("Could not get latest LTE firmware version for interface " . $IntName . ".");
} }
:if (($firmware->"installed") != ($firmware->"latest")) do={ :if (($Firmware->"installed") != ($Firmware->"latest")) do={
:log info ("Scheduling LTE firmware upgrade for interface " . $intname . "."); :log info ("Scheduling LTE firmware upgrade for interface " . $IntName . ".");
/ system script add name=($intname . "-firmware-upgrade") source=("# unattended-lte-firmware-upgrade\n" . \ / system script add name=($IntName . "-firmware-upgrade") source=("# unattended-lte-firmware-upgrade\n" . \
"/ system scheduler remove " . $intname . "-firmware-upgrade;\n" . \ "/ system scheduler remove " . $IntName . "-firmware-upgrade;\n" . \
"/ system script remove " . $intname . "-firmware-upgrade;\n" . \ "/ system script remove " . $IntName . "-firmware-upgrade;\n" . \
"/ interface lte firmware-upgrade " . $intname . " upgrade=yes;\n" . \ "/ interface lte firmware-upgrade " . $IntName . " upgrade=yes;\n" . \
":log info (\"LTE firmware upgrade finished, waiting for installation before reset.\");\n" . \ ":log info (\"LTE firmware upgrade finished, waiting for installation before reset.\");\n" . \
":delay 150s;\n" . \ ":delay 150s;\n" . \
"/ interface lte at-chat " . $intname . " input=\"AT+RESET\";"); "/ interface lte at-chat " . $IntName . " input=\"AT+RESET\";");
/ system scheduler add name=($intname . "-firmware-upgrade") on-event=($intname . "-firmware-upgrade") interval=1m; / system scheduler add name=($IntName . "-firmware-upgrade") on-event=($IntName . "-firmware-upgrade") interval=1m;
} }
} }

View file

@ -7,18 +7,18 @@
/ interface gre set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; / interface gre set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ];
:foreach peer in=[ / ip ipsec remote-peers find ] do={ :foreach Peer in=[ / ip ipsec remote-peers find ] do={
:local id [ / ip ipsec remote-peers get $peer id ]; :local Id [ / ip ipsec remote-peers get $Peer id ];
:local greint [ / interface gre find where comment=$id ]; :local GreInt [ / interface gre find where comment=$Id ];
:if ([ :len $greint ] > 0) do={ :if ([ :len $GreInt ] > 0) do={
:local grename [ / interface gre get $greint name ]; :local GreName [ / interface gre get $GreInt name ];
:local addrold [ / interface gre get $greint remote-address ]; :local AddrOld [ / interface gre get $GreInt remote-address ];
:local disabled [ / interface gre get $greint disabled ]; :local Disabled [ / interface gre get $GreInt disabled ];
:local addrnew [ / ip ipsec remote-peers get $peer dynamic-address ]; :local AddrNew [ / ip ipsec remote-peers get $Peer dynamic-address ];
:if ($addrnew != $addrold || $disabled = true) do={ :if ($AddrNew != $AddrOld || $Disabled = true) do={
:log info ("Update remote address for interface " . $grename . " to " . $addrnew); :log info ("Update remote address for interface " . $GreName . " to " . $AddrNew);
/ interface gre set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$addrnew name!=$grename ]; / interface gre set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$AddrNew name!=$GreName ];
/ interface gre set $greint remote-address=$addrnew disabled=no; / interface gre set $GreInt remote-address=$AddrNew disabled=no;
} }
} }
} }

View file

@ -3,11 +3,11 @@
# Copyright (c) 2013-2019 Christian Hesse <mail@eworm.de> # Copyright (c) 2013-2019 Christian Hesse <mail@eworm.de>
# Michael Gisbers <michael@gisbers.de> # Michael Gisbers <michael@gisbers.de>
:global tunnelurl; :global TunnelUrl;
:global tunneluser; :global TunnelUser;
:global tunnelpass; :global TunnelPass;
:global tunnelid; :global TunnelId;
:global tunnelint; :global TunnelInt;
:global CertificateAvailable; :global CertificateAvailable;
@ -16,22 +16,22 @@
} }
# get the last ip address from tunnel interface # get the last ip address from tunnel interface
:local tunnellastip [ / interface 6to4 get [ / interface 6to4 find where name=$tunnelint ] local-address ]; :local TunnelLastIp [ / interface 6to4 get [ / interface 6to4 find where name=$TunnelInt ] local-address ];
# Get the current ip address from cloud # Get the current ip address from cloud
/ ip cloud force-update; / ip cloud force-update;
while ([ / ip cloud get status ] != "updated" ) do={ :while ([ / ip cloud get status ] != "updated") do={
:delay 1s; :delay 1s;
} }
:local tunnelip [ / ip cloud get public-address ]; :local TunnelIp [ / ip cloud get public-address ];
:if ($tunnelip != $tunnellastip) do={ :if ($TunnelIp != $TunnelLastIp) do={
$CertificateAvailable "Starfield Secure Certificate Authority - G2" "starfield"; $CertificateAvailable "Starfield Secure Certificate Authority - G2" "starfield";
:log info ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $tunnelip); :log info ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $TunnelIp);
/ tool fetch mode=https check-certificate=yes-without-crl \ / tool fetch mode=https check-certificate=yes-without-crl \
("https://" . $tunnelurl . "/nic/update\?hostname=" . $tunnelid) \ ("https://" . $TunnelUrl . "/nic/update\?hostname=" . $TunnelId) \
user=$tunneluser password=$tunnelpass keep-result=no; user=$TunnelUser password=$TunnelPass keep-result=no;
/ interface 6to4 set [ / interface 6to4 find where name=$tunnelint ] local-address=$tunnelip; / interface 6to4 set [ / interface 6to4 find where name=$TunnelInt ] local-address=$TunnelIp;
} else={ } else={
:log debug "All tunnelbroker configuration is up to date."; :log debug "All tunnelbroker configuration is up to date.";
} }