From d4a1ea70451abb333e71f9cff09b624db59531a0 Mon Sep 17 00:00:00 2001 From: linuxdaemon Date: Wed, 6 Feb 2019 04:33:06 -0600 Subject: Expand searching in m_httpd_stats, add global handling of GET parameters (#1566) --- src/modules/m_httpd_stats.cpp | 190 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 164 insertions(+), 26 deletions(-) (limited to 'src/modules/m_httpd_stats.cpp') diff --git a/src/modules/m_httpd_stats.cpp b/src/modules/m_httpd_stats.cpp index 4b18eadc4..2b28c2628 100644 --- a/src/modules/m_httpd_stats.cpp +++ b/src/modules/m_httpd_stats.cpp @@ -99,7 +99,7 @@ namespace Stats { return data << "" << ServerInstance->Config->ServerName << "" << Sanitize(ServerInstance->Config->ServerDesc) << "" - << Sanitize(ServerInstance->GetVersionString()) << ""; + << Sanitize(ServerInstance->GetVersionString(true)) << ""; } std::ostream& ISupport(std::ostream& data) @@ -124,6 +124,7 @@ namespace Stats data << "" << ServerInstance->Users->all_opers.size() << ""; data << "" << (SocketEngine::GetUsedFds()) << "" << SocketEngine::GetMaxFds() << ""; data << "" << ServerInstance->startup_time << ""; + data << "" << ServerInstance->Time() << ""; data << ISupport; return data << ""; @@ -201,6 +202,37 @@ namespace Stats return data << ""; } + std::ostream& DumpUser(std::ostream& data, User* u) + { + data << ""; + data << "" << u->nick << "" << u->uuid << "" + << u->GetRealHost() << "" << u->GetDisplayedHost() << "" + << Sanitize(u->GetRealName()) << "" << u->server->GetName() << "" + << u->signon << "" << u->age << ""; + + if (u->IsAway()) + data << "" << Sanitize(u->awaymsg) << "" << u->awaytime << ""; + + if (u->IsOper()) + data << "" << Sanitize(u->oper->name) << ""; + + data << "" << u->GetModeLetters().substr(1) << "" << Sanitize(u->ident) << ""; + + LocalUser* lu = IS_LOCAL(u); + if (lu) + data << "" << lu->GetServerPort() << "" + << lu->server_sa.str() << "" + << lu->GetClass()->GetName() << "" + << lu->idle_lastmsg << ""; + + data << "" << u->GetIPString() << ""; + + DumpMeta(data, u); + + data << ""; + return data; + } + std::ostream& Users(std::ostream& data) { data << ""; @@ -209,24 +241,10 @@ namespace Stats { User* u = i->second; - data << ""; - data << "" << u->nick << "" << u->uuid << "" - << u->GetRealHost() << "" << u->GetDisplayedHost() << "" - << Sanitize(u->GetRealName()) << "" << u->server->GetName() << ""; - if (u->IsAway()) - data << "" << Sanitize(u->awaymsg) << "" << u->awaytime << ""; - if (u->IsOper()) - data << "" << Sanitize(u->oper->name) << ""; - data << "" << u->GetModeLetters().substr(1) << "" << Sanitize(u->ident) << ""; - LocalUser* lu = IS_LOCAL(u); - if (lu) - data << "" << lu->GetServerPort() << "" - << lu->server_sa.str() << ""; - data << "" << u->GetIPString() << ""; - - DumpMeta(data, u); + if (u->registered != REG_ALL) + continue; - data << ""; + DumpUser(data, u); } return data << ""; } @@ -265,28 +283,145 @@ namespace Stats } return data << ""; } + + enum OrderBy + { + OB_NICK, + OB_LASTMSG, + + OB_NONE + }; + + struct UserSorter + { + OrderBy order; + bool desc; + + UserSorter(OrderBy Order, bool Desc = false) : order(Order), desc(Desc) {} + + template + inline bool Compare(const T& a, const T& b) + { + return desc ? a > b : a < b; + } + + bool operator()(User* u1, User* u2) + { + switch (order) { + case OB_LASTMSG: + return Compare(IS_LOCAL(u1)->idle_lastmsg, IS_LOCAL(u2)->idle_lastmsg); + break; + case OB_NICK: + return Compare(u1->nick, u2->nick); + break; + default: + case OB_NONE: + return false; + break; + } + } + }; + + std::ostream& ListUsers(std::ostream& data, const HTTPQueryParameters& params) + { + if (params.empty()) + return Users(data); + + data << ""; + + // Filters + size_t limit = params.getNum("limit"); + bool showunreg = params.getBool("showunreg"); + bool localonly = params.getBool("localonly"); + + // Minimum time since a user's last message + unsigned long min_idle = params.getDuration("minidle"); + time_t maxlastmsg = ServerInstance->Time() - min_idle; + + if (min_idle) + // We can only check idle times on local users + localonly = true; + + // Sorting + const std::string& sortmethod = params.getString("sortby"); + bool desc = params.getBool("desc", false); + + OrderBy orderby; + if (stdalgo::string::equalsci(sortmethod, "nick")) + orderby = OB_NICK; + else if (stdalgo::string::equalsci(sortmethod, "lastmsg")) + { + orderby = OB_LASTMSG; + // We can only check idle times on local users + localonly = true; + } + else + orderby = OB_NONE; + + typedef std::list NewUserList; + NewUserList user_list; + user_hash users = ServerInstance->Users->GetUsers(); + for (user_hash::iterator i = users.begin(); i != users.end(); ++i) + { + User* u = i->second; + if (!showunreg && u->registered != REG_ALL) + continue; + + LocalUser* lu = IS_LOCAL(u); + if (localonly && !lu) + continue; + + if (min_idle && lu->idle_lastmsg > maxlastmsg) + continue; + + user_list.push_back(u); + } + + UserSorter sorter(orderby, desc); + if (sorter.order != OB_NONE && !(!localonly && sorter.order == OB_LASTMSG)) + user_list.sort(sorter); + + size_t count = 0; + for (NewUserList::const_iterator i = user_list.begin(); i != user_list.end() && (!limit || count < limit); ++i, ++count) + DumpUser(data, *i); + + data << ""; + return data; + } } class ModuleHttpStats : public Module, public HTTPRequestEventListener { HTTPdAPI API; + bool enableparams; public: ModuleHttpStats() : HTTPRequestEventListener(this) , API(this) + , enableparams(false) { } + void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE + { + ConfigTag* conf = ServerInstance->Config->ConfValue("httpstats"); + + // Parameterized queries may cause a performance issue + // Due to the sheer volume of data + // So default them to disabled + enableparams = conf->getBool("enableparams"); + } + ModResult HandleRequest(HTTPRequest* http) { - std::string uri = http->GetURI(); + std::string path = http->GetPath(); - if (uri != "/stats" && uri.substr(0, 7) != "/stats/") + if (path != "/stats" && path.substr(0, 7) != "/stats/") return MOD_RES_PASSTHRU; - if (uri[uri.size() - 1] == '/') - uri.erase(uri.size() - 1, 1); + if (path[path.size() - 1] == '/') + path.erase(path.size() - 1, 1); ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling httpd event"); @@ -294,20 +429,23 @@ class ModuleHttpStats : public Module, public HTTPRequestEventListener std::stringstream data; data << ""; - if (uri == "/stats") + if (path == "/stats") { data << Stats::ServerInfo << Stats::General << Stats::XLines << Stats::Modules << Stats::Channels << Stats::Users << Stats::Servers << Stats::Commands; } - else if (uri == "/stats/general") + else if (path == "/stats/general") { data << Stats::General; } - else if (uri == "/stats/users") + else if (path == "/stats/users") { - data << Stats::Users; + if (enableparams) + Stats::ListUsers(data, http->GetParsedURI().query_params); + else + data << Stats::Users; } else { -- cgit v1.3.1-10-gc9f91 From a7fc2fe0dc845ffba1f4575e694aa1bb7f60756b Mon Sep 17 00:00:00 2001 From: Peter Powell Date: Fri, 15 Feb 2019 10:58:43 +0000 Subject: Replace GetServerPort() with server_sa.port(). --- include/users.h | 5 ----- src/coremods/core_who.cpp | 2 +- src/modules/m_close.cpp | 2 +- src/modules/m_hostchange.cpp | 2 +- src/modules/m_httpd_stats.cpp | 2 +- src/modules/m_jumpserver.cpp | 2 +- src/users.cpp | 9 ++------- 7 files changed, 7 insertions(+), 17 deletions(-) (limited to 'src/modules/m_httpd_stats.cpp') diff --git a/include/users.h b/include/users.h index 39e7e90f0..9a90567a0 100644 --- a/include/users.h +++ b/include/users.h @@ -772,11 +772,6 @@ class CoreExport LocalUser : public User, public insp::intrusive_list_nodeGetServerPort()) + if (port == lu->server_sa.port()) { match = true; break; diff --git a/src/modules/m_close.cpp b/src/modules/m_close.cpp index b0b45b4b6..c2a94a6ff 100644 --- a/src/modules/m_close.cpp +++ b/src/modules/m_close.cpp @@ -44,7 +44,7 @@ class CommandClose : public Command if (user->registered != REG_ALL) { ServerInstance->Users->QuitUser(user, "Closing all unknown connections per request"); - std::string key = ConvToStr(user->GetIPString())+"."+ConvToStr(user->GetServerPort()); + std::string key = ConvToStr(user->GetIPString())+"."+ConvToStr(user->server_sa.port()); closed[key]++; } } diff --git a/src/modules/m_hostchange.cpp b/src/modules/m_hostchange.cpp index be503ba6b..895e0f04a 100644 --- a/src/modules/m_hostchange.cpp +++ b/src/modules/m_hostchange.cpp @@ -76,7 +76,7 @@ class HostRule bool Matches(LocalUser* user) const { - if (!ports.empty() && !ports.count(user->GetServerPort())) + if (!ports.empty() && !ports.count(user->server_sa.port())) return false; if (InspIRCd::MatchCIDR(user->MakeHost(), mask)) diff --git a/src/modules/m_httpd_stats.cpp b/src/modules/m_httpd_stats.cpp index 2b28c2628..3be8ec970 100644 --- a/src/modules/m_httpd_stats.cpp +++ b/src/modules/m_httpd_stats.cpp @@ -220,7 +220,7 @@ namespace Stats LocalUser* lu = IS_LOCAL(u); if (lu) - data << "" << lu->GetServerPort() << "" + data << "" << lu->server_sa.port() << "" << lu->server_sa.str() << "" << lu->GetClass()->GetName() << "" << lu->idle_lastmsg << ""; diff --git a/src/modules/m_jumpserver.cpp b/src/modules/m_jumpserver.cpp index 02950e0e9..80b0a84ab 100644 --- a/src/modules/m_jumpserver.cpp +++ b/src/modules/m_jumpserver.cpp @@ -151,7 +151,7 @@ class CommandJumpserver : public Command { int p = (sslapi && sslapi->GetCertificate(user) ? sslport : port); if (p == 0) - p = user->GetServerPort(); + p = user->server_sa.port(); return p; } }; diff --git a/src/users.cpp b/src/users.cpp index 4050337c7..cf676d2dc 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -560,7 +560,7 @@ void LocalUser::FullConnect() FOREACH_MOD(OnPostConnect, (this)); ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d (class %s): %s (%s) [%s]", - this->GetServerPort(), this->MyClass->name.c_str(), GetFullRealHost().c_str(), this->GetIPString().c_str(), this->GetRealName().c_str()); + this->server_sa.port(), this->MyClass->name.c_str(), GetFullRealHost().c_str(), this->GetIPString().c_str(), this->GetRealName().c_str()); ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Adding NEGATIVE hit for " + this->GetIPString()); ServerInstance->BanCache.AddHit(this->GetIPString(), "", ""); // reset the flood penalty (which could have been raised due to things like auto +x) @@ -656,11 +656,6 @@ void LocalUser::OverruleNick() this->ChangeNick(this->uuid); } -int LocalUser::GetServerPort() -{ - return this->server_sa.port(); -} - const std::string& User::GetIPString() { if (cachedip.empty()) @@ -1121,7 +1116,7 @@ void LocalUser::SetClass(const std::string &explicit_name) if (!c->ports.empty()) { /* and our port doesn't match, fail. */ - if (!c->ports.count(this->GetServerPort())) + if (!c->ports.count(this->server_sa.port())) { ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Requires a different port, skipping"); continue; -- cgit v1.3.1-10-gc9f91