local skynet = require "skynet" local oo = require "Class" local log = require "Log" local sqlUrl = require "SqlUrl" local Defense = oo.class() Defense.MaxUser = 1000 --最大记录1000个玩家 Defense.MsgInterval = 1 --消息间隔时间1秒 --系统触发 Defense.TriggerType_FastMsg = 100 --消息过快 Defense.TriggerType_ErrorRequest = 101 --错误请求 Defense.TriggerType_ErrorParam = 102 --错误参数 --游戏触发 Defense.TriggerType_FreeRed = 200 --免费红包 Defense.TriggerType_AdRed = 201 --付费红包 Defense.TriggerType_Exp = 202 --经验 Defense.TriggerType_GainCash = 203 --提现 Defense.TriggerType_GainDiamond = 204 --获得的钻石 Defense.TriggerType_ManualBlackList = 300 --手动添加黑名单 Defense.AccountStatus_Normal = 1 --正常玩家 Defense.AccountStatus_White = 2 --白名单 Defense.AccountStatus_Gray = 3 --灰名单 Defense.AccountStatus_Black = 4 --黑名单 Defense.ErrorRequestCount = 10 --达到错误请求多少次后IP进入黑名单 Defense.ErrorParamCount = 10 --达到错误参数多少次后IP进入黑名单 --用户触发信息 local userTrigger = { userId = 0 , --用户ID lastMsgTime = 0 , --上一条消息时间 count = {} } --初始化 function Defense:Init() self.userBlackList = {} --用户黑名单 self.ipBlackList = {} --黑名单IP列表 Defense.attackInfo = {} end --触发规则 function Defense:Trigger( userId , type ) if not Defense.userBlackList[ userId ] then return end if not Defense.userBlackList[ userId ].count[ type ] then --该类型没加入统计就统计 Defense.userBlackList[ userId ].count[ type ] = 0 end Defense.userBlackList[ userId ].count[ type ] = Defense.userBlackList[ userId ].count[ type ] + 1 log.info(string.format("玩家 %d 触发规则 %d %d 次" , userId , type , Defense.userBlackList[ userId ].count[ type ])) local count = Defense.userBlackList[ userId ].count[ type ] if Defense.TriggerType_FastMsg == type and count >= 500 then elseif Defense.TriggerType_ErrorParam == type and count >= 5 then self:ModifyAccountStatus(userId , Defense.AccountStatus_Black , type ) end end --是否为黑名单 function Defense:IsBlack( userId ) if self.AccountStatus_Black == Defense.userBlackList[ userId ].accountStatus then return true else return false end end --修改玩家帐号状态 function Defense:ModifyAccountStatus( userId , status , type ) Defense.userBlackList[ userId ].accountStatus = status local sql = string.format(sqlUrl.modifyAccountStatusToUser, status , userId ) local queryData = skynet.server.db:Query(sql) if self.AccountStatus_Black == status then local str = string.format("玩家 %d 因触发规则 %d %d 次 被列入黑名单" , userId , type , Defense.userBlackList[ userId ].count[ type ] or 0) log.info(str) --踢玩家下线 local c2sData = {} c2sData.userId = userId skynet.server.clusterMasterServer:SendAllServerUserOffline(c2sData) elseif self.AccountStatus_Normal == status then local str = string.format("玩家 %d 成功移除黑名单" , userId) log.info(str) end end --IP是否在黑名单中 function Defense:IsIPBlackList( addr ) if not Defense.ipBlackList[addr] then return false end if Defense.ipBlackList[addr] then return true end return false end --检查攻击相关 function Defense:CheckAttack( type , addr ) if not Defense.attackInfo[ addr ] then Defense.attackInfo[ addr ] = {} Defense.attackInfo[ addr ].count = {} end if not Defense.attackInfo[ addr ].count[ type ] then Defense.attackInfo[ addr ].count[ type ] = 0 end Defense.attackInfo[ addr ].count[ type ] = Defense.attackInfo[ addr ].count[ type ] + 1 local count = Defense.attackInfo[ addr ].count[ type ] log.info(string.format("IP %s 攻击类型 %d 数量 %d",addr , type , count)) if self.TriggerType_ErrorRequest == type and count >= self.ErrorRequestCount then --Defense.ipBlackList[addr] = true log.info(string.format("IP %s 已经达到上限 攻击类型 %d 数量 %d",addr , type , count)) elseif self.TriggerType_ErrorParam == type and count >= self.ErrorParamCount then --Defense.ipBlackList[addr] = true log.info(string.format("IP %s 已经达到上限 攻击类型 %d 数量 %d",addr , type , count)) end end --检查玩家错误的请求 function Defense:CheckRequest( userId , type , param1 ,param2) if not Defense.userBlackList[ userId ] then return end local isTrigger = false if Defense.TriggerType_FastMsg == type then --isTrigger = self:CheckFastMsg( userId ) elseif Defense.TriggerType_ErrorParam == type then isTrigger = true end if isTrigger then --激活触发统计 self:Trigger( userId , type ) end Defense.userBlackList[ userId ].lastMsgTime = skynet.GetTime() end --检查玩家消息是否过快 function Defense:CheckFastMsg( userId ) local user = Defense.userBlackList[ userId ] if not user then return end if skynet.GetTime() - user.lastMsgTime <= Defense.MsgInterval then return true else return false end end --检查游戏 function Defense:CheckGame( player , type ) local isOK = false if Defense.TriggerType_FreeRed == type then isOK = self:CheckFreeRed( player ) elseif Defense.TriggerType_AdRed == type then isOK = self:CheckAdRed( player ) elseif Defense.TriggerType_Exp == type then isOK = self:CheckExp( player ) elseif Defense.TriggerType_GainCash == type then isOK = self:CheckGainCash( player ) elseif Defense.TriggerType_GainDiamond == type then isOK = self:CheckGainDiamond( player ) end if not isOK then self:Warning(player.data.id , type) end return isOK end --检查经验 function Defense:CheckExp( player ) local level = player.data.level local exp = player.data.todayGain.exp if level < 10 and exp >= 1910 then return false elseif level >= 10 and level < 16 and exp >= 3410 then return false elseif level >= 16 and exp >= 4340 then return false else return true end end --检查获得的现金 function Defense:CheckGainCash( player ) if true then return true --暂时屏蔽这个功能 end local cash = player.data.todayGain.cash if cash > 200 then --超过两无就无法提现 return false end return true end --警告 function Defense:Warning( id , type ) log.info(string.format("警告!玩家 %d 已经触发了游戏中的限制类型 %d ",id ,type)) local sql = string.format("insert into warning values(%d , %d , %d)",id ,type , skynet.GetTime()) local queryData = skynet.server.db:Query(sql) end skynet.server.defense = Defense return Defense