mirror of https://github.com/znc/znc
Mirror of the official znc repository
https://znc.in
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
4.9 KiB
151 lines
4.9 KiB
/* |
|
* Copyright (C) 2004-2022 ZNC, see the NOTICE file for details. |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#include <znc/Modules.h> |
|
#include <znc/Chan.h> |
|
#include <time.h> |
|
|
|
class CCtcpFloodMod : public CModule { |
|
public: |
|
MODCONSTRUCTOR(CCtcpFloodMod) { |
|
AddHelpCommand(); |
|
AddCommand("Secs", t_d("<limit>"), t_d("Set seconds limit"), |
|
[=](const CString& sLine) { OnSecsCommand(sLine); }); |
|
AddCommand("Lines", t_d("<limit>"), t_d("Set lines limit"), |
|
[=](const CString& sLine) { OnLinesCommand(sLine); }); |
|
AddCommand("Show", "", t_d("Show the current limits"), |
|
[=](const CString& sLine) { OnShowCommand(sLine); }); |
|
} |
|
|
|
~CCtcpFloodMod() override {} |
|
|
|
void Save() { |
|
// We save the settings twice because the module arguments can |
|
// be more easily edited via webadmin, while the SetNV() stuff |
|
// survives e.g. /msg *status reloadmod ctcpflood. |
|
SetNV("secs", CString(m_iThresholdSecs)); |
|
SetNV("msgs", CString(m_iThresholdMsgs)); |
|
|
|
SetArgs(CString(m_iThresholdMsgs) + " " + CString(m_iThresholdSecs)); |
|
} |
|
|
|
bool OnLoad(const CString& sArgs, CString& sMessage) override { |
|
m_iThresholdMsgs = sArgs.Token(0).ToUInt(); |
|
m_iThresholdSecs = sArgs.Token(1).ToUInt(); |
|
|
|
if (m_iThresholdMsgs == 0 || m_iThresholdSecs == 0) { |
|
m_iThresholdMsgs = GetNV("msgs").ToUInt(); |
|
m_iThresholdSecs = GetNV("secs").ToUInt(); |
|
} |
|
|
|
if (m_iThresholdSecs == 0) m_iThresholdSecs = 2; |
|
if (m_iThresholdMsgs == 0) m_iThresholdMsgs = 4; |
|
|
|
Save(); |
|
|
|
return true; |
|
} |
|
|
|
EModRet Message(const CNick& Nick, const CString& sMessage) { |
|
// We never block /me, because it doesn't cause a reply |
|
if (sMessage.Token(0).Equals("ACTION")) return CONTINUE; |
|
|
|
if (m_tLastCTCP + m_iThresholdSecs < time(nullptr)) { |
|
m_tLastCTCP = time(nullptr); |
|
m_iNumCTCP = 0; |
|
} |
|
|
|
m_iNumCTCP++; |
|
|
|
if (m_iNumCTCP < m_iThresholdMsgs) |
|
return CONTINUE; |
|
else if (m_iNumCTCP == m_iThresholdMsgs) |
|
PutModule(t_f("Limit reached by {1}, blocking all CTCP")( |
|
Nick.GetHostMask())); |
|
|
|
// Reset the timeout so that we continue blocking messages |
|
m_tLastCTCP = time(nullptr); |
|
|
|
return HALT; |
|
} |
|
|
|
EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) override { |
|
return Message(Nick, sMessage); |
|
} |
|
|
|
EModRet OnChanCTCP(CNick& Nick, CChan& Channel, |
|
CString& sMessage) override { |
|
return Message(Nick, sMessage); |
|
} |
|
|
|
void OnSecsCommand(const CString& sCommand) { |
|
const CString& sArg = sCommand.Token(1, true); |
|
|
|
if (sArg.empty()) { |
|
PutModule(t_s("Usage: Secs <limit>")); |
|
return; |
|
} |
|
|
|
m_iThresholdSecs = sArg.ToUInt(); |
|
if (m_iThresholdSecs == 0) m_iThresholdSecs = 1; |
|
|
|
OnShowCommand(""); |
|
Save(); |
|
} |
|
|
|
void OnLinesCommand(const CString& sCommand) { |
|
const CString& sArg = sCommand.Token(1, true); |
|
|
|
if (sArg.empty()) { |
|
PutModule(t_s("Usage: Lines <limit>")); |
|
return; |
|
} |
|
|
|
m_iThresholdMsgs = sArg.ToUInt(); |
|
if (m_iThresholdMsgs == 0) m_iThresholdMsgs = 2; |
|
|
|
OnShowCommand(""); |
|
Save(); |
|
} |
|
|
|
void OnShowCommand(const CString& sCommand) { |
|
CString sMsgs = t_p("1 CTCP message", "{1} CTCP messages", |
|
m_iThresholdMsgs)(m_iThresholdMsgs); |
|
CString sSecs = t_p("every second", "every {1} seconds", |
|
m_iThresholdSecs)(m_iThresholdSecs); |
|
PutModule(t_f("Current limit is {1} {2}")(sMsgs, sSecs)); |
|
} |
|
|
|
private: |
|
time_t m_tLastCTCP = 0; |
|
unsigned int m_iNumCTCP = 0; |
|
|
|
time_t m_iThresholdSecs{}; |
|
unsigned int m_iThresholdMsgs{}; |
|
}; |
|
|
|
template <> |
|
void TModInfo<CCtcpFloodMod>(CModInfo& Info) { |
|
Info.SetWikiPage("ctcpflood"); |
|
Info.SetHasArgs(true); |
|
Info.SetArgsHelpText(Info.t_s( |
|
"This user module takes none to two arguments. The first argument is " |
|
"the number of lines after which the flood-protection is triggered. " |
|
"The second argument is the time (sec) to in which the number of lines " |
|
"is reached. The default setting is 4 CTCPs in 2 seconds")); |
|
} |
|
|
|
USERMODULEDEFS(CCtcpFloodMod, t_s("Don't forward CTCP floods to clients"))
|
|
|