From f0303997c09ce899c73c77f06352a4a3a8e2263c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 23 Jul 2026 12:47:15 +0200 Subject: [PATCH] hotspot-to-wpa: rework for RouterOS 7.24 compatibility --- README.md | 2 +- doc/hotspot-to-wpa.md | 21 +++--- global-functions.rsc | 2 +- hotspot-to-wpa-lease.capsman.rsc | 98 +++++++++++++++++++++++++ hotspot-to-wpa-lease.template.rsc | 118 ++++++++++++++++++++++++++++++ hotspot-to-wpa-lease.wifi.rsc | 95 ++++++++++++++++++++++++ hotspot-to-wpa.capsman.rsc | 100 ++++++------------------- hotspot-to-wpa.template.rsc | 118 ++++++------------------------ hotspot-to-wpa.wifi.rsc | 95 ++++++------------------ news-and-changes.rsc | 2 + 10 files changed, 398 insertions(+), 253 deletions(-) create mode 100644 hotspot-to-wpa-lease.capsman.rsc create mode 100644 hotspot-to-wpa-lease.template.rsc create mode 100644 hotspot-to-wpa-lease.wifi.rsc 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..1a04d2a2 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -26,35 +26,38 @@ 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 wireless with CAPsMAN (`/caps-man`) you need +to install a different set of scripts. Then set the `on-login` script in hotspot. For `wifi`: - $ScriptInstallUpdate hotspot-to-wpa.wifi; + $ScriptInstallUpdate hotspot-to-wpa.wifi,hotspot-to-wpa-lease.wifi,dhcpv4-server-lease; /ip/hotspot/user/profile/set on-login="hotspot-to-wpa.wifi" [ find ]; For legacy CAPsMAN: - $ScriptInstallUpdate hotspot-to-wpa.capsman; + $ScriptInstallUpdate hotspot-to-wpa.wifi,hotspot-to-wpa-lease.capsman,dhcpv4-server-lease; /ip/hotspot/user/profile/set on-login="hotspot-to-wpa.capsman" [ 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..489933de --- /dev/null +++ b/hotspot-to-wpa-lease.capsman.rsc @@ -0,0 +1,98 @@ +#!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; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :exit; + } + + :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); + + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic disabled comment~"\\bhotspot-to-wpa\\b" ] do={ + :local LeaseVal [ $ParseKeyValueStore [ /ip/dhcp-server/lease/get $Lease comment ] ]; + /ip/dhcp-server/lease/remove $Lease; + + :if (($LeaseVal->"hotspot-to-wpa") != true) do={ + :continue; + } + + :local MacAddress $"mac-address"; + :local UserName $username; + + :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 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) ]; + + $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-lease.template.rsc b/hotspot-to-wpa-lease.template.rsc new file mode 100644 index 00000000..734f7b2a --- /dev/null +++ b/hotspot-to-wpa-lease.template.rsc @@ -0,0 +1,118 @@ +#!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; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :exit; + } + + :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); + + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic disabled comment~"\\bhotspot-to-wpa\\b" ] do={ + :local LeaseVal [ $ParseKeyValueStore [ /ip/dhcp-server/lease/get $Lease comment ] ]; + /ip/dhcp-server/lease/remove $Lease; + + :if (($LeaseVal->"hotspot-to-wpa") != true) do={ + :continue; + } + + :local MacAddress $"mac-address"; + :local UserName $username; + + :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 \ + :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) ]; + + $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-lease.wifi.rsc b/hotspot-to-wpa-lease.wifi.rsc new file mode 100644 index 00000000..4b91a545 --- /dev/null +++ b/hotspot-to-wpa-lease.wifi.rsc @@ -0,0 +1,95 @@ +#!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; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :exit; + } + + :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); + + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic disabled comment~"\\bhotspot-to-wpa\\b" ] do={ + :local LeaseVal [ $ParseKeyValueStore [ /ip/dhcp-server/lease/get $Lease comment ] ]; + /ip/dhcp-server/lease/remove $Lease; + + :if (($LeaseVal->"hotspot-to-wpa") != true) do={ + :continue; + } + + :local MacAddress $"mac-address"; + :local UserName $username; + + :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 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) ]; + + $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/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc index 8d8afffc..82eb908a 100644 --- a/hotspot-to-wpa.capsman.rsc +++ b/hotspot-to-wpa.capsman.rsc @@ -5,6 +5,7 @@ # # 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 @@ -12,90 +13,37 @@ # !! 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 Address $"address"; + :local Interface $"interface"; :local MacAddress $"mac-address"; - :local UserName $username; + :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 . "'."); + :if ([ /caps-man/access-list/find where \ + comment=("hotspot-to-wpa template " . $Hotspot) disabled action="reject" ] ] > 0) do={ + :log info ($ScriptName . ": Ignoring login for " . $MacAddress . " on hotspot '" . $Hotspot . "'."); :exit; } - # allow login page to load + :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 . "!"); + :exit; + } + + /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; - - $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/disable $Lease; } do={ - :global ExitOnError; $ExitOnError [ :jobname ] $Err; + :log error ([ :jobname ] . ": " . $Err); } diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc index eca5202e..fb9fee62 100644 --- a/hotspot-to-wpa.template.rsc +++ b/hotspot-to-wpa.template.rsc @@ -5,6 +5,7 @@ # # 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 @@ -13,109 +14,38 @@ # !! 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 Address $"address"; + :local Interface $"interface"; :local MacAddress $"mac-address"; - :local UserName $username; + :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 ([ /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 . "'."); + comment=("hotspot-to-wpa template " . $Hotspot) disabled action="reject" ] ] > 0) do={ + :log info ($ScriptName . ": Ignoring login for " . $MacAddress . " on hotspot '" . $Hotspot . "'."); :exit; } - # allow login page to load + :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 . "!"); + :exit; + } + + /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; - - $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/disable $Lease; } do={ - :global ExitOnError; $ExitOnError [ :jobname ] $Err; + :log error ([ :jobname ] . ": " . $Err); } diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc index 432a9b6d..5f7222ea 100644 --- a/hotspot-to-wpa.wifi.rsc +++ b/hotspot-to-wpa.wifi.rsc @@ -5,6 +5,7 @@ # # 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 @@ -12,87 +13,37 @@ # !! 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 Address $"address"; + :local Interface $"interface"; :local MacAddress $"mac-address"; - :local UserName $username; + :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 . "'."); + comment=("hotspot-to-wpa template " . $Hotspot) disabled action="reject" ] ] > 0) do={ + :log info ($ScriptName . ": Ignoring login for " . $MacAddress . " on hotspot '" . $Hotspot . "'."); :exit; } - # allow login page to load + :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 . "!"); + :exit; + } + + /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; - - $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/disable $Lease; } do={ - :global ExitOnError; $ExitOnError [ :jobname ] $Err; + :log error ([ :jobname ] . ": " . $Err); } diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 1b3adb26..49f61729 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); :global ScriptInstallUpdate; \$ScriptInstallUpdate (\"dhcpv4-server-lease,hostspot-to-wap-lease.\" . \$Type); :foreach Hotspot in=[ /ip/hotspot/find ] do={ /ip/dhcp-server/set lease-script=\"dhcpv4-server-lease\" [ find where interface=[ /ip/hotspot/get \$Hotspot interface ] ]; }; };"; };