aboutsummaryrefslogtreecommitdiffstats
path: root/src/modules
diff options
context:
space:
mode:
authorGravatar Sadie Powell2019-12-08 17:38:47 +0000
committerGravatar Sadie Powell2019-12-08 17:47:07 +0000
commit034dad6ab0df48172a70de70a9d0de4a9092112e (patch)
tree0e852f3554dbce37d8e2e360fa099148155e8cab /src/modules
parentMove the nationalchars locale files to the docs directory. (diff)
parentClean up the initialisation of the InspIRCd class. (diff)
Merge branch 'insp3' into master.
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/extra/m_mysql.cpp112
-rw-r--r--src/modules/extra/m_ssl_gnutls.cpp1
-rw-r--r--src/modules/extra/m_ssl_mbedtls.cpp1
-rw-r--r--src/modules/extra/m_ssl_openssl.cpp1
-rw-r--r--src/modules/m_blockcolor.cpp8
-rw-r--r--src/modules/m_conn_umodes.cpp22
-rw-r--r--src/modules/m_conn_waitpong.cpp2
-rw-r--r--src/modules/m_ldapoper.cpp6
-rw-r--r--src/modules/m_nationalchars.cpp8
-rw-r--r--src/modules/m_noctcp.cpp6
-rw-r--r--src/modules/m_nokicks.cpp6
-rw-r--r--src/modules/m_nonicks.cpp8
-rw-r--r--src/modules/m_nonotice.cpp20
-rw-r--r--src/modules/m_ojoin.cpp6
-rw-r--r--src/modules/m_spanningtree/fjoin.cpp9
-rw-r--r--src/modules/m_timedbans.cpp8
-rw-r--r--src/modules/m_uninvite.cpp5
-rw-r--r--src/modules/m_websocket.cpp77
18 files changed, 183 insertions, 123 deletions
diff --git a/src/modules/extra/m_mysql.cpp b/src/modules/extra/m_mysql.cpp
index 85bccc173..db5bfd018 100644
--- a/src/modules/extra/m_mysql.cpp
+++ b/src/modules/extra/m_mysql.cpp
@@ -83,24 +83,43 @@ class SQLConnection;
class MySQLresult;
class DispatcherThread;
-struct QQueueItem
+struct QueryQueueItem
{
- SQL::Query* q;
- std::string query;
- SQLConnection* c;
- QQueueItem(SQL::Query* Q, const std::string& S, SQLConnection* C) : q(Q), query(S), c(C) {}
+ // An SQL database which this query is executed on.
+ SQLConnection* connection;
+
+ // An object which handles the result of the query.
+ SQL::Query* query;
+
+ // The SQL query which is to be executed.
+ std::string querystr;
+
+ QueryQueueItem(SQL::Query* q, const std::string& s, SQLConnection* c)
+ : connection(c)
+ , query(q)
+ , querystr(s)
+ {
+ }
};
-struct RQueueItem
+struct ResultQueueItem
{
- SQL::Query* q;
- MySQLresult* r;
- RQueueItem(SQL::Query* Q, MySQLresult* R) : q(Q), r(R) {}
+ // An object which handles the result of the query.
+ SQL::Query* query;
+
+ // The result returned from executing the MySQL query.
+ MySQLresult* result;
+
+ ResultQueueItem(SQL::Query* q, MySQLresult* r)
+ : query(q)
+ , result(r)
+ {
+ }
};
typedef insp::flat_map<std::string, SQLConnection*> ConnMap;
-typedef std::deque<QQueueItem> QueryQueue;
-typedef std::deque<RQueueItem> ResultQueue;
+typedef std::deque<QueryQueueItem> QueryQueue;
+typedef std::deque<ResultQueueItem> ResultQueue;
/** MySQL module
* */
@@ -131,10 +150,6 @@ class DispatcherThread : public SocketThread
void OnNotify() override;
};
-#if !defined(MYSQL_VERSION_ID) || MYSQL_VERSION_ID<32224
-#define mysql_field_count mysql_num_fields
-#endif
-
/** Represents a mysql result set
*/
class MySQLresult : public SQL::Result
@@ -146,7 +161,10 @@ class MySQLresult : public SQL::Result
std::vector<std::string> colnames;
std::vector<SQL::Row> fieldlists;
- MySQLresult(MYSQL_RES* res, int affected_rows) : err(SQL::SUCCESS), currentrow(0), rows(0)
+ MySQLresult(MYSQL_RES* res, int affected_rows)
+ : err(SQL::SUCCESS)
+ , currentrow(0)
+ , rows(0)
{
if (affected_rows >= 1)
{
@@ -189,7 +207,10 @@ class MySQLresult : public SQL::Result
}
}
- MySQLresult(SQL::Error& e) : err(e)
+ MySQLresult(SQL::Error& e)
+ : err(e)
+ , currentrow(0)
+ , rows(0)
{
}
@@ -286,7 +307,7 @@ class SQLConnection : public SQL::Provider
~SQLConnection()
{
- Close();
+ mysql_close(connection);
}
// This method connects to the database using the credentials supplied to the constructor, and returns
@@ -365,21 +386,11 @@ class SQLConnection : public SQL::Provider
return true;
}
- std::string GetError()
- {
- return mysql_error(connection);
- }
-
- void Close()
- {
- mysql_close(connection);
- }
-
void Submit(SQL::Query* q, const std::string& qs) override
{
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "Executing MySQL query: " + qs);
Parent()->Dispatcher->LockQueue();
- Parent()->qq.push_back(QQueueItem(q, qs, this));
+ Parent()->qq.push_back(QueryQueueItem(q, qs, this));
Parent()->Dispatcher->UnlockQueueWakeup();
}
@@ -422,8 +433,8 @@ class SQLConnection : public SQL::Provider
};
ModuleSQL::ModuleSQL()
+ : Dispatcher(NULL)
{
- Dispatcher = NULL;
}
void ModuleSQL::init()
@@ -488,10 +499,10 @@ void ModuleSQL::ReadConfig(ConfigStatus& status)
for (size_t j = qq.size(); j > 0; j--)
{
size_t k = j - 1;
- if (qq[k].c == i->second)
+ if (qq[k].connection == i->second)
{
- qq[k].q->OnError(err);
- delete qq[k].q;
+ qq[k].query->OnError(err);
+ delete qq[k].query;
qq.erase(qq.begin() + k);
}
}
@@ -510,17 +521,16 @@ void ModuleSQL::OnUnloadModule(Module* mod)
while (i > 0)
{
i--;
- if (qq[i].q->creator == mod)
+ if (qq[i].query->creator == mod)
{
if (i == 0)
{
// need to wait until the query is done
// (the result will be discarded)
- qq[i].c->lock.lock();
- qq[i].c->lock.unlock();
+ qq[i].connection->lock.lock();
}
- qq[i].q->OnError(err);
- delete qq[i].q;
+ qq[i].query->OnError(err);
+ delete qq[i].query;
qq.erase(qq.begin() + i);
}
}
@@ -541,23 +551,23 @@ void DispatcherThread::OnStart()
{
if (!Parent->qq.empty())
{
- QQueueItem i = Parent->qq.front();
- i.c->lock.lock();
+ QueryQueueItem i = Parent->qq.front();
+ i.connection->lock.lock();
this->UnlockQueue();
- MySQLresult* res = i.c->DoBlockingQuery(i.query);
- i.c->lock.unlock();
+ MySQLresult* res = i.connection->DoBlockingQuery(i.querystr);
+ i.connection->lock.unlock();
/*
* At this point, the main thread could be working on:
- * Rehash - delete i.c out from under us. We don't care about that.
- * UnloadModule - delete i.q and the qq item. Need to avoid reporting results.
+ * Rehash - delete i.connection out from under us. We don't care about that.
+ * UnloadModule - delete i.query and the qq item. Need to avoid reporting results.
*/
this->LockQueue();
- if (!Parent->qq.empty() && Parent->qq.front().q == i.q)
+ if (!Parent->qq.empty() && Parent->qq.front().query == i.query)
{
Parent->qq.pop_front();
- Parent->rq.push_back(RQueueItem(i.q, res));
+ Parent->rq.push_back(ResultQueueItem(i.query, res));
NotifyParent();
}
else
@@ -583,13 +593,13 @@ void DispatcherThread::OnNotify()
this->LockQueue();
for(ResultQueue::iterator i = Parent->rq.begin(); i != Parent->rq.end(); i++)
{
- MySQLresult* res = i->r;
+ MySQLresult* res = i->result;
if (res->err.code == SQL::SUCCESS)
- i->q->OnResult(*res);
+ i->query->OnResult(*res);
else
- i->q->OnError(res->err);
- delete i->q;
- delete i->r;
+ i->query->OnError(res->err);
+ delete i->query;
+ delete i->result;
}
Parent->rq.clear();
this->UnlockQueue();
diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp
index 16bdb9a8d..29f1b414f 100644
--- a/src/modules/extra/m_ssl_gnutls.cpp
+++ b/src/modules/extra/m_ssl_gnutls.cpp
@@ -1199,6 +1199,7 @@ class ModuleSSLGnuTLS : public Module
try
{
ReadProfiles();
+ ServerInstance->SNO.WriteToSnoMask('a', "SSL module %s rehashed.", MODNAME);
}
catch (ModuleException& ex)
{
diff --git a/src/modules/extra/m_ssl_mbedtls.cpp b/src/modules/extra/m_ssl_mbedtls.cpp
index 8b5c720f2..6151a799c 100644
--- a/src/modules/extra/m_ssl_mbedtls.cpp
+++ b/src/modules/extra/m_ssl_mbedtls.cpp
@@ -932,6 +932,7 @@ class ModuleSSLmbedTLS : public Module
try
{
ReadProfiles();
+ ServerInstance->SNO.WriteToSnoMask('a', "SSL module %s rehashed.", MODNAME);
}
catch (ModuleException& ex)
{
diff --git a/src/modules/extra/m_ssl_openssl.cpp b/src/modules/extra/m_ssl_openssl.cpp
index 801b54b82..a54a0ef0e 100644
--- a/src/modules/extra/m_ssl_openssl.cpp
+++ b/src/modules/extra/m_ssl_openssl.cpp
@@ -986,6 +986,7 @@ class ModuleSSLOpenSSL : public Module
try
{
ReadProfiles();
+ ServerInstance->SNO.WriteToSnoMask('a', "SSL module %s rehashed.", MODNAME);
}
catch (ModuleException& ex)
{
diff --git a/src/modules/m_blockcolor.cpp b/src/modules/m_blockcolor.cpp
index d66cbc748..62b932b0a 100644
--- a/src/modules/m_blockcolor.cpp
+++ b/src/modules/m_blockcolor.cpp
@@ -46,19 +46,21 @@ class ModuleBlockColor : public Module
if ((target.type == MessageTarget::TYPE_CHANNEL) && (IS_LOCAL(user)))
{
Channel* c = target.Get<Channel>();
- ModResult res = CheckExemption::Call(exemptionprov, user, c, "blockcolor");
+ ModResult res = CheckExemption::Call(exemptionprov, user, c, "blockcolor");
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
- if (!c->GetExtBanStatus(user, 'c').check(!c->IsModeSet(bc)))
+ bool modeset = c->IsModeSet(bc);
+ if (!c->GetExtBanStatus(user, 'c').check(!modeset))
{
for (std::string::iterator i = details.text.begin(); i != details.text.end(); i++)
{
// Block all control codes except \001 for CTCP
if ((*i >= 0) && (*i < 32) && (*i != 1))
{
- user->WriteNumeric(ERR_CANNOTSENDTOCHAN, c->name, "Can't send colors to channel (+c is set)");
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, c->name, InspIRCd::Format("Can't send colors to channel (%s)",
+ modeset ? "+c is set" : "you're extbanned"));
return MOD_RES_DENY;
}
}
diff --git a/src/modules/m_conn_umodes.cpp b/src/modules/m_conn_umodes.cpp
index 49d56acc0..705fa732d 100644
--- a/src/modules/m_conn_umodes.cpp
+++ b/src/modules/m_conn_umodes.cpp
@@ -32,22 +32,18 @@ class ModuleModesOnConnect : public Module
void OnUserConnect(LocalUser* user) override
{
- ConfigTag* tag = user->MyClass->config;
- std::string ThisModes = tag->getString("modes");
- if (!ThisModes.empty())
- {
- std::string buf;
- irc::spacesepstream ss(ThisModes);
+ const std::string modestr = user->MyClass->config->getString("modes");
+ if (modestr.empty())
+ return;
- CommandBase::Params modes;
- modes.push_back(user->nick);
+ CommandBase::Params params;
+ params.push_back(user->nick);
- // split ThisUserModes into modes and mode params
- while (ss.GetToken(buf))
- modes.push_back(buf);
+ irc::spacesepstream modestream(modestr);
+ for (std::string modetoken; modestream.GetToken(modetoken); )
+ params.push_back(modetoken);
- ServerInstance->Parser.CallHandler("MODE", modes, user);
- }
+ ServerInstance->Parser.CallHandler("MODE", params, user);
}
};
diff --git a/src/modules/m_conn_waitpong.cpp b/src/modules/m_conn_waitpong.cpp
index fdf935ba3..6b22812aa 100644
--- a/src/modules/m_conn_waitpong.cpp
+++ b/src/modules/m_conn_waitpong.cpp
@@ -39,7 +39,7 @@ class ModuleWaitPong : public Module
void ReadConfig(ConfigStatus& status) override
{
ConfigTag* tag = ServerInstance->Config->ConfValue("waitpong");
- sendsnotice = tag->getBool("sendsnotice", true);
+ sendsnotice = tag->getBool("sendsnotice", false);
killonbadreply = tag->getBool("killonbadreply", true);
}
diff --git a/src/modules/m_ldapoper.cpp b/src/modules/m_ldapoper.cpp
index 360c4b2f7..76d2af57c 100644
--- a/src/modules/m_ldapoper.cpp
+++ b/src/modules/m_ldapoper.cpp
@@ -180,14 +180,14 @@ class AdminBindInterface : public LDAPInterface
}
};
-class ModuleLDAPAuth : public Module
+class ModuleLDAPOper : public Module
{
dynamic_reference<LDAPProvider> LDAP;
std::string base;
std::string attribute;
public:
- ModuleLDAPAuth()
+ ModuleLDAPOper()
: LDAP(this, "LDAP")
{
me = this;
@@ -246,4 +246,4 @@ class ModuleLDAPAuth : public Module
}
};
-MODULE_INIT(ModuleLDAPAuth)
+MODULE_INIT(ModuleLDAPOper)
diff --git a/src/modules/m_nationalchars.cpp b/src/modules/m_nationalchars.cpp
index 884efed23..82cac8358 100644
--- a/src/modules/m_nationalchars.cpp
+++ b/src/modules/m_nationalchars.cpp
@@ -222,6 +222,7 @@ class ModuleNationalChars : public Module
std::function<bool(const std::string&)> rememberer;
bool forcequit;
const unsigned char * lowermap_rememberer;
+ std::string casemapping_rememberer;
unsigned char prev_map[256];
template <typename T>
@@ -248,7 +249,9 @@ class ModuleNationalChars : public Module
public:
ModuleNationalChars()
- : rememberer(ServerInstance->IsNick), lowermap_rememberer(national_case_insensitive_map)
+ : rememberer(ServerInstance->IsNick)
+ , lowermap_rememberer(national_case_insensitive_map)
+ , casemapping_rememberer(ServerInstance->Config->CaseMapping)
{
memcpy(prev_map, national_case_insensitive_map, sizeof(prev_map));
}
@@ -305,6 +308,9 @@ class ModuleNationalChars : public Module
{
ServerInstance->IsNick = rememberer;
national_case_insensitive_map = lowermap_rememberer;
+ ServerInstance->Config->CaseMapping = casemapping_rememberer;
+ // The core rebuilds ISupport on module unload, but before the dtor.
+ ServerInstance->ISupport.Build();
CheckForceQuit("National characters module unloaded");
CheckRehash();
}
diff --git a/src/modules/m_noctcp.cpp b/src/modules/m_noctcp.cpp
index ba9babdcf..cc9017f36 100644
--- a/src/modules/m_noctcp.cpp
+++ b/src/modules/m_noctcp.cpp
@@ -70,9 +70,11 @@ class ModuleNoCTCP : public Module
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
- if (!c->GetExtBanStatus(user, 'C').check(!c->IsModeSet(nc)))
+ bool modeset = c->IsModeSet(nc);
+ if (!c->GetExtBanStatus(user, 'C').check(!modeset))
{
- user->WriteNumeric(ERR_CANNOTSENDTOCHAN, c->name, "Can't send CTCP to channel (+C is set)");
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, c->name, InspIRCd::Format("Can't send CTCP to channel (%s)",
+ modeset ? "+C is set" : "you're extbanned"));
return MOD_RES_DENY;
}
break;
diff --git a/src/modules/m_nokicks.cpp b/src/modules/m_nokicks.cpp
index ff113db35..14402e6d7 100644
--- a/src/modules/m_nokicks.cpp
+++ b/src/modules/m_nokicks.cpp
@@ -39,10 +39,12 @@ class ModuleNoKicks : public Module
ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason) override
{
- if (!memb->chan->GetExtBanStatus(source, 'Q').check(!memb->chan->IsModeSet(nk)))
+ bool modeset = memb->chan->IsModeSet(nk);
+ if (!memb->chan->GetExtBanStatus(source, 'Q').check(!modeset))
{
// Can't kick with Q in place, not even opers with override, and founders
- source->WriteNumeric(ERR_CHANOPRIVSNEEDED, memb->chan->name, InspIRCd::Format("Can't kick user %s from channel (+Q is set)", memb->user->nick.c_str()));
+ source->WriteNumeric(ERR_CHANOPRIVSNEEDED, memb->chan->name, InspIRCd::Format("Can't kick user %s from channel (%s)",
+ memb->user->nick.c_str(), modeset ? "+Q is set" : "you're extbanned"));
return MOD_RES_DENY;
}
return MOD_RES_PASSTHRU;
diff --git a/src/modules/m_nonicks.cpp b/src/modules/m_nonicks.cpp
index 194c326d7..f0efd771a 100644
--- a/src/modules/m_nonicks.cpp
+++ b/src/modules/m_nonicks.cpp
@@ -50,17 +50,17 @@ class ModuleNoNickChange : public Module
Channel* curr = (*i)->chan;
ModResult res = CheckExemption::Call(exemptionprov, user, curr, "nonick");
-
if (res == MOD_RES_ALLOW)
continue;
if (user->HasPrivPermission("channels/ignore-nonicks"))
continue;
- if (!curr->GetExtBanStatus(user, 'N').check(!curr->IsModeSet(nn)))
+ bool modeset = curr->IsModeSet(nn);
+ if (!curr->GetExtBanStatus(user, 'N').check(!modeset))
{
- user->WriteNumeric(ERR_CANTCHANGENICK, InspIRCd::Format("Cannot change nickname while on %s (+N is set)",
- curr->name.c_str()));
+ user->WriteNumeric(ERR_CANTCHANGENICK, InspIRCd::Format("Can't change nickname while on %s (%s)",
+ curr->name.c_str(), modeset ? "+N is set" : "you're extbanned"));
return MOD_RES_DENY;
}
}
diff --git a/src/modules/m_nonotice.cpp b/src/modules/m_nonotice.cpp
index 92d0f4482..450e476bf 100644
--- a/src/modules/m_nonotice.cpp
+++ b/src/modules/m_nonotice.cpp
@@ -41,20 +41,20 @@ class ModuleNoNotice : public Module
ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) override
{
- ModResult res;
if ((details.type == MSG_NOTICE) && (target.type == MessageTarget::TYPE_CHANNEL) && (IS_LOCAL(user)))
{
Channel* c = target.Get<Channel>();
- if (!c->GetExtBanStatus(user, 'T').check(!c->IsModeSet(nt)))
+
+ ModResult res = CheckExemption::Call(exemptionprov, user, c, "nonotice");
+ if (res == MOD_RES_ALLOW)
+ return MOD_RES_PASSTHRU;
+
+ bool modeset = c->IsModeSet(nt);
+ if (!c->GetExtBanStatus(user, 'T').check(!modeset))
{
- res = CheckExemption::Call(exemptionprov, user, c, "nonotice");
- if (res == MOD_RES_ALLOW)
- return MOD_RES_PASSTHRU;
- else
- {
- user->WriteNumeric(ERR_CANNOTSENDTOCHAN, c->name, "Can't send NOTICE to channel (+T is set)");
- return MOD_RES_DENY;
- }
+ user->WriteNumeric(ERR_CANNOTSENDTOCHAN, c->name, InspIRCd::Format("Can't send NOTICE to channel (%s)",
+ modeset ? "+T is set" : "you're extbanned"));
+ return MOD_RES_DENY;
}
}
return MOD_RES_PASSTHRU;
diff --git a/src/modules/m_ojoin.cpp b/src/modules/m_ojoin.cpp
index 77faf5065..91431d642 100644
--- a/src/modules/m_ojoin.cpp
+++ b/src/modules/m_ojoin.cpp
@@ -57,11 +57,7 @@ class CommandOjoin : public SplitCommand
ServerInstance->SNO.WriteGlobalSno('a', user->nick+" used OJOIN to join "+channel->name);
if (notice)
- {
- const std::string msg = user->nick + " joined on official network business.";
- channel->WriteNotice(msg);
- ServerInstance->PI->SendChannelNotice(channel, 0, msg);
- }
+ channel->WriteNotice(user->nick + " joined on official network business.");
}
else
{
diff --git a/src/modules/m_spanningtree/fjoin.cpp b/src/modules/m_spanningtree/fjoin.cpp
index 62a51faba..258d8ee4c 100644
--- a/src/modules/m_spanningtree/fjoin.cpp
+++ b/src/modules/m_spanningtree/fjoin.cpp
@@ -276,8 +276,13 @@ void CommandFJoin::RemoveStatus(Channel* c)
void CommandFJoin::LowerTS(Channel* chan, time_t TS, const std::string& newname)
{
if (Utils->AnnounceTSChange)
- chan->WriteNotice(InspIRCd::Format("Creation time of %s changed from %s to %s", newname.c_str(),
- InspIRCd::TimeString(chan->age).c_str(), InspIRCd::TimeString(TS).c_str()));
+ {
+ // WriteNotice is not used here because the message only needs to go to the local server.
+ const std::string tsmessage = InspIRCd::Format("Creation time of %s changed from %s to %s", newname.c_str(),
+ InspIRCd::TimeString(chan->age).c_str(), InspIRCd::TimeString(TS).c_str());
+ ClientProtocol::Messages::Privmsg privmsg(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, chan, tsmessage, MSG_NOTICE);
+ chan->Write(ServerInstance->GetRFCEvents().privmsg, privmsg);
+ }
// While the name is equal in case-insensitive compare, it might differ in case; use the remote version
chan->name = newname;
diff --git a/src/modules/m_timedbans.cpp b/src/modules/m_timedbans.cpp
index edc2e2946..a1b4ac3e7 100644
--- a/src/modules/m_timedbans.cpp
+++ b/src/modules/m_timedbans.cpp
@@ -128,9 +128,7 @@ class CommandTban : public Command
PrefixMode* mh = ServerInstance->Modes.FindPrefixMode('h');
char pfxchar = (mh && mh->name == "halfop") ? mh->GetPrefix() : '@';
- ClientProtocol::Messages::Privmsg notice(ServerInstance->FakeClient, channel, message, MSG_NOTICE);
- channel->Write(ServerInstance->GetRFCEvents().privmsg, notice, pfxchar);
- ServerInstance->PI->SendChannelNotice(channel, pfxchar, message);
+ channel->WriteNotice(message, pfxchar);
return CMD_SUCCESS;
}
@@ -221,9 +219,7 @@ class ModuleTimedBans : public Module
PrefixMode* mh = ServerInstance->Modes.FindPrefixMode('h');
char pfxchar = (mh && mh->name == "halfop") ? mh->GetPrefix() : '@';
- ClientProtocol::Messages::Privmsg notice(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, cr, message, MSG_NOTICE);
- cr->Write(ServerInstance->GetRFCEvents().privmsg, notice, pfxchar);
- ServerInstance->PI->SendChannelNotice(cr, pfxchar, message);
+ cr->WriteNotice(message, pfxchar);
Modes::ChangeList setban;
setban.push_remove(ServerInstance->Modes.FindMode('b', MODETYPE_CHANNEL), mask);
diff --git a/src/modules/m_uninvite.cpp b/src/modules/m_uninvite.cpp
index 5d4fb07a5..d0751dc56 100644
--- a/src/modules/m_uninvite.cpp
+++ b/src/modules/m_uninvite.cpp
@@ -100,10 +100,7 @@ class CommandUninvite : public Command
user->WriteRemoteNumeric(n);
lu->WriteNumeric(RPL_UNINVITED, InspIRCd::Format("You were uninvited from %s by %s", c->name.c_str(), user->nick.c_str()));
-
- std::string msg = "*** " + user->nick + " uninvited " + u->nick + ".";
- c->WriteNotice(msg);
- ServerInstance->PI->SendChannelNotice(c, 0, msg);
+ c->WriteNotice(InspIRCd::Format("*** %s uninvited %s.", user->nick.c_str(), u->nick.c_str()));
}
return CMD_SUCCESS;
diff --git a/src/modules/m_websocket.cpp b/src/modules/m_websocket.cpp
index fece5fdb1..69e01914b 100644
--- a/src/modules/m_websocket.cpp
+++ b/src/modules/m_websocket.cpp
@@ -25,18 +25,29 @@
#include <utf8.h>
-typedef std::vector<std::string> OriginList;
-
static const char MagicGUID[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
static const char whitespace[] = " \t\r\n";
static dynamic_reference_nocheck<HashProvider>* sha1;
-class WebSocketHookProvider : public IOHookProvider
+struct WebSocketConfig
{
- public:
+ typedef std::vector<std::string> OriginList;
+ typedef std::vector<std::string> ProxyRanges;
+
+ // The HTTP origins that can connect to the server.
OriginList allowedorigins;
+
+ // The IP ranges which send trustworthy X-Real-IP or X-Forwarded-For headers.
+ ProxyRanges proxyranges;
+
+ // Whether to send as UTF-8 text instead of binary data.
bool sendastext;
+};
+class WebSocketHookProvider : public IOHookProvider
+{
+ public:
+ WebSocketConfig config;
WebSocketHookProvider(Module* mod)
: IOHookProvider(mod, "websocket", IOHookProvider::IOH_UNKNOWN, true)
{
@@ -110,8 +121,7 @@ class WebSocketHook : public IOHookMiddle
State state;
time_t lastpingpong;
- OriginList& allowedorigins;
- bool& sendastext;
+ WebSocketConfig& config;
static size_t FillHeader(unsigned char* outbuf, size_t sendlength, OpCode opcode)
{
@@ -318,7 +328,7 @@ class WebSocketHook : public IOHookMiddle
if (originheader.Find(recvq, "Origin:", 7, reqend))
{
const std::string origin = originheader.ExtractValue(recvq);
- for (OriginList::const_iterator iter = allowedorigins.begin(); iter != allowedorigins.end(); ++iter)
+ for (WebSocketConfig::OriginList::const_iterator iter = config.allowedorigins.begin(); iter != config.allowedorigins.end(); ++iter)
{
if (InspIRCd::Match(origin, *iter, ascii_case_insensitive_map))
{
@@ -334,6 +344,36 @@ class WebSocketHook : public IOHookMiddle
return -1;
}
+ if (!config.proxyranges.empty() && sock->type == StreamSocket::SS_USER)
+ {
+ LocalUser* luser = static_cast<UserIOHandler*>(sock)->user;
+ irc::sockets::sockaddrs realsa(luser->client_sa);
+
+ HTTPHeaderFinder proxyheader;
+ if (proxyheader.Find(recvq, "X-Real-IP:", 10, reqend)
+ && irc::sockets::aptosa(proxyheader.ExtractValue(recvq), realsa.port(), realsa))
+ {
+ // Nothing to do here.
+ }
+ else if (proxyheader.Find(recvq, "X-Forwarded-For:", 16, reqend)
+ && irc::sockets::aptosa(proxyheader.ExtractValue(recvq), realsa.port(), realsa))
+ {
+ // Nothing to do here.
+ }
+
+ for (WebSocketConfig::ProxyRanges::const_iterator iter = config.proxyranges.begin(); iter != config.proxyranges.end(); ++iter)
+ {
+ if (InspIRCd::MatchCIDR(luser->GetIPString(), *iter, ascii_case_insensitive_map))
+ {
+ // Give the user their real IP address.
+ if (realsa != luser->client_sa)
+ luser->SetClientIP(realsa);
+ break;
+ }
+ }
+ }
+
+
HTTPHeaderFinder keyheader;
if (!keyheader.Find(recvq, "Sec-WebSocket-Key:", 18, reqend))
{
@@ -364,12 +404,11 @@ class WebSocketHook : public IOHookMiddle
}
public:
- WebSocketHook(IOHookProvider* Prov, StreamSocket* sock, OriginList& AllowedOrigins, bool& SendAsText)
+ WebSocketHook(IOHookProvider* Prov, StreamSocket* sock, WebSocketConfig& cfg)
: IOHookMiddle(Prov)
, state(STATE_HTTPREQ)
, lastpingpong(0)
- , allowedorigins(AllowedOrigins)
- , sendastext(SendAsText)
+ , config(cfg)
{
sock->AddIOHook(this);
}
@@ -390,7 +429,7 @@ class WebSocketHook : public IOHookMiddle
if (*chr == '\n')
{
// We have found an entire message. Send it in its own frame.
- if (sendastext)
+ if (config.sendastext)
{
// If we send messages as text then we need to ensure they are valid UTF-8.
std::string encoded;
@@ -451,7 +490,7 @@ class WebSocketHook : public IOHookMiddle
void WebSocketHookProvider::OnAccept(StreamSocket* sock, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server)
{
- new WebSocketHook(this, sock, allowedorigins, sendastext);
+ new WebSocketHook(this, sock, config);
}
class ModuleWebSocket : public Module
@@ -473,7 +512,7 @@ class ModuleWebSocket : public Module
if (tags.first == tags.second)
throw ModuleException("You have loaded the websocket module but not configured any allowed origins!");
- OriginList allowedorigins;
+ WebSocketConfig config;
for (ConfigIter i = tags.first; i != tags.second; ++i)
{
ConfigTag* tag = i->second;
@@ -483,12 +522,18 @@ class ModuleWebSocket : public Module
if (allow.empty())
throw ModuleException("<wsorigin:allow> is a mandatory field, at " + tag->getTagLocation());
- allowedorigins.push_back(allow);
+ config.allowedorigins.push_back(allow);
}
ConfigTag* tag = ServerInstance->Config->ConfValue("websocket");
- hookprov->sendastext = tag->getBool("sendastext", true);
- hookprov->allowedorigins.swap(allowedorigins);
+ config.sendastext = tag->getBool("sendastext", true);
+
+ irc::spacesepstream proxyranges(tag->getString("proxyranges"));
+ for (std::string proxyrange; proxyranges.GetToken(proxyrange); )
+ config.proxyranges.push_back(proxyrange);
+
+ // Everything is okay; apply the new config.
+ hookprov->config = config;
}
void OnCleanup(ExtensionItem::ExtensibleType type, Extensible* item) override