137 lines
3.9 KiB
Lua
137 lines
3.9 KiB
Lua
local _M = {}
|
|
_M.__index = _M
|
|
|
|
local utils = require "utils"
|
|
local datastore = require "datastore"
|
|
local logger = require "logger"
|
|
local cjson = require "cjson"
|
|
local resolver = require "resty.dns.resolver"
|
|
|
|
function _M.new()
|
|
local self = setmetatable({}, _M)
|
|
return self, nil
|
|
end
|
|
|
|
function _M:init()
|
|
-- Check if init is needed
|
|
local init_needed, err = utils.has_variable("USE_DNSBL", "yes")
|
|
if init_needed == nil then
|
|
return false, "can't check USE_DNS variable : " .. err
|
|
end
|
|
if not init_needed then
|
|
return true, "no service uses Blacklist, skipping init"
|
|
end
|
|
-- Read DNSBL list
|
|
local str_dnsbls, err = utils.get_variable("DNSBL_LIST", false)
|
|
if not str_dnsbls then
|
|
return false, "can't get DNSBL_LIST variable : " .. err
|
|
end
|
|
local dnsbls = {}
|
|
local i = 0
|
|
for dnsbl in str_dnsbls:gmatch("%S+") do
|
|
table.insert(dnsbls, dnsbl)
|
|
i = i + 1
|
|
end
|
|
-- Load it into datastore
|
|
local ok, err = datastore:set("plugin_dnsbl_list", cjson.encode(dnsbls))
|
|
if not ok then
|
|
return false, "can't store DNSBL list into datastore : " .. err
|
|
end
|
|
return true, "successfully loaded " .. tostring(i) .. " DNSBL server(s)"
|
|
end
|
|
|
|
function _M:access()
|
|
-- Check if access is needed
|
|
local access_needed, err = utils.get_variable("USE_DNSBL")
|
|
if access_needed == nil then
|
|
return false, err
|
|
end
|
|
if access_needed ~= "yes" then
|
|
return true, "DNSBL not activated"
|
|
end
|
|
|
|
-- Check if IP is in cache
|
|
local dnsbl, err = self:is_in_cache(ngx.var.remote_addr)
|
|
if dnsbl then
|
|
if dnsbl == "ok" then
|
|
return true, "client IP " .. ngx.var.remote_addr .. " is in DNSBL cache (not blacklisted)", nil, nil
|
|
end
|
|
return true, "client IP " .. ngx.var.remote_addr .. " is in DNSBL cache (server = " .. dnsbl .. ")", true, ngx.HTTP_FORBIDDEN
|
|
end
|
|
|
|
-- Don't go further if IP is not global
|
|
local is_global, err = utils.ip_is_global(ngx.var.remote_addr)
|
|
if is_global == nil then
|
|
return false, "can't check if client IP is global : " .. err, nil, nil
|
|
end
|
|
if not utils.ip_is_global(ngx.var.remote_addr) then
|
|
self:add_to_cache(ngx.var.remote_addr, "ok")
|
|
return true, "client IP is not global, skipping DNSBL check", nil, nil
|
|
end
|
|
|
|
-- Get list
|
|
local data, err = datastore:get("plugin_dnsbl_list")
|
|
if not data then
|
|
return false, "can't get DNSBL list : " .. err, false, nil
|
|
end
|
|
local ok, dnsbls = pcall(cjson.decode, data)
|
|
if not ok then
|
|
return false, "error while decoding DNSBL list : " .. dnsbls, false, nil
|
|
end
|
|
|
|
-- Loop on dnsbl list
|
|
for i, dnsbl in ipairs(dnsbls) do
|
|
local result, err = self:is_in_dnsbl(dnsbl, ngx.var.remote_addr)
|
|
if result then
|
|
self:add_to_cache(ngx.var.remote_addr, dnsbl)
|
|
return ret, "client IP " .. ngx.var.remote_addr .. " is in DNSBL (server = " .. dnsbl .. ")", true, ngx.HTTP_FORBIDDEN
|
|
end
|
|
end
|
|
|
|
-- IP is not in DNSBL
|
|
local ok, err = self:add_to_cache(ngx.var.remote_addr, "ok")
|
|
if not ok then
|
|
return false, "IP is not in DNSBL (error = " .. err .. ")", false, nil
|
|
end
|
|
return true, "IP is not in DNSBL", false, nil
|
|
|
|
end
|
|
|
|
function _M:is_in_dnsbl(dnsbl, ip)
|
|
local request = resolver.arpa_str(ip) .. "." .. dnsbl
|
|
local ips, err = utils.get_ips(request)
|
|
if not ips then
|
|
logger.log(ngx.ERR, "DNSBL", "Error while asking DNSBL server " .. dnsbl .. " : " .. err)
|
|
return false, err
|
|
end
|
|
for i, ip in ipairs(ips) do
|
|
local a, b, c, d = ip:match("([%d]+).([%d]+).([%d]+).([%d]+)")
|
|
if a == "127" then
|
|
return true, "success"
|
|
end
|
|
end
|
|
return false, "success"
|
|
end
|
|
|
|
function _M:is_in_cache(ip)
|
|
local kind, err = datastore:get("plugin_dnsbl_cache_" .. ip)
|
|
if not kind then
|
|
if err ~= "not found" then
|
|
logger.log(ngx.ERR, "DNSBL", "Error while accessing cache : " .. err)
|
|
end
|
|
return false, err
|
|
end
|
|
return kind, "success"
|
|
end
|
|
|
|
function _M:add_to_cache(ip, kind)
|
|
local ok, err = datastore:set("plugin_dnsbl_cache_" .. ip, kind, 3600)
|
|
if not ok then
|
|
logger.log(ngx.ERR, "DNSBL", "Error while adding ip to cache : " .. err)
|
|
return false, err
|
|
end
|
|
return true, "success"
|
|
end
|
|
|
|
return _M
|