mirror of
https://github.com/bunkerity/bunkerized-nginx
synced 2023-12-13 21:30:18 +01:00
various redis fixes and display ready log
This commit is contained in:
parent
17a3d933b3
commit
edf7e06e07
10 changed files with 162 additions and 22 deletions
3
TODO
3
TODO
|
@ -1,4 +1,5 @@
|
|||
- load inline values for white/black/grey list core
|
||||
- bwcli with redis
|
||||
- move bans to cachestore
|
||||
- direct access to ANTIBOT_URI without prepare_challenge call
|
||||
- don't fail if session err is not nil (new session will be created)
|
||||
- limit refactoring with redis scripts if needed
|
||||
|
|
|
@ -69,13 +69,12 @@ function cachestore:get(key)
|
|||
return {ret_get, ret_ttl}
|
||||
]]
|
||||
local ret, err = clusterstore:call("eval", redis_script, 1, key)
|
||||
-- local cjson = require "cjson"
|
||||
-- require "bunkerweb.logger":new("DEBUG"):log(ngx.ERR, cjson.encode(ret))
|
||||
if not ret then
|
||||
clusterstore:close()
|
||||
return nil, err, nil
|
||||
end
|
||||
-- Extract values
|
||||
clusterstore:close(redis)
|
||||
clusterstore:close()
|
||||
if ret[1] == ngx.null then
|
||||
ret[1] = nil
|
||||
end
|
||||
|
|
|
@ -30,7 +30,7 @@ function datastore:keys()
|
|||
return self.dict:get_keys(0)
|
||||
end
|
||||
|
||||
function datastore:exp(key)
|
||||
function datastore:ttl(key)
|
||||
local ttl, err = self.dict:ttl(key)
|
||||
if not ttl then
|
||||
return false, err
|
||||
|
|
|
@ -490,4 +490,96 @@ utils.get_session_var = function(key)
|
|||
return false, "no session"
|
||||
end
|
||||
|
||||
utils.is_banned = function(ip)
|
||||
-- Check on local datastore
|
||||
local reason, err = datastore:get("bans_ip_" .. ip)
|
||||
if not reason and err ~= "not found" then
|
||||
return nil, "datastore:get() error : " .. reason
|
||||
elseif reason and err ~= "not found" then
|
||||
local ok, ttl = datastore:ttl("bans_ip_" .. ip)
|
||||
if not ok then
|
||||
return true, reason, -1
|
||||
end
|
||||
return true, reason, ttl
|
||||
end
|
||||
-- Redis case
|
||||
local use_redis, err = utils.get_variable("USE_REDIS", false)
|
||||
if not use_redis then
|
||||
return nil, "can't get USE_REDIS variable : " .. err
|
||||
elseif use_redis ~= "yes" then
|
||||
return false, "not banned"
|
||||
end
|
||||
-- Connect
|
||||
local clusterstore = require "bunkerweb.clusterstore":new()
|
||||
local ok, err = clusterstore:connect()
|
||||
if not ok then
|
||||
return nil, "can't connect to redis server : " .. err
|
||||
end
|
||||
-- Redis atomic script : GET+TTL
|
||||
local redis_script = [[
|
||||
local ret_get = redis.pcall("GET", KEYS[1])
|
||||
if type(ret_get) == "table" and ret_get["err"] ~= nil then
|
||||
redis.log(redis.LOG_WARNING, "access GET error : " .. ret_get["err"])
|
||||
return ret_get
|
||||
end
|
||||
local ret_ttl = nil
|
||||
if ret_get ~= nil then
|
||||
ret_ttl = redis.pcall("TTL", KEYS[1])
|
||||
if type(ret_ttl) == "table" and ret_ttl["err"] ~= nil then
|
||||
redis.log(redis.LOG_WARNING, "access TTL error : " .. ret_ttl["err"])
|
||||
return ret_ttl
|
||||
end
|
||||
end
|
||||
return {ret_get, ret_ttl}
|
||||
]]
|
||||
-- Execute redis script
|
||||
local data, err = clusterstore:call("eval", redis_script, 1, "bans_ip_" .. ip)
|
||||
if not data then
|
||||
clusterstore:close()
|
||||
return nil, "redis call error : " .. err
|
||||
elseif data.err then
|
||||
clusterstore:close()
|
||||
return nil, "redis script error : " .. data.err
|
||||
elseif data[1] ~= ngx.null then
|
||||
clusterstore:close()
|
||||
-- Update local cache
|
||||
local ok, err = datastore:set("bans_ip_" .. ip, data[1], data[2])
|
||||
if not ok then
|
||||
return nil, "datastore:set() error : " .. err
|
||||
end
|
||||
return true, data[1], data[2]
|
||||
end
|
||||
clusterstore:close()
|
||||
return false, "not banned"
|
||||
end
|
||||
|
||||
utils.add_ban = function(ip, reason, ttl)
|
||||
-- Set on local datastore
|
||||
local ok, err = datastore:set("bans_ip_" .. ip, reason, ttl)
|
||||
if not ok then
|
||||
return false, "datastore:set() error : " .. err
|
||||
end
|
||||
-- Set on redis
|
||||
local use_redis, err = utils.get_variable("USE_REDIS", false)
|
||||
if not use_redis then
|
||||
return nil, "can't get USE_REDIS variable : " .. err
|
||||
elseif use_redis ~= "yes" then
|
||||
return true, "success"
|
||||
end
|
||||
-- Connect
|
||||
local clusterstore = require "bunkerweb.clusterstore":new()
|
||||
local ok, err = clusterstore:connect()
|
||||
if not ok then
|
||||
return false, "can't connect to redis server : " .. err
|
||||
end
|
||||
-- SET call
|
||||
local ok, err = clusterstore:call("set", "bans_ip_" .. ip, reason, "EX", ttl)
|
||||
if not ok then
|
||||
clusterstore:close()
|
||||
return false, "redis SET failed : " .. err
|
||||
end
|
||||
clusterstore:close()
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
return utils
|
|
@ -53,6 +53,9 @@ lua_shared_dict cachestore_locks {{ CACHESTORE_LOCKS_MEMORY_SIZE }};
|
|||
# LUA init block
|
||||
include /etc/nginx/init-lua.conf;
|
||||
|
||||
# LUA init worker block
|
||||
include /etc/nginx/init-worker-lua.conf;
|
||||
|
||||
# API server
|
||||
{% if USE_API == "yes" %}include /etc/nginx/api.conf;{% endif +%}
|
||||
|
||||
|
|
39
src/common/confs/init-worker-lua.conf
Normal file
39
src/common/confs/init-worker-lua.conf
Normal file
|
@ -0,0 +1,39 @@
|
|||
lua_shared_dict ready_lock 16k;
|
||||
|
||||
init_worker_by_lua_block {
|
||||
|
||||
-- Our timer function
|
||||
local ready_log = function(premature)
|
||||
-- Instantiate objects
|
||||
local logger = require "bunkerweb.logger":new("INIT")
|
||||
local datastore = require "bunkerweb.datastore":new()
|
||||
local lock = require "resty.lock":new("ready_lock")
|
||||
if not lock then
|
||||
logger:log(ngx.ERR, "lock:new() failed : " .. err)
|
||||
return
|
||||
end
|
||||
-- Acquire lock
|
||||
local elapsed, err = lock:lock("ready")
|
||||
if elapsed == nil then
|
||||
logger:log(ngx.ERR, "lock:lock() failed : " .. err)
|
||||
else
|
||||
-- Display ready log
|
||||
local ok, err = datastore:get("misc_ready")
|
||||
if not ok and err ~= "not found" then
|
||||
logger:log(ngx.ERR, "datastore:get() failed : " .. err)
|
||||
elseif not ok and err == "not found" then
|
||||
logger:log(ngx.NOTICE, "BunkerWeb is ready to fool hackers ! 🚀")
|
||||
local ok, err = datastore:set("misc_ready", "ok")
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "datastore:set() failed : " .. err)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Release lock
|
||||
lock:unlock()
|
||||
end
|
||||
|
||||
-- Start timer
|
||||
ngx.timer.at(5, ready_log)
|
||||
|
||||
}
|
|
@ -5,6 +5,7 @@ local clogger = require "bunkerweb.logger"
|
|||
local helpers = require "bunkerweb.helpers"
|
||||
local utils = require "bunkerweb.utils"
|
||||
local cdatastore = require "bunkerweb.datastore"
|
||||
local cclusterstore = require "bunkerweb.clusterstore"
|
||||
local cjson = require "cjson"
|
||||
|
||||
-- Don't process internal requests
|
||||
|
@ -31,12 +32,14 @@ end
|
|||
logger:log(ngx.INFO, "ngx.ctx filled (ret = " .. ret .. ")")
|
||||
|
||||
-- Process bans as soon as possible
|
||||
local reason, err = datastore:get("bans_ip_" .. ngx.ctx.bw.remote_addr)
|
||||
if not reason and err ~= "not found" then
|
||||
logger:log(ngx.ERR, "error while checking if client is banned : " .. reason)
|
||||
elseif reason and err ~= "not found" then
|
||||
logger:log(ngx.WARN, "IP " .. ngx.ctx.bw.remote_addr .. " is banned with reason : " .. reason)
|
||||
local banned, reason, ttl = utils.is_banned(ngx.ctx.bw.remote_addr)
|
||||
if banned == nil then
|
||||
logger:log(ngx.ERR, "can't check if IP " .. ngx.ctx.bw.remote_addr .. " is banned : " .. reason)
|
||||
elseif banned then
|
||||
logger:log(ngx.WARN, "IP " .. ngx.ctx.bw.remote_addr .. " is banned with reason " .. reason .. " (" .. tostring(ttl) .. "s remaining)")
|
||||
return ngx.exit(utils.get_deny_status())
|
||||
else
|
||||
logger:log(ngx.INFO, "IP " .. ngx.ctx.bw.remote_addr .. " is not banned")
|
||||
end
|
||||
|
||||
-- Get plugins
|
||||
|
|
|
@ -53,7 +53,7 @@ function badbehavior.increase(premature, ip, count_time, ban_time, threshold, us
|
|||
local counter = false
|
||||
-- Redis case
|
||||
if use_redis then
|
||||
local redis_counter, err = bad_behavior.redis_increase(ip, count_time, ban_time)
|
||||
local redis_counter, err = badbehavior.redis_increase(ip, count_time, ban_time)
|
||||
if not redis_counter then
|
||||
logger:log(ngx.ERR, "(increase) redis_increase failed, falling back to local : " .. err)
|
||||
else
|
||||
|
@ -84,9 +84,9 @@ function badbehavior.increase(premature, ip, count_time, ban_time, threshold, us
|
|||
end
|
||||
-- Store local ban
|
||||
if counter > threshold then
|
||||
local ok, err = datastore:set("bans_ip_" .. ip, "bad behavior", ban_time)
|
||||
local ok, err = utils.add_ban(ip, "bad behavior", ban_time)
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "(increase) can't save ban to the datastore : " .. err)
|
||||
logger:log(ngx.ERR, "(increase) can't save ban : " .. err)
|
||||
return
|
||||
end
|
||||
logger:log(ngx.WARN, "IP " .. ip .. " is banned for " .. ban_time .. "s (" .. tostring(counter) .. "/" .. tostring(threshold) .. ")")
|
||||
|
@ -102,9 +102,9 @@ function badbehavior.decrease(premature, ip, count_time, threshold, use_redis)
|
|||
local counter = false
|
||||
-- Redis case
|
||||
if use_redis then
|
||||
local redis_counter, err = badbehavior.redis_decrease(ip)
|
||||
local redis_counter, err = badbehavior.redis_decrease(ip, count_time)
|
||||
if not redis_counter then
|
||||
logger:log(ngx.ERR, "(increase) redis_increase failed, falling back to local : " .. err)
|
||||
logger:log(ngx.ERR, "(decrease) redis_decrease failed, falling back to local : " .. err)
|
||||
else
|
||||
counter = redis_counter
|
||||
end
|
||||
|
@ -113,7 +113,7 @@ function badbehavior.decrease(premature, ip, count_time, threshold, use_redis)
|
|||
if not counter then
|
||||
local local_counter, err = datastore:get("plugin_badbehavior_count_" .. ip)
|
||||
if not local_counter and err ~= "not found" then
|
||||
logger:log(ngx.ERR, "(increase) can't get counts from the datastore : " .. err)
|
||||
logger:log(ngx.ERR, "(decrease) can't get counts from the datastore : " .. err)
|
||||
end
|
||||
if local_counter == nil or local_counter <= 1 then
|
||||
counter = 0
|
||||
|
@ -123,11 +123,12 @@ function badbehavior.decrease(premature, ip, count_time, threshold, use_redis)
|
|||
end
|
||||
-- Store local counter
|
||||
if counter <= 0 then
|
||||
counter = 0
|
||||
local ok, err = datastore:delete("plugin_badbehavior_count_" .. ip)
|
||||
else
|
||||
local ok, err = datastore:set("plugin_badbehavior_count_" .. ip, counter, count_time)
|
||||
if not ok then
|
||||
logger:log(ngx.ERR, "(increase) can't save counts to the datastore : " .. err)
|
||||
logger:log(ngx.ERR, "(decrease) can't save counts to the datastore : " .. err)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
@ -149,7 +150,7 @@ function badbehavior.redis_increase(ip, count_time, ban_time)
|
|||
redis.log(redis.LOG_WARNING, "Bad behavior increase EXPIRE error : " .. ret_expire["err"])
|
||||
return ret_expire
|
||||
end
|
||||
if ret_incr > ARGV[2] then
|
||||
if ret_incr > tonumber(ARGV[2]) then
|
||||
local ret_set = redis.pcall("SET", KEYS[2], "bad behavior", "EX", ARGV[2])
|
||||
if type(ret_set) == "table" and ret_set["err"] ~= nil then
|
||||
redis.log(redis.LOG_WARNING, "Bad behavior increase SET error : " .. ret_set["err"])
|
||||
|
|
|
@ -16,7 +16,7 @@ function redis:init()
|
|||
if self.variables["USE_REDIS"] ~= "yes" or self.is_loading then
|
||||
return self:ret(true, "init not needed")
|
||||
end
|
||||
-- Check redis connection
|
||||
-- Check redis connection ()
|
||||
local ok, err = clusterstore:connect()
|
||||
if not ok then
|
||||
return self:ret(false, "redis connect error : " .. err)
|
|
@ -19,16 +19,18 @@ function sessions:init()
|
|||
["USE_REDIS"] = "",
|
||||
["REDIS_HOST"] = "",
|
||||
["REDIS_PORT"] = "",
|
||||
["REDIS_DATABASE"] = "",
|
||||
["REDIS_SSL"] = "",
|
||||
["REDIS_TIMEOUT"] = "",
|
||||
["REDIS_KEEPALIVE_IDLE"] = "",
|
||||
["REDIS_KEEPALIVE_POOL"] = ""
|
||||
}
|
||||
for k, v in pairs(redis_vars) do
|
||||
local var, err = utils.get_variable(k, false)
|
||||
if var == nil then
|
||||
local value, err = utils.get_variable(k, false)
|
||||
if value == nil then
|
||||
return self:ret(false, "can't get " .. k .. " variable : " .. err)
|
||||
end
|
||||
redis_vars[k] = value
|
||||
end
|
||||
-- Init configuration
|
||||
local config = {
|
||||
|
@ -58,7 +60,7 @@ function sessions:init()
|
|||
pool_size = tonumber(redis_vars["REDIS_KEEPALIVE_POOL"]),
|
||||
ssl = redis_vars["REDIS_SSL"] == "yes",
|
||||
host = redis_vars["REDIS_HOST"],
|
||||
port = tonumber(redis_vars["REDIS_HOST"]),
|
||||
port = tonumber(redis_vars["REDIS_PORT"]),
|
||||
database = tonumber(redis_vars["REDIS_DATABASE"])
|
||||
}
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue