HomeServer/Server/Common/Monitor.lua
2024-11-20 15:41:37 +08:00

255 lines
8.0 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local skynet = require "skynet"
local oo = require "Class"
local gameCmd = require "GameCmd"
local json =require "json"
local log = require "Log"
local sqlUrl = require "SqlUrl"
local errorInfo = require "ErrorInfo"
local curServerId = tonumber(skynet.getenv "serverId")
local redisKeyUrl = require "RedisKeyUrl"
local clusterServer = require "ClusterServer"
local Monitor = oo.class(clusterServer)
Monitor.per5Second = 5
Monitor.per5SecondIpCount = 100 --每5秒IP最大访问次数
Monitor.iPUnlockTime = 3600 --黑名单IP解锁时间
Monitor.IpOutTime = 1800 --访问IP过期时间
Monitor.MaxIllegalCount = 200 --最大非法数量
Monitor.ResetTriggerTime = 300 --重置触发规则时间为5分钟
--触发类型
Monitor.TriggerType_MsgTooFast = 1 --消息过快
Monitor.TriggerType_Max = 2 --触发最大类型
--[[
触发信息
下面为通用参数,每条信息都必须带,其余参数可以根据条件自己定 比如触发MsgTooFast 的自定义参数为cmds
type 触发类型
funcName 函数名,里面的字符串必须和定的函数名一样,否则不会触发相应功能
count 触发次数达到一定数量会将IP加入到黑名单里
firstTime 第一次触发时间
]]
Monitor.TriggerInfo =
{
{ type = Monitor.TriggerType_MsgTooFast , funcName = "CheckMsgTooFast" , count = 0 , firstTime = 0 , cmds = {} } --触发消息过快 参数 cmds 保存消息各种信息
}
--初始化
function Monitor:Init()
if true then
return true
end
self.ipBlackList = {} --IP黑名单
self.ipList = {} --统计当前IP
log.info("开始同步IP黑名单")
local key = redisKeyUrl.MonitorServerIPBlackListZSet
local ipList = skynet.server.redis:zrange( key , 0 , -1 , "withscores")
ipList = redisKeyUrl:CovertTable(ipList)
local ipCount = 0
for ip, recordTime in pairs( ipList ) do
self.ipBlackList[ ip ] = {}
self.ipBlackList[ ip ].recordTime = recordTime
ipCount = ipCount + 1
end
log.info(string.format("成功同步IP黑名单 数量 %d",ipCount))
end
--跨天
function Monitor:OnNewDay()
end
--1秒Timer
function Monitor:On1SecTimer()
end
--5秒Timer
function Monitor:On5SecTimer()
--self:CheckAttack()
--self:CheckIpOutTime()
--self:CheckUnlockIP()
--self:ResetTrigger()
end
--检测攻击行为
--[[
function Monitor:CheckAttack()
local curTime = skynet.GetTime()
for k, v in pairs( self.ipList ) do
if curTime <= v.record5SecTime + self.per5Second then
if v.record5SecCount >= self.per5SecondIpCount then --在指定的时间内大于阈值就拉黑
self:AddIPBlackList( k )
end
end
end
end
]]
--是否为合法IP
function Monitor:IsVaildIP( ip , cmd )
if self.ipBlackList[ ip ] then
return errorInfo.ErrorCode.IPBlackList
end
local errorCode = errorInfo.Suc
cmd = tostring(cmd)
local curTime = skynet.GetTime()
if not self.ipList[ ip ] then
self.ipList[ ip ] = {}
--一开始就需要用到该触发器可以在这里加,其它可以在触发功能的地方加都行。
self:AddTrigger( ip , self.TriggerType_MsgTooFast )
else
--对该IP的各种触发检测
for k, v in pairs( self.ipList[ ip ].trigger ) do
errorCode = self[ v.funcName ]( self , ip , cmd )
if errorInfo.Suc ~= errorCode then
return errorCode
end
end
end
self.ipList[ ip ].lastRecordTime = curTime --记录最新时间
return errorInfo.Suc
end
--添加IP到黑名单
function Monitor:AddIPBlackList( ip )
local key = redisKeyUrl.MonitorServerIPBlackListZSet
skynet.server.redis:zadd( key , skynet.GetTime() , ip )
self.ipBlackList[ ip ] = {}
self.ipBlackList[ ip ].recordTime = skynet.GetTime()
local c2sData = {}
c2sData.sendServerId = curServerId
c2sData.ip = ip
local curServer = skynet.server.serverManage:GetServer()
for k, v in pairs( curServer.clusterInfo ) do
if curServerId ~= v.serverId then
curServer:SendMsgToServer( v.serverId , curServer.Moniter2All_AddIPToBlack , c2sData )
end
end
log.info(string.format("监控服 IP %s 加入黑名单 " , ip ))
end
--检测IP是否能解锁
function Monitor:CheckUnlockIP()
--删除当前时间之前一小时的黑名单IP
local key =redisKeyUrl.MonitorServerIPBlackListZSet
local unlockTime = skynet.GetTime() - self.iPUnlockTime
skynet.server.redis:zremrangebyscore( key , "-inf" , unlockTime )
for ip, v in pairs( self.ipBlackList ) do
if skynet.GetTime() >= v.recordTime + self.iPUnlockTime then
self.ipBlackList[ ip ] = nil
end
end
end
--检测过期IP
function Monitor:CheckIpOutTime()
local curTime = skynet.GetTime()
for k, v in pairs( self.ipList ) do
if curTime >= v.lastRecordTime + self.IpOutTime then
--删除过期IP
self.ipList[ k ] = nil
end
end
end
--增加触发
function Monitor:AddTrigger( ip , triggerType )
triggerType = triggerType or 0
if triggerType <= 0 or triggerType >= self.TriggerType_Max then
log.info(string.format("监控服 IP %s 增加触发 %d 类型失败 " , ip , triggerType ))
return
end
if not self.ipList[ ip ].trigger then
--初始化该IP的触发器
self.ipList[ ip ].trigger = {}
end
if not self.ipList[ ip ].trigger[ triggerType ] then
--该IP没有指定触发类型就加进来
for k, v in pairs( self.TriggerInfo ) do
if triggerType == v.type then
self.ipList[ ip ].trigger[ triggerType ] = v
break
end
end
end
end
--重置触发
function Monitor:ResetTrigger()
local curTime = skynet.GetTime()
for k1, v1 in pairs( self.ipList ) do
for k2, v2 in pairs( v1.trigger ) do
if curTime - v2.firstTime >= self.ResetTriggerTime then
--违规信息重置
v2.firstTime = 0
v2.count = 0
end
end
end
end
--获取触发
function Monitor:GetTrigger( ip , triggerType )
triggerType = triggerType or 0
if triggerType <= 0 or triggerType >= self.TriggerType_Max then
log.info(string.format("监控服 IP %s 获取触发 %d 类型失败 " , ip , triggerType ))
return
end
return self.ipList[ ip ].trigger[ triggerType ]
end
--触发违规
function Monitor:TriggerIllegal( ip , triggerType )
local curTrigger = self:GetTrigger( ip , triggerType )
curTrigger.count = curTrigger.count + 1
if 0 == curTrigger.firstTime then
--记录下首次触发时间
curTrigger.firstTime = skynet.GetTime()
end
--5分钟内触发最大次数加入黑名单
if curTrigger.count >= self.MaxIllegalCount then
self:AddIPBlackList( ip )
end
end
--检查是否消息过快
function Monitor:CheckMsgTooFast( ip , cmd )
local curTime = skynet.GetTime()
--获取当前类型的触发器
local triggerType = self.TriggerType_MsgTooFast
local curTrigger = self:GetTrigger( ip , triggerType )
if not curTrigger.cmds[ cmd ] then
--对此命令进行初始化
curTrigger.cmds[ cmd ] = {}
curTrigger.cmds[ cmd ].recordTime = curTime
else
local cmdInfo = curTrigger.cmds[ cmd ]
if curTime - cmdInfo.recordTime <= 0 then --1秒内两次执行相同命令就返回消息过快的错误然后触发非法类型
self:TriggerIllegal( ip , triggerType )
return errorInfo.ErrorCode.RequestMsgTooFast
else
curTrigger.cmds[ cmd ].recordTime = curTime
end
end
return errorInfo.Suc
end
skynet.server.monitor = Monitor
return Monitor