On Tue, Jul 11, 2017 at 10:31:59PM -0400, Thor Lancelot Simon wrote: > Captive-portal login is a very real problem. How best to solve it otherwise? > Remember, small embedded systems (easily supported by adding additional sets > using our existing framework) are within scope.
If anyone wants to try it out, I don't have a captive portal at home (thankfully), fetch pkgsrc/*/lua-socket and try the attached. Some tinkering may be needed.
#!/usr/pkg/bin/lua5.2 -- if a captive portal exists -- extract first action url -- submit it a username & password -- CAVEATS: -- assumes the first 'action' url is the right one -- assumes the fields are called 'username' and 'password' -- Public domain local io = require("io") local http = require("socket.http") local ltn12 = require("ltn12") local url = require("socket.url") function usage() print("Usage: captive_portal username password [url]") end -- Captive portals redirect normal URL accesses function find_captive(test_url) local response_body = {} local res, code, headers = http.request { url = test_url, redirect = false, sink = ltn12.sink.table(response_body) } if (tonumber(code) ~= nil) and (type(headers.location) == "string") and (code < 400) and (code >= 300) then return headers.location else return nil end end -- Given a portal page, return the form submit URL -- XXX assumes the first action="" is the valid one. function find_action_page(portal_url) local portal_html = http.request(portal_url) print("html") print(html) local action_url = portal_html:match('[Aa][Cc][Tt][Ii][Oo][Nn]%s*=%s*"([^"]*)"') if action_url == nil then return nil end print("DEBUG action url: " .. action_url) print("DEBUG absolute url: " ..url.absolute(portal_url, action_url)) return url.absolute(portal_url, action_url) end function submit_credentials(username, password, action_url) local request_body = "login=" .. url.escape(username) .. "&password=" .. url.escape(password) local response_body = { } local res, code, response_headers = http.request { url = action_url; method = "POST"; headers = { ["Content-Type"] = "application/x-www-form-urlencoded"; ["Content-Length"] = #request_body; }; source = ltn12.source.string(request_body); sink = ltn12.sink.table(response_body) } print(response_body[1]) end function main() if (#arg < 2) then usage() os.exit() end local username = arg[1] local password = arg[2] local normally_working_url = "http://www.google.com" if (#arg > 2) then normally_working_url = arg[3] end local portal_url = find_captive(normally_working_url) if portal_url == nil then print("Not a captive portal") os.exit() end local action_url = find_action_page(portal_url) if action_url == nil then print("Didn't find a submit URL") os.exit() end submit_credentials(username, password, action_url) end main()