diff -r 57757fba40cc dcpp/ClientListener.h --- a/dcpp/ClientListener.h Sat Jan 17 11:57:53 2015 +0100 +++ b/dcpp/ClientListener.h Thu Feb 19 07:41:47 2015 -0600 @@ -42,16 +42,17 @@ public: typedef X<12> StatusMessage; typedef X<13> HubUserCommand; typedef X<14> HubFull; typedef X<15> NickTaken; typedef X<16> SearchFlood; typedef X<17> NmdcSearch; typedef X<18> AdcSearch; typedef X<19> ClientLine; + typedef X<20> BadSearch; enum StatusFlags { FLAG_NORMAL = 0x00, FLAG_IS_SPAM = 0x01 }; virtual void on(Connecting, Client*) noexcept { } virtual void on(Connected, Client*) noexcept { } @@ -66,13 +67,14 @@ public: virtual void on(StatusMessage, Client*, const string&, int = FLAG_NORMAL) noexcept { } virtual void on(HubUserCommand, Client*, int, int, const string&, const string&) noexcept { } virtual void on(HubFull, Client*) noexcept { } virtual void on(NickTaken, Client*) noexcept { } virtual void on(SearchFlood, Client*, const string&) noexcept { } virtual void on(NmdcSearch, Client*, const string&, int, int64_t, int, const string&) noexcept { } virtual void on(AdcSearch, Client*, const AdcCommand&, const OnlineUser&) noexcept { } virtual void on(ClientLine, Client*, const string& line, int type) noexcept { }; + virtual void on(BadSearch, const string&) noexcept { }; }; } // namespace dcpp #endif /*CLIENTLISTENER_H_*/ diff -r 57757fba40cc dcpp/ClientManager.cpp --- a/dcpp/ClientManager.cpp Sat Jan 17 11:57:53 2015 +0100 +++ b/dcpp/ClientManager.cpp Thu Feb 19 07:41:47 2015 -0600 @@ -217,24 +217,17 @@ bool ClientManager::isHubConnected(const return false; } string ClientManager::findHub(const string& ipPort) const { Lock l(cs); string ip; string port; - string::size_type i = ipPort.rfind(':'); - if(i == string::npos) { - ip = ipPort; - port = "411"; - } else { - ip = ipPort.substr(0, i); - port = ipPort.substr(i+1); - } + Util::parseIpPort(ipPort, ip, port); string url; for(auto c: clients) { if(c->getIp() == ip) { // If exact match is found, return it if(c->getPort() == port) return c->getHubUrl(); @@ -508,18 +501,18 @@ void ClientManager::on(NmdcSearch, Clien str += name; str += '|'; } if(!str.empty()) aClient->send(str); } else { - string ip, port, file, proto, query, fragment; - Util::decodeUrl(aSeeker, proto, ip, port, file, query, fragment); + string ip, port; + Util::parseIpPort(aSeeker, ip, port); ip = Socket::resolve(ip, AF_INET); if(static_cast(aClient)->isProtectedIP(ip)) return; if(port.empty()) port = "412"; diff -r 57757fba40cc dcpp/NmdcHub.cpp --- a/dcpp/NmdcHub.cpp Sat Jan 17 11:57:53 2015 +0100 +++ b/dcpp/NmdcHub.cpp Thu Feb 19 07:41:47 2015 -0600 @@ -35,17 +35,18 @@ #include "version.h" namespace dcpp { NmdcHub::NmdcHub(const string& aHubURL) : Client(aHubURL, '|', false), supportFlags(0), lastUpdate(0), -lastProtectedIPsUpdate(0) +lastProtectedIPsUpdate(0), +badSearchCount(0) { } NmdcHub::~NmdcHub() { clearUsers(); } @@ -124,16 +125,17 @@ void NmdcHub::putUser(const string& aNic ou = i->second; users.erase(i); } ClientManager::getInstance()->putOffline(ou); delete ou; } void NmdcHub::clearUsers() { + badSearchCount = 0; decltype(users) u2; { Lock l(cs); u2.swap(users); } for(auto& i: u2) { @@ -250,25 +252,27 @@ void NmdcHub::onLine(const string& aLine } string::size_type i = 0; string::size_type j = param.find(' ', i); if(j == string::npos || i == j) return; string seeker = param.substr(i, j-i); + const bool isPassive = (seeker.size() > 4 && seeker.compare(0, 4, "Hub:") == 0); + // Filter own searches - if(ClientManager::getInstance()->isActive()) { + if(ClientManager::getInstance()->isActive() && !isPassive) { if(seeker == localIp + ":" + SearchManager::getInstance()->getPort()) { return; } } else { // Hub:seeker - if(seeker.size() > 4 && - Util::stricmp(seeker.c_str() + 4, getMyNick().c_str()) == 0) + if(isPassive && seeker.size() > 4) + if(Util::stricmp(seeker.c_str() + 4, getMyNick().c_str()) == 0) { return; } } i = j + 1; uint64_t tick = GET_TICK(); @@ -316,27 +320,46 @@ void NmdcHub::onLine(const string& aLine j = param.find('?', i); if(j == string::npos || i == j) return; int type = Util::toInt(param.substr(i, j-i)) - 1; i = j + 1; string terms = unescape(param.substr(i)); if(!terms.empty()) { - if(seeker.compare(0, 4, "Hub:") == 0) { + if(seeker.size() > 4 && seeker.compare(0, 4, "Hub:") == 0) { OnlineUser* u = findUser(seeker.substr(4)); - if(u == NULL) { + if(u == nullptr) { return; } if(!u->getUser()->isSet(User::PASSIVE)) { u->getUser()->setFlag(User::PASSIVE); updated(*u); } + } else { + + auto isValidSearch = [&seeker] (const string& seeker) { + unsigned slashCnt = 0, colonCnt = 0; + for (auto cnt = 0; cnt < seeker.size(); ++cnt) { + if (seeker[cnt] == '/') { slashCnt++; } + else if (seeker[cnt] == ':') { colonCnt++; } + if (colonCnt && slashCnt == 2) { return false; } + } + return true; + }; + + if (!isValidSearch(seeker)) { + if (!badSearchCount) { + const string error = "Bad NMDC search - $Search" + param + " - Hub IP = " + getIp(); + fire(ClientListener::BadSearch(), error); // Or just a log message? + badSearchCount++; + } + } } fire(ClientListener::NmdcSearch(), this, seeker, a, Util::toInt64(size), type, terms); } } else if(cmd == "$MyINFO") { string::size_type i, j; i = 5; j = param.find(' ', i); diff -r 57757fba40cc dcpp/NmdcHub.h --- a/dcpp/NmdcHub.h Sat Jan 17 11:57:53 2015 +0100 +++ b/dcpp/NmdcHub.h Thu Feb 19 07:41:47 2015 -0600 @@ -82,16 +82,18 @@ private: typedef list > FloodMap; typedef FloodMap::iterator FloodIter; FloodMap seekers; FloodMap flooders; uint64_t lastProtectedIPsUpdate; StringList protectedIPs; + unsigned badSearchCount; + NmdcHub(const string& aHubURL); virtual ~NmdcHub(); void clearUsers(); void onLine(const string& aLine) noexcept; OnlineUser& getUser(const string& aNick); OnlineUser* findUser(const string& aNick); diff -r 57757fba40cc dcpp/Util.cpp --- a/dcpp/Util.cpp Sat Jan 17 11:57:53 2015 +0100 +++ b/dcpp/Util.cpp Thu Feb 19 07:41:47 2015 -0600 @@ -482,16 +482,27 @@ void Util::decodeUrl(const string& url, } dcdebug("\n"); path = url.substr(fileStart, fileEnd - fileStart); query = url.substr(queryStart, queryEnd - queryStart); fragment = url.substr(fragmentStart, fragmentEnd - fragmentStart); } +void Util::parseIpPort(const string& aIpPort, string& ip, string& port) { + string::size_type i = aIpPort.rfind(':'); + + if (i == string::npos) { + ip = aIpPort; + } else { + ip = aIpPort.substr(0, i); + port = aIpPort.substr(i + 1); + } +} + map Util::decodeQuery(const string& query) { map ret; size_t start = 0; while(start < query.size()) { auto eq = query.find('=', start); if(eq == string::npos) { break; } diff -r 57757fba40cc dcpp/Util.h --- a/dcpp/Util.h Sat Jan 17 11:57:53 2015 +0100 +++ b/dcpp/Util.h Thu Feb 19 07:41:47 2015 -0600 @@ -200,16 +200,18 @@ public: } } template static inline void replace(const typename string_t::value_type* search, const typename string_t::value_type* replacement, string_t& str) { replace(string_t(search), string_t(replacement), str); } static void sanitizeUrl(string& url); + // Decode NMDC-style IP:Port combinations taken from AirDC++ + static void parseIpPort(const string& aIpPort, string& ip, string& port); static void decodeUrl(const string& aUrl, string& protocol, string& host, string& port, string& path, string& query, string& fragment); static map decodeQuery(const string& query); static string validateFileName(string aFile); static bool checkExtension(const string& tmp); static string cleanPathChars(const string& str); static string addBrackets(const string& s); diff -r 57757fba40cc win32/HubFrame.cpp --- a/win32/HubFrame.cpp Sat Jan 17 11:57:53 2015 +0100 +++ b/win32/HubFrame.cpp Thu Feb 19 07:41:47 2015 -0600 @@ -1087,16 +1087,20 @@ void HubFrame::on(ClientLine, Client*, c callAsync([=] { onStatusMessage(line, ClientListener::FLAG_IS_SPAM); }); } else if(type == MSG_SYSTEM) { callAsync([=] { onStatusMessage(line, ClientListener::FLAG_NORMAL); }); } else { callAsync([=] { addChat(Text::toT(line)); }); } } +void HubFrame::on(BadSearch, const string& line) noexcept { + callAsync([=] { addStatus(Text::toT(line)); }); +} + void HubFrame::onStatusMessage(const string& line, int flags) { callAsync([=] { addStatus(Text::toT(line), !(flags & ClientListener::FLAG_IS_SPAM) || !SETTING(FILTER_MESSAGES)); }); } size_t HubFrame::getUserCount() const { size_t userCount = 0; diff -r 57757fba40cc win32/HubFrame.h --- a/win32/HubFrame.h Sat Jan 17 11:57:53 2015 +0100 +++ b/win32/HubFrame.h Thu Feb 19 07:41:47 2015 -0600 @@ -279,16 +279,17 @@ private: virtual void on(Failed, Client*, const string&) noexcept; virtual void on(GetPassword, Client*) noexcept; virtual void on(HubUpdated, Client*) noexcept; virtual void on(Message, Client*, const ChatMessage&) noexcept; virtual void on(StatusMessage, Client*, const string&, int = ClientListener::FLAG_NORMAL) noexcept; virtual void on(NickTaken, Client*) noexcept; virtual void on(SearchFlood, Client*, const string&) noexcept; virtual void on(ClientLine, Client*, const string& line, int type) noexcept; + virtual void on(BadSearch, const string& line) noexcept; void onStatusMessage(const string& line, int flags); // Icon management void setTabIcon(); int tabIcon; };