diff options
-rw-r--r-- | docs/conf/modules.conf.example | 22 | ||||
-rw-r--r-- | include/base.h | 15 | ||||
-rw-r--r-- | include/modules.h | 10 | ||||
-rw-r--r-- | include/socket.h | 2 | ||||
-rw-r--r-- | include/users.h | 6 | ||||
-rw-r--r-- | src/commands/cmd_notice.cpp | 9 | ||||
-rw-r--r-- | src/configreader.cpp | 12 | ||||
-rw-r--r-- | src/modules.cpp | 1 | ||||
-rw-r--r-- | src/modules/extra/m_mysql.cpp | 2 | ||||
-rw-r--r-- | src/modules/extra/m_regex_stdlib.cpp | 112 | ||||
-rw-r--r-- | src/modules/m_blockamsg.cpp | 6 | ||||
-rw-r--r-- | src/modules/m_cgiirc.cpp | 61 | ||||
-rw-r--r-- | src/modules/m_dnsbl.cpp | 6 | ||||
-rw-r--r-- | src/modules/m_knock.cpp | 32 | ||||
-rw-r--r-- | src/modules/m_shun.cpp | 1 | ||||
-rw-r--r-- | src/modules/m_sslinfo.cpp | 4 | ||||
-rw-r--r-- | src/socket.cpp | 1 | ||||
-rw-r--r-- | src/socketengine.cpp | 7 | ||||
-rw-r--r-- | src/usermanager.cpp | 6 | ||||
-rw-r--r-- | src/users.cpp | 42 |
20 files changed, 294 insertions, 63 deletions
diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example index 76563fbeb..ea0431499 100644 --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@ -943,6 +943,14 @@ #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Knock module: adds the /KNOCK command and +K channel mode #<module name="m_knock.so"> +# This setting specifes what to do when someone successfully /KNOCKs. +# If set to "notice", then a NOTICE will be sent to the channel. +# This is the default and the compatible setting, as it requires no +# special support from the clients. +# If set to "numeric" then a 710 numeric will be sent to the channel. +# This allows easier scripting but not all clients support it. +# If set to "both" then (surprise!) both will be sent. +#<knock notify="notice"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # LDAP authentication module: Adds the ability to authenticate users # @@ -1381,6 +1389,20 @@ #<module name="m_regex_posix.so"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# +# Regular Expression Provider for C++11 std::regex Regular Expressions. +# This module works on any fully compliant implementation of the C++11 +# std::regex container. Examples for such are Visual C++ 2010 and newer +# but not libstdc++ (which GCC uses) +# You should verify that std::regex is supported by your setup before +# using this module, as it may compile normally but won't do anything +# on some implementations. +#<module name="m_regex_stdlib.so"> + +# Specify the Regular Expression engine to use here. Valid settings are +# bre, ere, awk, grep, egrep, ecmascript (default if not specified) +#<stdregex type="ecmascript"> + +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Regular Expression Provider for TRE Regular Expressions. # This is the same regular expression engine used by UnrealIRCd, so # if you are most familiar with the syntax of /spamfilter from there, diff --git a/include/base.h b/include/base.h index 45c60802c..230ed1db4 100644 --- a/include/base.h +++ b/include/base.h @@ -142,6 +142,21 @@ class CoreExport reference if (value && value->refcount_dec()) delete value; } + + inline reference<T>& operator=(T* other) + { + if (value != other) + { + if (value && value->refcount_dec()) + delete value; + value = other; + if (value) + value->refcount_inc(); + } + + return *this; + } + inline operator bool() const { return value; } inline operator T*() const { return value; } inline T* operator->() const { return value; } diff --git a/include/modules.h b/include/modules.h index 49c16ae61..281da2705 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 1 +#define INSPIRCD_VERSION_API 2 /** * This #define allows us to call a method in all @@ -338,7 +338,7 @@ enum Implementation I_OnPostOper, I_OnSyncNetwork, I_OnSetAway, I_OnPostCommand, I_OnPostJoin, I_OnWhoisLine, I_OnBuildNeighborList, I_OnGarbageCollect, I_OnSetConnectClass, I_OnText, I_OnPassCompare, I_OnRunTestSuite, I_OnNamesListItem, I_OnNumeric, I_OnHookIO, - I_OnPreRehash, I_OnModuleRehash, I_OnSendWhoLine, I_OnChangeIdent, + I_OnPreRehash, I_OnModuleRehash, I_OnSendWhoLine, I_OnChangeIdent, I_OnSetUserIP, I_END }; @@ -1288,6 +1288,12 @@ class CoreExport Module : public classbase, public usecountbase * @param line The raw line to send; modifiable, if empty no line will be returned. */ virtual void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, std::string& line); + + /** Called whenever a local user's IP is set for the first time, or when a local user's IP changes due to + * a module like m_cgiirc changing it. + * @param user The user whose IP is being set + */ + virtual void OnSetUserIP(LocalUser* user); }; diff --git a/include/socket.h b/include/socket.h index 16809c3f8..e868af93e 100644 --- a/include/socket.h +++ b/include/socket.h @@ -146,7 +146,7 @@ namespace irc class CoreExport ListenSocket : public EventHandler { public: - const reference<ConfigTag> bind_tag; + reference<ConfigTag> bind_tag; std::string bind_addr; int bind_port; /** Human-readable bind description */ diff --git a/include/users.h b/include/users.h index 57dea3fa5..5a8864cdd 100644 --- a/include/users.h +++ b/include/users.h @@ -395,6 +395,8 @@ class CoreExport User : public Extensible */ bool SetClientIP(const char* sip); + void SetClientIP(const irc::sockets::sockaddrs& sa); + /** Constructor * @throw CoreException if the UID allocated to the user already exists */ @@ -819,6 +821,10 @@ class CoreExport LocalUser : public User, public InviteBase */ void SetClass(const std::string &explicit_name = ""); + bool SetClientIP(const char* sip); + + void SetClientIP(const irc::sockets::sockaddrs& sa); + void SendText(const std::string& line); void Write(const std::string& text); void Write(const char*, ...) CUSTOM_PRINTF(2, 3); diff --git a/src/commands/cmd_notice.cpp b/src/commands/cmd_notice.cpp index e10d6286d..b060a534f 100644 --- a/src/commands/cmd_notice.cpp +++ b/src/commands/cmd_notice.cpp @@ -110,6 +110,15 @@ CmdResult CommandNotice::Handle (const std::vector<std::string>& parameters, Use user->WriteNumeric(404, "%s %s :Cannot send to channel (+m)", user->nick.c_str(), chan->name.c_str()); return CMD_FAILURE; } + + if (ServerInstance->Config->RestrictBannedUsers) + { + if (chan->IsBanned(user)) + { + user->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", user->nick.c_str(), chan->name.c_str()); + return CMD_FAILURE; + } + } } ModResult MOD_RESULT; diff --git a/src/configreader.cpp b/src/configreader.cpp index b8796430b..37742cc9f 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -657,10 +657,14 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid) for (int Index = 0; Index * sizeof(Deprecated) < sizeof(ChangedConfig); Index++) { std::string dummy; - if (ConfValue(ChangedConfig[Index].tag)->readString(ChangedConfig[Index].value, dummy, true)) - errstr << "Your configuration contains a deprecated value: <" - << ChangedConfig[Index].tag << ":" << ChangedConfig[Index].value << "> - " << ChangedConfig[Index].reason - << " (at " << ConfValue(ChangedConfig[Index].tag)->getTagLocation() << ")\n"; + ConfigTagList tags = ConfTags(ChangedConfig[Index].tag); + for(ConfigIter i = tags.first; i != tags.second; ++i) + { + if (i->second->readString(ChangedConfig[Index].value, dummy, true)) + errstr << "Your configuration contains a deprecated value: <" + << ChangedConfig[Index].tag << ":" << ChangedConfig[Index].value << "> - " << ChangedConfig[Index].reason + << " (at " << i->second->getTagLocation() << ")\n"; + } } Fill(); diff --git a/src/modules.cpp b/src/modules.cpp index ccd78a8f0..075bbf85b 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -176,6 +176,7 @@ ModResult Module::OnNumeric(User*, unsigned int, const std::string&) { return MO void Module::OnHookIO(StreamSocket*, ListenSocket*) { } ModResult Module::OnAcceptConnection(int, ListenSocket*, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) { return MOD_RES_PASSTHRU; } void Module::OnSendWhoLine(User*, const std::vector<std::string>&, User*, std::string&) { } +void Module::OnSetUserIP(LocalUser*) { } ModuleManager::ModuleManager() : ModCount(0) { diff --git a/src/modules/extra/m_mysql.cpp b/src/modules/extra/m_mysql.cpp index 86d9273c3..570e7d9ec 100644 --- a/src/modules/extra/m_mysql.cpp +++ b/src/modules/extra/m_mysql.cpp @@ -503,7 +503,7 @@ void DispatcherThread::Run() */ this->LockQueue(); - if (Parent->qq.front().q == i.q) + if (!Parent->qq.empty() && Parent->qq.front().q == i.q) { Parent->qq.pop_front(); Parent->rq.push_back(RQueueItem(i.q, res)); diff --git a/src/modules/extra/m_regex_stdlib.cpp b/src/modules/extra/m_regex_stdlib.cpp new file mode 100644 index 000000000..4942e9739 --- /dev/null +++ b/src/modules/extra/m_regex_stdlib.cpp @@ -0,0 +1,112 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2012 ChrisTX <chris@rev-crew.info> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "inspircd.h" +#include "m_regex.h" +#include <regex> + +/* $ModDesc: Regex Provider Module for std::regex Regular Expressions */ +/* $ModConfig: <stdregex type="ecmascript"> + * Specify the Regular Expression engine to use here. Valid settings are + * bre, ere, awk, grep, egrep, ecmascript (default if not specified)*/ +/* $CompileFlags: -std=c++11 */ +/* $ModDep: m_regex.h */ + +class StdRegexException : public ModuleException +{ +public: + StdRegexException(const std::string& rx, const std::string& error) + : ModuleException(std::string("Error in regex ") + rx + ": " + error) + { + } +}; + +class StdRegex : public Regex +{ +private: + std::regex regexcl; +public: + StdRegex(const std::string& rx, std::regex::flag_type fltype) : Regex(rx) + { + try{ + regexcl.assign(rx, fltype | std::regex::optimize); + } + catch(std::regex_error rxerr) + { + throw StdRegexException(rx, rxerr.what()); + } + } + + virtual bool Matches(const std::string& text) + { + return std::regex_search(text, regexcl); + } +}; + +class StdRegexFactory : public RegexFactory +{ + public: + std::regex::flag_type regextype; + StdRegexFactory(Module* m) : RegexFactory(m, "regex/stdregex") {} + Regex* Create(const std::string& expr) + { + return new StdRegex(expr, regextype); + } +}; + +class ModuleRegexStd : public Module +{ +public: + StdRegexFactory ref; + ModuleRegexStd() : ref(this) { + ServerInstance->Modules->AddService(ref); + Implementation eventlist[] = { I_OnRehash }; + ServerInstance->Modules->Attach(eventlist, this, 1); + OnRehash(NULL); + } + + Version GetVersion() + { + return Version("Regex Provider Module for std::regex", VF_VENDOR); + } + + void OnRehash(User* u) + { + ConfigTag* Conf = ServerInstance->Config->ConfValue("stdregex"); + std::string regextype = Conf->getString("type", "ecmascript"); + + if(regextype == "bre") + ref.regextype = std::regex::basic; + else if(regextype == "ere") + ref.regextype = std::regex::extended; + else if(regextype == "awk") + ref.regextype = std::regex::awk; + else if(regextype == "grep") + ref.regextype = std::regex::grep; + else if(regextype == "egrep") + ref.regextype = std::regex::egrep; + else + { + if(regextype != "ecmascript") + ServerInstance->SNO->WriteToSnoMask('a', "WARNING: Non-existent regex engine '%s' specified. Falling back to ECMAScript.", regextype.c_str()); + ref.regextype = std::regex::ECMAScript; + } + } +}; + +MODULE_INIT(ModuleRegexStd) diff --git a/src/modules/m_blockamsg.cpp b/src/modules/m_blockamsg.cpp index 8160fcf54..c570e0a71 100644 --- a/src/modules/m_blockamsg.cpp +++ b/src/modules/m_blockamsg.cpp @@ -102,11 +102,7 @@ class ModuleBlockAmsg : public Module if (user->registered != REG_ALL) return MOD_RES_PASSTHRU; - // We want case insensitive command comparison. - // Add std::string contructor for irc::string :x - irc::string cmd = command.c_str(); - - if(validated && (cmd == "PRIVMSG" || cmd == "NOTICE") && (parameters.size() >= 2)) + if ((validated) && (parameters.size() >= 2) && ((command == "PRIVMSG") || (command == "NOTICE"))) { // parameters[0] should have the target(s) in it. // I think it will be faster to first check if there are any commas, and if there are then try and parse it out. diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp index 330c1b6c4..f47dc4b53 100644 --- a/src/modules/m_cgiirc.cpp +++ b/src/modules/m_cgiirc.cpp @@ -181,16 +181,10 @@ public: ServerInstance->Extensions.Register(&cmd.realip); ServerInstance->Extensions.Register(&cmd.webirc_hostname); ServerInstance->Extensions.Register(&cmd.webirc_ip); + ServerInstance->Extensions.Register(&waiting); - Implementation eventlist[] = { I_OnRehash, I_OnUserRegister, I_OnCheckReady, I_OnUserConnect }; - ServerInstance->Modules->Attach(eventlist, this, 4); - } - - void Prioritize() - { - ServerInstance->Modules->SetPriority(this, I_OnUserConnect, PRIORITY_FIRST); - Module* umodes = ServerInstance->Modules->Find("m_conn_umodes.so"); - ServerInstance->Modules->SetPriority(this, I_OnUserConnect, PRIORITY_BEFORE, &umodes); + Implementation eventlist[] = { I_OnRehash, I_OnUserRegister, I_OnCheckReady }; + ServerInstance->Modules->Attach(eventlist, this, 3); } void OnRehash(User* user) @@ -245,6 +239,32 @@ public: { if (waiting.get(user)) return MOD_RES_DENY; + + std::string *webirc_ip = cmd.webirc_ip.get(user); + if (!webirc_ip) + return MOD_RES_PASSTHRU; + + ServerInstance->Users->RemoveCloneCounts(user); + user->SetClientIP(webirc_ip->c_str()); + cmd.webirc_ip.unset(user); + + std::string* webirc_hostname = cmd.webirc_hostname.get(user); + if (webirc_hostname && webirc_hostname->length() < 64) + user->host = user->dhost = *webirc_hostname; + else + user->host = user->dhost = user->GetIPString(); + + user->InvalidateCache(); + cmd.webirc_hostname.unset(user); + + ServerInstance->Users->AddLocalClone(user); + ServerInstance->Users->AddGlobalClone(user); + user->SetClass(); + user->CheckClass(); + user->CheckLines(true); + if (user->quitting) + return MOD_RES_DENY; + return MOD_RES_PASSTHRU; } @@ -287,29 +307,6 @@ public: return MOD_RES_PASSTHRU; } - virtual void OnUserConnect(LocalUser* user) - { - std::string *webirc_hostname = cmd.webirc_hostname.get(user); - std::string *webirc_ip = cmd.webirc_ip.get(user); - if (!webirc_ip) - return; - ServerInstance->Users->RemoveCloneCounts(user); - user->SetClientIP(webirc_ip->c_str()); - user->InvalidateCache(); - if (webirc_hostname && webirc_hostname->length() < 64) - user->host = user->dhost = *webirc_hostname; - else - user->host = user->dhost = user->GetIPString(); - user->InvalidateCache(); - ServerInstance->Users->AddLocalClone(user); - ServerInstance->Users->AddGlobalClone(user); - user->SetClass(); - user->CheckClass(); - user->CheckLines(true); - cmd.webirc_ip.unset(user); - cmd.webirc_hostname.unset(user); - } - bool CheckPass(LocalUser* user) { if(IsValidHost(user->password)) diff --git a/src/modules/m_dnsbl.cpp b/src/modules/m_dnsbl.cpp index 2160b02dc..645949006 100644 --- a/src/modules/m_dnsbl.cpp +++ b/src/modules/m_dnsbl.cpp @@ -185,7 +185,7 @@ class DNSBLResolver : public Resolver break; } - ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s detected as being on a DNS blacklist (%s) with result %d", them->GetFullRealHost().c_str(), ConfEntry->domain.c_str(), (ConfEntry->type==DNSBLConfEntry::A_BITMASK) ? bitmask : record); + ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s%s detected as being on a DNS blacklist (%s) with result %d", them->nick.empty() ? "<unknown>" : "", them->GetFullRealHost().c_str(), ConfEntry->domain.c_str(), (ConfEntry->type==DNSBLConfEntry::A_BITMASK) ? bitmask : record); } else ConfEntry->stats_misses++; @@ -243,7 +243,7 @@ class ModuleDNSBL : public Module ReadConf(); ServerInstance->Modules->AddService(nameExt); ServerInstance->Modules->AddService(countExt); - Implementation eventlist[] = { I_OnRehash, I_OnUserInit, I_OnStats, I_OnSetConnectClass, I_OnCheckReady }; + Implementation eventlist[] = { I_OnRehash, I_OnSetUserIP, I_OnStats, I_OnSetConnectClass, I_OnCheckReady }; ServerInstance->Modules->Attach(eventlist, this, 5); } @@ -348,7 +348,7 @@ class ModuleDNSBL : public Module ReadConf(); } - void OnUserInit(LocalUser* user) + void OnSetUserIP(LocalUser* user) { if (user->exempt) return; diff --git a/src/modules/m_knock.cpp b/src/modules/m_knock.cpp index 8cd5088bc..97eb0e005 100644 --- a/src/modules/m_knock.cpp +++ b/src/modules/m_knock.cpp @@ -28,6 +28,8 @@ class CommandKnock : public Command { public: + bool sendnotice; + bool sendnumeric; CommandKnock(Module* Creator) : Command(Creator,"KNOCK", 2, 2) { syntax = "<channel> <reason>"; @@ -62,7 +64,12 @@ class CommandKnock : public Command return CMD_FAILURE; } - c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :User %s is KNOCKing on %s (%s)", c->name.c_str(), user->nick.c_str(), c->name.c_str(), parameters[1].c_str()); + if (sendnotice) + c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :User %s is KNOCKing on %s (%s)", c->name.c_str(), user->nick.c_str(), c->name.c_str(), parameters[1].c_str()); + + if (sendnumeric) + c->WriteChannelWithServ(ServerInstance->Config->ServerName, "710 %s %s %s :is KNOCKing: %s", c->name.c_str(), c->name.c_str(), user->GetFullHost().c_str(), parameters[1].c_str()); + user->WriteServ("NOTICE %s :KNOCKing on %s", user->nick.c_str(), c->name.c_str()); return CMD_SUCCESS; } @@ -92,11 +99,30 @@ class ModuleKnock : public Module throw ModuleException("Could not add new modes!"); ServerInstance->AddCommand(&cmd); + ServerInstance->Modules->Attach(I_OnRehash, this); + OnRehash(NULL); } - - virtual ~ModuleKnock() + void OnRehash(User* user) { + std::string knocknotify = ServerInstance->Config->ConfValue("knock")->getString("notify"); + irc::string notify(knocknotify.c_str()); + + if (notify == "numeric") + { + cmd.sendnotice = false; + cmd.sendnumeric = true; + } + else if (notify == "both") + { + cmd.sendnotice = true; + cmd.sendnumeric = true; + } + else + { + cmd.sendnotice = true; + cmd.sendnumeric = false; + } } virtual Version GetVersion() diff --git a/src/modules/m_shun.cpp b/src/modules/m_shun.cpp index 197bbc1bf..78046954c 100644 --- a/src/modules/m_shun.cpp +++ b/src/modules/m_shun.cpp @@ -215,6 +215,7 @@ class ModuleShun : public Module { ConfigReader MyConf; std::string cmds = MyConf.ReadValue("shun", "enabledcommands", 0); + std::transform(cmds.begin(), cmds.end(), cmds.begin(), ::toupper); if (cmds.empty()) cmds = "PING PONG QUIT"; diff --git a/src/modules/m_sslinfo.cpp b/src/modules/m_sslinfo.cpp index 22be27383..33a36d3b4 100644 --- a/src/modules/m_sslinfo.cpp +++ b/src/modules/m_sslinfo.cpp @@ -174,9 +174,7 @@ class ModuleSSLInfo : public Module ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) { - irc::string pcmd = command.c_str(); - - if ((pcmd == "OPER") && (validated)) + if ((command == "OPER") && (validated)) { OperIndex::iterator i = ServerInstance->Config->oper_blocks.find(parameters[0]); if (i != ServerInstance->Config->oper_blocks.end()) diff --git a/src/socket.cpp b/src/socket.cpp index 98ff3e00c..8c7ec97d8 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -105,6 +105,7 @@ int InspIRCd::BindPorts(FailedPortList &failed_ports) { if ((**n).bind_desc == bind_readable) { + (*n)->bind_tag = tag; // Replace tag, we know addr and port match, but other info (type, ssl) may not skip = true; old_ports.erase(n); break; diff --git a/src/socketengine.cpp b/src/socketengine.cpp index 72075dd49..ccaa71aed 100644 --- a/src/socketengine.cpp +++ b/src/socketengine.cpp @@ -208,7 +208,12 @@ int SocketEngine::SendTo(EventHandler* fd, const void *buf, size_t len, int flag int SocketEngine::Connect(EventHandler* fd, const sockaddr *serv_addr, socklen_t addrlen) { - return connect(fd->GetFd(), serv_addr, addrlen); + int ret = connect(fd->GetFd(), serv_addr, addrlen); +#ifdef WINDOWS + if ((ret == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK)) + errno = EINPROGRESS; +#endif + return ret; } int SocketEngine::Shutdown(EventHandler* fd, int how) diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 785d23625..d65f47128 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -66,16 +66,10 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs New->nick.assign(New->uuid, 0, ServerInstance->Config->Limits.NickMax); (*(this->clientlist))[New->nick] = New; - New->ident.assign("unknown"); - New->registered = REG_NONE; New->signon = ServerInstance->Time() + ServerInstance->Config->dns_timeout; New->lastping = 1; - /* Smarter than your average bear^H^H^H^Hset of strlcpys. */ - New->dhost.assign(New->GetIPString(), 0, 64); - New->host.assign(New->GetIPString(), 0, 64); - ServerInstance->Users->AddLocalClone(New); ServerInstance->Users->AddGlobalClone(New); diff --git a/src/users.cpp b/src/users.cpp index 6e282f7c0..f211f6b49 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -222,10 +222,22 @@ LocalUser::LocalUser(int myfd, irc::sockets::sockaddrs* client, irc::sockets::so bytes_in(0), bytes_out(0), cmds_in(0), cmds_out(0), nping(0), CommandFloodPenalty(0), already_sent(0) { + ident = "unknown"; lastping = 0; eh.SetFd(myfd); - memcpy(&client_sa, client, sizeof(irc::sockets::sockaddrs)); memcpy(&server_sa, servaddr, sizeof(irc::sockets::sockaddrs)); + + /* + * Initialize host and dhost here to the user's IP. + * It is important to do this before calling SetClientIP() + * as that can pass execution to modules that expect these + * fields to be valid. + */ + + int port; + irc::sockets::satoap(*client, host, port); + dhost = host; + SetClientIP(*client); } User::~User() @@ -980,10 +992,36 @@ irc::sockets::cidr_mask User::GetCIDRMask() bool User::SetClientIP(const char* sip) { - this->cachedip = ""; + cachedip.clear(); return irc::sockets::aptosa(sip, 0, client_sa); } +void User::SetClientIP(const irc::sockets::sockaddrs& sa) +{ + cachedip.clear(); + memcpy(&client_sa, &sa, sizeof(irc::sockets::sockaddrs)); +} + +bool LocalUser::SetClientIP(const char* sip) +{ + irc::sockets::sockaddrs sa; + if (!irc::sockets::aptosa(sip, 0, sa)) + // Invalid + return false; + + LocalUser::SetClientIP(sa); + return true; +} + +void LocalUser::SetClientIP(const irc::sockets::sockaddrs& sa) +{ + if (sa != client_sa) + { + User::SetClientIP(sa); + FOREACH_MOD(I_OnSetUserIP,OnSetUserIP(this)); + } +} + static std::string wide_newline("\r\n"); void User::Write(const std::string& text) |