mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
refactor - blacklist, errors, greylist, letsencrypt and redis
This commit is contained in:
parent
2075a5d4c2
commit
666b7a1bac
7 changed files with 276 additions and 402 deletions
|
|
@ -10,7 +10,7 @@ local blacklist = class("blacklist", plugin)
|
|||
|
||||
function blacklist:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "antibot")
|
||||
local ok, err = plugin.new(self, "blacklist")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ local cachestore = require "bunkerweb.cachestore"
|
|||
local cjson = require "cjson"
|
||||
local resolver = require "resty.dns.resolver"
|
||||
|
||||
local dnsbl = class("country", plugin)
|
||||
local dnsbl = class("dnsbl", plugin)
|
||||
|
||||
local dnsbl:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "country")
|
||||
local ok, err = plugin.new(self, "dnsbl")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ location = {{ page }} {
|
|||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if INTERCEPTED_ERROR_CODES != "" %}
|
||||
{% for intercepted_error_code in INTERCEPTED_ERROR_CODES.split(" ") %}
|
||||
{% if not intercepted_error_code + "=" in ERRORS +%}
|
||||
|
|
@ -27,16 +26,18 @@ location = {{ page }} {
|
|||
modsecurity off;
|
||||
default_type 'text/html';
|
||||
content_by_lua_block {
|
||||
local logger = require "logger"
|
||||
local logger = require "bunkerweb.logger"
|
||||
local errors = require "errors.errors"
|
||||
local html, err
|
||||
logger:new("errors")
|
||||
errors:new()
|
||||
if ngx.status == 200 then
|
||||
html, err = errors.error_html(tostring(405))
|
||||
html, err = errors:error_html(tostring(405))
|
||||
else
|
||||
html, err = errors.error_html(tostring(ngx.status))
|
||||
html, err = errors:error_html(tostring(ngx.status))
|
||||
end
|
||||
if not html then
|
||||
logger.log(ngx.ERR, "ERRORS", "Error while computing HTML error template for {{ intercepted_error_code }} : " .. err)
|
||||
logger:log(ngx.ERR, "error while computing HTML error template for {{ intercepted_error_code }} : " .. err)
|
||||
else
|
||||
ngx.say(html)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,17 +1,21 @@
|
|||
local _M = {}
|
||||
_M.__index = _M
|
||||
local class = require "middleclass"
|
||||
local plugin = require "bunkerweb.plugin"
|
||||
local utils = require "bunkerweb.utils"
|
||||
local cachestore = require "bunkerweb.cachestore"
|
||||
local cjson = require "cjson"
|
||||
|
||||
local utils = require "utils"
|
||||
local datastore = require "datastore"
|
||||
local logger = require "logger"
|
||||
local cjson = require "cjson"
|
||||
local errors = class("errors", plugin)
|
||||
|
||||
function _M.new()
|
||||
local self = setmetatable({}, _M)
|
||||
return self, nil
|
||||
function errors:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "errors")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
function _M:init()
|
||||
function errors:init()
|
||||
-- Save default errors into datastore
|
||||
local default_errors = {
|
||||
["400"] = {
|
||||
|
|
@ -65,12 +69,12 @@ function _M:init()
|
|||
}
|
||||
local ok, err = datastore:set("plugin_errors_default_errors", cjson.encode(default_errors))
|
||||
if not ok then
|
||||
return false, "can't save default errors to datastore : " .. err
|
||||
return self:ret(false, "can't save default errors to datastore : " .. err)
|
||||
end
|
||||
-- Save generic template into datastore
|
||||
local f, err = io.open("/usr/share/bunkerweb/core/errors/files/error.html", "r")
|
||||
if not f then
|
||||
return false, "can't open error.html : " .. err
|
||||
return self:ret(false, "can't open error.html : " .. err)
|
||||
end
|
||||
local template = f:read("*all")
|
||||
f:close()
|
||||
|
|
@ -81,7 +85,7 @@ function _M:init()
|
|||
return true, "success"
|
||||
end
|
||||
|
||||
function _M.error_html(code)
|
||||
function errors:error_html(code)
|
||||
-- Load default errors texts
|
||||
local default_errors, err = datastore:get("plugin_errors_default_errors")
|
||||
if not default_errors then
|
||||
|
|
@ -98,4 +102,4 @@ function _M.error_html(code)
|
|||
default_errors[code].body2), "success"
|
||||
end
|
||||
|
||||
return _M
|
||||
return errors
|
||||
|
|
@ -1,365 +1,232 @@
|
|||
local _M = {}
|
||||
_M.__index = _M
|
||||
local class = require "middleclass"
|
||||
local plugin = require "bunkerweb.plugin"
|
||||
local utils = require "bunkerweb.utils"
|
||||
local cjson = require "cjson"
|
||||
local ipmatcher = require "resty.ipmatcher"
|
||||
|
||||
local utils = require "utils"
|
||||
local datastore = require "datastore"
|
||||
local logger = require "logger"
|
||||
local cjson = require "cjson"
|
||||
local ipmatcher = require "resty.ipmatcher"
|
||||
local greylist = class("dnsbl", plugin)
|
||||
|
||||
function _M.new()
|
||||
local self = setmetatable({}, _M)
|
||||
return self, nil
|
||||
end
|
||||
|
||||
function _M:init()
|
||||
function greylist:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "greylist")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
-- Check if redis is enabled
|
||||
local use_redis, err = utils.get_variable("USE_REDIS", false)
|
||||
if not use_redis then
|
||||
return false, err
|
||||
end
|
||||
self.use_redis = use_redis == "yes"
|
||||
-- Check if init is needed
|
||||
local init_needed, err = utils.has_variable("USE_GREYLIST", "yes")
|
||||
if init_needed == nil then
|
||||
return false, err
|
||||
end
|
||||
if not init_needed then
|
||||
return true, "no service uses Greylist, skipping init"
|
||||
end
|
||||
-- Read greylists
|
||||
local greylists = {
|
||||
["IP"] = {},
|
||||
["RDNS"] = {},
|
||||
["ASN"] = {},
|
||||
["USER_AGENT"] = {},
|
||||
["URI"] = {}
|
||||
}
|
||||
local i = 0
|
||||
for kind, _ in pairs(greylists) do
|
||||
local f, err = io.open("/var/cache/bunkerweb/greylist/" .. kind .. ".list", "r")
|
||||
if f then
|
||||
for line in f:lines() do
|
||||
table.insert(greylists[kind], line)
|
||||
i = i + 1
|
||||
end
|
||||
f:close()
|
||||
if ngx.get_phase() == "init" then
|
||||
local init_needed, err = utils.has_variable("USE_GREYLIST", "yes")
|
||||
if init_needed == nil then
|
||||
return false, err
|
||||
end
|
||||
end
|
||||
-- Load them into datastore
|
||||
local ok, err = datastore:set("plugin_greylist_list", cjson.encode(greylists))
|
||||
if not ok then
|
||||
return false, "can't store Greylist list into datastore : " .. err
|
||||
end
|
||||
return true, "successfully loaded " .. tostring(i) .. " greylisted IP/network/rDNS/ASN/User-Agent/URI"
|
||||
end
|
||||
|
||||
function _M:access()
|
||||
-- Check if access is needed
|
||||
local access_needed, err = utils.get_variable("USE_GREYLIST")
|
||||
if access_needed == nil then
|
||||
return false, err, false, nil
|
||||
end
|
||||
if access_needed ~= "yes" then
|
||||
return true, "Greylist not activated", false, nil
|
||||
end
|
||||
|
||||
-- Check the cache
|
||||
local cached_ip, err = self:is_in_cache("ip" .. ngx.var.remote_addr)
|
||||
if cached_ip and cached_ip ~= "ok" then
|
||||
return true, "IP is in greylist cache (info = " .. cached_ip .. ")", false, ngx.OK
|
||||
end
|
||||
local cached_uri, err = self:is_in_cache("uri" .. ngx.var.uri)
|
||||
if cached_uri and cached_uri ~= "ok" then
|
||||
return true, "URI is in greylist cache (info = " .. cached_uri .. ")", false, ngx.OK
|
||||
end
|
||||
local cached_ua = true
|
||||
if ngx.var.http_user_agent then
|
||||
cached_ua, err = self:is_in_cache("ua" .. ngx.var.http_user_agent)
|
||||
if cached_ua and cached_ua ~= "ok" then
|
||||
return true, "User-Agent is in greylist cache (info = " .. cached_ua .. ")", false, ngx.OK
|
||||
self.init_needed = init_needed
|
||||
-- Decode lists
|
||||
else
|
||||
local lists, err = datastore:get("plugin_greylist_lists")
|
||||
if not lists then
|
||||
return false, err
|
||||
end
|
||||
self.lists = cjson.decode(lists)
|
||||
end
|
||||
if cached_ip and cached_uri and cached_ua then
|
||||
return true, "full request is in greylist cache (not greylisted)", false, nil
|
||||
end
|
||||
|
||||
-- Get list
|
||||
local data, err = datastore:get("plugin_greylist_list")
|
||||
if not data then
|
||||
return false, "can't get Greylist list : " .. err, false, nil
|
||||
end
|
||||
local ok, greylists = pcall(cjson.decode, data)
|
||||
if not ok then
|
||||
return false, "error while decoding greylists : " .. greylists, false, nil
|
||||
end
|
||||
|
||||
-- Return value
|
||||
local ret, ret_err = true, "success"
|
||||
|
||||
-- Check if IP is in IP/net greylist
|
||||
local ip_net, err = utils.get_variable("GREYLIST_IP")
|
||||
if ip_net and ip_net ~= "" then
|
||||
for element in ip_net:gmatch("%S+") do
|
||||
table.insert(greylists["IP"], element)
|
||||
end
|
||||
end
|
||||
if not cached_ip then
|
||||
local ipm, err = ipmatcher.new(greylists["IP"])
|
||||
if not ipm then
|
||||
ret = false
|
||||
ret_err = "can't instantiate ipmatcher " .. err
|
||||
else
|
||||
if ipm:match(ngx.var.remote_addr) then
|
||||
self:add_to_cache("ip" .. ngx.var.remote_addr, "ip/net")
|
||||
return ret, "client IP " .. ngx.var.remote_addr .. " is in greylist", false, ngx.OK
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if rDNS is in greylist
|
||||
local rdns_global, err = utils.get_variable("GREYLIST_RDNS_GLOBAL")
|
||||
local check = true
|
||||
if not rdns_global then
|
||||
logger.log(ngx.ERR, "GREYLIST", "Error while getting GREYLIST_RDNS_GLOBAL variable : " .. err)
|
||||
elseif rdns_global == "yes" then
|
||||
check, err = utils.ip_is_global(ngx.var.remote_addr)
|
||||
if check == nil then
|
||||
logger.log(ngx.ERR, "GREYLIST", "Error while getting checking if IP is global : " .. err)
|
||||
end
|
||||
end
|
||||
if not cached_ip and check then
|
||||
local rdns, err = utils.get_rdns(ngx.var.remote_addr)
|
||||
if not rdns then
|
||||
ret = false
|
||||
ret_err = "error while trying to get reverse dns : " .. err
|
||||
else
|
||||
local rdns_list, err = utils.get_variable("GREYLIST_RDNS")
|
||||
if rdns_list and rdns_list ~= "" then
|
||||
for element in rdns_list:gmatch("%S+") do
|
||||
table.insert(greylists["RDNS"], element)
|
||||
end
|
||||
end
|
||||
for i, suffix in ipairs(greylists["RDNS"]) do
|
||||
if rdns:sub(- #suffix) == suffix then
|
||||
self:add_to_cache("ip" .. ngx.var.remote_addr, "rDNS " .. suffix)
|
||||
return ret, "client IP " .. ngx.var.remote_addr .. " is in greylist (info = rDNS " .. suffix .. ")", false, ngx.OK
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if ASN is in greylist
|
||||
if not cached_ip then
|
||||
if utils.ip_is_global(ngx.var.remote_addr) then
|
||||
local asn, err = utils.get_asn(ngx.var.remote_addr)
|
||||
if not asn then
|
||||
ret = false
|
||||
ret_err = "error while trying to get asn number : " .. err
|
||||
else
|
||||
local asn_list, err = utils.get_variable("GREYLIST_ASN")
|
||||
if asn_list and asn_list ~= "" then
|
||||
for element in asn_list:gmatch("%S+") do
|
||||
table.insert(greylists["ASN"], element)
|
||||
end
|
||||
end
|
||||
for i, asn_bl in ipairs(greylists["ASN"]) do
|
||||
if tostring(asn) == asn_bl then
|
||||
self:add_to_cache("ip" .. ngx.var.remote_addr, "ASN " .. tostring(asn))
|
||||
return ret, "client IP " .. ngx.var.remote_addr .. " is in greylist (kind = ASN " .. tostring(asn) .. ")", false,
|
||||
ngx.OK
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- IP is not greylisted
|
||||
local ok, err = self:add_to_cache("ip" .. ngx.var.remote_addr, "ok")
|
||||
if not ok then
|
||||
ret = false
|
||||
ret_err = err
|
||||
end
|
||||
|
||||
-- Check if User-Agent is in greylist
|
||||
if not cached_ua and ngx.var.http_user_agent then
|
||||
local ua_list, err = utils.get_variable("GREYLIST_USER_AGENT")
|
||||
if ua_list and ua_list ~= "" then
|
||||
for element in ua_list:gmatch("%S+") do
|
||||
table.insert(greylists["USER_AGENT"], element)
|
||||
end
|
||||
end
|
||||
for i, ua_bl in ipairs(greylists["USER_AGENT"]) do
|
||||
if ngx.var.http_user_agent:match(ua_bl) then
|
||||
self:add_to_cache("ua" .. ngx.var.http_user_agent, "UA " .. ua_bl)
|
||||
return ret, "client User-Agent " .. ngx.var.http_user_agent .. " is in greylist (matched " .. ua_bl .. ")", false,
|
||||
ngx.OK
|
||||
end
|
||||
end
|
||||
-- UA is not greylisted
|
||||
local ok, err = self:add_to_cache("ua" .. ngx.var.http_user_agent, "ok")
|
||||
if not ok then
|
||||
ret = false
|
||||
ret_err = err
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if URI is in greylist
|
||||
if not cached_uri then
|
||||
local uri_list, err = utils.get_variable("GREYLIST_URI")
|
||||
if uri_list and uri_list ~= "" then
|
||||
for element in uri_list:gmatch("%S+") do
|
||||
table.insert(greylists["URI"], element)
|
||||
end
|
||||
end
|
||||
for i, uri_bl in ipairs(greylists["URI"]) do
|
||||
if ngx.var.uri:match(uri_bl) then
|
||||
self:add_to_cache("uri" .. ngx.var.uri, "URI " .. uri_bl)
|
||||
return ret, "client URI " .. ngx.var.uri .. " is in greylist (matched " .. uri_bl .. ")", false, ngx.OK
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- URI is not greylisted
|
||||
local ok, err = self:add_to_cache("uri" .. ngx.var.uri, "ok")
|
||||
if not ok then
|
||||
ret = false
|
||||
ret_err = err
|
||||
end
|
||||
|
||||
return ret, "IP is not in list (error = " .. ret_err .. ")", true, utils.get_deny_status()
|
||||
end
|
||||
|
||||
function _M:preread()
|
||||
-- Check if preread is needed
|
||||
local preread_needed, err = utils.get_variable("USE_GREYLIST")
|
||||
if preread_needed == nil then
|
||||
return false, err, false, nil
|
||||
end
|
||||
if preread_needed ~= "yes" then
|
||||
return true, "Greylist not activated", false, nil
|
||||
end
|
||||
|
||||
-- Check the cache
|
||||
local cached_ip, err = self:is_in_cache("ip" .. ngx.var.remote_addr)
|
||||
if cached_ip and cached_ip ~= "ok" then
|
||||
return true, "IP is in greylist cache (info = " .. cached_ip .. ")", false, ngx.OK
|
||||
end
|
||||
if cached_ip then
|
||||
return true, "full request is in greylist cache (not greylisted)", false, nil
|
||||
end
|
||||
|
||||
-- Get list
|
||||
local data, err = datastore:get("plugin_greylist_list")
|
||||
if not data then
|
||||
return false, "can't get Greylist list : " .. err, false, nil
|
||||
end
|
||||
local ok, greylists = pcall(cjson.decode, data)
|
||||
if not ok then
|
||||
return false, "error while decoding greylists : " .. greylists, false, nil
|
||||
end
|
||||
|
||||
-- Return value
|
||||
local ret, ret_err = true, "success"
|
||||
|
||||
-- Check if IP is in IP/net greylist
|
||||
local ip_net, err = utils.get_variable("GREYLIST_IP")
|
||||
if ip_net and ip_net ~= "" then
|
||||
for element in ip_net:gmatch("%S+") do
|
||||
table.insert(greylists["IP"], element)
|
||||
end
|
||||
end
|
||||
if not cached_ip then
|
||||
local ipm, err = ipmatcher.new(greylists["IP"])
|
||||
if not ipm then
|
||||
ret = false
|
||||
ret_err = "can't instantiate ipmatcher " .. err
|
||||
else
|
||||
if ipm:match(ngx.var.remote_addr) then
|
||||
self:add_to_cache("ip" .. ngx.var.remote_addr, "ip/net")
|
||||
return ret, "client IP " .. ngx.var.remote_addr .. " is in greylist", false, ngx.OK
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if rDNS is in greylist
|
||||
local rdns_global, err = utils.get_variable("GREYLIST_RDNS_GLOBAL")
|
||||
local check = true
|
||||
if not rdns_global then
|
||||
logger.log(ngx.ERR, "GREYLIST", "Error while getting GREYLIST_RDNS_GLOBAL variable : " .. err)
|
||||
elseif rdns_global == "yes" then
|
||||
check, err = utils.ip_is_global(ngx.var.remote_addr)
|
||||
if check == nil then
|
||||
logger.log(ngx.ERR, "GREYLIST", "Error while getting checking if IP is global : " .. err)
|
||||
end
|
||||
end
|
||||
if not cached_ip and check then
|
||||
local rdns, err = utils.get_rdns(ngx.var.remote_addr)
|
||||
if not rdns then
|
||||
ret = false
|
||||
ret_err = "error while trying to get reverse dns : " .. err
|
||||
else
|
||||
local rdns_list, err = utils.get_variable("GREYLIST_RDNS")
|
||||
if rdns_list and rdns_list ~= "" then
|
||||
for element in rdns_list:gmatch("%S+") do
|
||||
table.insert(greylists["RDNS"], element)
|
||||
end
|
||||
end
|
||||
for i, suffix in ipairs(greylists["RDNS"]) do
|
||||
if rdns:sub(- #suffix) == suffix then
|
||||
self:add_to_cache("ip" .. ngx.var.remote_addr, "rDNS " .. suffix)
|
||||
return ret, "client IP " .. ngx.var.remote_addr .. " is in greylist (info = rDNS " .. suffix .. ")", false, ngx.OK
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if ASN is in greylist
|
||||
if not cached_ip then
|
||||
if utils.ip_is_global(ngx.var.remote_addr) then
|
||||
local asn, err = utils.get_asn(ngx.var.remote_addr)
|
||||
if not asn then
|
||||
ret = false
|
||||
ret_err = "error while trying to get asn number : " .. err
|
||||
else
|
||||
local asn_list, err = utils.get_variable("GREYLIST_ASN")
|
||||
if asn_list and asn_list ~= "" then
|
||||
for element in asn_list:gmatch("%S+") do
|
||||
table.insert(greylists["ASN"], element)
|
||||
end
|
||||
end
|
||||
for i, asn_bl in ipairs(greylists["ASN"]) do
|
||||
if tostring(asn) == asn_bl then
|
||||
self:add_to_cache("ip" .. ngx.var.remote_addr, "ASN " .. tostring(asn))
|
||||
return ret, "client IP " .. ngx.var.remote_addr .. " is in greylist (kind = ASN " .. tostring(asn) .. ")", false,
|
||||
ngx.OK
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- IP is not greylisted
|
||||
local ok, err = self:add_to_cache("ip" .. ngx.var.remote_addr, "ok")
|
||||
if not ok then
|
||||
ret = false
|
||||
ret_err = err
|
||||
end
|
||||
return ret, "IP is not in list (error = " .. ret_err .. ")", true, utils.get_deny_status()
|
||||
end
|
||||
|
||||
function _M:is_in_cache(ele)
|
||||
local kind, err = datastore:get("plugin_greylist_cache_" .. ngx.var.server_name .. ele)
|
||||
if not kind then
|
||||
if err ~= "not found" then
|
||||
logger.log(ngx.ERR, "GREYLIST", "Error while accessing cache : " .. err)
|
||||
end
|
||||
return false, err
|
||||
end
|
||||
return kind, "success"
|
||||
end
|
||||
|
||||
function _M:add_to_cache(ele, kind)
|
||||
local ok, err = datastore:set("plugin_greylist_cache_" .. ngx.var.server_name .. ele, kind, 3600)
|
||||
if not ok then
|
||||
logger.log(ngx.ERR, "GREYLIST", "Error while adding element to cache : " .. err)
|
||||
return false, err
|
||||
end
|
||||
-- Instantiate cachestore
|
||||
cachestore:new(use_redis)
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
return _M
|
||||
function greylist:init()
|
||||
if self.init_needed then
|
||||
-- Read blacklists
|
||||
local greylists = {
|
||||
["IP"] = {},
|
||||
["RDNS"] = {},
|
||||
["ASN"] = {},
|
||||
["USER_AGENT"] = {},
|
||||
["URI"] = {},
|
||||
}
|
||||
local i = 0
|
||||
for kind, _ in pairs(greylists) do
|
||||
local f, err = io.open("/var/cache/bunkerweb/greylist/" .. kind .. ".list", "r")
|
||||
if f then
|
||||
for line in f:lines() do
|
||||
table.insert(greylists[kind], line)
|
||||
i = i + 1
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
-- Load them into datastore
|
||||
local ok, err = datastore:set("plugin_greylist_lists", cjson.encode(greylists))
|
||||
if not ok then
|
||||
return self:ret(false, "can't store greylist list into datastore : " .. err)
|
||||
end
|
||||
return self:ret(true, "successfully loaded " .. tostring(i) .. " bad IP/network/rDNS/ASN/User-Agent/URI")
|
||||
end
|
||||
end
|
||||
|
||||
function greylist:access()
|
||||
-- Check if access is needed
|
||||
if self.variables["USE_GREYLIST"] ~= "yes" then
|
||||
return self:ret(true, "greylist not activated")
|
||||
end
|
||||
-- Check the caches
|
||||
local checks = {
|
||||
["IP"] = "ip" .. ngx.var.remote_addr
|
||||
}
|
||||
if ngx.var.http_user_agent then
|
||||
checks["UA"] = "ua" .. ngx.var.http_user_agent
|
||||
end
|
||||
if ngx.var.uri then
|
||||
checks["URI"] = "uri" .. ngx.var.uri
|
||||
end
|
||||
local already_cached = {
|
||||
["IP"] = false,
|
||||
["URI"] = false,
|
||||
["UA"] = false
|
||||
}
|
||||
for k, v in pairs(checks) do
|
||||
local cached, err = self:is_in_cache(v)
|
||||
if not cached and err ~= "success" then
|
||||
self.logger:log(ngx.ERR, "error while checking cache : " .. err)
|
||||
elseif cached and cached ~= "ok" then
|
||||
return self:ret(true, k + " is in cached greylist", utils.get_deny_status())
|
||||
end
|
||||
if cached then
|
||||
already_cached[k] = true
|
||||
end
|
||||
end
|
||||
-- Check lists
|
||||
if not self.lists then
|
||||
return self:ret(false, "lists is nil")
|
||||
end
|
||||
-- Perform checks
|
||||
for k, v in pairs(checks) do
|
||||
if not already_cached[k] then
|
||||
local greylisted, err = self:is_greylisted(k)
|
||||
if greylisted == nil then
|
||||
self.logger:log(ngx.ERR, "error while checking if " .. k .. " is greylisted : " .. err)
|
||||
else
|
||||
local ok, err = self:add_to_cache(v, greylisted or "ok")
|
||||
if not ok then
|
||||
self.logger:log(ngx.ERR, "error while adding element to cache : " .. err)
|
||||
end
|
||||
if greylisted == "ko" then
|
||||
return self:ret(true, k + " is not in greylist", utils.get_deny_status())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Return
|
||||
return self:ret(true, "greylisted")
|
||||
end
|
||||
|
||||
function greylist:preread()
|
||||
return self:access()
|
||||
end
|
||||
|
||||
function greylist:is_greylisted(kind)
|
||||
if kind == "IP" then
|
||||
return self:is_greylisted_ip()
|
||||
elseif kind == "URI"
|
||||
return self:is_greylisted_uri()
|
||||
elseif kind == "UA"
|
||||
return self:is_greylisted_ua()
|
||||
return false, "unknown kind " .. kind
|
||||
end
|
||||
|
||||
function greylist:is_greylisted_ip()
|
||||
-- Check if IP is in blacklist
|
||||
local ipm, err = ipmatcher.new(self.lists["IP"])
|
||||
if not ipm then
|
||||
return nil, err
|
||||
end
|
||||
local match, err = ipm:match(ngx.var.remote_addr)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
if match then
|
||||
return true, "ip"
|
||||
end
|
||||
|
||||
-- Check if rDNS is needed
|
||||
local check_rdns = true
|
||||
if self.variables["BLACKLIST_RDNS_GLOBAL"] == "yes" then
|
||||
local is_global, err = utils.ip_is_global(ngx.var.remote_addr)
|
||||
if is_global == nil then
|
||||
return nil, err
|
||||
end
|
||||
if not is_global then
|
||||
check_rdns = false
|
||||
end
|
||||
end
|
||||
if check_rdns then
|
||||
-- Get rDNS
|
||||
local rdns_list, err = utils.get_rdns(ngx.var.remote_addr)
|
||||
if not rdns_list then
|
||||
return nil, err
|
||||
end
|
||||
-- Check if rDNS is in greylist
|
||||
for i, suffix in ipairs(self.lists["RDNS"]) do
|
||||
for j, rdns in ipairs(rdns_list) do
|
||||
if rdns:sub(-#suffix) == suffix then
|
||||
return true, "rDNS " .. suffix
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if ASN is in greylist
|
||||
for i, bl_asn in ipairs(self.lists["ASN"]) do
|
||||
if bl_asn == tostring(asn) then
|
||||
return true, "ASN " .. bl_asn
|
||||
end
|
||||
end
|
||||
|
||||
-- Not greylisted
|
||||
return false, "ko"
|
||||
end
|
||||
|
||||
function greylist:is_greylisted_uri()
|
||||
-- Check if URI is in blacklist
|
||||
for i, uri in ipairs(self.lists["URI"]) do
|
||||
if ngx.var.uri:match(uri) then
|
||||
return true, "URI " .. uri
|
||||
end
|
||||
end
|
||||
-- URI is not greylisted
|
||||
return false, "ko"
|
||||
end
|
||||
|
||||
function greylist:is_greylisted_ua()
|
||||
-- Check if UA is in greylist
|
||||
for i, ua in ipairs(self.lists["USER_AGENT"]) do
|
||||
if ngx.var.http_user_agent:match(ua) then
|
||||
return true, "UA " .. ua
|
||||
end
|
||||
end
|
||||
-- UA is not greylisted
|
||||
return false, "ko"
|
||||
end
|
||||
|
||||
function greylist:is_in_cache(ele)
|
||||
local ok, data = cachestore:get("plugin_greylist_" .. ele)
|
||||
if not ok then then
|
||||
return false, data
|
||||
end
|
||||
return true, data
|
||||
end
|
||||
|
||||
function greylist:add_to_cache(ele, value)
|
||||
local ok, err = cachestore:set("plugin_greylist_" .. ele, value)
|
||||
if not ok then then
|
||||
return false, err
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
return greylist
|
||||
|
|
@ -1,23 +1,27 @@
|
|||
local _M = {}
|
||||
_M.__index = _M
|
||||
local class = require "middleclass"
|
||||
local plugin = require "bunkerweb.plugin"
|
||||
local utils = require "bunkerweb.utils"
|
||||
local cjson = require "cjson"
|
||||
|
||||
local logger = require "logger"
|
||||
local cjson = require "cjson"
|
||||
local letsencrypt = class("letsencrypt", plugin)
|
||||
|
||||
function _M.new()
|
||||
local self = setmetatable({}, _M)
|
||||
return self, nil
|
||||
end
|
||||
|
||||
function _M:access()
|
||||
if string.sub(ngx.var.uri, 1, string.len("/.well-known/acme-challenge/")) == "/.well-known/acme-challenge/" then
|
||||
logger.log(ngx.NOTICE, "LETS-ENCRYPT", "Got a visit from Let's Encrypt, let's whitelist it.")
|
||||
return true, "success", true, ngx.exit(ngx.OK)
|
||||
function letsencrypt:new()
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "letsencrypt")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
return true, "success", false, nil
|
||||
end
|
||||
|
||||
function _M:api()
|
||||
function letsencrypt:access()
|
||||
if string.sub(ngx.var.uri, 1, string.len("/.well-known/acme-challenge/")) == "/.well-known/acme-challenge/" then
|
||||
self.logger:log(ngx.NOTICE, "got a visit from Let's Encrypt, let's whitelist it")
|
||||
return self:ret(true, "visit from LE", ngx.OK)
|
||||
end
|
||||
return self:ret(true, "success")
|
||||
end
|
||||
|
||||
function letsencrypt:api()
|
||||
if not string.match(ngx.var.uri, "^/lets%-encrypt/challenge$") or
|
||||
(ngx.var.request_method ~= "POST" and ngx.var.request_method ~= "DELETE") then
|
||||
return false, nil, nil
|
||||
|
|
@ -47,4 +51,4 @@ function _M:api()
|
|||
return true, ngx.HTTP_NOT_FOUND, { status = "error", msg = "unknown request" }
|
||||
end
|
||||
|
||||
return _M
|
||||
return letsencrypt
|
||||
|
|
@ -7,19 +7,17 @@ local clusterstore = require "bunkerweb.clusterstore"
|
|||
local redis = class("redis", plugin)
|
||||
|
||||
function redis:new()
|
||||
plugin.new(self, "redis")
|
||||
-- Store variable for later use
|
||||
local use_redis, err = utils.get_variable("USE_REDIS", false)
|
||||
if use_redis == nil then
|
||||
return self:ret(false, "can't check USE_REDIS variable : " .. err)
|
||||
-- Call parent new
|
||||
local ok, err = plugin.new(self, "redis")
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
self.use_redis = use_redis == "yes"
|
||||
return self:ret(true, "success")
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
function redis:init()
|
||||
-- Check if init is needed
|
||||
if not self.use_redis then
|
||||
if self.variables["USE_REDIS"] then
|
||||
return self:ret(true, "redis not used")
|
||||
end
|
||||
-- Check redis connection
|
||||
|
|
|
|||
Loading…
Reference in a new issue