Sindbad~EG File Manager
--[[
This lib is used to temporary ban IPs addresses that attack us.
The list is automaticaly generated from the autoMitigation system, when an IP exceed the threshold.
The ban is temporary, the connection is also drop early on the SSL handshake to avoid using too much CPU / SSL DDOS
--]]
local o2config = require "lib/o2switch_config"
local o2debug = require "lib/o2switch_debug"
local ipUtils = require "lib/o2switch_ip_utils"
local mlcache = require("resty.mlcache")
local timer = require("resty.timer")
local banDict = ngx.shared.ip_blacklist_dict
local ngx = ngx
local cache, err = nil, nil
local tostring = tostring
local type = type
local ipairs = ipairs
local sub = string.sub
local table_insert = table.insert
local useCache = false
local defaultMlcacheOpts = { ttl = o2config.tmpBanTime, neg_ttl = 60, }
local _M = {}
-- This module will have his own cache and not use the o2switch_cache_wrapper because it's on a separate dict.
if o2config.useInternalCache and not cache then
--o2debug.debug('Create cache called : ' .. tostring(o2config.tmpBanTime) .. ',' .. tostring(60))
-- @See https://github.com/thibaultcha/lua-resty-mlcache
cache, err = mlcache.new("ip_bl", "ip_blacklist_dict", {
lru_size = 50000, -- size of the L1 (Lua VM) cache (nb of items)
ttl = o2config.tmpBanTime,
neg_ttl = 60,
ipc_shm = 'sync_dict' -- Name of the lua_shared_dict used by the workers sync, to purge/empty L1 cache
})
if not cache then
o2debug.debugErr("Cache : Could not create mlcache." .. (err or ''))
else
useCache = true
end
end
-- Add an IP address to the blacklist
-- @binaryIp The IP address to blacklist, in the binary form (ngx.var.binary_remote_addr)
-- @whitelistMapValue The value of the $map_underattack_wl. We need to check that here because we deny on the SSL level, we cant rely on the customer_security/*.conf file, it's too early.
-- @return bool, err|nil
function _M.addIpToBlacklist(binaryIp, whitelistMapValue)
if whitelistMapValue == "1" or whitelistMapValue == 1 then
return false, "IP is whitelisted"
end
local ok, err = nil, nil
if useCache and cache then
ok, err = cache:set(binaryIp, defaultMlcacheOpts, binaryIp)
else
ok, err = banDict:set(binaryIp, binaryIp, o2config.tmpBanTime)
end
return ok, err
end
-- Remove an IP address from the blacklist
-- @binaryIp The IP address, in the binary form (ngx.var.binary_remote_addr)
-- @return bool, err|nil
function _M.removeFromBlacklist(binaryIp)
local ok, err = nil, nil
if useCache and cache then
ok, err = cache:delete(binaryIp)
else
ok, err = banDict:delete(binaryIp)
end
return ok, err
end
-- Check if an IP address is blacklisted. Return true if so
-- @binaryIp The IP address in the binary form (ngx.var.binary_remote_addr)
-- @return bool
function _M.isBlacklisted(binaryIp)
local ok, err = nil, nil
if useCache and cache then
ok, err = cache:get(binaryIp)
else
ok, err = banDict:get(binaryIp)
end
if ok == nil or not ok then
return false
end
return true
end
-- Export the list of the currently banned IP addresses
-- @return table, err|nil
function _M.exportBlacklistedIp()
local keys = banDict:get_keys(0)
local result = {}
for _, k in ipairs(keys) do
local value = nil
if useCache then
k = sub(k, 6) -- Remove the prefix of the mlcache to retrieve the original key
value = cache:get(k)
else
value = banDict:get(k)
end
if type(value) == 'string' then
value = ipUtils.binaryToStringIp(value)
if type(value) == 'string' then
table_insert(result, value)
end
end
end
return result, nil
end
--- Check if the cache is active, if so, execute the cache invalidation on the Nginx Worker. It will remove the stale
-- elements from the L1 cache. It can (should) be done once per requests.
-- @return {bool success, string|nil errMsg}
function _M.executeInvalidation()
--o2debug.debug("o2switch_ban.executeInvalidation: Called")
if o2config.useInternalCache == false then
return true, nil -- Do we return an error or not ? Not sure.
end
if not cache then
--o2debug.debug("o2switch_ban.executeInvalidation: Can't executeInvalidation, the cache object is null.")
return false, "Can't executeInvalidation, the cache object is null."
end
local ok, err = cache:update(1);
if not ok then
--o2debug.debug("o2switch_ban.executeInvalidation:" .. (err or "no err msg"));
return false, (err or "no err msg")
end
--o2debug.debug("o2switch_ban.executeInvalidation: Looks fine")
return true, nil
end
-- Register one timer per nginx worker that will execute the cache invalidation (if the case is activated)
function _M.registerTimers()
--o2debug.debug('o2switch_ban.registerTimers() called')
if o2config.useInternalCache == false then
return nil
end
timer({
interval = 89,
recurring = true,
immediate = false,
detached = true,
jitter = 0.1,
expire = function()
local ban = require "lib/o2switch_ban"
ban.executeInvalidation()
end
})
return nil
end
return _M
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists