/*
* PtokaX - hub server for Direct Connect peer to peer network.
* Copyright (C) 2004-2022 Petr Kozelka, PPK at PtokaX dot org
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3
* as published by the Free Software Foundation.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
#include "stdinc.h"
//---------------------------------------------------------------------------
#include "GlobalDataQueue.h"
#include "hashBanManager.h"
#include "LanguageManager.h"
#include "ServerManager.h"
#include "SettingManager.h"
#include "UdpDebug.h"
#include "User.h"
#include "utility.h"
//---------------------------------------------------------------------------
#include "DeFlood.h"
//---------------------------------------------------------------------------
bool DeFloodCheckForFlood(User * pUser, const uint8_t ui8DefloodType, const int16_t ui16Action,
uint16_t &ui16Count, uint64_t &ui64LastOkTick,
const int16_t ui16DefloodCount, const uint32_t ui32DefloodTime, const char * sOtherNick/* = NULL*/)
{
if (ui16Count == 0)
{
ui64LastOkTick = ServerManager::m_ui64ActualTick;
}
else if (ui16Count == ui16DefloodCount)
{
if ((ui64LastOkTick + ui32DefloodTime) > ServerManager::m_ui64ActualTick)
{
DeFloodDoAction(pUser, ui8DefloodType, ui16Action, ui16Count, sOtherNick);
return true;
}
else
{
ui64LastOkTick = ServerManager::m_ui64ActualTick;
ui16Count = 0;
}
}
else if (ui16Count > ui16DefloodCount)
{
if ((ui64LastOkTick + ui32DefloodTime) > ServerManager::m_ui64ActualTick)
{
if (ui16Action == 2 && ui16Count == (ui16DefloodCount * 2))
{
pUser->m_ui32DefloodWarnings++;
if (DeFloodCheckForWarn(pUser, ui8DefloodType, sOtherNick) == true)
{
return true;
}
ui16Count -= ui16DefloodCount;
}
ui16Count++;
return true;
}
else
{
ui64LastOkTick = ServerManager::m_ui64ActualTick;
ui16Count = 0;
}
}
else if ((ui64LastOkTick + ui32DefloodTime) <= ServerManager::m_ui64ActualTick)
{
ui64LastOkTick = ServerManager::m_ui64ActualTick;
ui16Count = 0;
}
ui16Count++;
return false;
}
//---------------------------------------------------------------------------
bool DeFloodCheckForSameFlood(User * pUser, const uint8_t ui8DefloodType, const int16_t ui16Action,
uint16_t &ui16Count, const uint64_t &ui64LastOkTick,
const int16_t ui16DefloodCount, const uint32_t ui32DefloodTime,
const char * sNewData, const size_t ui32NewDataLen,
const char * sOldData, const uint16_t ui16OldDataLen, bool &bNewData, const char * sOtherNick/* = NULL*/)
{
if (ui16OldDataLen == 0 && ui32NewDataLen == 0)
return false;
if ((uint32_t)ui16OldDataLen == ui32NewDataLen && (ServerManager::m_ui64ActualTick >= ui64LastOkTick &&
(ui64LastOkTick + ui32DefloodTime) > ServerManager::m_ui64ActualTick) &&
memcmp(sNewData, sOldData, ui16OldDataLen) == 0)
{
if (ui16Count < ui16DefloodCount)
{
ui16Count++;
return false;
}
else if (ui16Count == ui16DefloodCount)
{
DeFloodDoAction(pUser, ui8DefloodType, ui16Action, ui16Count, sOtherNick);
if (pUser->m_ui8State < User::STATE_CLOSING)
{
ui16Count++;
}
return true;
}
else
{
if (ui16Action == 2 && ui16Count == (ui16DefloodCount * 2))
{
pUser->m_ui32DefloodWarnings++;
if (DeFloodCheckForWarn(pUser, ui8DefloodType, sOtherNick) == true)
{
return true;
}
ui16Count -= ui16DefloodCount;
}
ui16Count++;
return true;
}
}
else
{
bNewData = true;
return false;
}
}
//---------------------------------------------------------------------------
bool DeFloodCheckForDataFlood(User * pUser, const uint8_t ui8DefloodType, const int16_t ui16Action,
uint32_t &ui32Count, uint64_t &ui64LastOkTick,
const int16_t ui16DefloodCount, const uint32_t ui32DefloodTime)
{
if ((uint16_t)(ui32Count / 1024) >= ui16DefloodCount)
{
if ((ui64LastOkTick + ui32DefloodTime) > ServerManager::m_ui64ActualTick)
{
if ((pUser->m_ui32BoolBits & User::BIT_RECV_FLOODER) == User::BIT_RECV_FLOODER)
{
return true;
}
pUser->m_ui32BoolBits |= User::BIT_RECV_FLOODER;
uint16_t ui16Count = (uint16_t)ui32Count;
DeFloodDoAction(pUser, ui8DefloodType, ui16Action, ui16Count, NULL);
return true;
}
else
{
pUser->m_ui32BoolBits &= ~User::BIT_RECV_FLOODER;
ui64LastOkTick = ServerManager::m_ui64ActualTick;
ui32Count = 0;
return false;
}
}
else if ((ui64LastOkTick + ui32DefloodTime) <= ServerManager::m_ui64ActualTick)
{
pUser->m_ui32BoolBits &= ~User::BIT_RECV_FLOODER;
ui64LastOkTick = ServerManager::m_ui64ActualTick;
ui32Count = 0;
return false;
}
return false;
}
//---------------------------------------------------------------------------
void DeFloodDoAction(User * pUser, const uint8_t ui8DefloodType, const int16_t ui16Action, uint16_t &ui16Count, const char * sOtherNick)
{
switch (ui16Action)
{
case 1:
{
pUser->SendFormatCheckPM("DeFloodDoAction1", sOtherNick, true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], DeFloodGetMessage(ui8DefloodType, 0));
if (ui8DefloodType != DEFLOOD_MAX_DOWN)
{
ui16Count++;
}
return;
}
case 2:
pUser->m_ui32DefloodWarnings++;
if (DeFloodCheckForWarn(pUser, ui8DefloodType, sOtherNick) == false && ui8DefloodType != DEFLOOD_MAX_DOWN)
{
ui16Count++;
}
return;
case 3:
{
pUser->SendFormatCheckPM("DeFloodDoAction2", sOtherNick, false, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], DeFloodGetMessage(ui8DefloodType, 0));
DeFloodReport(pUser, ui8DefloodType, LanguageManager::m_Ptr->m_sTexts[LAN_WAS_DISCONNECTED]);
pUser->Close();
return;
}
case 4:
{
BanManager::m_Ptr->TempBan(pUser, DeFloodGetMessage(ui8DefloodType, 1), NULL, 0, 0, false);
pUser->SendFormatCheckPM("DeFloodDoAction3", sOtherNick, false, "<%s> %s: %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_BEING_KICKED_BCS], DeFloodGetMessage(ui8DefloodType, 1));
DeFloodReport(pUser, ui8DefloodType, LanguageManager::m_Ptr->m_sTexts[LAN_WAS_KICKED]);
pUser->Close();
return;
}
case 5:
{
BanManager::m_Ptr->TempBan(pUser, DeFloodGetMessage(ui8DefloodType, 1), NULL, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_DEFLOOD_TEMP_BAN_TIME], 0, false);
pUser->SendFormatCheckPM("DeFloodDoAction4", sOtherNick, false, "<%s> %s: %s %s: %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_HAD_BEEN_TEMP_BANNED_TO], formatTime(SettingManager::m_Ptr->m_i16Shorts[SETSHORT_DEFLOOD_TEMP_BAN_TIME]),
LanguageManager::m_Ptr->m_sTexts[LAN_BECAUSE_LWR], DeFloodGetMessage(ui8DefloodType, 1));
DeFloodReport(pUser, ui8DefloodType, LanguageManager::m_Ptr->m_sTexts[LAN_WAS_TEMPORARY_BANNED]);
pUser->Close();
return;
}
case 6:
{
BanManager::m_Ptr->Ban(pUser, DeFloodGetMessage(ui8DefloodType, 1), NULL, false);
pUser->SendFormatCheckPM("DeFloodDoAction5", sOtherNick, false, "<%s> %s: %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_ARE_BEING_BANNED_BECAUSE], DeFloodGetMessage(ui8DefloodType, 1));
DeFloodReport(pUser, ui8DefloodType, LanguageManager::m_Ptr->m_sTexts[LAN_WAS_BANNED]);
pUser->Close();
return;
}
}
}
//---------------------------------------------------------------------------
bool DeFloodCheckForWarn(User * pUser, const uint8_t ui8DefloodType, const char * sOtherNick)
{
if (pUser->m_ui32DefloodWarnings < (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_DEFLOOD_WARNING_COUNT])
{
pUser->SendFormat("DeFloodCheckForWarn", true, "<%s> %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], DeFloodGetMessage(ui8DefloodType, 0));
return false;
}
else
{
switch (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_DEFLOOD_WARNING_ACTION])
{
case 0:
{
pUser->SendFormatCheckPM("DeFloodCheckForWarn1", sOtherNick, false, "<%s> %s: %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_ARE_BEING_DISCONNECTED_BECAUSE], DeFloodGetMessage(ui8DefloodType, 1));
DeFloodReport(pUser, ui8DefloodType, LanguageManager::m_Ptr->m_sTexts[LAN_WAS_DISCONNECTED]);
break;
}
case 1:
{
BanManager::m_Ptr->TempBan(pUser, DeFloodGetMessage(ui8DefloodType, 1), NULL, 0, 0, false);
pUser->SendFormatCheckPM("DeFloodCheckForWarn2", sOtherNick, false, "<%s> %s: %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_BEING_KICKED_BCS], DeFloodGetMessage(ui8DefloodType, 1));
DeFloodReport(pUser, ui8DefloodType, LanguageManager::m_Ptr->m_sTexts[LAN_WAS_KICKED]);
break;
}
case 2:
{
BanManager::m_Ptr->TempBan(pUser, DeFloodGetMessage(ui8DefloodType, 1), NULL, SettingManager::m_Ptr->m_i16Shorts[SETSHORT_DEFLOOD_TEMP_BAN_TIME], 0, false);
pUser->SendFormatCheckPM("DeFloodCheckForWarn3", sOtherNick, false, "<%s> %s: %s %s: %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_HAD_BEEN_TEMP_BANNED_TO], formatTime(SettingManager::m_Ptr->m_i16Shorts[SETSHORT_DEFLOOD_TEMP_BAN_TIME]),
LanguageManager::m_Ptr->m_sTexts[LAN_BECAUSE_LWR], DeFloodGetMessage(ui8DefloodType, 1));
DeFloodReport(pUser, ui8DefloodType, LanguageManager::m_Ptr->m_sTexts[LAN_WAS_TEMPORARY_BANNED]);
break;
}
case 3:
{
BanManager::m_Ptr->Ban(pUser, DeFloodGetMessage(ui8DefloodType, 1), NULL, false);
pUser->SendFormatCheckPM("DeFloodCheckForWarn4", sOtherNick, false, "<%s> %s: %s!|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_ARE_BEING_BANNED_BECAUSE], DeFloodGetMessage(ui8DefloodType, 1));
DeFloodReport(pUser, ui8DefloodType, LanguageManager::m_Ptr->m_sTexts[LAN_WAS_BANNED]);
break;
}
}
pUser->Close();
return true;
}
}
//---------------------------------------------------------------------------
const char * DeFloodGetMessage(const uint8_t ui8DefloodType, const uint8_t ui8MsgId)
{
switch (ui8DefloodType)
{
case DEFLOOD_GETNICKLIST:
switch (ui8MsgId)
{
case 0:
return LanguageManager::m_Ptr->m_sTexts[LAN_PLS_DONT_FLOOD_WITH_GetNickList];
case 1:
return LanguageManager::m_Ptr->m_sTexts[LAN_GetNickList_FLOODING];
case 2:
return LanguageManager::m_Ptr->m_sTexts[LAN_GetNickList_FLOODER];
}
break;
case DEFLOOD_MYINFO:
switch (ui8MsgId)
{
case 0:
return LanguageManager::m_Ptr->m_sTexts[LAN_PLS_DONT_FLOOD_WITH_MyINFO];
case 1:
return LanguageManager::m_Ptr->m_sTexts[LAN_MyINFO_FLOODING];
case 2:
return LanguageManager::m_Ptr->m_sTexts[LAN_MyINFO_FLOODER];
}
break;
case DEFLOOD_SEARCH:
switch (ui8MsgId)
{
case 0:
return LanguageManager::m_Ptr->m_sTexts[LAN_PLS_DONT_FLOOD_WITH_SEARCHES];
case 1:
return LanguageManager::m_Ptr->m_sTexts[LAN_SEARCH_FLOODING];
case 2:
return LanguageManager::m_Ptr->m_sTexts[LAN_SEARCH_FLOODER];
}
break;
case DEFLOOD_CHAT:
switch (ui8MsgId)
{
case 0:
return LanguageManager::m_Ptr->m_sTexts[LAN_PLS_DONT_FLOOD_CHAT];
case 1:
return LanguageManager::m_Ptr->m_sTexts[LAN_CHAT_FLOODING];
case 2:
return LanguageManager::m_Ptr->m_sTexts[LAN_CHAT_FLOODER];
}
break;
case DEFLOOD_PM:
switch (ui8MsgId)
{
case 0:
return LanguageManager::m_Ptr->m_sTexts[LAN_PLS_DONT_FLOOD_WITH_PM];
case 1:
return LanguageManager::m_Ptr->m_sTexts[LAN_PM_FLOODING];
case 2:
return LanguageManager::m_Ptr->m_sTexts[LAN_PM_FLOODER];
}
break;
case DEFLOOD_SAME_SEARCH:
switch (ui8MsgId)
{
case 0:
return LanguageManager::m_Ptr->m_sTexts[LAN_PLS_DONT_FLOOD_WITH_SAME_SEARCHES];
case 1:
return LanguageManager::m_Ptr->m_sTexts[LAN_SAME_SEARCH_FLOODING];
case 2:
return LanguageManager::m_Ptr->m_sTexts[LAN_SAME_SEARCH_FLOODER];
}
break;
case DEFLOOD_SAME_PM:
switch (ui8MsgId)
{
case 0:
return LanguageManager::m_Ptr->m_sTexts[LAN_PLS_DONT_FLOOD_WITH_SAME_PM];
case 1:
return LanguageManager::m_Ptr->m_sTexts[LAN_SAME_PM_FLOODING];
case 2:
return LanguageManager::m_Ptr->m_sTexts[LAN_SAME_PM_FLOODER];
}
break;
case DEFLOOD_SAME_CHAT:
switch (ui8MsgId)
{
case 0:
return LanguageManager::m_Ptr->m_sTexts[LAN_PLS_DONT_FLOOD_SAME_CHAT];
case 1:
return LanguageManager::m_Ptr->m_sTexts[LAN_SAME_CHAT_FLOODING];
case 2:
return LanguageManager::m_Ptr->m_sTexts[LAN_SAME_CHAT_FLOODER];
}
break;
case DEFLOOD_SAME_MULTI_PM:
switch (ui8MsgId)
{
case 0:
return LanguageManager::m_Ptr->m_sTexts[LAN_PLS_DONT_FLOOD_WITH_SAME_MULTI_PM];
case 1:
return LanguageManager::m_Ptr->m_sTexts[LAN_SAME_MULTI_PM_FLOODING];
case 2:
return LanguageManager::m_Ptr->m_sTexts[LAN_SAME_MULTI_PM_FLOODER];
}
break;
case DEFLOOD_SAME_MULTI_CHAT:
switch (ui8MsgId)
{
case 0:
return LanguageManager::m_Ptr->m_sTexts[LAN_PLS_DONT_FLOOD_SAME_MULTI_CHAT];
case 1:
return LanguageManager::m_Ptr->m_sTexts[LAN_SAME_MULTI_CHAT_FLOODING];
case 2:
return LanguageManager::m_Ptr->m_sTexts[LAN_SAME_MULTI_CHAT_FLOODER];
}
break;
case DEFLOOD_CTM:
switch (ui8MsgId)
{
case 0:
return LanguageManager::m_Ptr->m_sTexts[LAN_PLS_DONT_FLOOD_WITH_CTM];
case 1:
return LanguageManager::m_Ptr->m_sTexts[LAN_CTM_FLOODING];
case 2:
return LanguageManager::m_Ptr->m_sTexts[LAN_CTM_FLOODER];
}
break;
case DEFLOOD_RCTM:
switch (ui8MsgId)
{
case 0:
return LanguageManager::m_Ptr->m_sTexts[LAN_PLS_DONT_FLOOD_WITH_RCTM];
case 1:
return LanguageManager::m_Ptr->m_sTexts[LAN_RCTM_FLOODING];
case 2:
return LanguageManager::m_Ptr->m_sTexts[LAN_RCTM_FLOODER];
}
break;
case DEFLOOD_SR:
switch (ui8MsgId)
{
case 0:
return LanguageManager::m_Ptr->m_sTexts[LAN_PLS_DONT_FLOOD_WITH_SR];
case 1:
return LanguageManager::m_Ptr->m_sTexts[LAN_SR_FLOODING];
case 2:
return LanguageManager::m_Ptr->m_sTexts[LAN_SR_FLOODER];
}
break;
case DEFLOOD_MAX_DOWN:
switch (ui8MsgId)
{
case 0:
return LanguageManager::m_Ptr->m_sTexts[LAN_PLS_DONT_FLOOD_WITH_DATA];
case 1:
return LanguageManager::m_Ptr->m_sTexts[LAN_DATA_FLOODING];
case 2:
return LanguageManager::m_Ptr->m_sTexts[LAN_DATA_FLOODER];
}
break;
case INTERVAL_CHAT:
return LanguageManager::m_Ptr->m_sTexts[LAN_SECONDS_BEFORE_NEXT_CHAT_MSG];
case INTERVAL_PM:
return LanguageManager::m_Ptr->m_sTexts[LAN_SECONDS_BEFORE_NEXT_PM];
case INTERVAL_SEARCH:
return LanguageManager::m_Ptr->m_sTexts[LAN_SECONDS_BEFORE_NEXT_SEARCH];
}
return "";
}
//---------------------------------------------------------------------------
void DeFloodReport(User * pUser, const uint8_t ui8DefloodType, const char *sAction)
{
if (SettingManager::m_Ptr->m_bBools[SETBOOL_DEFLOOD_REPORT] == true)
{
GlobalDataQueue::m_Ptr->StatusMessageFormat("DeFloodReport", "<%s> *** %s %s %s %s %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], DeFloodGetMessage(ui8DefloodType, 2), pUser->m_sNick, LanguageManager::m_Ptr->m_sTexts[LAN_WITH_IP], pUser->m_sIP, sAction);
}
UdpDebug::m_Ptr->BroadcastFormat("[SYS] Flood type %hu from %s (%s) - user closed.", (uint16_t)ui8DefloodType, pUser->m_sNick, pUser->m_sIP);
}
//---------------------------------------------------------------------------
bool DeFloodCheckInterval(User * pUser, const uint8_t ui8DefloodType, uint16_t &ui16Count, uint64_t &ui64LastOkTick, const int16_t ui16DefloodCount, const uint32_t ui32DefloodTime, const char * sOtherNick/* = NULL*/)
{
if (ui16Count == 0)
{
ui64LastOkTick = ServerManager::m_ui64ActualTick;
}
else if (ui16Count >= ui16DefloodCount)
{
if ((ui64LastOkTick + ui32DefloodTime) > ServerManager::m_ui64ActualTick)
{
ui16Count++;
pUser->SendFormatCheckPM("DeFloodCheckInterval", sOtherNick, true, "<%s> %s %" PRIu64 " %s.|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_PLEASE_WAIT], (ui64LastOkTick + ui32DefloodTime) - ServerManager::m_ui64ActualTick, DeFloodGetMessage(ui8DefloodType, 0));
return true;
}
else
{
ui64LastOkTick = ServerManager::m_ui64ActualTick;
ui16Count = 0;
}
}
else if ((ui64LastOkTick + ui32DefloodTime) <= ServerManager::m_ui64ActualTick)
{
ui64LastOkTick = ServerManager::m_ui64ActualTick;
ui16Count = 0;
}
ui16Count++;
return false;
}
//---------------------------------------------------------------------------
↑ V1042 This file is marked with copyleft license, which requires you to open the derived source code.