first commit

This commit is contained in:
2026-05-06 17:36:25 +08:00
commit c9c2fa8185
6 changed files with 707 additions and 0 deletions

151
modules/rate_limiter.lua Normal file
View File

@@ -0,0 +1,151 @@
-- IP频率限制核心模块
-- 功能统计指定IP在时间段内的请求次数根据配置执行相应处置策略
local _M = {}
local config_module = require "config.rate_limit_config"
local common_config = require "config.common_config"
local logger = require "lib.logger"
-- 获取配置
local function get_config()
return config_module.get_config()
end
-- 检查域名是否应该应用限流
local function should_apply_rate_limit(host)
local cfg = get_config()
-- 如果未启用直接返回false
if not cfg.enabled then
return false
end
-- 如果没有host默认不应用
if not host or host == "" then
return false
end
-- 从公共配置获取域名列表
local domains = common_config.domains
-- 如果domains列表为空对所有域名生效
if #domains == 0 then
return true
end
-- 检查域名是否在配置的列表中
for _, domain in ipairs(domains) do
if host == domain then
return true
end
end
return false
end
-- 主函数检查并限制IP请求频率
-- 返回值:
-- - true: 允许访问
-- - false: 拒绝访问(已执行相应处置)
function _M.check_rate_limit()
local cfg = get_config()
-- 如果未启用,直接放行
if not cfg.enabled then
return true
end
-- 获取当前域名
local host = ngx.var.host
-- 检查是否应该对此域名应用限流
if not should_apply_rate_limit(host) then
logger.log_info("Rate limit skipped for domain", {
domain = host,
reason = "not_in_domains_list"
})
return true
end
-- 获取共享内存字典
local dict = ngx.shared[cfg.shared_dict]
if not dict then
logger.log_error("Shared dictionary not found", {
dict_name = cfg.shared_dict
})
return true
end
-- 获取客户端IP
local client_ip = ngx.var.remote_addr
if not client_ip then
logger.log_warn("Failed to get client IP")
return true
end
-- 记录请求详情(可选)
logger.log_request_details(
client_ip,
ngx.var.request_uri,
ngx.var.request_method,
ngx.var.http_user_agent
)
local current_time = ngx.time()
local time_window = cfg.time_window
local max_requests = cfg.max_requests
-- 构建key使用时间窗口的起始时间戳
local window_start = math.floor(current_time / time_window) * time_window
local key = client_ip .. ":" .. window_start
-- 使用原子操作增加计数
local new_count, err = dict:incr(key, 1, 0)
if not new_count then
logger.log_error("Failed to increment counter", {
ip = client_ip,
error = err or "unknown"
})
return true
end
-- 设置过期时间
if new_count == 1 then
dict:expire(key, time_window + 10)
end
-- 检查是否超过限制
if new_count > max_requests then
-- 根据配置的处置策略执行相应操作
if cfg.action == config_module.ACTION_ALLOW then
-- 放行:仅记录日志,不阻止
logger.log_allowed(client_ip, new_count, time_window)
return true
elseif cfg.action == config_module.ACTION_RATE_LIMIT then
-- 限制速率返回429
logger.log_rate_limited(client_ip, new_count, max_requests, time_window)
ngx.status = cfg.status_code or 429
ngx.header["Content-Type"] = "text/plain; charset=utf-8"
ngx.say(cfg.message or "Rate limit exceeded")
return false
elseif cfg.action == config_module.ACTION_BLOCK then
-- 封禁返回403
logger.log_blocked(client_ip, new_count, max_requests, time_window)
ngx.status = cfg.status_code or 403
ngx.header["Content-Type"] = "text/plain; charset=utf-8"
ngx.say(cfg.message or "Access denied")
return false
end
end
-- 正常放行
logger.log_allowed(client_ip, new_count, time_window)
return true
end
return _M

93
modules/ua_limiter.lua Normal file
View File

@@ -0,0 +1,93 @@
-- User-Agent限制模块
-- 功能根据User-Agent进行访问控制黑白名单
local _M = {}
local common_config = require "config.common_config"
local logger = require "lib.logger"
-- 获取配置
local function get_config()
return common_config.ua_limit
end
-- 检查User-Agent是否在列表中支持部分匹配
local function ua_in_list(ua, list)
if not ua or #list == 0 then
return false
end
for _, pattern in ipairs(list) do
-- 使用字符串查找,支持部分匹配
if ua:find(pattern, 1, true) then
return true
end
end
return false
end
-- 主函数检查User-Agent
-- 返回值:
-- - true: 允许访问
-- - false: 拒绝访问
function _M.check_ua_limit()
local cfg = get_config()
-- 如果未启用,直接放行
if not cfg.enabled then
return true
end
-- 获取User-Agent
local ua = ngx.var.http_user_agent
-- 如果没有UA记录日志但不阻止可根据需求调整
if not ua or ua == "" then
logger.log_info("Empty User-Agent", {
ip = ngx.var.remote_addr,
uri = ngx.var.request_uri
})
return true
end
-- 检查白名单在白名单中的UA总是放行
if ua_in_list(ua, cfg.whitelist) then
logger.log_info("User-Agent whitelisted", {
ua = ua,
action = "ALLOWED"
})
return true
end
-- 检查黑名单在黑名单中的UA会被阻止
if ua_in_list(ua, cfg.blacklist) then
logger.log_warn("User-Agent blocked", {
ua = ua,
action = cfg.action,
status = tostring(cfg.status_code)
})
-- 执行处置策略
if cfg.action == "allow" then
-- 仅记录日志,不阻止
return true
elseif cfg.action == "rate_limit" then
ngx.status = cfg.status_code or 429
ngx.header["Content-Type"] = "text/plain; charset=utf-8"
ngx.say(cfg.message or "Rate limit exceeded")
return false
else
-- 默认封禁
ngx.status = cfg.status_code or 403
ngx.header["Content-Type"] = "text/plain; charset=utf-8"
ngx.say(cfg.message or "Access denied")
return false
end
end
-- 不在任何列表中,正常放行
return true
end
return _M