113 lines
2.2 KiB
Lua
113 lines
2.2 KiB
Lua
local lrucache = require "resty.lrucache"
|
|
local ipmatcher = require "resty.ipmatcher"
|
|
local kong_meta = require "kong.meta"
|
|
|
|
|
|
local error = error
|
|
local kong = kong
|
|
local log = kong.log
|
|
local ngx_var = ngx.var
|
|
|
|
|
|
local IPMATCHER_COUNT = 512
|
|
local IPMATCHER_TTL = 3600
|
|
local cache = lrucache.new(IPMATCHER_COUNT)
|
|
|
|
|
|
local IpRestrictionHandler = {
|
|
PRIORITY = 990,
|
|
VERSION = kong_meta.version,
|
|
}
|
|
|
|
|
|
local isempty
|
|
do
|
|
local tb_isempty = require "table.isempty"
|
|
|
|
isempty = function(t)
|
|
return t == nil or tb_isempty(t)
|
|
end
|
|
end
|
|
|
|
|
|
local is_http_subsystem = ngx.config.subsystem == "http"
|
|
|
|
|
|
local function do_exit(status, message)
|
|
status = status or 403
|
|
message = message or
|
|
string.format("IP address not allowed: %s", ngx_var.remote_addr)
|
|
|
|
log.warn(message)
|
|
|
|
if is_http_subsystem then
|
|
return kong.response.error(status, message)
|
|
else
|
|
return ngx.exit(status)
|
|
end
|
|
end
|
|
|
|
|
|
local function match_bin(list, binary_remote_addr)
|
|
local matcher, err
|
|
|
|
matcher = cache:get(list)
|
|
if not matcher then
|
|
matcher, err = ipmatcher.new(list)
|
|
if err then
|
|
return error("failed to create a new ipmatcher instance: " .. err)
|
|
end
|
|
|
|
cache:set(list, matcher, IPMATCHER_TTL)
|
|
end
|
|
|
|
local is_match
|
|
is_match, err = matcher:match_bin(binary_remote_addr)
|
|
if err then
|
|
return error("invalid binary ip address: " .. err)
|
|
end
|
|
|
|
return is_match
|
|
end
|
|
|
|
|
|
local function do_restrict(conf)
|
|
local binary_remote_addr = ngx_var.binary_remote_addr
|
|
if not binary_remote_addr then
|
|
return do_exit(403,
|
|
"Cannot identify the client IP address, " ..
|
|
"unix domain sockets are not supported.")
|
|
end
|
|
|
|
local deny = conf.deny
|
|
|
|
if not isempty(deny) then
|
|
local blocked = match_bin(deny, binary_remote_addr)
|
|
if blocked then
|
|
return do_exit(conf.status, conf.message)
|
|
end
|
|
end
|
|
|
|
local allow = conf.allow
|
|
|
|
if not isempty(allow) then
|
|
local allowed = match_bin(allow, binary_remote_addr)
|
|
if not allowed then
|
|
return do_exit(conf.status, conf.message)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function IpRestrictionHandler:access(conf)
|
|
return do_restrict(conf)
|
|
end
|
|
|
|
|
|
function IpRestrictionHandler:preread(conf)
|
|
return do_restrict(conf)
|
|
end
|
|
|
|
|
|
return IpRestrictionHandler
|