diff --git a/README.md b/README.md index 5b99bfcd..0cb6b691 100644 --- a/README.md +++ b/README.md @@ -288,7 +288,7 @@ Available scripts * [Download, import and update firewall address-lists](doc/fw-addr-lists.md) (`fw-addr-lists`) * [Wait for global functions und modules](doc/global-wait.md) (`global-wait`) * [Send GPS position to server](doc/gps-track.md) (`gps-track`) -* [Use WPA network with hotspot credentials](doc/hotspot-to-wpa.md) (`hotspot-to-wpa` & `hotspot-to-wpa-cleanup`) +* [Use WPA network with hotspot credentials](doc/hotspot-to-wpa.md) (`hotspot-to-wpa`, `hotspot-to-wpa-lease` & `hotspot-to-wpa-cleanup`) * [Create DNS records for IPSec peers](doc/ipsec-to-dns.md) (`ipsec-to-dns`) * [Update configuration on IPv6 prefix change](doc/ipv6-update.md) (`ipv6-update`) * [Manage IP addresses with bridge status](doc/ip-addr-bridge.md) (`ip-addr-bridge`) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index e5a47839..eb6e598b 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -26,35 +26,40 @@ Requirements and installation You need a properly configured hotspot on one (open) SSID and a WPA enabled SSID with suffix "`-wpa`". -Then install the script. -Depending on whether you use `wifi` package (`/interface/wifi`)or legacy -wifi with CAPsMAN (`/caps-man`) you need to install a different script and -set it as `on-login` script in hotspot. +Then install the scripts. Depending on whether you use `wifi` package +(`/interface/wifi`) or legacy wifi with CAPsMAN (`/caps-man`) you need to +install a different set of scripts. For `wifi`: - $ScriptInstallUpdate hotspot-to-wpa.wifi; - /ip/hotspot/user/profile/set on-login="hotspot-to-wpa.wifi" [ find ]; + $ScriptInstallUpdate hotspot-to-wpa,hotspot-to-wpa-lease.wifi,dhcpv4-server-lease; For legacy CAPsMAN: - $ScriptInstallUpdate hotspot-to-wpa.capsman; - /ip/hotspot/user/profile/set on-login="hotspot-to-wpa.capsman" [ find ]; + $ScriptInstallUpdate hotspot-to-wpa,hotspot-to-wpa-lease.capsman,dhcpv4-server-lease; + +Then set `hotspot-to-wpa` as `on-login` script in hotspot. + + /ip/hotspot/user/profile/set on-login="hotspot-to-wpa" [ find ]; + +Finally ad add the lease script your hotspot interfaces' dhcp server. + + /ip/dhcp-server/set lease-script="dhcpv4-server-lease" hotspot; ### Automatic cleanup -With just `hotspot-to-wpa` installed the mac addresses will last in the +With just the above scripts installed the mac addresses will last in the access list forever. Install the optional script for automatic cleanup and add a scheduler. For `wifi`: - $ScriptInstallUpdate hotspot-to-wpa-cleanup.wifi,dhcpv4-server-lease; + $ScriptInstallUpdate hotspot-to-wpa-cleanup.wifi; /system/scheduler/add interval=1d name="hotspot-to-wpa-cleanup" on-event="/system/script/run hotspot-to-wpa-cleanup.wifi;" start-time=startup; For legacy CAPsMAN: - $ScriptInstallUpdate hotspot-to-wpa-cleanup.capsman,dhcpv4-server-lease; + $ScriptInstallUpdate hotspot-to-wpa-cleanup.capsman; /system/scheduler/add interval=1d name="hotspot-to-wpa-cleanup" on-event="/system/script/run hotspot-to-wpa-cleanup.capsman;" start-time=startup; And add the lease script and matcher comment to your wpa interfaces' dhcp diff --git a/global-functions.rsc b/global-functions.rsc index 469a077c..c3525190 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -15,7 +15,7 @@ # Git commit id & info, expected configuration version :global CommitId "unknown"; :global CommitInfo "unknown"; -:global ExpectedConfigVersion 144; +:global ExpectedConfigVersion 145; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/hotspot-to-wpa-lease.capsman.rsc b/hotspot-to-wpa-lease.capsman.rsc new file mode 100644 index 00000000..3d350aad --- /dev/null +++ b/hotspot-to-wpa-lease.capsman.rsc @@ -0,0 +1,109 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa-lease.capsman +# Copyright (c) 2019-2026 Christian Hesse +# https://rsc.eworm.de/COPYING.md +# +# provides: dhcpv4-server-lease, order=40 +# requires RouterOS, version=7.22 +# requires device-mode, hotspot +# +# add private WPA passphrase after hotspot login +# https://rsc.eworm.de/doc/hotspot-to-wpa.md +# +# !! Do not edit this file, it is generated from template! + +:onerror Err { + :global GlobalConfigReady; :global GlobalFunctionsReady; + :retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \ + do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50; + :local ScriptName [ :jobname ]; + + :global EitherOr; + :global LogPrint; + :global ParseKeyValueStore; + :global ScriptLock; + + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic disabled comment~"hotspot-to-wpa" ] do={ + :local LeaseVal [ $ParseKeyValueStore [ /ip/dhcp-server/lease/get $Lease comment ] ]; + + :if (($LeaseVal->"hotspot-to-wpa") != true) do={ + :continue; + } + + :local MacAddress $"mac-address"; + :local UserName $username; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :exit; + } + + :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ + $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); + :exit; + } + + :local Date [ /system/clock/get date ]; + :local UserVal ({}); + :if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ + :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; + } + :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; + :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; + + :if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'."); + } + :local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + + :if ([ :len [ /caps-man/access-list/find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ + /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + $LogPrint warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'."); + } + :local Template [ /caps-man/access-list/get ([ find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; + + :if ($Template->"action" = "reject") do={ + $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); + :exit; + } + + $LogPrint info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ")."); + /caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; + /caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + action=reject place-before=$PlaceBefore; + + :local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ + comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; + :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; + :if ([ :len $PrivatePassphrase ] > 0) do={ + :if ($PrivatePassphrase = "ignore") do={ + /caps-man/access-list/set $Entry !private-passphrase; + } else={ + /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; + } + } + :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; + :if ([ :len $SsidRegexp ] > 0) do={ + /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; + } + :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; + :if ([ :len $VlanId ] > 0) do={ + /caps-man/access-list/set $Entry vlan-id=$VlanId; + } + :local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; + :if ([ :len $VlanMode] > 0) do={ + /caps-man/access-list/set $Entry vlan-mode=$VlanMode; + } + + :delay 2s; + /caps-man/access-list/set $Entry action=accept; + + /ip/dhcp-server/lease/remove $Lease; + } +} do={ + :global ExitOnError; $ExitOnError [ :jobname ] $Err; +} diff --git a/hotspot-to-wpa-lease.template.rsc b/hotspot-to-wpa-lease.template.rsc new file mode 100644 index 00000000..c8f9a787 --- /dev/null +++ b/hotspot-to-wpa-lease.template.rsc @@ -0,0 +1,129 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa-lease%TEMPL% +# Copyright (c) 2019-2026 Christian Hesse +# https://rsc.eworm.de/COPYING.md +# +# provides: dhcpv4-server-lease, order=40 +# requires RouterOS, version=7.22 +# requires device-mode, hotspot +# +# add private WPA passphrase after hotspot login +# https://rsc.eworm.de/doc/hotspot-to-wpa.md +# +# !! This is just a template to generate the real script! +# !! Pattern '%TEMPL%' is replaced, paths are filtered. + +:onerror Err { + :global GlobalConfigReady; :global GlobalFunctionsReady; + :retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \ + do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50; + :local ScriptName [ :jobname ]; + + :global EitherOr; + :global LogPrint; + :global ParseKeyValueStore; + :global ScriptLock; + + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic disabled comment~"hotspot-to-wpa" ] do={ + :local LeaseVal [ $ParseKeyValueStore [ /ip/dhcp-server/lease/get $Lease comment ] ]; + + :if (($LeaseVal->"hotspot-to-wpa") != true) do={ + :continue; + } + + :local MacAddress $"mac-address"; + :local UserName $username; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :exit; + } + + :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ + $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); + :exit; + } + + :local Date [ /system/clock/get date ]; + :local UserVal ({}); + :if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ + :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; + } + :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; + :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; + + :if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + :if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'."); + } + :local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + + :if ([ :len [ /caps-man/access-list/find where \ + :if ([ :len [ /interface/wifi/access-list/find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ + /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + $LogPrint warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'."); + } + :local Template [ /caps-man/access-list/get ([ find where \ + :local Template [ /interface/wifi/access-list/get ([ find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; + + :if ($Template->"action" = "reject") do={ + $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); + :exit; + } + + $LogPrint info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ")."); + /caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; + /interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; + /caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + /interface/wifi/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + action=reject place-before=$PlaceBefore; + + :local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ + :local Entry [ /interface/wifi/access-list/find where mac-address=$MacAddress \ + comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; +# NOT /caps-man/ # + :set ($Template->"private-passphrase") ($Template->"passphrase"); +# NOT /caps-man/ # + :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; + :if ([ :len $PrivatePassphrase ] > 0) do={ + :if ($PrivatePassphrase = "ignore") do={ + /caps-man/access-list/set $Entry !private-passphrase; + /interface/wifi/access-list/set $Entry !passphrase; + } else={ + /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; + /interface/wifi/access-list/set $Entry passphrase=$PrivatePassphrase; + } + } + :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; + :if ([ :len $SsidRegexp ] > 0) do={ + /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; + /interface/wifi/access-list/set $Entry ssid-regexp=$SsidRegexp; + } + :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; + :if ([ :len $VlanId ] > 0) do={ + /caps-man/access-list/set $Entry vlan-id=$VlanId; + /interface/wifi/access-list/set $Entry vlan-id=$VlanId; + } +# NOT /interface/wifi/ # + :local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; + :if ([ :len $VlanMode] > 0) do={ + /caps-man/access-list/set $Entry vlan-mode=$VlanMode; + } +# NOT /interface/wifi/ # + + :delay 2s; + /caps-man/access-list/set $Entry action=accept; + /interface/wifi/access-list/set $Entry action=accept; + + /ip/dhcp-server/lease/remove $Lease; + } +} do={ + :global ExitOnError; $ExitOnError [ :jobname ] $Err; +} diff --git a/hotspot-to-wpa-lease.wifi.rsc b/hotspot-to-wpa-lease.wifi.rsc new file mode 100644 index 00000000..4959c7ec --- /dev/null +++ b/hotspot-to-wpa-lease.wifi.rsc @@ -0,0 +1,106 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa-lease.wifi +# Copyright (c) 2019-2026 Christian Hesse +# https://rsc.eworm.de/COPYING.md +# +# provides: dhcpv4-server-lease, order=40 +# requires RouterOS, version=7.22 +# requires device-mode, hotspot +# +# add private WPA passphrase after hotspot login +# https://rsc.eworm.de/doc/hotspot-to-wpa.md +# +# !! Do not edit this file, it is generated from template! + +:onerror Err { + :global GlobalConfigReady; :global GlobalFunctionsReady; + :retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \ + do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50; + :local ScriptName [ :jobname ]; + + :global EitherOr; + :global LogPrint; + :global ParseKeyValueStore; + :global ScriptLock; + + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic disabled comment~"hotspot-to-wpa" ] do={ + :local LeaseVal [ $ParseKeyValueStore [ /ip/dhcp-server/lease/get $Lease comment ] ]; + + :if (($LeaseVal->"hotspot-to-wpa") != true) do={ + :continue; + } + + :local MacAddress $"mac-address"; + :local UserName $username; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :exit; + } + + :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ + $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); + :exit; + } + + :local Date [ /system/clock/get date ]; + :local UserVal ({}); + :if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ + :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; + } + :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; + :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; + + :if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; + $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'."); + } + :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + + :if ([ :len [ /interface/wifi/access-list/find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ + /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; + $LogPrint warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'."); + } + :local Template [ /interface/wifi/access-list/get ([ find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; + + :if ($Template->"action" = "reject") do={ + $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); + :exit; + } + + $LogPrint info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ + " (user " . $UserName . ")."); + /interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; + /interface/wifi/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ + mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + action=reject place-before=$PlaceBefore; + + :local Entry [ /interface/wifi/access-list/find where mac-address=$MacAddress \ + comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; + :set ($Template->"private-passphrase") ($Template->"passphrase"); + :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; + :if ([ :len $PrivatePassphrase ] > 0) do={ + :if ($PrivatePassphrase = "ignore") do={ + /interface/wifi/access-list/set $Entry !passphrase; + } else={ + /interface/wifi/access-list/set $Entry passphrase=$PrivatePassphrase; + } + } + :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; + :if ([ :len $SsidRegexp ] > 0) do={ + /interface/wifi/access-list/set $Entry ssid-regexp=$SsidRegexp; + } + :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; + :if ([ :len $VlanId ] > 0) do={ + /interface/wifi/access-list/set $Entry vlan-id=$VlanId; + } + + :delay 2s; + /interface/wifi/access-list/set $Entry action=accept; + + /ip/dhcp-server/lease/remove $Lease; + } +} do={ + :global ExitOnError; $ExitOnError [ :jobname ] $Err; +} diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc deleted file mode 100644 index 8d8afffc..00000000 --- a/hotspot-to-wpa.capsman.rsc +++ /dev/null @@ -1,101 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: hotspot-to-wpa.capsman -# Copyright (c) 2019-2026 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.22 -# requires device-mode, hotspot -# -# add private WPA passphrase after hotspot login -# https://rsc.eworm.de/doc/hotspot-to-wpa.md -# -# !! Do not edit this file, it is generated from template! - -:onerror Err { - :global GlobalConfigReady; :global GlobalFunctionsReady; - :retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \ - do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50; - :local ScriptName [ :jobname ]; - - :global EitherOr; - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptLock; - - :local MacAddress $"mac-address"; - :local UserName $username; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :exit; - } - - :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ - $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); - :exit; - } - - :local Date [ /system/clock/get date ]; - :local UserVal ({}); - :if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ - :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; - } - :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; - :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; - - :if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'."); - } - :local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - - :if ([ :len [ /caps-man/access-list/find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrint warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'."); - } - :local Template [ /caps-man/access-list/get ([ find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; - - :if ($Template->"action" = "reject") do={ - $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); - :exit; - } - - # allow login page to load - :delay 1s; - - $LogPrint info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ")."); - /caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; - /caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - action=reject place-before=$PlaceBefore; - - :local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ - comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; - :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; - :if ([ :len $PrivatePassphrase ] > 0) do={ - :if ($PrivatePassphrase = "ignore") do={ - /caps-man/access-list/set $Entry !private-passphrase; - } else={ - /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; - } - } - :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; - :if ([ :len $SsidRegexp ] > 0) do={ - /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; - } - :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; - :if ([ :len $VlanId ] > 0) do={ - /caps-man/access-list/set $Entry vlan-id=$VlanId; - } - :local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; - :if ([ :len $VlanMode] > 0) do={ - /caps-man/access-list/set $Entry vlan-mode=$VlanMode; - } - - :delay 2s; - /caps-man/access-list/set $Entry action=accept; -} do={ - :global ExitOnError; $ExitOnError [ :jobname ] $Err; -} diff --git a/hotspot-to-wpa.rsc b/hotspot-to-wpa.rsc new file mode 100644 index 00000000..6bb8d50e --- /dev/null +++ b/hotspot-to-wpa.rsc @@ -0,0 +1,44 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa.wifi +# Copyright (c) 2019-2026 Christian Hesse +# https://rsc.eworm.de/COPYING.md +# +# requires RouterOS, version=7.22 +# requires device-mode, hotspot +# requires policy, policy=read;write +# +# add private WPA passphrase after hotspot login +# https://rsc.eworm.de/doc/hotspot-to-wpa.md + +:local ExitOK false; +:onerror Err { + :local ScriptName [ :jobname ]; + + :local Address $"address"; + :local Interface $"interface"; + :local MacAddress $"mac-address"; + :local UserName $"username"; + + :local Lease [ /ip/dhcp-server/lease/find where mac-address=$MacAddress address=$Address ]; + + :if ([ :len $Lease ] != 1) do={ + :log warning ($ScriptName . ": Did not find exactly one lease for " . $MacAddress . "!"); + :set ExitOK true; + :error false; + } + + /ip/dhcp-server/lease/set \ + comment=[ :serialize to=json ({ \ + "hotspot-to-wpa"=true; \ + "address"=$Address; \ + "interface"=$Interface; \ + "mac-address"=$MacAddress; \ + "username"=$UserName }) ] $Lease; + /ip/dhcp-server/lease/make-static $Lease; + :delay 1s; + /ip/dhcp-server/lease/disable $Lease; +} do={ + :if ($ExitOK = false) do={ + :log error ([ :jobname ] . ": " . $Err); + } +} diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc deleted file mode 100644 index eca5202e..00000000 --- a/hotspot-to-wpa.template.rsc +++ /dev/null @@ -1,121 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: hotspot-to-wpa%TEMPL% -# Copyright (c) 2019-2026 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.22 -# requires device-mode, hotspot -# -# add private WPA passphrase after hotspot login -# https://rsc.eworm.de/doc/hotspot-to-wpa.md -# -# !! This is just a template to generate the real script! -# !! Pattern '%TEMPL%' is replaced, paths are filtered. - -:onerror Err { - :global GlobalConfigReady; :global GlobalFunctionsReady; - :retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \ - do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50; - :local ScriptName [ :jobname ]; - - :global EitherOr; - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptLock; - - :local MacAddress $"mac-address"; - :local UserName $username; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :exit; - } - - :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ - $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); - :exit; - } - - :local Date [ /system/clock/get date ]; - :local UserVal ({}); - :if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ - :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; - } - :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; - :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; - - :if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - :if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'."); - } - :local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - - :if ([ :len [ /caps-man/access-list/find where \ - :if ([ :len [ /interface/wifi/access-list/find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrint warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'."); - } - :local Template [ /caps-man/access-list/get ([ find where \ - :local Template [ /interface/wifi/access-list/get ([ find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; - - :if ($Template->"action" = "reject") do={ - $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); - :exit; - } - - # allow login page to load - :delay 1s; - - $LogPrint info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ")."); - /caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; - /interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; - /caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - /interface/wifi/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - action=reject place-before=$PlaceBefore; - - :local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ - :local Entry [ /interface/wifi/access-list/find where mac-address=$MacAddress \ - comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; -# NOT /caps-man/ # - :set ($Template->"private-passphrase") ($Template->"passphrase"); -# NOT /caps-man/ # - :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; - :if ([ :len $PrivatePassphrase ] > 0) do={ - :if ($PrivatePassphrase = "ignore") do={ - /caps-man/access-list/set $Entry !private-passphrase; - /interface/wifi/access-list/set $Entry !passphrase; - } else={ - /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; - /interface/wifi/access-list/set $Entry passphrase=$PrivatePassphrase; - } - } - :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; - :if ([ :len $SsidRegexp ] > 0) do={ - /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; - /interface/wifi/access-list/set $Entry ssid-regexp=$SsidRegexp; - } - :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; - :if ([ :len $VlanId ] > 0) do={ - /caps-man/access-list/set $Entry vlan-id=$VlanId; - /interface/wifi/access-list/set $Entry vlan-id=$VlanId; - } -# NOT /interface/wifi/ # - :local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; - :if ([ :len $VlanMode] > 0) do={ - /caps-man/access-list/set $Entry vlan-mode=$VlanMode; - } -# NOT /interface/wifi/ # - - :delay 2s; - /caps-man/access-list/set $Entry action=accept; - /interface/wifi/access-list/set $Entry action=accept; -} do={ - :global ExitOnError; $ExitOnError [ :jobname ] $Err; -} diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc deleted file mode 100644 index 432a9b6d..00000000 --- a/hotspot-to-wpa.wifi.rsc +++ /dev/null @@ -1,98 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: hotspot-to-wpa.wifi -# Copyright (c) 2019-2026 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.22 -# requires device-mode, hotspot -# -# add private WPA passphrase after hotspot login -# https://rsc.eworm.de/doc/hotspot-to-wpa.md -# -# !! Do not edit this file, it is generated from template! - -:onerror Err { - :global GlobalConfigReady; :global GlobalFunctionsReady; - :retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \ - do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50; - :local ScriptName [ :jobname ]; - - :global EitherOr; - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptLock; - - :local MacAddress $"mac-address"; - :local UserName $username; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :exit; - } - - :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ - $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); - :exit; - } - - :local Date [ /system/clock/get date ]; - :local UserVal ({}); - :if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ - :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; - } - :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; - :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; - - :if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'."); - } - :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - - :if ([ :len [ /interface/wifi/access-list/find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrint warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'."); - } - :local Template [ /interface/wifi/access-list/get ([ find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; - - :if ($Template->"action" = "reject") do={ - $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); - :exit; - } - - # allow login page to load - :delay 1s; - - $LogPrint info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ")."); - /interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; - /interface/wifi/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - action=reject place-before=$PlaceBefore; - - :local Entry [ /interface/wifi/access-list/find where mac-address=$MacAddress \ - comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; - :set ($Template->"private-passphrase") ($Template->"passphrase"); - :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; - :if ([ :len $PrivatePassphrase ] > 0) do={ - :if ($PrivatePassphrase = "ignore") do={ - /interface/wifi/access-list/set $Entry !passphrase; - } else={ - /interface/wifi/access-list/set $Entry passphrase=$PrivatePassphrase; - } - } - :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; - :if ([ :len $SsidRegexp ] > 0) do={ - /interface/wifi/access-list/set $Entry ssid-regexp=$SsidRegexp; - } - :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; - :if ([ :len $VlanId ] > 0) do={ - /interface/wifi/access-list/set $Entry vlan-id=$VlanId; - } - - :delay 2s; - /interface/wifi/access-list/set $Entry action=accept; -} do={ - :global ExitOnError; $ExitOnError [ :jobname ] $Err; -} diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 1b3adb26..4139dd8e 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -69,6 +69,7 @@ 142="Added a setting for 'mod/notification-email' to check availability of certificate chain."; 143="Made backup scripts 'backup-email' and 'backup-upload' support date & time in filenames."; 144="Split and reworked 'mode-button' for compatibility with RouterOS 7.24, configuration was updated automatically."; + 145="Split and reworked 'hotspot-to-wpa' for compatibility with RouterOS 7.24, configuration was updated automatically."; }; # Migration steps to be applied on script updates @@ -81,4 +82,5 @@ 138="/certificate/set trusted=yes [ find where trusted=yes ];"; 140=":if ([ :len [ /system/script/find where name=\"lease-script\" ] ] > 0) do={ /system/script/set name=\"dhcpv4-server-lease\" \"lease-script\"; :global ScriptInstallUpdate; \$ScriptInstallUpdate; /ip/dhcp-server/set lease-script=\"dhcpv4-server-lease\" [ find where lease-script=\"lease-script\" ]; };"; 144=":if ([ :len [ /system/script/find where name=\"mode-button\" ] ] > 0) do={ :global ScriptInstallUpdate; \$ScriptInstallUpdate mode-button-scheduler; };"; + 145=":local Script [ /system/script/find where name~\"^hostspot-to-wap\\\\.\"; :if ([ :len \$Script ] > 0) do={ :local Type ([ :toarray delimiter=\".\" [ /system/script/get name \$Script ] ]->1); /system/script/set name=\"hostspot-to-wap\" \$Script; :global ScriptInstallUpdate; \$ScriptInstallUpdate (\"dhcpv4-server-lease,hostspot-to-wap-lease.\" . \$Type); /ip/hotspot/user/profile/set on-login=\"hotspot-to-wpa\" [ find where on-login~\"hotspot-to-wpa\" ]; :foreach Hotspot in=[ /ip/hotspot/find ] do={ /ip/dhcp-server/set lease-script=\"dhcpv4-server-lease\" [ find where interface=[ /ip/hotspot/get \$Hotspot interface ] ]; }; };"; };