pirania: fix dead captive portal redirect server (uhttpd-mod-lua contract) - #1288
Merged
a-gave merged 2 commits intoOct 2, 2026
Merged
Conversation
Commit ba4f382 ('fix: luacheck: pirania') localized handle_request and added 'return handle_request'. That is valid Lua and it keeps the busted tests passing, because they load the file as a module via require(). uhttpd-mod-lua, the actual consumer, uses a different contract: it loadfile()s the handler, executes it and then looks up the GLOBAL handle_request. With a local function the lookup fails, uhttpd exits with 'provides no handle_request() callback', procd gives up after five respawns and pirania-uhttpd never listens on :59080. Every HTTP capture redirect then lands on a closed port and the captive portal is dead. Keep the function global (with a luacheck directive so lint stays clean) and keep the module-style return, so both consumers work. Add a test that loads the file the way uhttpd does and asserts the global is defined, so the regression cannot pass CI again.
The packaged default only listed wlan0-ap, so on two-radio LibreMesh nodes (e.g. Ubiquiti UniFi 6 Lite) clients on the 5 GHz AP were never captured by the captive portal. The consumer is an nft set of type ifname, so a name that does not exist on single-radio devices never matches and the extra entry is harmless there.
a-gave
approved these changes
Oct 2, 2026
a-gave
left a comment
Contributor
There was a problem hiding this comment.
Thanks! Assuming it has been tested/fixed also on a real device: approving
And personally sorry for having introduced the regression, the luacheck globals is more appropriate!
This branch is waiting to be deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Pirania's HTTP capture redirect server (
pirania-uhttpd, port 59080) never listens: procd gives up after five respawn attempts and every HTTP capture redirect lands on a closed port, so the captive portal is dead on any build that includesba4f3824("fix: luacheck: pirania", merged 2026-08-05).Root cause
That commit localized
handle_requestinpackages/pirania/files/www/paradise... packages/pirania/files/www/pirania-redirect/redirectand addedreturn handle_request.That is valid Lua and it keeps the busted tests green, because they load the file as a module via
require(). But the real consumer, uhttpd-mod-lua, uses a different contract: itloadfile()s the handler, executes it, and then looks up the globalhandle_request. With a local function the lookup fails, uhttpd exits withError: Lua handler ... provides no handle_request() callback, procd respawns five times and gives up.Fix
handle_requestglobal (with a-- luacheck: globals handle_requestdirective so lint stays clean) and keep the module-style return, so both consumers work.loadfile()+ assert global), so this regression cannot pass CI again.Verification
Found live on LibreMesh master builds flashed onto UniFi 6 Lite nodes:
/etc/init.d/pirania-uhttpd status= not running; manual invocation of the init command line reproducedError: Lua handler /www/pirania-redirect/redirect provides no handle_request() callbackinstantly; after the fix the service stays up, port 59080 answers302to the portal URL, and/portal/auth.htmlanswers200. CI will also run the new contract test.Also in this PR (second commit)
The packaged default
catch_bridged_interfacesonly listedwlan0-ap, so on two-radio nodes (UniFi 6 Lite) 5 GHz clients bypassed the portal. Addedwlan1-ap; consumer is an nft set of typeifname, so the extra default entry is harmless on single-radio devices.