mirror of
https://gitgud.io/fatchan/haproxy-protection.git
synced 2025-05-09 02:05:37 +00:00
86 lines
2.3 KiB
Lua
86 lines
2.3 KiB
Lua
local _M = {}
|
|
local sha = require("sha")
|
|
local tor_control_port_password = os.getenv("TOR_CONTROL_PORT_PASSWORD")
|
|
|
|
-- get header from different place depending on action vs view
|
|
function _M.get_header_from_context(context, header_name, is_applet)
|
|
local header_content = ""
|
|
if is_applet == true then
|
|
header_content = context.headers[header_name] or {}
|
|
header_content = header_content[0] or ""
|
|
else
|
|
header_content = context.sf:req_fhdr(header_name) or ""
|
|
end
|
|
return header_content
|
|
end
|
|
|
|
-- generate the challenge hash/user hash
|
|
function _M.generate_challenge(context, salt, user_key, ddos_config, is_applet)
|
|
|
|
-- optional IP to lock challenges/user_keys to IP (for clearnet or single-onion aka 99% of cases)
|
|
local ip = ""
|
|
if ddos_config["cip"] == true then
|
|
ip = context.sf:src()
|
|
end
|
|
|
|
-- if ddos_config["fp"] == true then
|
|
local custom_value = context:get_var("txn.fp_custom2") or ""
|
|
-- end
|
|
|
|
-- user agent to counter very dumb spammers
|
|
local user_agent = _M.get_header_from_context(context, "user-agent", is_applet)
|
|
|
|
local challenge_hash = sha.sha3_256(salt .. ip .. user_key .. custom_value .. user_agent)
|
|
|
|
local expiry = core.now()["sec"] + ddos_config["cex"]
|
|
|
|
return challenge_hash, expiry
|
|
|
|
end
|
|
|
|
-- split string by delimiter
|
|
function _M.split(inputstr, sep)
|
|
local t = {}
|
|
for str in string.gmatch(inputstr, "([^"..sep.."]*)") do
|
|
table.insert(t, str)
|
|
end
|
|
return t
|
|
end
|
|
|
|
-- check if elem in list
|
|
function _M.contains(list, elem)
|
|
for _, v in pairs(list) do
|
|
if v == elem then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- return true if hash passes difficulty
|
|
function _M.checkdiff(hash, diff)
|
|
if #hash == 0 then
|
|
return false
|
|
end
|
|
local i = 1
|
|
for j = 0, (diff-8), 8 do
|
|
if hash:sub(i, i) ~= "0" then
|
|
return false
|
|
end
|
|
i = i + 1
|
|
end
|
|
local lnm = tonumber(hash:sub(i, i), 16)
|
|
local msk = 0xff >> ((i*8)-diff)
|
|
return (lnm & msk) == 0
|
|
end
|
|
|
|
-- connect to the tor control port and instruct it to close a circuit
|
|
function _M.send_tor_control_port(circuit_identifier)
|
|
local tcp = core.tcp();
|
|
tcp:settimeout(1);
|
|
tcp:connect("127.0.0.1", 9051); --TODO: configurable host/port
|
|
-- not buffered, so we are better off sending it all at once
|
|
tcp:send('AUTHENTICATE "' .. tor_control_port_password .. '"\nCLOSECIRCUIT ' .. circuit_identifier ..'\n')
|
|
tcp:close()
|
|
end
|
|
|
|
return _M
|