301 lines
9.0 KiB
Lua
301 lines
9.0 KiB
Lua
|
|
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()
|
||
|
|
Defense.userInfo = {}
|
||
|
|
Defense.attackInfo = {}
|
||
|
|
Defense.ipBlackList = {} --黑名单IP列表
|
||
|
|
end
|
||
|
|
|
||
|
|
--玩家进入
|
||
|
|
function Defense:Enter( userId )
|
||
|
|
if not Defense.userInfo[ userId ] then
|
||
|
|
Defense.userInfo[ userId ] = {}
|
||
|
|
local userInfo ={}
|
||
|
|
userInfo.userId = userId
|
||
|
|
userInfo.lastMsgTime = skynet.GetTime()
|
||
|
|
userInfo.count = {} --各种触发的统计
|
||
|
|
userInfo.accountStatus = self.AccountStatus_Normal
|
||
|
|
Defense.userInfo[ userId ] = userInfo
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--玩家退出
|
||
|
|
function Defense:Exit( userId)
|
||
|
|
if Defense.userInfo[ userId ] then
|
||
|
|
Defense.userInfo[ userId ] = nil
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--触发规则
|
||
|
|
function Defense:Trigger( userId , type )
|
||
|
|
if not Defense.userInfo[ userId ] then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
if not Defense.userInfo[ userId ].count[ type ] then
|
||
|
|
--该类型没加入统计就统计
|
||
|
|
Defense.userInfo[ userId ].count[ type ] = 0
|
||
|
|
end
|
||
|
|
|
||
|
|
Defense.userInfo[ userId ].count[ type ] = Defense.userInfo[ userId ].count[ type ] + 1
|
||
|
|
log.info(string.format("玩家 %d 触发规则 %d %d 次" , userId , type , Defense.userInfo[ userId ].count[ type ]))
|
||
|
|
|
||
|
|
local count = Defense.userInfo[ 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.userInfo[ userId ].accountStatus then
|
||
|
|
return true
|
||
|
|
else
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--修改玩家帐号状态
|
||
|
|
function Defense:ModifyAccountStatus( userId , status , type )
|
||
|
|
Defense.userInfo[ 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.userInfo[ 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.userInfo[ 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.userInfo[ userId ].lastMsgTime = skynet.GetTime()
|
||
|
|
end
|
||
|
|
|
||
|
|
--检查玩家消息是否过快
|
||
|
|
function Defense:CheckFastMsg( userId )
|
||
|
|
local user = Defense.userInfo[ 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:CheckFreeRed( player )
|
||
|
|
--[[
|
||
|
|
local unlockCount = 0
|
||
|
|
for key, value in pairs( player.data.landUnlock ) do
|
||
|
|
if value then
|
||
|
|
unlockCount = unlockCount + 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if unlockCount < 1 or unlockCount > 3 then
|
||
|
|
log.info("检查免费红包数量异常",unlockCount)
|
||
|
|
end
|
||
|
|
]]
|
||
|
|
|
||
|
|
|
||
|
|
local level = player.data.level
|
||
|
|
local todayFreeRed = player.data.todayGain.freeRed
|
||
|
|
|
||
|
|
if level < 10 and todayFreeRed >= 4900 then
|
||
|
|
return false
|
||
|
|
elseif level >= 10 and level < 16 and todayFreeRed >= 9400 then
|
||
|
|
return false
|
||
|
|
elseif level >= 16 and todayFreeRed >= 12200 then
|
||
|
|
return false
|
||
|
|
else
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--检查付费红包
|
||
|
|
function Defense:CheckAdRed( player )
|
||
|
|
local level = player.data.level
|
||
|
|
local adRed = player.data.todayGain.adRed
|
||
|
|
|
||
|
|
if level < 10 and adRed >= 225000 then
|
||
|
|
return false
|
||
|
|
elseif level >= 10 and level < 16 and adRed >= 450000 then
|
||
|
|
return false
|
||
|
|
elseif level >= 16 and adRed >= 675300 then
|
||
|
|
return false
|
||
|
|
else
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
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:CheckGainDiamond( player )
|
||
|
|
local diamond = player.data.todayGain.buyDiamond
|
||
|
|
if diamond > 9000 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
|