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