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()

Reply via email to