mirror of
https://github.com/znc/znc.git
synced 2026-06-27 21:41:25 +02:00
Add a way to disable certain capabilities
This is a way for admins to mitigate some issues caused by caps if such issues ever arise. E.g. add this to global level in znc.conf: DisableClientCap = sasl DisableServerCap = chghost DisableServerCap = message-tags Then these caps will be NAKed to client / not requested from server. Note that this mechanism doesn't fully prevent a cap from being activated, e.g. one could use *send_raw module to request it from server even when disabled.
This commit is contained in:
@@ -83,6 +83,8 @@ class CZNC : private CCoreTranslationMixin {
|
||||
void ClearTrustedProxies();
|
||||
bool AddTrustedProxy(const CString& sHost);
|
||||
bool RemTrustedProxy(const CString& sHost);
|
||||
const SCString& GetClientCapBlacklist() const { return m_ssClientCapBlacklist; }
|
||||
const SCString& GetServerCapBlacklist() const { return m_ssServerCapBlacklist; }
|
||||
void Broadcast(const CString& sMessage, bool bAdminOnly = false,
|
||||
CUser* pSkipUser = nullptr, CClient* pSkipClient = nullptr);
|
||||
void AddBytesRead(unsigned long long u) { m_uBytesRead += u; }
|
||||
@@ -307,6 +309,8 @@ class CZNC : private CCoreTranslationMixin {
|
||||
VCString m_vsBindHosts; // TODO: remove (deprecated in 1.7.0)
|
||||
VCString m_vsTrustedProxies;
|
||||
VCString m_vsMotd;
|
||||
SCString m_ssClientCapBlacklist;
|
||||
SCString m_ssServerCapBlacklist;
|
||||
CFile* m_pLockFile;
|
||||
unsigned int m_uiConnectDelay;
|
||||
unsigned int m_uiAnonIPLimit;
|
||||
|
||||
+12
-3
@@ -815,7 +815,8 @@ void CClient::RespondCap(const CString& sResponse) {
|
||||
PutClient(":irc.znc.in CAP " + GetNick() + " " + sResponse);
|
||||
}
|
||||
|
||||
static VCString MultiLine(const SCString& ssCaps) {
|
||||
template <typename ManyStrings>
|
||||
static VCString MultiLine(const ManyStrings& ssCaps) {
|
||||
VCString vsRes = {""};
|
||||
for (const CString& sCap : ssCaps) {
|
||||
if (vsRes.back().length() + sCap.length() > 400) {
|
||||
@@ -917,7 +918,15 @@ void CClient::HandleCap(const CMessage& Message) {
|
||||
}
|
||||
}
|
||||
NETWORKMODULECALL(OnClientCapLs(this, ssOfferCaps), GetUser(), GetNetwork(), this, NOTHING);
|
||||
VCString vsCaps = MultiLine(ssOfferCaps);
|
||||
VCString vsFilteredCaps;
|
||||
vsFilteredCaps.reserve(ssOfferCaps.size());
|
||||
for (CString sCap : std::move(ssOfferCaps)) {
|
||||
if (!CZNC::Get().GetClientCapBlacklist().count(
|
||||
sCap.Token(0, false, "="))) {
|
||||
vsFilteredCaps.push_back(std::move(sCap));
|
||||
}
|
||||
}
|
||||
VCString vsCaps = MultiLine(vsFilteredCaps);
|
||||
m_bInCap = true;
|
||||
if (HasCap302()) {
|
||||
m_bCapNotify = true;
|
||||
@@ -961,7 +970,7 @@ void CClient::HandleCap(const CMessage& Message) {
|
||||
NETWORKMODULECALL(IsClientCapSupported(this, sCap, bVal), GetUser(), GetNetwork(), this,
|
||||
&bAccepted);
|
||||
|
||||
if (!bAccepted) {
|
||||
if (!bAccepted || CZNC::Get().GetClientCapBlacklist().count(sCap)) {
|
||||
// Some unsupported capability is requested
|
||||
RespondCap("NAK :" + Message.GetParam(1));
|
||||
return;
|
||||
|
||||
@@ -416,6 +416,9 @@ bool CIRCSock::OnCapabilityMessage(CMessage& Message) {
|
||||
sCap = sToken.substr(0, eq);
|
||||
sValue = sToken.substr(eq + 1);
|
||||
}
|
||||
if (CZNC::Get().GetServerCapBlacklist().count(sCap)) {
|
||||
continue;
|
||||
}
|
||||
m_msCapLsValues[sCap] = sValue;
|
||||
if (OnServerCapAvailable(sCap, sValue) || mSupportedCaps.count(sCap)) {
|
||||
m_ssPendingCaps.insert(sCap);
|
||||
|
||||
+15
-1
@@ -55,11 +55,14 @@ CZNC::CZNC()
|
||||
m_vsBindHosts(),
|
||||
m_vsTrustedProxies(),
|
||||
m_vsMotd(),
|
||||
m_ssClientCapBlacklist(),
|
||||
m_ssServerCapBlacklist(),
|
||||
m_pLockFile(nullptr),
|
||||
m_uiConnectDelay(5),
|
||||
m_uiAnonIPLimit(10),
|
||||
m_uiMaxBufferSize(500),
|
||||
m_uDisabledSSLProtocols(Csock::EDP_SSL | Csock::EDP_TLSv1 | Csock::EDP_TLSv1_1),
|
||||
m_uDisabledSSLProtocols(Csock::EDP_SSL | Csock::EDP_TLSv1 |
|
||||
Csock::EDP_TLSv1_1),
|
||||
m_pModules(new CModules),
|
||||
m_uBytesRead(0),
|
||||
m_uBytesWritten(0),
|
||||
@@ -1185,6 +1188,17 @@ bool CZNC::LoadGlobal(CConfig& config, CString& sError) {
|
||||
AddTrustedProxy(sProxy);
|
||||
}
|
||||
|
||||
m_ssClientCapBlacklist.clear();
|
||||
config.FindStringVector("disableclientcap", vsList);
|
||||
for (const CString& sCap : vsList) {
|
||||
m_ssClientCapBlacklist.insert(sCap);
|
||||
}
|
||||
m_ssServerCapBlacklist.clear();
|
||||
config.FindStringVector("disableservercap", vsList);
|
||||
for (const CString& sCap : vsList) {
|
||||
m_ssServerCapBlacklist.insert(sCap);
|
||||
}
|
||||
|
||||
CString sVal;
|
||||
if (config.FindStringEntry("pidfile", sVal)) m_sPidFile = sVal;
|
||||
if (config.FindStringEntry("statusprefix", sVal)) m_sStatusPrefix = sVal;
|
||||
|
||||
@@ -1104,5 +1104,29 @@ TEST_F(ZNCTest, InviteNotify) {
|
||||
ASSERT_THAT(ircd.ReadRemainder().toStdString(), Not(HasSubstr("__INV__")));
|
||||
}
|
||||
|
||||
TEST_F(ZNCTest, DisableCap) {
|
||||
{
|
||||
QFile conf(m_dir.path() + "/configs/znc.conf");
|
||||
ASSERT_TRUE(conf.open(QIODevice::Append | QIODevice::Text));
|
||||
QTextStream out(&conf);
|
||||
out << R"(
|
||||
DisableClientCap = sasl
|
||||
DisableServerCap = chghost
|
||||
)";
|
||||
}
|
||||
auto znc = Run();
|
||||
auto ircd = ConnectIRCd();
|
||||
|
||||
ircd.Write("CAP user LS :chghost");
|
||||
ASSERT_THAT(ircd.ReadRemainder().toStdString(), Not(HasSubstr("chghost")));
|
||||
|
||||
auto client = ConnectClient();
|
||||
client.Write("NICK foo");
|
||||
client.Write("CAP LS 302");
|
||||
ASSERT_THAT(client.ReadRemainder().toStdString(), Not(HasSubstr("sasl")));
|
||||
client.Write("CAP REQ sasl");
|
||||
client.ReadUntil("CAP foo NAK :sasl");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace znc_inttest
|
||||
|
||||
Reference in New Issue
Block a user