diff options
author | Peter Powell <petpow@saberuk.com> | 2018-10-27 18:13:29 +0100 |
---|---|---|
committer | Peter Powell <petpow@saberuk.com> | 2018-10-27 18:13:29 +0100 |
commit | ac09aff7f4db2e915cf9fb84d209f577530c09e2 (patch) | |
tree | 63a8230901f1c97c3ba75b2af9ebd4c4c6a0baf0 /src/modules/m_spanningtree | |
parent | 0fc595caac348944f1154cc7dabf44e206e58bf5 (diff) |
Improve CAPAB negotiation in the spanningtree module.
- Remove the CHANMODES, USERMODES, and PREFIX tokens in the 1205
protocol. These have entirely been superceded by the CHANMODES
and USERMODES CAPAB commands.
- Only compare the 1202 PREFIX tokens if the remote server did not
send CAPAB CHANMODES. This replicates the existing behaviour
used for the CHANMODES token.
- Fix checking whether the remote server has an appropriate case
mapping. If it is not sent we assume it is the same as the local
server as always. This should prevent issues with people using
services packages that do not send this token yet.
- Fix checking if the user modes are mismatched and then promptly
overwriting the error message with mismatched channel modes.
- Fix servers not being able to tell whether a mode on the remote
server is a prefixless prefix mode. Requires the 1205 protocol.
- Fix servers that receive CAPAB CHANMODES or CAPAB USERMODES not
checking the type of those modes. Requires the 1205 protocol.
Diffstat (limited to 'src/modules/m_spanningtree')
-rw-r--r-- | src/modules/m_spanningtree/capab.cpp | 80 | ||||
-rw-r--r-- | src/modules/m_spanningtree/treesocket.h | 5 |
2 files changed, 55 insertions, 30 deletions
diff --git a/src/modules/m_spanningtree/capab.cpp b/src/modules/m_spanningtree/capab.cpp index 256a3d069..795627a61 100644 --- a/src/modules/m_spanningtree/capab.cpp +++ b/src/modules/m_spanningtree/capab.cpp @@ -79,14 +79,26 @@ std::string TreeSocket::MyModules(int filter) return capabilities; } -static std::string BuildModeList(ModeType type) +std::string TreeSocket::BuildModeList(ModeType type) { std::vector<std::string> modes; const ModeParser::ModeHandlerMap& mhs = ServerInstance->Modes.GetModes(type); for (ModeParser::ModeHandlerMap::const_iterator i = mhs.begin(); i != mhs.end(); ++i) { const ModeHandler* const mh = i->second; - std::string mdesc = mh->name; + std::string mdesc; + if (proto_version != 1202) + { + if (mh->IsPrefixMode()) + mdesc.append("prefix:"); + else if (mh->IsListMode()) + mdesc.append("list:"); + else if (mh->NeedsParam(true)) + mdesc.append(mh->NeedsParam(false) ? "param:" : "param-set:"); + else + mdesc.append("simple:"); + } + mdesc.append(mh->name); mdesc.push_back('='); const PrefixMode* const pm = mh->IsPrefixMode(); if (pm) @@ -166,8 +178,11 @@ void TreeSocket::SendCapabilities(int phase) // 2.0 needs these keys. if (proto_version == 1202) { - extra.append(" PROTOCOL="+ConvToStr(ProtocolVersion)); - extra.append(" MAXGECOS="+ConvToStr(ServerInstance->Config->Limits.MaxReal)); + extra.append(" PROTOCOL="+ConvToStr(ProtocolVersion)) + .append(" MAXGECOS="+ConvToStr(ServerInstance->Config->Limits.MaxReal)) + .append(" CHANMODES="+ServerInstance->Modes->GiveModeList(MODETYPE_CHANNEL)) + .append(" USERMODES="+ServerInstance->Modes->GiveModeList(MODETYPE_USER)) + .append(" PREFIX="+ ServerInstance->Modes->BuildPrefixes()); } this->WriteLine("CAPAB CAPABILITIES " /* Preprocessor does this one. */ @@ -182,9 +197,6 @@ void TreeSocket::SendCapabilities(int phase) " MAXAWAY="+ConvToStr(ServerInstance->Config->Limits.MaxAway)+ " MAXHOST="+ConvToStr(ServerInstance->Config->Limits.MaxHost)+ extra+ - " PREFIX="+ServerInstance->Modes->BuildPrefixes()+ - " CHANMODES="+ServerInstance->Modes->GiveModeList(MODETYPE_CHANNEL)+ - " USERMODES="+ServerInstance->Modes->GiveModeList(MODETYPE_USER)+ " CASEMAPPING="+ServerInstance->Config->CaseMapping+ // XXX: Advertise the presence or absence of m_globops in CAPAB CAPABILITIES. // Services want to know about it, and since m_globops was not marked as VF_(OPT)COMMON @@ -275,6 +287,7 @@ bool TreeSocket::Capab(const CommandBase::Params& params) return false; } } + if (this->capab->OptModuleList != this->MyModules(VF_OPTCOMMON) && this->capab->OptModuleList.length()) { std::string diffIneed, diffUneed; @@ -290,7 +303,7 @@ bool TreeSocket::Capab(const CommandBase::Params& params) } else { - reason = "Optional modules incorrectly matched on these servers, and options::allowmismatch not set."; + reason = "Optional modules incorrectly matched on these servers and <options:allowmismatch> is not enabled."; if (diffIneed.length()) reason += " Not loaded here:" + diffIneed; if (diffUneed.length()) @@ -301,9 +314,6 @@ bool TreeSocket::Capab(const CommandBase::Params& params) } } - if(this->capab->CapKeys.find("PREFIX") != this->capab->CapKeys.end() && this->capab->CapKeys.find("PREFIX")->second != ServerInstance->Modes->BuildPrefixes()) - reason = "One or more of the prefixes on the remote server are invalid on this server."; - if (!capab->ChanModes.empty()) { if (capab->ChanModes != BuildModeList(MODETYPE_CHANNEL)) @@ -320,10 +330,25 @@ bool TreeSocket::Capab(const CommandBase::Params& params) } } } - else if (this->capab->CapKeys.find("CHANMODES") != this->capab->CapKeys.end()) + else if (proto_version == 1202) + { + if (this->capab->CapKeys.find("CHANMODES") != this->capab->CapKeys.end()) + { + if (this->capab->CapKeys.find("CHANMODES")->second != ServerInstance->Modes->GiveModeList(MODETYPE_CHANNEL)) + reason = "One or more of the channel modes on the remote server are invalid on this server."; + } + + else if (this->capab->CapKeys.find("PREFIX") != this->capab->CapKeys.end()) + { + if (this->capab->CapKeys.find("PREFIX")->second != ServerInstance->Modes->BuildPrefixes()) + reason = "One or more of the prefixes on the remote server are invalid on this server."; + } + } + + if (!reason.empty()) { - if (this->capab->CapKeys.find("CHANMODES")->second != ServerInstance->Modes->GiveModeList(MODETYPE_CHANNEL)) - reason = "One or more of the channel modes on the remote server are invalid on this server."; + this->SendError("CAPAB negotiation failed: " + reason); + return false; } if (!capab->UserModes.empty()) @@ -342,28 +367,29 @@ bool TreeSocket::Capab(const CommandBase::Params& params) } } } - else if (this->capab->CapKeys.find("USERMODES") != this->capab->CapKeys.end()) + else if (proto_version == 1202 && this->capab->CapKeys.find("USERMODES") != this->capab->CapKeys.end()) { if (this->capab->CapKeys.find("USERMODES")->second != ServerInstance->Modes->GiveModeList(MODETYPE_USER)) reason = "One or more of the user modes on the remote server are invalid on this server."; } - else + + if (!reason.empty()) { - // We default to rfc1459 here because if this key is not sent then - // the remote server is running the 2.0 protocol which uses rfc1459 - // by default. - std::string casemapping = "rfc1459"; - std::map<std::string, std::string>::iterator citer = this->capab->CapKeys.find("CASEMAPPING"); - if (citer != this->capab->CapKeys.end()) - casemapping = citer->second; + this->SendError("CAPAB negotiation failed: " + reason); + return false; + } + if (this->capab->CapKeys.find("CASEMAPPING") != this->capab->CapKeys.end()) + { + const std::string casemapping = this->capab->CapKeys.find("CASEMAPPING")->second; if (casemapping != ServerInstance->Config->CaseMapping) { reason = "The casemapping of the remote server differs to that of the local server." " Local casemapping: " + ServerInstance->Config->CaseMapping + " Remote casemapping: " + casemapping; + this->SendError("CAPAB negotiation failed: " + reason); + return false; } - } /* Challenge response, store their challenge for our password */ @@ -387,12 +413,6 @@ bool TreeSocket::Capab(const CommandBase::Params& params) this->WriteLine("SERVER "+ServerInstance->Config->ServerName+" "+capab->link->SendPass+" 0 "+ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc); } } - - if (reason.length()) - { - this->SendError("CAPAB negotiation failed: "+reason); - return false; - } } else if ((params[0] == "MODULES") && (params.size() == 2)) { diff --git a/src/modules/m_spanningtree/treesocket.h b/src/modules/m_spanningtree/treesocket.h index d99dc9104..e8dbfd7cf 100644 --- a/src/modules/m_spanningtree/treesocket.h +++ b/src/modules/m_spanningtree/treesocket.h @@ -238,6 +238,11 @@ class TreeSocket : public BufferedSocket */ std::string MyModules(int filter); + /** Returns mode list as a string, filtered by type. + * @param type The type of modes to return. + */ + std::string BuildModeList(ModeType type); + /** Send my capabilities to the remote side */ void SendCapabilities(int phase); |