From 157d9445f53ff63cfabf19d5f16ebdf84e6e0454 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Mon, 1 Apr 2013 16:32:01 +0200 Subject: cmd_invite Check if the inviting user is on the channel before potentially telling him the target is already on it --- src/commands/cmd_invite.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/commands/cmd_invite.cpp b/src/commands/cmd_invite.cpp index fd595d618..c69e6bd1b 100644 --- a/src/commands/cmd_invite.cpp +++ b/src/commands/cmd_invite.cpp @@ -72,16 +72,16 @@ CmdResult CommandInvite::Handle (const std::vector& parameters, Use return CMD_FAILURE; } - if (c->HasUser(u)) - { - user->WriteNumeric(ERR_USERONCHANNEL, "%s %s %s :is already on channel",user->nick.c_str(),u->nick.c_str(),c->name.c_str()); - return CMD_FAILURE; - } - if ((IS_LOCAL(user)) && (!c->HasUser(user))) - { + { user->WriteNumeric(ERR_NOTONCHANNEL, "%s %s :You're not on that channel!",user->nick.c_str(), c->name.c_str()); - return CMD_FAILURE; + return CMD_FAILURE; + } + + if (c->HasUser(u)) + { + user->WriteNumeric(ERR_USERONCHANNEL, "%s %s %s :is already on channel",user->nick.c_str(),u->nick.c_str(),c->name.c_str()); + return CMD_FAILURE; } FIRST_MOD_RESULT(OnUserPreInvite, MOD_RESULT, (user,u,c,timeout)); -- cgit v1.3.1-10-gc9f91 From 153bd37b598373f4f52024747ee3bc2cbb76f629 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Mon, 1 Apr 2013 16:42:04 +0200 Subject: cmd_stats List opers without iterating the whole userlist --- src/commands/cmd_stats.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/commands/cmd_stats.cpp b/src/commands/cmd_stats.cpp index 9a5bfc52d..898e89a7d 100644 --- a/src/commands/cmd_stats.cpp +++ b/src/commands/cmd_stats.cpp @@ -161,13 +161,14 @@ void CommandStats::DoStats(char statschar, User* user, string_list &results) case 'P': { - int idx = 0; - for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++) + unsigned int idx = 0; + for (std::list::const_iterator i = ServerInstance->Users->all_opers.begin(); i != ServerInstance->Users->all_opers.end(); ++i) { - if (IS_OPER(i->second) && !ServerInstance->ULine(i->second->server)) + User* oper = *i; + if (!ServerInstance->ULine(oper->server)) { - results.push_back(sn+" 249 "+user->nick+" :"+i->second->nick+" ("+i->second->ident+"@"+i->second->dhost+") Idle: "+ - (IS_LOCAL(i->second) ? ConvToStr(ServerInstance->Time() - i->second->idle_lastmsg) + " secs" : "unavailable")); + results.push_back(sn+" 249 " + user->nick + " :" + oper->nick + " (" + oper->ident + "@" + oper->dhost + ") Idle: " + + (IS_LOCAL(oper) ? ConvToStr(ServerInstance->Time() - oper->idle_lastmsg) + " secs" : "unavailable")); idx++; } } -- cgit v1.3.1-10-gc9f91 From 08a566b5d7f4a9c1bafd4bf74d2a05ed8010d6b6 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Fri, 5 Apr 2013 18:21:16 +0200 Subject: Fix LUSERS not working in a PURE_STATIC build --- src/modmanager_static.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modmanager_static.cpp b/src/modmanager_static.cpp index 69420a4f9..d2a2f2c09 100644 --- a/src/modmanager_static.cpp +++ b/src/modmanager_static.cpp @@ -183,6 +183,7 @@ void ModuleManager::LoadAll() { Load("cmd_all", true); Load("cmd_whowas.so", true); + Load("cmd_lusers.so", true); ConfigTagList tags = ServerInstance->Config->ConfTags("module"); for(ConfigIter i = tags.first; i != tags.second; ++i) -- cgit v1.3.1-10-gc9f91 From 0fa365373eb9110a05ee4be5c36c9757c30f1a25 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Fri, 5 Apr 2013 18:23:44 +0200 Subject: Don't attempt to unload or reload modules that are waiting to be unloaded --- include/modules.h | 7 ++++++- src/modmanager_dynamic.cpp | 1 + src/modmanager_static.cpp | 1 + src/modules.cpp | 4 +++- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/modules.h b/include/modules.h index e450233da..8aedaabdd 100644 --- a/include/modules.h +++ b/include/modules.h @@ -116,7 +116,7 @@ struct ModResult { * and numerical comparisons in preprocessor macros if they wish to support * multiple versions of InspIRCd in one file. */ -#define INSPIRCD_VERSION_API 4 +#define INSPIRCD_VERSION_API 5 /** * This #define allows us to call a method in all @@ -357,6 +357,11 @@ class CoreExport Module : public classbase, public usecountbase */ DLLManager* ModuleDLLManager; + /** If true, this module will be unloaded soon, further unload attempts will fail + * Value is used by the ModuleManager internally, you should not modify it + */ + bool dying; + /** Default constructor. * Creates a module class. Don't do any type of hook registration or checks * for other modules here; do that in init(). diff --git a/src/modmanager_dynamic.cpp b/src/modmanager_dynamic.cpp index dab1143ad..7dae49a18 100644 --- a/src/modmanager_dynamic.cpp +++ b/src/modmanager_dynamic.cpp @@ -66,6 +66,7 @@ bool ModuleManager::Load(const std::string& filename, bool defer) { newmod->ModuleSourceFile = filename; newmod->ModuleDLLManager = newhandle; + newmod->dying = false; Modules[filename] = newmod; std::string version = newhandle->GetVersion(); if (defer) diff --git a/src/modmanager_static.cpp b/src/modmanager_static.cpp index d2a2f2c09..8f532ee80 100644 --- a/src/modmanager_static.cpp +++ b/src/modmanager_static.cpp @@ -93,6 +93,7 @@ bool ModuleManager::Load(const std::string& name, bool defer) mod = (*it->second->init)(); mod->ModuleSourceFile = name; mod->ModuleDLLManager = NULL; + mod->dying = false; Modules[name] = mod; if (defer) { diff --git a/src/modules.cpp b/src/modules.cpp index 4e4d20c70..a7b3364ae 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -328,7 +328,7 @@ bool ModuleManager::CanUnload(Module* mod) { std::map::iterator modfind = Modules.find(mod->ModuleSourceFile); - if (modfind == Modules.end() || modfind->second != mod) + if ((modfind == Modules.end()) || (modfind->second != mod) || (mod->dying)) { LastModuleError = "Module " + mod->ModuleSourceFile + " is not loaded, cannot unload it!"; ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); @@ -340,6 +340,8 @@ bool ModuleManager::CanUnload(Module* mod) ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); return false; } + + mod->dying = true; return true; } -- cgit v1.3.1-10-gc9f91 From ac705cd20e12f46bd638093f000dfd541ffc5d22 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Tue, 9 Apr 2013 18:57:05 +0200 Subject: Remove some uline checks that ran after an IS_LOCAL() check --- src/modules/m_nonotice.cpp | 5 ----- src/modules/m_services_account.cpp | 16 ++-------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/modules/m_nonotice.cpp b/src/modules/m_nonotice.cpp index d95ea8b8a..c5b9f3a1c 100644 --- a/src/modules/m_nonotice.cpp +++ b/src/modules/m_nonotice.cpp @@ -59,11 +59,6 @@ class ModuleNoNotice : public Module Channel* c = (Channel*)dest; if (!c->GetExtBanStatus(user, 'T').check(!c->IsModeSet('T'))) { - if (ServerInstance->ULine(user->server)) - { - // ulines are exempt. - return MOD_RES_PASSTHRU; - } res = ServerInstance->OnCheckExemption(user,c,"nonotice"); if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; diff --git a/src/modules/m_services_account.cpp b/src/modules/m_services_account.cpp index 50e2c76a6..cb3f089c6 100644 --- a/src/modules/m_services_account.cpp +++ b/src/modules/m_services_account.cpp @@ -37,7 +37,7 @@ class Channel_r : public ModeHandler ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { // only a u-lined server may add or remove the +r mode. - if (!IS_LOCAL(source) || ServerInstance->ULine(source->server)) + if (!IS_LOCAL(source)) { // Only change the mode if it's not redundant if ((adding != channel->IsModeSet('r'))) @@ -64,7 +64,7 @@ class User_r : public ModeHandler ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { - if (!IS_LOCAL(source) || ServerInstance->ULine(source->server)) + if (!IS_LOCAL(source)) { if ((adding != dest->IsModeSet('r'))) { @@ -171,12 +171,6 @@ class ModuleServicesAccount : public Module std::string *account = accountname.get(user); bool is_registered = account && !account->empty(); - if ((ServerInstance->ULine(user->nick.c_str())) || (ServerInstance->ULine(user->server))) - { - // user is ulined, can speak regardless - return MOD_RES_PASSTHRU; - } - if (target_type == TYPE_CHANNEL) { Channel* c = (Channel*)dest; @@ -255,12 +249,6 @@ class ModuleServicesAccount : public Module if (chan) { - if ((ServerInstance->ULine(user->nick.c_str())) || (ServerInstance->ULine(user->server))) - { - // user is ulined, won't be stopped from joining - return MOD_RES_PASSTHRU; - } - if (chan->IsModeSet('R')) { if (!is_registered) -- cgit v1.3.1-10-gc9f91 From 65072d44f23804d85dd800c5ce6aa3548831142e Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Wed, 10 Apr 2013 17:05:13 +0200 Subject: m_spanningtree Create new TreeServers for incoming connections only when they've accepted our credentials, not when they send SERVER --- src/modules/m_spanningtree/server.cpp | 62 ++++++++++++++++++------------ src/modules/m_spanningtree/treesocket.h | 11 ++++++ src/modules/m_spanningtree/treesocket2.cpp | 12 ++++++ 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/src/modules/m_spanningtree/server.cpp b/src/modules/m_spanningtree/server.cpp index 33c7f47b3..a04454f51 100644 --- a/src/modules/m_spanningtree/server.cpp +++ b/src/modules/m_spanningtree/server.cpp @@ -180,6 +180,33 @@ bool TreeSocket::Outbound_Reply_Server(parameterlist ¶ms) return false; } +bool TreeSocket::CheckDuplicate(const std::string& sname, const std::string& sid) +{ + /* Check for fully initialized instances of the server by name */ + TreeServer* CheckDupe = Utils->FindServer(sname); + if (CheckDupe) + { + std::string pname = CheckDupe->GetParent() ? CheckDupe->GetParent()->GetName() : ""; + SendError("Server "+sname+" already exists on server "+pname+"!"); + ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+pname); + return false; + } + + /* Check for fully initialized instances of the server by id */ + ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Looking for dupe SID %s", sid.c_str()); + CheckDupe = Utils->FindServerID(sid); + + if (CheckDupe) + { + this->SendError("Server ID "+CheckDupe->GetID()+" already exists on server "+CheckDupe->GetName()+"! You may want to specify the server ID for the server manually with so they do not conflict."); + ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server ID '"+CheckDupe->GetID()+ + "' already exists on server "+CheckDupe->GetName()); + return false; + } + + return true; +} + /* * Someone else is attempting to connect to us if this is called. Validate their credentials etc. * -- w @@ -226,39 +253,24 @@ bool TreeSocket::Inbound_Server(parameterlist ¶ms) continue; } - /* Now check for fully initialized ServerInstances of the server by name */ - TreeServer* CheckDupe = Utils->FindServer(sname); - if (CheckDupe) - { - std::string pname = CheckDupe->GetParent() ? CheckDupe->GetParent()->GetName() : ""; - SendError("Server "+sname+" already exists on server "+pname+"!"); - ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+pname); + if (!CheckDuplicate(sname, sid)) return false; - } - /* Check for fully initialized instances of the server by id */ - ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Looking for dupe SID %s", sid.c_str()); - CheckDupe = Utils->FindServerID(sid); + ServerInstance->SNO->WriteToSnoMask('l',"Verified incoming server connection " + linkID + " ("+description+")"); - if (CheckDupe) - { - this->SendError("Server ID "+CheckDupe->GetID()+" already exists on server "+CheckDupe->GetName()+"! You may want to specify the server ID for the server manually with so they do not conflict."); - ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server ID '"+CheckDupe->GetID()+ - "' already exists on server "+CheckDupe->GetName()); - return false; - } + this->SendCapabilities(2); - ServerInstance->SNO->WriteToSnoMask('l',"Verified incoming server connection " + linkID + " ("+description+")"); - linkID = sname; + // Save these for later, so when they accept our credentials (indicated by BURST) we remember them + this->capab->hidden = x->Hidden; + this->capab->sid = sid; + this->capab->description = description; + this->capab->name = sname; - // this is good. Send our details: Our server name and description and hopcount of 0, + // Send our details: Our server name and description and hopcount of 0, // along with the sendpass from this block. - this->SendCapabilities(2); this->WriteLine("SERVER "+ServerInstance->Config->ServerName+" "+this->MakePass(x->SendPass, this->GetTheirChallenge())+" 0 "+ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc); - // move to the next state, we are now waiting for THEM. - MyRoot = new TreeServer(Utils, sname, description, sid, Utils->TreeRoot, this, x->Hidden); - Utils->TreeRoot->AddChild(MyRoot); + // move to the next state, we are now waiting for THEM. this->LinkState = WAIT_AUTH_2; return true; } diff --git a/src/modules/m_spanningtree/treesocket.h b/src/modules/m_spanningtree/treesocket.h index c1ca5e74a..d8445572b 100644 --- a/src/modules/m_spanningtree/treesocket.h +++ b/src/modules/m_spanningtree/treesocket.h @@ -78,6 +78,12 @@ struct CapabData int capab_phase; /* Have sent CAPAB already */ bool auth_fingerprint; /* Did we auth using SSL fingerprint */ bool auth_challenge; /* Did we auth using challenge/response */ + + // Data saved from incoming SERVER command, for later use when our credentials have been accepted by the other party + std::string description; + std::string sid; + std::string name; + bool hidden; }; /** Every SERVER connection inbound or outbound is represented by an object of @@ -95,6 +101,11 @@ class TreeSocket : public BufferedSocket bool LastPingWasGood; /* Responded to last ping we sent? */ int proto_version; /* Remote protocol version */ bool ConnectionFailureShown; /* Set to true if a connection failure message was shown */ + + /** Checks if the given servername and sid are both free + */ + bool CheckDuplicate(const std::string& servername, const std::string& sid); + public: time_t age; diff --git a/src/modules/m_spanningtree/treesocket2.cpp b/src/modules/m_spanningtree/treesocket2.cpp index 04ca9edb1..5007fe921 100644 --- a/src/modules/m_spanningtree/treesocket2.cpp +++ b/src/modules/m_spanningtree/treesocket2.cpp @@ -164,9 +164,21 @@ void TreeSocket::ProcessLine(std::string &line) ServerInstance->SNO->WriteGlobalSno('l',"\2WARNING\2: Your clocks are out by %d seconds. Please consider synching your clocks.", abs((long)delta)); } } + + // Check for duplicate server name/sid again, it's possible that a new + // server was introduced while we were waiting for them to send BURST. + // (we do not reserve their server name/sid when they send SERVER, we do it now) + if (!CheckDuplicate(capab->name, capab->sid)) + return; + this->LinkState = CONNECTED; Utils->timeoutlist.erase(this); + linkID = capab->name; + + MyRoot = new TreeServer(Utils, capab->name, capab->description, capab->sid, Utils->TreeRoot, this, capab->hidden); + Utils->TreeRoot->AddChild(MyRoot); + MyRoot->bursting = true; this->DoBurst(MyRoot); -- cgit v1.3.1-10-gc9f91 From ac8a394a5c01d8cecd6d1fd364173825ecb452ae Mon Sep 17 00:00:00 2001 From: Peter Powell Date: Wed, 10 Apr 2013 06:06:53 +0100 Subject: Fix ModuleManager error caused by a lack of arguments. --- modulemanager | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modulemanager b/modulemanager index d1212faf5..7884654af 100755 --- a/modulemanager +++ b/modulemanager @@ -262,7 +262,7 @@ sub resolve_deps { } } -my $action = lc shift @ARGV; +my $action = $#ARGV > 0 ? lc shift @ARGV : 'help'; if ($action eq 'install') { for my $mod (@ARGV) { -- cgit v1.3.1-10-gc9f91 From dbc6dc90283220c06b4f4946cf0a131d2f965884 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Tue, 16 Apr 2013 00:20:01 +0200 Subject: Do not enable SO_LINGER on our sockets Using this option allowed close() to block for up to a second Thanks to Shamsdeen and Rix for their assistance that made this fix possible Fixes issue #445 reported by @shaggie76 Fixes issue #494 reported by @Rixcho --- src/socketengine.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/socketengine.cpp b/src/socketengine.cpp index 27abd0ad6..6c99edc95 100644 --- a/src/socketengine.cpp +++ b/src/socketengine.cpp @@ -166,12 +166,7 @@ int SocketEngine::NonBlocking(int fd) void SocketEngine::SetReuse(int fd) { int on = 1; - struct linger linger = { 0, 0 }; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)); - /* This is BSD compatible, setting l_onoff to 0 is *NOT* http://web.irc.org/mla/ircd-dev/msg02259.html */ - linger.l_onoff = 1; - linger.l_linger = 1; - setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(linger)); } int SocketEngine::RecvFrom(EventHandler* fd, void *buf, size_t len, int flags, sockaddr *from, socklen_t *fromlen) -- cgit v1.3.1-10-gc9f91 From 45ec564b05a80a84ea55ad49989bbcc211e7ee87 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Tue, 16 Apr 2013 13:11:21 +0200 Subject: Close listening sockets regardless of the return value of shutdown() --- src/listensocket.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/listensocket.cpp b/src/listensocket.cpp index 3a4473697..07ae491e0 100644 --- a/src/listensocket.cpp +++ b/src/listensocket.cpp @@ -75,7 +75,8 @@ ListenSocket::~ListenSocket() { ServerInstance->SE->DelFd(this); ServerInstance->Logs->Log("SOCKET", DEBUG,"Shut down listener on fd %d", this->fd); - if (ServerInstance->SE->Shutdown(this, 2) || ServerInstance->SE->Close(this)) + ServerInstance->SE->Shutdown(this, 2); + if (ServerInstance->SE->Close(this) != 0) ServerInstance->Logs->Log("SOCKET", DEBUG,"Failed to cancel listener: %s", strerror(errno)); this->fd = -1; } -- cgit v1.3.1-10-gc9f91 From e3939559e4496c520ec29ad16a5cab99efe7257e Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Sun, 2 Dec 2012 17:54:23 +0100 Subject: m_kicknorejoin Minor improvements - Ignore remote users - Remove expired items in one pass --- src/modules/m_kicknorejoin.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/modules/m_kicknorejoin.cpp b/src/modules/m_kicknorejoin.cpp index 836f92e6c..6d2d10c84 100644 --- a/src/modules/m_kicknorejoin.cpp +++ b/src/modules/m_kicknorejoin.cpp @@ -81,9 +81,7 @@ public: delaylist* dl = kr.ext.get(chan); if (dl) { - std::vector itemstoremove; - - for (delaylist::iterator iter = dl->begin(); iter != dl->end(); iter++) + for (delaylist::iterator iter = dl->begin(); iter != dl->end(); ) { if (iter->second > ServerInstance->Time()) { @@ -94,17 +92,15 @@ public: user->nick.c_str(), chan->name.c_str(), modeparam.c_str()); return MOD_RES_DENY; } + ++iter; } else { // Expired record, remove. - itemstoremove.push_back(iter->first); + dl->erase(iter++); } } - for (unsigned int i = 0; i < itemstoremove.size(); i++) - dl->erase(itemstoremove[i]); - if (!dl->size()) kr.ext.unset(chan); } @@ -114,7 +110,7 @@ public: void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) { - if (memb->chan->IsModeSet(&kr) && (source != memb->user)) + if (memb->chan->IsModeSet(&kr) && (IS_LOCAL(memb->user)) && (source != memb->user)) { delaylist* dl = kr.ext.get(memb->chan); if (!dl) -- cgit v1.3.1-10-gc9f91 From 4b81b4004d086555885d5e4a2541b0a92eb4a9ae Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Mon, 18 Feb 2013 19:56:05 +0100 Subject: m_kicknorejoin Limit time to 30m by default In the current implementation we only expire entries when someone joins, without a limit it was possible to make us practically never remove entries and consume (a tiny amount of) memory for each entry until the mode was removed/parameter was changed The default limit of 30m is chosen to not surprise people when they upgrade. If you need to prevent rejoins for more than a minute then you should set a (timed)ban instead Config option is available to change the limit (2.0 only) --- docs/conf/modules.conf.example | 2 ++ src/modules/m_kicknorejoin.cpp | 51 ++++++++++++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example index 0e7b3a29b..7a6c478f1 100644 --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@ -954,6 +954,8 @@ #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Anti-Auto-Rejoin: Adds support for prevention of auto-rejoin (+J) # +# Set the maximum time that is accepted as a parameter for +J here. +# #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Knock module: adds the /KNOCK command and +K channel mode diff --git a/src/modules/m_kicknorejoin.cpp b/src/modules/m_kicknorejoin.cpp index 6d2d10c84..9614b84f2 100644 --- a/src/modules/m_kicknorejoin.cpp +++ b/src/modules/m_kicknorejoin.cpp @@ -31,27 +31,42 @@ typedef std::map delaylist; /** Handles channel mode +J */ -class KickRejoin : public ParamChannelModeHandler +class KickRejoin : public ModeHandler { public: + unsigned int max; SimpleExtItem ext; - KickRejoin(Module* Creator) : ParamChannelModeHandler(Creator, "kicknorejoin", 'J'), ext("norejoinusers", Creator) { } - - bool ParamValidate(std::string& parameter) + KickRejoin(Module* Creator) + : ModeHandler(Creator, "kicknorejoin", 'J', PARAM_SETONLY, MODETYPE_CHANNEL) + , ext("norejoinusers", Creator) { - int v = atoi(parameter.c_str()); - if (v <= 0) - return false; - parameter = ConvToStr(v); - return true; } - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) { - ModeAction rv = ParamChannelModeHandler::OnModeChange(source, dest, channel, parameter, adding); - if (rv == MODEACTION_ALLOW && !adding) + if (adding) + { + int v = ConvToInt(parameter); + if (v <= 0) + return MODEACTION_DENY; + if (parameter == channel->GetModeParameter(this)) + return MODEACTION_DENY; + + if ((IS_LOCAL(source) && ((unsigned int)v > max))) + v = max; + + parameter = ConvToStr(v); + channel->SetModeParam(this, parameter); + } + else + { + if (!channel->IsModeSet(this)) + return MODEACTION_DENY; + ext.unset(channel); - return rv; + channel->SetModeParam(this, ""); + } + return MODEACTION_ALLOW; } }; @@ -70,8 +85,16 @@ public: { ServerInstance->Modules->AddService(kr); ServerInstance->Modules->AddService(kr.ext); - Implementation eventlist[] = { I_OnUserPreJoin, I_OnUserKick }; + Implementation eventlist[] = { I_OnUserPreJoin, I_OnUserKick, I_OnRehash }; ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); + OnRehash(NULL); + } + + void OnRehash(User* user) + { + kr.max = ServerInstance->Duration(ServerInstance->Config->ConfValue("kicknorejoin")->getString("maxtime")); + if (!kr.max) + kr.max = 30*60; } ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven) -- cgit v1.3.1-10-gc9f91 From 1dfead3b2cc9e8c603f6ad6f7216576a2ce361fb Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Tue, 16 Apr 2013 13:20:24 +0200 Subject: m_kicknorejoin Store and compare uuids instead pointers Fixes the off chance scenario where we disallow a join because a previously kicked user has quit and the User who is trying to join happens to be allocated at the exact same memory location --- src/modules/m_kicknorejoin.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/m_kicknorejoin.cpp b/src/modules/m_kicknorejoin.cpp index 9614b84f2..c754aa0f0 100644 --- a/src/modules/m_kicknorejoin.cpp +++ b/src/modules/m_kicknorejoin.cpp @@ -27,7 +27,7 @@ /* $ModDesc: Provides channel mode +J (delay rejoin after kick) */ -typedef std::map delaylist; +typedef std::map delaylist; /** Handles channel mode +J */ @@ -108,7 +108,7 @@ public: { if (iter->second > ServerInstance->Time()) { - if (iter->first == user) + if (iter->first == user->uuid) { std::string modeparam = chan->GetModeParameter(&kr); user->WriteNumeric(ERR_DELAYREJOIN, "%s %s :You must wait %s seconds after being kicked to rejoin (+J)", @@ -141,7 +141,7 @@ public: dl = new delaylist; kr.ext.set(memb->chan, dl); } - (*dl)[memb->user] = ServerInstance->Time() + ConvToInt(memb->chan->GetModeParameter(&kr)); + (*dl)[memb->user->uuid] = ServerInstance->Time() + ConvToInt(memb->chan->GetModeParameter(&kr)); } } -- cgit v1.3.1-10-gc9f91 From 47332d6e9b990498dd35457090dd8983d8aae8d3 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 16 Apr 2013 03:34:58 -0500 Subject: Fix m_ssl_gnutls and perhaps some other things on Windows by recognizing WSAEWOULDBLOCK --- include/socketengine.h | 5 +++++ src/inspsocket.cpp | 6 +++--- src/modules/extra/m_ssl_gnutls.cpp | 12 ++++++++++++ src/socketengine.cpp | 14 ++++++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/include/socketengine.h b/include/socketengine.h index b790f6d77..293d27e43 100644 --- a/include/socketengine.h +++ b/include/socketengine.h @@ -489,6 +489,11 @@ public: /** Get data transfer statistics, kilobits per second in and out and total. */ void GetStats(float &kbitpersec_in, float &kbitpersec_out, float &kbitpersec_total); + + /** Should we ignore the error in errno? + * Checks EAGAIN and WSAEWOULDBLOCK + */ + static bool IgnoreError(); }; SocketEngine* CreateSocketEngine(); diff --git a/src/inspsocket.cpp b/src/inspsocket.cpp index 27c6f87ec..d78ace318 100644 --- a/src/inspsocket.cpp +++ b/src/inspsocket.cpp @@ -200,7 +200,7 @@ void StreamSocket::DoRead() error = "Connection closed"; ServerInstance->SE->ChangeEventMask(this, FD_WANT_NO_READ | FD_WANT_NO_WRITE); } - else if (errno == EAGAIN) + else if (SocketEngine::IgnoreError()) { ServerInstance->SE->ChangeEventMask(this, FD_WANT_FAST_READ | FD_READ_WILL_BLOCK); } @@ -291,7 +291,7 @@ void StreamSocket::DoWrite() } else if (rv < 0) { - if (errno == EAGAIN || errno == EINTR) + if (errno == EINTR || SocketEngine::IgnoreError()) ServerInstance->SE->ChangeEventMask(this, FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK); else SetError(strerror(errno)); @@ -388,7 +388,7 @@ void StreamSocket::DoWrite() { error = "Connection closed"; } - else if (errno == EAGAIN) + else if (SocketEngine::IgnoreError()) { eventChange = FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK; } diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index 38b3700b5..e329186a5 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -86,6 +86,12 @@ static ssize_t gnutls_pull_wrapper(gnutls_transport_ptr_t user_wrap, void* buffe return -1; } int rv = ServerInstance->SE->Recv(user, reinterpret_cast(buffer), size, 0); + if (rv < 0) + { + /* On Windows we need to set errno for gnutls */ + if (SocketEngine::IgnoreError()) + errno = EAGAIN; + } if (rv < (int)size) ServerInstance->SE->ChangeEventMask(user, FD_READ_WILL_BLOCK); return rv; @@ -100,6 +106,12 @@ static ssize_t gnutls_push_wrapper(gnutls_transport_ptr_t user_wrap, const void* return -1; } int rv = ServerInstance->SE->Send(user, reinterpret_cast(buffer), size, 0); + if (rv < 0) + { + /* On Windows we need to set errno for gnutls */ + if (SocketEngine::IgnoreError()) + errno = EAGAIN; + } if (rv < (int)size) ServerInstance->SE->ChangeEventMask(user, FD_WRITE_WILL_BLOCK); return rv; diff --git a/src/socketengine.cpp b/src/socketengine.cpp index 6c99edc95..cbdfb5651 100644 --- a/src/socketengine.cpp +++ b/src/socketengine.cpp @@ -255,3 +255,17 @@ void SocketEngine::GetStats(float &kbitpersec_in, float &kbitpersec_out, float & kbitpersec_in = in_kbit / 1024; kbitpersec_out = out_kbit / 1024; } + +bool SocketEngine::IgnoreError() +{ + if (errno == EAGAIN) + return true; + +#ifdef _WIN32 + if (WSAGetLastError() == WSAEWOULDBLOCK) + return true; +#endif + + return false; +} + -- cgit v1.3.1-10-gc9f91 From 82c53822ecef034b1b88f47ebaa13b4d8c8ac836 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Thu, 18 Apr 2013 03:30:22 +0200 Subject: m_callerid Fix bookkeeping error introduced when unserializing callerid_data This also fixes a memory leak that didn't occur naturally but was triggerable by remote servers Thanks to @SimosNap for the report --- src/modules/m_callerid.cpp | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/modules/m_callerid.cpp b/src/modules/m_callerid.cpp index 7f843f252..812df1da0 100644 --- a/src/modules/m_callerid.cpp +++ b/src/modules/m_callerid.cpp @@ -38,26 +38,6 @@ class callerid_data std::list wholistsme; callerid_data() : lastnotify(0) { } - callerid_data(const std::string& str) - { - irc::commasepstream s(str); - std::string tok; - if (s.GetToken(tok)) - { - lastnotify = ConvToInt(tok); - } - while (s.GetToken(tok)) - { - if (tok.empty()) - { - continue; - } - - User *u = ServerInstance->FindNick(tok); - if ((u) && (u->registered == REG_ALL) && (!u->quitting) && (!IS_SERVER(u))) - accepting.insert(u); - } - } std::string ToString(SerializeFormat format) const { @@ -88,8 +68,29 @@ struct CallerIDExtInfo : public ExtensionItem void unserialize(SerializeFormat format, Extensible* container, const std::string& value) { - callerid_data* dat = new callerid_data(value); - set_raw(container, dat); + callerid_data* dat = new callerid_data; + irc::commasepstream s(value); + std::string tok; + if (s.GetToken(tok)) + dat->lastnotify = ConvToInt(tok); + + while (s.GetToken(tok)) + { + if (tok.empty()) + continue; + + User *u = ServerInstance->FindNick(tok); + if ((u) && (u->registered == REG_ALL) && (!u->quitting) && (!IS_SERVER(u))) + { + callerid_data* other = this->get(u, true); + other->wholistsme.push_back(dat); + dat->accepting.insert(u); + } + } + + void* old = set_raw(container, dat); + if (old) + this->free(old); } callerid_data* get(User* user, bool create) -- cgit v1.3.1-10-gc9f91 From 5ca81cf89a1d7cf78a2bb078a25305c1ebab8746 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Thu, 18 Apr 2013 13:25:28 +0200 Subject: m_callerid Ignore duplicate entries when unserializing callerid_data --- src/modules/m_callerid.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/modules/m_callerid.cpp b/src/modules/m_callerid.cpp index 812df1da0..b0d6b9c64 100644 --- a/src/modules/m_callerid.cpp +++ b/src/modules/m_callerid.cpp @@ -82,9 +82,11 @@ struct CallerIDExtInfo : public ExtensionItem User *u = ServerInstance->FindNick(tok); if ((u) && (u->registered == REG_ALL) && (!u->quitting) && (!IS_SERVER(u))) { - callerid_data* other = this->get(u, true); - other->wholistsme.push_back(dat); - dat->accepting.insert(u); + if (dat->accepting.insert(u).second) + { + callerid_data* other = this->get(u, true); + other->wholistsme.push_back(dat); + } } } -- cgit v1.3.1-10-gc9f91 From ddba35710aa04e33bb061225764a7a9a1165beae Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Thu, 18 Apr 2013 22:50:12 +0200 Subject: m_spanningtree Fix IS_LOCAL() check in OnRehash handler --- src/modules/m_spanningtree/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp index e7892526e..fdb9ef200 100644 --- a/src/modules/m_spanningtree/main.cpp +++ b/src/modules/m_spanningtree/main.cpp @@ -783,7 +783,7 @@ void ModuleSpanningTree::OnRehash(User* user) std::string msg = "Error in configuration: "; msg.append(e.GetReason()); ServerInstance->SNO->WriteToSnoMask('l', msg); - if (!IS_LOCAL(user)) + if (user && !IS_LOCAL(user)) ServerInstance->PI->SendSNONotice("L", msg); } } -- cgit v1.3.1-10-gc9f91 From f4dda34d06b5f93b28e0ec7d34557199717e147d Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Fri, 19 Apr 2013 17:05:50 +0200 Subject: m_callerid Allow messaging yourself while +g regardless of the ACCEPT list --- src/modules/m_callerid.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/m_callerid.cpp b/src/modules/m_callerid.cpp index b0d6b9c64..4b167f2db 100644 --- a/src/modules/m_callerid.cpp +++ b/src/modules/m_callerid.cpp @@ -362,7 +362,7 @@ public: ModResult PreText(User* user, User* dest, std::string& text) { - if (!dest->IsModeSet('g')) + if (!dest->IsModeSet('g') || (user == dest)) return MOD_RES_PASSTHRU; if (operoverride && IS_OPER(user)) -- cgit v1.3.1-10-gc9f91 From 9d43a08903592e82655d7afcf978006d64198808 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Fri, 19 Apr 2013 17:06:07 +0200 Subject: m_ident Invalidate cache after changing User::ident --- src/modules/m_ident.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/m_ident.cpp b/src/modules/m_ident.cpp index f1c3b81fd..6099e7c14 100644 --- a/src/modules/m_ident.cpp +++ b/src/modules/m_ident.cpp @@ -371,6 +371,7 @@ class ModuleIdent : public Module user->WriteServ("NOTICE Auth :*** Found your ident, '%s'", user->ident.c_str()); } + user->InvalidateCache(); isock->Close(); ext.unset(user); return MOD_RES_PASSTHRU; -- cgit v1.3.1-10-gc9f91 From 89a8e22b6698c3f4ee1d32e0e864c293cd9335d0 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Fri, 19 Apr 2013 17:06:35 +0200 Subject: Fix uuids getting truncated in the nick hash in UserManager::AddUser() if nickmax is < 9 --- src/usermanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 124c4d140..2f2eeb6dd 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -63,7 +63,7 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs this->unregistered_count++; /* The users default nick is their UUID */ - New->nick.assign(New->uuid, 0, ServerInstance->Config->Limits.NickMax); + New->nick = New->uuid; (*(this->clientlist))[New->nick] = New; New->registered = REG_NONE; -- cgit v1.3.1-10-gc9f91 From 92da062c028f4a6546a938631e7574e324040274 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Fri, 19 Apr 2013 17:07:10 +0200 Subject: Immediately stop processing whenever we detect and handle a RecvQ overrun Thanks to @SimosNap for the report and cooperation --- src/users.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/users.cpp b/src/users.cpp index adfa7642c..dbc3ea444 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -455,6 +455,7 @@ void UserIOHandler::OnDataReady() ServerInstance->Users->QuitUser(user, "RecvQ exceeded"); ServerInstance->SNO->WriteToSnoMask('a', "User %s RecvQ of %lu exceeds connect class maximum of %lu", user->nick.c_str(), (unsigned long)recvq.length(), user->MyClass->GetRecvqMax()); + return; } unsigned long sendqmax = ULONG_MAX; if (!user->HasPrivPermission("users/flood/increased-buffers")) -- cgit v1.3.1-10-gc9f91 From 1250abdc0915975f0a99cdcea1a4f6cb006b0a74 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Sun, 21 Apr 2013 15:30:51 +0200 Subject: Don't crop the channel name if it's too long in Channel::Channel() ...and especially don't use the shortened name in one place and the original in another Having different values on the same network is not supported --- src/channels.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/channels.cpp b/src/channels.cpp index 229e2b8ea..3502abe12 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -31,12 +31,10 @@ Channel::Channel(const std::string &cname, time_t ts) { - chan_hash::iterator findchan = ServerInstance->chanlist->find(cname); - if (findchan != ServerInstance->chanlist->end()) + if (!ServerInstance->chanlist->insert(std::make_pair(cname, this)).second) throw CoreException("Cannot create duplicate channel " + cname); - (*(ServerInstance->chanlist))[cname.c_str()] = this; - this->name.assign(cname, 0, ServerInstance->Config->Limits.ChanMax); + this->name = cname; this->age = ts ? ts : ServerInstance->Time(); maxbans = topicset = 0; -- cgit v1.3.1-10-gc9f91 From 4b8b3eca8cd30fe6c992c86a333b2defa79ba765 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Sun, 21 Apr 2013 15:40:19 +0200 Subject: m_permchannels Workaround for alphabetical module initialization order Read database after all modules have been inited Add exception logging Fixes #485 reported by @gholms --- src/modules/m_permchannels.cpp | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/modules/m_permchannels.cpp b/src/modules/m_permchannels.cpp index b12b9bbeb..a59518b28 100644 --- a/src/modules/m_permchannels.cpp +++ b/src/modules/m_permchannels.cpp @@ -172,14 +172,6 @@ public: ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); - - // Load only when there are no linked servers - we set the TS of the channels we - // create to the current time, this can lead to desync because spanningtree has - // no way of knowing what we do - ProtoServerList serverlist; - ServerInstance->PI->GetServerList(serverlist); - if (serverlist.size() < 2) - LoadDatabase(); } CullResult cull() @@ -300,6 +292,38 @@ public: dirty = false; } + void Prioritize() + { + // XXX: Load the DB here because the order in which modules are init()ed at boot is + // alphabetical, this means we must wait until all modules have done their init() + // to be able to set the modes they provide (e.g.: m_stripcolor is inited after us) + // Prioritize() is called after all module initialization is complete, consequently + // all modes are available now + + static bool loaded = false; + if (loaded) + return; + + loaded = true; + + // Load only when there are no linked servers - we set the TS of the channels we + // create to the current time, this can lead to desync because spanningtree has + // no way of knowing what we do + ProtoServerList serverlist; + ServerInstance->PI->GetServerList(serverlist); + if (serverlist.size() < 2) + { + try + { + LoadDatabase(); + } + catch (CoreException& e) + { + ServerInstance->Logs->Log("m_permchannels", DEFAULT, "Error loading permchannels database: " + std::string(e.GetReason())); + } + } + } + virtual Version GetVersion() { return Version("Provides support for channel mode +P to provide permanent channels",VF_VENDOR); -- cgit v1.3.1-10-gc9f91 From 6e79197210e58d69e7bd512d0b5569c4cb06f3e5 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Sun, 21 Apr 2013 17:20:28 +0200 Subject: Log some internal errors on DEFAULT loglevel instead of DEBUG, log detected errors in m_callerid --- src/modules/m_callerid.cpp | 11 +++++++++++ src/usermanager.cpp | 6 +++--- src/users.cpp | 8 ++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/modules/m_callerid.cpp b/src/modules/m_callerid.cpp index 4b167f2db..37787b525 100644 --- a/src/modules/m_callerid.cpp +++ b/src/modules/m_callerid.cpp @@ -116,11 +116,16 @@ struct CallerIDExtInfo : public ExtensionItem callerid_data *targ = this->get(*it, false); if (!targ) + { + ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (1)"); continue; // shouldn't happen, but oh well. + } std::list::iterator it2 = std::find(targ->wholistsme.begin(), targ->wholistsme.end(), dat); if (it2 != targ->wholistsme.end()) targ->wholistsme.erase(it2); + else + ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (2)"); } delete dat; } @@ -280,6 +285,7 @@ public: if (!dat2) { // How the fuck is this possible. + ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (3)"); return false; } @@ -287,6 +293,9 @@ public: if (it != dat2->wholistsme.end()) // Found me! dat2->wholistsme.erase(it); + else + ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (4)"); + user->WriteServ("NOTICE %s :%s is no longer on your accept list", user->nick.c_str(), whotoremove->nick.c_str()); return true; @@ -324,6 +333,8 @@ private: if (it2 != dat->accepting.end()) dat->accepting.erase(it2); + else + ServerInstance->Logs->Log("m_callerid", DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (5)"); } userdata->wholistsme.clear(); diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 2f2eeb6dd..e3ddfc9f2 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -167,13 +167,13 @@ void UserManager::QuitUser(User *user, const std::string &quitreason, const char { if (user->quitting) { - ServerInstance->Logs->Log("CULLLIST",DEBUG, "*** Warning *** - You tried to quit a user (%s) twice. Did your module call QuitUser twice?", user->nick.c_str()); + ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: Tried to quit quitting user: " + user->nick); return; } if (IS_SERVER(user)) { - ServerInstance->Logs->Log("CULLLIST",DEBUG, "*** Warning *** - You tried to quit a fake user (%s)", user->nick.c_str()); + ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: Tried to quit server user: " + user->nick); return; } @@ -239,7 +239,7 @@ void UserManager::QuitUser(User *user, const std::string &quitreason, const char if (iter != this->clientlist->end()) this->clientlist->erase(iter); else - ServerInstance->Logs->Log("USERS", DEBUG, "iter == clientlist->end, can't remove them from hash... problematic.."); + ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: Nick not found in clientlist, cannot remove: " + user->nick); ServerInstance->Users->uuidlist->erase(user->uuid); } diff --git a/src/users.cpp b/src/users.cpp index dbc3ea444..f48e3642f 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -546,6 +546,8 @@ CullResult LocalUser::cull() // is only a precaution currently. if (localuseriter != ServerInstance->Users->local_users.end()) ServerInstance->Users->local_users.erase(localuseriter); + else + ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: LocalUserIter does not point to a valid entry for " + this->nick); ClearInvites(); eh.cull(); @@ -840,6 +842,12 @@ void User::InvalidateCache() bool User::ChangeNick(const std::string& newnick, bool force) { + if (quitting) + { + ServerInstance->Logs->Log("USERS", DEFAULT, "ERROR: Attempted to change nick of a quitting user: " + this->nick); + return false; + } + ModResult MOD_RESULT; if (force) -- cgit v1.3.1-10-gc9f91 From 822f3f13f18b7e79d5740416f9417dabb9296859 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Sun, 21 Apr 2013 17:41:03 +0200 Subject: m_filter Fix memory leak on unload --- src/modules/m_filter.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/modules/m_filter.cpp b/src/modules/m_filter.cpp index 86ef0d4f6..25941e5d8 100644 --- a/src/modules/m_filter.cpp +++ b/src/modules/m_filter.cpp @@ -165,6 +165,8 @@ class ImplFilter : public FilterResult class ModuleFilter : public Module { + void FreeFilters(); + public: CommandFilter filtcommand; dynamic_reference RegexEngine; @@ -178,6 +180,7 @@ class ModuleFilter : public Module ModuleFilter(); void init(); + CullResult cull(); ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list); FilterResult* FilterMatch(User* user, const std::string &text, int flags); bool DeleteFilter(const std::string &freeform); @@ -304,6 +307,20 @@ void ModuleFilter::init() OnRehash(NULL); } +CullResult ModuleFilter::cull() +{ + FreeFilters(); + return Module::cull(); +} + +void ModuleFilter::FreeFilters() +{ + for (std::vector::const_iterator i = filters.begin(); i != filters.end(); ++i) + delete i->regex; + + filters.clear(); +} + ModResult ModuleFilter::OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) { if (!IS_LOCAL(user)) -- cgit v1.3.1-10-gc9f91 From 216877cc5b595b5b6bbc5f953e226618201cc0f6 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Sun, 21 Apr 2013 18:03:07 +0200 Subject: m_filter, m_rline Remove rlines and filters when the regex engine changes or becomes unavailable --- src/modules/m_filter.cpp | 57 +++++++++++++++++++++++++++++++++++++----------- src/modules/m_rline.cpp | 38 +++++++++++++++++++++++++++++--- 2 files changed, 79 insertions(+), 16 deletions(-) diff --git a/src/modules/m_filter.cpp b/src/modules/m_filter.cpp index 25941e5d8..5e1b4d38d 100644 --- a/src/modules/m_filter.cpp +++ b/src/modules/m_filter.cpp @@ -165,6 +165,8 @@ class ImplFilter : public FilterResult class ModuleFilter : public Module { + bool initing; + RegexFactory* factory; void FreeFilters(); public: @@ -172,8 +174,6 @@ class ModuleFilter : public Module dynamic_reference RegexEngine; std::vector filters; - const char *error; - int erroffset; int flags; std::set exemptfromfilter; // List of channel names excluded from filtering. @@ -194,6 +194,7 @@ class ModuleFilter : public Module void OnDecodeMetaData(Extensible* target, const std::string &extname, const std::string &extdata); ModResult OnStats(char symbol, User* user, string_list &results); ModResult OnPreCommand(std::string &command, std::vector ¶meters, LocalUser *user, bool validated, const std::string &original_line); + void OnUnloadModule(Module* mod); bool AppliesToMe(User* user, FilterResult* filter, int flags); void ReadFilters(); static bool StringToFilterAction(const std::string& str, FilterAction& fa); @@ -295,14 +296,15 @@ bool ModuleFilter::AppliesToMe(User* user, FilterResult* filter, int iflags) return true; } -ModuleFilter::ModuleFilter() : filtcommand(this), RegexEngine(this, "regex") +ModuleFilter::ModuleFilter() + : initing(true), filtcommand(this), RegexEngine(this, "regex") { } void ModuleFilter::init() { ServerInstance->Modules->AddService(filtcommand); - Implementation eventlist[] = { I_OnPreCommand, I_OnStats, I_OnSyncNetwork, I_OnDecodeMetaData, I_OnUserPreMessage, I_OnUserPreNotice, I_OnRehash }; + Implementation eventlist[] = { I_OnPreCommand, I_OnStats, I_OnSyncNetwork, I_OnDecodeMetaData, I_OnUserPreMessage, I_OnUserPreNotice, I_OnRehash, I_OnUnloadModule }; ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); OnRehash(NULL); } @@ -474,20 +476,35 @@ void ModuleFilter::OnRehash(User* user) if (!chan.empty()) exemptfromfilter.insert(chan); } - std::string newrxengine = "regex/" + ServerInstance->Config->ConfValue("filteropts")->getString("engine"); - if (newrxengine == "regex/") - newrxengine = "regex"; - if (RegexEngine.GetProvider() == newrxengine) - return; - //ServerInstance->SNO->WriteGlobalSno('a', "Dumping all filters due to regex engine change (was '%s', now '%s')", RegexEngine.GetProvider().c_str(), newrxengine.c_str()); - //ServerInstance->XLines->DelAll("R"); + std::string newrxengine = ServerInstance->Config->ConfValue("filteropts")->getString("engine"); + + factory = RegexEngine ? (RegexEngine.operator->()) : NULL; + + if (newrxengine.empty()) + RegexEngine.SetProvider("regex"); + else + RegexEngine.SetProvider("regex/" + newrxengine); - RegexEngine.SetProvider(newrxengine); if (!RegexEngine) { - ServerInstance->SNO->WriteGlobalSno('a', "WARNING: Regex engine '%s' is not loaded - Filter functionality disabled until this is corrected.", newrxengine.c_str()); + if (newrxengine.empty()) + ServerInstance->SNO->WriteGlobalSno('a', "WARNING: No regex engine loaded - Filter functionality disabled until this is corrected."); + else + ServerInstance->SNO->WriteGlobalSno('a', "WARNING: Regex engine '%s' is not loaded - Filter functionality disabled until this is corrected.", newrxengine.c_str()); + + initing = false; + FreeFilters(); + return; + } + + if ((!initing) && (RegexEngine.operator->() != factory)) + { + ServerInstance->SNO->WriteGlobalSno('a', "Dumping all filters due to regex engine change"); + FreeFilters(); } + + initing = false; ReadFilters(); } @@ -714,4 +731,18 @@ ModResult ModuleFilter::OnStats(char symbol, User* user, string_list &results) return MOD_RES_PASSTHRU; } +void ModuleFilter::OnUnloadModule(Module* mod) +{ + // If the regex engine became unavailable or has changed, remove all filters + if (!RegexEngine) + { + FreeFilters(); + } + else if (RegexEngine.operator->() != factory) + { + factory = RegexEngine.operator->(); + FreeFilters(); + } +} + MODULE_INIT(ModuleFilter) diff --git a/src/modules/m_rline.cpp b/src/modules/m_rline.cpp index a234c02c6..bbe8ede9a 100644 --- a/src/modules/m_rline.cpp +++ b/src/modules/m_rline.cpp @@ -224,9 +224,13 @@ class ModuleRLine : public Module RLineFactory f; CommandRLine r; bool MatchOnNickChange; + bool initing; + RegexFactory* factory; public: - ModuleRLine() : rxfactory(this, "regex"), f(rxfactory), r(this, f) + ModuleRLine() + : rxfactory(this, "regex"), f(rxfactory), r(this, f) + , initing(true) { } @@ -237,7 +241,7 @@ class ModuleRLine : public Module ServerInstance->Modules->AddService(r); ServerInstance->XLines->RegisterFactory(&f); - Implementation eventlist[] = { I_OnUserConnect, I_OnRehash, I_OnUserPostNick, I_OnStats, I_OnBackgroundTimer }; + Implementation eventlist[] = { I_OnUserConnect, I_OnRehash, I_OnUserPostNick, I_OnStats, I_OnBackgroundTimer, I_OnUnloadModule }; ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } @@ -272,14 +276,29 @@ class ModuleRLine : public Module ZlineOnMatch = tag->getBool("zlineonmatch"); std::string newrxengine = tag->getString("engine"); + factory = rxfactory ? (rxfactory.operator->()) : NULL; + if (newrxengine.empty()) rxfactory.SetProvider("regex"); else rxfactory.SetProvider("regex/" + newrxengine); + if (!rxfactory) { - ServerInstance->SNO->WriteToSnoMask('a', "WARNING: Regex engine '%s' is not loaded - R-Line functionality disabled until this is corrected.", newrxengine.c_str()); + if (newrxengine.empty()) + ServerInstance->SNO->WriteToSnoMask('a', "WARNING: No regex engine loaded - R-Line functionality disabled until this is corrected."); + else + ServerInstance->SNO->WriteToSnoMask('a', "WARNING: Regex engine '%s' is not loaded - R-Line functionality disabled until this is corrected.", newrxengine.c_str()); + + ServerInstance->XLines->DelAll(f.GetType()); } + else if ((!initing) && (rxfactory.operator->() != factory)) + { + ServerInstance->SNO->WriteToSnoMask('a', "Regex engine has changed, removing all R-Lines"); + ServerInstance->XLines->DelAll(f.GetType()); + } + + initing = false; } virtual ModResult OnStats(char symbol, User* user, string_list &results) @@ -317,6 +336,19 @@ class ModuleRLine : public Module } } + void OnUnloadModule(Module* mod) + { + // If the regex engine became unavailable or has changed, remove all rlines + if (!rxfactory) + { + ServerInstance->XLines->DelAll(f.GetType()); + } + else if (rxfactory.operator->() != factory) + { + factory = rxfactory.operator->(); + ServerInstance->XLines->DelAll(f.GetType()); + } + } }; MODULE_INIT(ModuleRLine) -- cgit v1.3.1-10-gc9f91 From 25d00181cd5a6b89c926e188e5f7569335ca64d0 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Sun, 21 Apr 2013 18:09:41 +0200 Subject: m_rline Switch to OnUserRegister hook to disconnect banned users earlier --- src/modules/m_rline.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/modules/m_rline.cpp b/src/modules/m_rline.cpp index bbe8ede9a..160092a63 100644 --- a/src/modules/m_rline.cpp +++ b/src/modules/m_rline.cpp @@ -241,7 +241,7 @@ class ModuleRLine : public Module ServerInstance->Modules->AddService(r); ServerInstance->XLines->RegisterFactory(&f); - Implementation eventlist[] = { I_OnUserConnect, I_OnRehash, I_OnUserPostNick, I_OnStats, I_OnBackgroundTimer, I_OnUnloadModule }; + Implementation eventlist[] = { I_OnUserRegister, I_OnRehash, I_OnUserPostNick, I_OnStats, I_OnBackgroundTimer, I_OnUnloadModule }; ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } @@ -256,7 +256,7 @@ class ModuleRLine : public Module return Version("RLINE: Regexp user banning.", VF_COMMON | VF_VENDOR, rxfactory ? rxfactory->name : ""); } - virtual void OnUserConnect(LocalUser* user) + ModResult OnUserRegister(LocalUser* user) { // Apply lines on user connect XLine *rl = ServerInstance->XLines->MatchesLine("R", user); @@ -265,7 +265,9 @@ class ModuleRLine : public Module { // Bang. :P rl->Apply(user); + return MOD_RES_DENY; } + return MOD_RES_PASSTHRU; } virtual void OnRehash(User *user) @@ -349,6 +351,12 @@ class ModuleRLine : public Module ServerInstance->XLines->DelAll(f.GetType()); } } + + void Prioritize() + { + Module* mod = ServerInstance->Modules->Find("m_cgiirc.so"); + ServerInstance->Modules->SetPriority(this, I_OnUserRegister, PRIORITY_AFTER, mod); + } }; MODULE_INIT(ModuleRLine) -- cgit v1.3.1-10-gc9f91 From b742311a7039655c63c4d08902b43cebdeeb8d33 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Tue, 23 Apr 2013 15:01:15 +0200 Subject: Add config option to disable somaxconn range() check --- docs/conf/inspircd.conf.example | 6 ++++++ src/configreader.cpp | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/conf/inspircd.conf.example b/docs/conf/inspircd.conf.example index 0767e9ff5..ca61bb416 100644 --- a/docs/conf/inspircd.conf.example +++ b/docs/conf/inspircd.conf.example @@ -639,6 +639,12 @@ # to 5, while others (such as linux and *BSD) default to 128. somaxconn="128" + # limitsomaxconn: By default, somaxconn (see above) is limited to a + # safe maximum value in the 2.0 branch for compatibility reasons. + # This setting can be used to disable this limit, forcing InspIRCd + # to use the value specifed above. + limitsomaxconn="true" + # softlimit: This optional feature allows a defined softlimit for # connections. If defined, it sets a soft max connections value. softlimit="12800" diff --git a/src/configreader.cpp b/src/configreader.cpp index 2577b83b8..e8707cc3e 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -554,7 +554,8 @@ void ServerConfig::Fill() WelcomeNotice = options->getBool("welcomenotice", true); range(SoftLimit, 10, ServerInstance->SE->GetMaxFds(), ServerInstance->SE->GetMaxFds(), ""); - range(MaxConn, 0, SOMAXCONN, SOMAXCONN, ""); + if (ConfValue("performance")->getBool("limitsomaxconn", true)) + range(MaxConn, 0, SOMAXCONN, SOMAXCONN, ""); range(MaxTargets, 1, 31, 20, ""); range(NetBufferSize, 1024, 65534, 10240, ""); range(WhoWasGroupSize, 0, 10000, 10, ""); -- cgit v1.3.1-10-gc9f91 From f6aea98dc5c3d9e2e54cde5aaf3198eee3c1ebfb Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Tue, 23 Apr 2013 15:10:33 +0200 Subject: m_spanningtree Fix crash when connecting to a remote server that has the same name as we do and also there is a link block with our server name and their password See 49223cfe12ecd9071123f724e615e63841f2421d --- src/modules/m_spanningtree/server.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/m_spanningtree/server.cpp b/src/modules/m_spanningtree/server.cpp index a04454f51..05441da0c 100644 --- a/src/modules/m_spanningtree/server.cpp +++ b/src/modules/m_spanningtree/server.cpp @@ -137,8 +137,9 @@ bool TreeSocket::Outbound_Reply_Server(parameterlist ¶ms) TreeServer* CheckDupe = Utils->FindServer(sname); if (CheckDupe) { - this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!"); - ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName()); + std::string pname = CheckDupe->GetParent() ? CheckDupe->GetParent()->GetName() : ""; + SendError("Server "+sname+" already exists on server "+pname+"!"); + ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+pname); return false; } CheckDupe = Utils->FindServer(sid); -- cgit v1.3.1-10-gc9f91 From 40398162c326eab06d1ce6e9397c25b0a32fa368 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Sun, 10 Mar 2013 14:08:51 +0100 Subject: m_ssl_gnutls Add ability to load DH params from file This greatly decreases the load time because the DH parameters no longer have to be (re)generated each time the module is loaded --- src/modules/extra/m_ssl_gnutls.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index e329186a5..b3c7bca3e 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -335,6 +335,7 @@ class ModuleSSLGnuTLS : public Module { gnutls_dh_params_deinit(dh_params); dh_alloc = false; + dh_params = NULL; } if (cred_alloc) @@ -422,10 +423,30 @@ class ModuleSSLGnuTLS : public Module ret = gnutls_dh_params_init(&dh_params); dh_alloc = (ret >= 0); if (!dh_alloc) + { ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to initialise DH parameters: %s", gnutls_strerror(ret)); + return; + } - // This may be on a large (once a day or week) timer eventually. - GenerateDHParams(); + std::string dhfile = Conf->getString("dhfile"); + if (!dhfile.empty()) + { + // Try to load DH params from file + reader.LoadFile(dhfile); + std::string dhstring = reader.Contents(); + gnutls_datum_t dh_datum = { (unsigned char*)dhstring.data(), static_cast(dhstring.length()) }; + + if ((ret = gnutls_dh_params_import_pkcs3(dh_params, &dh_datum, GNUTLS_X509_FMT_PEM)) < 0) + { + // File unreadable or GnuTLS was unhappy with the contents, generate the DH primes now + ServerInstance->Logs->Log("m_ssl_gnutls", DEFAULT, "m_ssl_gnutls.so: Generating DH parameters because I failed to load them from file '%s': %s", dhfile.c_str(), gnutls_strerror(ret)); + GenerateDHParams(); + } + } + else + { + GenerateDHParams(); + } } void GenerateDHParams() -- cgit v1.3.1-10-gc9f91 From 2bb64c5dcfb66e9bf7f6114de6501fd5dcd97138 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Wed, 24 Apr 2013 19:54:58 +0200 Subject: Move SocketEngine::IgnoreError() code into socketengine.h and add test for EWOULDBLOCK --- include/socketengine.h | 13 +++++++++++++ src/socketengine.cpp | 14 -------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/include/socketengine.h b/include/socketengine.h index 293d27e43..2fc3cdbfd 100644 --- a/include/socketengine.h +++ b/include/socketengine.h @@ -496,6 +496,19 @@ public: static bool IgnoreError(); }; +inline bool SocketEngine::IgnoreError() +{ + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) + return true; + +#ifdef _WIN32 + if (WSAGetLastError() == WSAEWOULDBLOCK) + return true; +#endif + + return false; +} + SocketEngine* CreateSocketEngine(); #endif diff --git a/src/socketengine.cpp b/src/socketengine.cpp index cbdfb5651..6c99edc95 100644 --- a/src/socketengine.cpp +++ b/src/socketengine.cpp @@ -255,17 +255,3 @@ void SocketEngine::GetStats(float &kbitpersec_in, float &kbitpersec_out, float & kbitpersec_in = in_kbit / 1024; kbitpersec_out = out_kbit / 1024; } - -bool SocketEngine::IgnoreError() -{ - if (errno == EAGAIN) - return true; - -#ifdef _WIN32 - if (WSAGetLastError() == WSAEWOULDBLOCK) - return true; -#endif - - return false; -} - -- cgit v1.3.1-10-gc9f91 From 9b96fee72a3720e6d12812243edb4192d0790b34 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Wed, 24 Apr 2013 19:55:01 +0200 Subject: Release 2.0.12 --- src/version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.sh b/src/version.sh index 49887380b..d759d06a7 100755 --- a/src/version.sh +++ b/src/version.sh @@ -1,2 +1,2 @@ #!/bin/sh -echo "InspIRCd-2.0.11" +echo "InspIRCd-2.0.12" -- cgit v1.3.1-10-gc9f91