From: Marcus Eggenberger Date: Sun, 5 Sep 2010 19:41:19 +0000 (+0200) Subject: Fixing issues with multiple CTCP requests in one message X-Git-Tag: 0.6.3~1 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=a4ca568cdf68cf4a0343eb161518dc8e50cea87d Fixing issues with multiple CTCP requests in one message If we receive multiple CTCP requests in one PRIVMSG we now answer with one packed NOTICE containing all CTCP replies. This fixes a possible DoS Attack rendering Quassels IRC connection useless. Upgrading is strongly recommended. Thanks to Jima for reporting and supporting. --- diff --git a/src/core/ctcphandler.cpp b/src/core/ctcphandler.cpp index 655f1700..758d2ef1 100644 --- a/src/core/ctcphandler.cpp +++ b/src/core/ctcphandler.cpp @@ -129,6 +129,7 @@ void CtcpHandler::parse(Message::Type messageType, const QString &prefix, const int xdelimPos = -1; int xdelimEndPos = -1; int spacePos = -1; + QList replies; while((xdelimPos = dequotedMessage.indexOf(XDELIM)) != -1) { if(xdelimPos > 0) displayMsg(messageType, target, userDecode(target, dequotedMessage.left(xdelimPos)), prefix, flags); @@ -154,7 +155,16 @@ void CtcpHandler::parse(Message::Type messageType, const QString &prefix, const ctcpparam = QString(); } - handle(ctcpcmd, Q_ARG(CtcpType, ctcptype), Q_ARG(QString, prefix), Q_ARG(QString, target), Q_ARG(QString, ctcpparam)); + if(!_ignoreListManager->ctcpMatch(prefix, network()->networkName(), ctcpcmd.toUpper())) { + QString reply_; + handle(ctcpcmd, Q_ARG(CtcpType, ctcptype), Q_ARG(QString, prefix), Q_ARG(QString, target), Q_ARG(QString, ctcpparam), Q_ARG(QString, reply_)); + if(ctcptype == CtcpQuery && !reply_.isNull()) { + replies << lowLevelQuote(pack(serverEncode(ctcpcmd), userEncode(nickFromMask(prefix), reply_))); + } + } + } + if(ctcptype == CtcpQuery && !replies.isEmpty()) { + packedReply(nickFromMask(prefix), replies); } if(!dequotedMessage.isEmpty()) @@ -180,20 +190,39 @@ void CtcpHandler::reply(const QString &bufname, const QString &ctcpTag, const QS emit putCmd("NOTICE", params); } +void CtcpHandler::packedReply(const QString &bufname, const QList &replies) { + QList params; + + int answerSize = 0; + for(int i = 0; i < replies.count(); i++) { + answerSize += replies.at(i).size(); + } + + QByteArray quotedReply(answerSize, 0); + int nextPos = 0; + QByteArray &reply = quotedReply; + for(int i = 0; i < replies.count(); i++) { + reply = replies.at(i); + quotedReply.replace(nextPos, reply.size(), reply); + nextPos += reply.size(); + } + + params << serverEncode(bufname) << quotedReply; + emit putCmd("NOTICE", params); +} + //******************************/ // CTCP HANDLER //******************************/ -void CtcpHandler::handleAction(CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m) { +void CtcpHandler::handleAction(CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m, QString &/*reply*/) { Q_UNUSED(ctcptype) emit displayMsg(Message::Action, typeByTarget(target), target, param, prefix); } -void CtcpHandler::handlePing(CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m) { +void CtcpHandler::handlePing(CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m, QString &reply) { Q_UNUSED(target) if(ctcptype == CtcpQuery) { - if(_ignoreListManager->ctcpMatch(prefix, network()->networkName(), "PING")) - return; - reply(nickFromMask(prefix), "PING", param); + reply = param; emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP PING request from %1").arg(prefix)); } else { // display ping answer @@ -204,14 +233,10 @@ void CtcpHandler::handlePing(CtcpType ctcptype, const QString &prefix, const QSt } } -void CtcpHandler::handleVersion(CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m) { +void CtcpHandler::handleVersion(CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m, QString &reply) { Q_UNUSED(target) if(ctcptype == CtcpQuery) { - if(_ignoreListManager->ctcpMatch(prefix, network()->networkName(), "VERSION")) - return; - reply(nickFromMask(prefix), "VERSION", QString("Quassel IRC %1 (built on %2) -- http://www.quassel-irc.org") - .arg(Quassel::buildInfo().plainVersionString) - .arg(Quassel::buildInfo().buildDate)); + reply = QString("Quassel IRC %1 (built on %2) -- http://www.quassel-irc.org").arg(Quassel::buildInfo().plainVersionString).arg(Quassel::buildInfo().buildDate); emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP VERSION request by %1").arg(prefix)); } else { // display Version answer @@ -220,28 +245,24 @@ void CtcpHandler::handleVersion(CtcpType ctcptype, const QString &prefix, const } } -void CtcpHandler::handleTime(CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m) { +void CtcpHandler::handleTime(CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m, QString &reply) { Q_UNUSED(target) if(ctcptype == CtcpQuery) { - if(_ignoreListManager->ctcpMatch(prefix, network()->networkName(), "TIME")) - return; - reply(nickFromMask(prefix), "TIME", QDateTime::currentDateTime().toString()); + reply = QDateTime::currentDateTime().toString(); emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP TIME request by %1").arg(prefix)); - } - else { + } else { emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP TIME answer from %1: %2") .arg(nickFromMask(prefix)).arg(param)); } } -void CtcpHandler::defaultHandler(const QString &cmd, CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m) { +void CtcpHandler::defaultHandler(const QString &cmd, CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m, QString &reply) { Q_UNUSED(ctcptype); Q_UNUSED(target); - if(!_ignoreListManager->ctcpMatch(prefix, network()->networkName())) { - QString str = tr("Received unknown CTCP %1 by %2").arg(cmd).arg(prefix); - if(!param.isEmpty()) - str.append(tr(" with arguments: %1").arg(param)); - emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", str); - } + Q_UNUSED(reply); + QString str = tr("Received unknown CTCP %1 by %2").arg(cmd).arg(prefix); + if(!param.isEmpty()) + str.append(tr(" with arguments: %1").arg(param)); + emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", str); } diff --git a/src/core/ctcphandler.h b/src/core/ctcphandler.h index 169ec16f..e2f43a58 100644 --- a/src/core/ctcphandler.h +++ b/src/core/ctcphandler.h @@ -48,14 +48,16 @@ public: void reply(const QString &bufname, const QString &ctcpTag, const QString &message); public slots: - void handleAction(CtcpType, const QString &prefix, const QString &target, const QString ¶m); - void handlePing(CtcpType, const QString &prefix, const QString &target, const QString ¶m); - void handleTime(CtcpType, const QString &prefix, const QString &target, const QString ¶m); - void handleVersion(CtcpType, const QString &prefix, const QString &target, const QString ¶m); + void handleAction(CtcpType, const QString &prefix, const QString &target, const QString ¶m, QString &reply); + void handlePing(CtcpType, const QString &prefix, const QString &target, const QString ¶m, QString &reply); + void handleTime(CtcpType, const QString &prefix, const QString &target, const QString ¶m, QString &reply); + void handleVersion(CtcpType, const QString &prefix, const QString &target, const QString ¶m, QString &reply); - void defaultHandler(const QString &cmd, CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m); + void defaultHandler(const QString &cmd, CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m, QString &reply); private: + void packedReply(const QString &bufname, const QList &replies); + QByteArray XDELIM; QHash ctcpMDequoteHash; QHash ctcpXDelimDequoteHash;