HomeServer/Server/Common/Monitor.lua

255 lines
8.0 KiB
Lua
Raw Normal View History

2024-11-20 15:41:09 +08:00
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