From cf8db5e33d42caa1b6d9c089b7615bd09b6772ba Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Thu, 22 Sep 2011 20:18:26 +0200 Subject: [PATCH] Send a MODE request when JOINing This kind of reverts/fixes f1cb09bd9ce0489d96f4ef91b3e226e0b0a37662. Robby found a bug with evil ChanServ which goes like this: - You join an empty, but registered channel and the IRCd applies its default modes (+nt), but ZNC didn't ask for MODE, so doesn't know this. - ChanServ applies whatever channel modes it wants to apply. This causes ZNC to see a mode change (e.g. +s). The result of this is that ZNC thinks that the channel has mode +s and it will tell every client that connects to it about this. The fix is to send a MODE request when JOINing. To make sure that we don't confuse clients, we block the reply. Signed-off-by: Uli Schlachter --- Chan.cpp | 1 + Chan.h | 3 +++ IRCSock.cpp | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/Chan.cpp b/Chan.cpp index d6f7502b..5f1a94fe 100644 --- a/Chan.cpp +++ b/Chan.cpp @@ -54,6 +54,7 @@ CChan::~CChan() { void CChan::Reset() { m_bIsOn = false; + m_bModeKnown = false; m_musModes.clear(); m_sTopic = ""; m_sTopicOwner = ""; diff --git a/Chan.h b/Chan.h index 5d3ad5b0..2845e9ae 100644 --- a/Chan.h +++ b/Chan.h @@ -100,6 +100,7 @@ public: // !wrappers // Setters + void SetModeKnown(bool b) { m_bModeKnown = b; } void SetIsOn(bool b) { m_bIsOn = b; if (!b) { Reset(); } } void SetKey(const CString& s) { m_sKey = s; } void SetTopic(const CString& s) { m_sTopic = s; } @@ -118,6 +119,7 @@ public: // !Setters // Getters + bool IsModeKnown() const { return m_bModeKnown; } bool HasMode(unsigned char uMode) const; CString GetOptions() const; CString GetModeArg(unsigned char uMode) const; @@ -162,6 +164,7 @@ protected: unsigned int m_uBufferCount; vector m_vsBuffer; + bool m_bModeKnown; map m_musModes; }; diff --git a/IRCSock.cpp b/IRCSock.cpp index a62ce009..80cb4a70 100644 --- a/IRCSock.cpp +++ b/IRCSock.cpp @@ -196,6 +196,15 @@ void CIRCSock::ReadLine(const CString& sData) { if (pChan) { pChan->SetModes(sRest.Token(1, true)); + + // We don't SetModeKnown(true) here, + // because a 329 will follow + if (!pChan->IsModeKnown()) { + // When we JOIN, we send a MODE + // request. This makes sure the + // reply isn't forwarded. + return; + } } } break; @@ -206,6 +215,14 @@ void CIRCSock::ReadLine(const CString& sData) { if (pChan) { unsigned long ulDate = sLine.Token(4).ToULong(); pChan->SetCreationDate(ulDate); + + if (!pChan->IsModeKnown()) { + pChan->SetModeKnown(true); + // When we JOIN, we send a MODE + // request. This makes sure the + // reply isn't forwarded. + return; + } } } break; @@ -455,6 +472,7 @@ void CIRCSock::ReadLine(const CString& sData) { pChan->ResetJoinTries(); pChan->Enable(); pChan->SetIsOn(true); + PutIRC("MODE " + sChan); } } else { pChan = m_pUser->FindChan(sChan);