]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/m_hostchange.cpp
Update copyright headers.
[user/henk/code/inspircd.git] / src / modules / m_hostchange.cpp
index a4d839fb16fa91cb72931fbce3fcd326e3f13347..365d0bcadf6344a8ee22116bfa318abeb34e26c4 100644 (file)
-/*       +------------------------------------+
- *       | Inspire Internet Relay Chat Daemon |
- *       +------------------------------------+
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
  *
- *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
- * See: http://www.inspircd.org/wiki/index.php/Credits
+ *   Copyright (C) 2013, 2018-2021 Sadie Powell <sadie@witchery.services>
+ *   Copyright (C) 2012-2014 Attila Molnar <attilamolnar@hush.com>
+ *   Copyright (C) 2012 Robby <robby@chatbelgie.be>
+ *   Copyright (C) 2009 Robin Burchell <robin+git@viroteck.net>
+ *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
+ *   Copyright (C) 2005-2007, 2010 Craig Edwards <brain@inspircd.org>
  *
- * This program is free but copyrighted software; see
- *            the file COPYING for details.
+ * 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 "wildcard.h"
 
-/* $ModDesc: Provides masking of user hostnames in a different way to m_cloaking */
+#include "inspircd.h"
+#include "modules/account.h"
 
-/** Holds information on a host set by m_hostchange
- */
-class Host : public classbase
+// Holds information about a <hostchange> rule.
+class HostRule
 {
  public:
-       std::string action;
-       std::string newhost;
-       std::string ports;
-};
+       enum HostChangeAction
+       {
+               // Add the user's account name to their hostname.
+               HCA_ADDACCOUNT,
 
-typedef std::map<std::string,Host*> hostchanges_t;
+               // Add the user's nickname to their hostname.
+               HCA_ADDNICK,
+
+               // Set the user's hostname to the specific value.
+               HCA_SET
+       };
 
-class ModuleHostChange : public Module
-{
  private:
-       hostchanges_t hostchanges;
-       std::string MySuffix;
-       std::string MyPrefix;
-       std::string MySeparator;
-        
+       HostChangeAction action;
+       std::string host;
+       std::string mask;
+       insp::flat_set<int> ports;
+       std::string prefix;
+       std::string suffix;
+
  public:
-       ModuleHostChange(InspIRCd* Me)
-               : Module(Me)
+       HostRule(const std::string& Mask, const std::string& Host, const insp::flat_set<int>& Ports)
+               : action(HCA_SET)
+               , host(Host)
+               , mask(Mask)
+               , ports(Ports)
        {
-               OnRehash(NULL,"");
-               Implementation eventlist[] = { I_OnRehash, I_OnUserConnect };
-               ServerInstance->Modules->Attach(eventlist, this, 2);
        }
-       
-       virtual ~ModuleHostChange()
+
+       HostRule(HostChangeAction Action, const std::string& Mask, const insp::flat_set<int>& Ports, const std::string& Prefix, const std::string& Suffix)
+               : action(Action)
+               , mask(Mask)
+               , ports(Ports)
+               , prefix(Prefix)
+               , suffix(Suffix)
        {
-               for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++)
-               {
-                       delete i->second;
-               }
-               hostchanges.clear();
        }
 
-       void Prioritize()
+       HostChangeAction GetAction() const
        {
-               Module* cloak = ServerInstance->Modules->Find("m_cloaking.so");
-               ServerInstance->Modules->SetPriority(this, I_OnUserConnect, PRIO_AFTER, &cloak);
+               return action;
        }
 
+       const std::string& GetHost() const
+       {
+               return host;
+       }
 
-       virtual void OnRehash(User* user, const std::string &parameter)
+       bool Matches(LocalUser* user) const
        {
-               ConfigReader Conf(ServerInstance);
-               MySuffix = Conf.ReadValue("host","suffix",0);
-               MyPrefix = Conf.ReadValue("host","prefix","",0);
-               MySeparator = Conf.ReadValue("host","separator",".",0);
-               for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++)
+               if (!ports.empty() && !ports.count(user->server_sa.port()))
+                       return false;
+
+               if (InspIRCd::MatchCIDR(user->MakeHost(), mask))
+                       return true;
+
+               return InspIRCd::MatchCIDR(user->MakeHostIP(), mask);
+       }
+
+       void Wrap(const std::string& value, std::string& out) const
+       {
+               if (!prefix.empty())
+                       out.append(prefix);
+
+               out.append(value);
+
+               if (!suffix.empty())
+                       out.append(suffix);
+       }
+};
+
+typedef std::vector<HostRule> HostRules;
+
+class ModuleHostChange : public Module
+{
+private:
+       std::bitset<UCHAR_MAX + 1> hostmap;
+       HostRules hostrules;
+
+       std::string CleanName(const std::string& name)
+       {
+               std::string buffer;
+               buffer.reserve(name.length());
+               for (std::string::const_iterator iter = name.begin(); iter != name.end(); ++iter)
                {
-                       delete i->second;
+                       if (hostmap.test(static_cast<unsigned char>(*iter)))
+                       {
+                               buffer.push_back(*iter);
+                       }
                }
-               hostchanges.clear();
-               for (int index = 0; index < Conf.Enumerate("hostchange"); index++)
+               return buffer;
+       }
+
+ public:
+       void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+       {
+               HostRules rules;
+
+               ConfigTagList tags = ServerInstance->Config->ConfTags("hostchange");
+               for (ConfigIter i = tags.first; i != tags.second; ++i)
                {
-                       std::string mask = Conf.ReadValue("hostchange", "mask", index);
-                       std::string ports = Conf.ReadValue("hosthange", "ports", index);
-                       std::string action = Conf.ReadValue("hostchange", "action", index);
-                       std::string newhost = Conf.ReadValue("hostchange", "value", index);
-                       Host* x = new Host;
-                       x->action = action;
-                       x->ports = ports;
-                       x->newhost = newhost;
-                       hostchanges[mask] = x;
+                       ConfigTag* tag = i->second;
+
+                       // Ensure that we have the <hostchange:mask> parameter.
+                       const std::string mask = tag->getString("mask");
+                       if (mask.empty())
+                               throw ModuleException("<hostchange:mask> is a mandatory field, at " + tag->getTagLocation());
+
+                       insp::flat_set<int> ports;
+                       const std::string portlist = tag->getString("ports");
+                       if (!portlist.empty())
+                       {
+                               irc::portparser portrange(portlist, false);
+                               while (int port = portrange.GetToken())
+                                       ports.insert(port);
+                       }
+
+                       // Determine what type of host rule this is.
+                       const std::string action = tag->getString("action");
+                       if (stdalgo::string::equalsci(action, "addaccount"))
+                       {
+                               // The hostname is in the format [prefix]<account>[suffix].
+                               rules.push_back(HostRule(HostRule::HCA_ADDACCOUNT, mask, ports, tag->getString("prefix"), tag->getString("suffix")));
+                       }
+                       else if (stdalgo::string::equalsci(action, "addnick"))
+                       {
+                               // The hostname is in the format [prefix]<nick>[suffix].
+                               rules.push_back(HostRule(HostRule::HCA_ADDNICK, mask, ports, tag->getString("prefix"), tag->getString("suffix")));
+                       }
+                       else if (stdalgo::string::equalsci(action, "set"))
+                       {
+                               // Ensure that we have the <hostchange:value> parameter.
+                               const std::string value = tag->getString("value");
+                               if (value.empty())
+                                       throw ModuleException("<hostchange:value> is a mandatory field when using the 'set' action, at " + tag->getTagLocation());
+
+                               // The hostname is in the format <value>.
+                               rules.push_back(HostRule(mask, value, ports));
+                               continue;
+                       }
+                       else
+                       {
+                               throw ModuleException(action + " is an invalid <hostchange:action> type, at " + tag->getTagLocation());
+                       }
                }
+
+               ConfigTag* tag = ServerInstance->Config->ConfValue("hostname");
+               const std::string hmap = tag->getString("charmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789", 1);
+
+               hostmap.reset();
+               for (std::string::const_iterator iter = hmap.begin(); iter != hmap.end(); ++iter)
+                       hostmap.set(static_cast<unsigned char>(*iter));
+               hostrules.swap(rules);
        }
-       
-       virtual Version GetVersion()
+
+       Version GetVersion() CXX11_OVERRIDE
        {
-               // returns the version number of the module to be
-               // listed in /MODULES
-               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+               return Version("Allows the server administrator to define custom rules for applying hostnames to users.", VF_VENDOR);
        }
-       
-       virtual void OnUserConnect(User* user)
+
+       void OnUserConnect(LocalUser* user) CXX11_OVERRIDE
        {
-               for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++)
+               for (HostRules::const_iterator iter = hostrules.begin(); iter != hostrules.end(); ++iter)
                {
-                       if (((match(user->MakeHost(),i->first.c_str(),true)) || (match(user->MakeHostIP(),i->first.c_str()))))
+                       const HostRule& rule = *iter;
+                       if (!rule.Matches(user))
+                               continue;
+
+                       std::string newhost;
+                       if (rule.GetAction() == HostRule::HCA_ADDACCOUNT)
+                       {
+                               // Retrieve the account name.
+                               const AccountExtItem* accountext = GetAccountExtItem();
+                               const std::string* accountptr = accountext ? accountext->get(user) : NULL;
+                               if (!accountptr)
+                                       continue;
+
+                               // Remove invalid hostname characters.
+                               std::string accountname = CleanName(*accountptr);
+                               if (accountname.empty())
+                                       continue;
+
+                               // Create the hostname.
+                               rule.Wrap(accountname, newhost);
+                       }
+                       else if (rule.GetAction() == HostRule::HCA_ADDNICK)
+                       {
+                               // Remove invalid hostname characters.
+                               const std::string nickname = CleanName(user->nick);
+                               if (nickname.empty())
+                                       continue;
+
+                               // Create the hostname.
+                               rule.Wrap(nickname, newhost);
+                       }
+                       else if (rule.GetAction() == HostRule::HCA_SET)
+                       {
+                               newhost.assign(rule.GetHost());
+                       }
+
+                       if (!newhost.empty())
                        {
-                               Host* h = i->second;
-
-                               if (!h->ports.empty())
-                               {
-                                       irc::portparser portrange(h->ports, false);
-                                       long portno = -1;
-                                       bool foundany = false;
-
-                                       while ((portno = portrange.GetToken()))
-                                               if (portno == user->GetPort())
-                                                       foundany = true;
-
-                                       if (!foundany)
-                                               continue;
-                               }
-
-                               // host of new user matches a hostchange tag's mask
-                               std::string newhost;
-                               if (h->action == "set")
-                               {
-                                       newhost = h->newhost;
-                               }
-                               else if (h->action == "suffix")
-                               {
-                                       newhost = MySuffix;
-                               }
-                               else if (h->action == "addnick")
-                               {
-                                       // first take their nick and strip out non-dns, leaving just [A-Z0-9\-]
-                                       std::string complete;
-                                       std::string old = user->nick;
-                                       for (unsigned int j = 0; j < old.length(); j++)
-                                       {
-                                               if  (((old[j] >= 'A') && (old[j] <= 'Z')) ||
-                                                   ((old[j] >= 'a') && (old[j] <= 'z')) ||
-                                                   ((old[j] >= '0') && (old[j] <= '9')) ||
-                                                   (old[j] == '-'))
-                                               {
-                                                       complete = complete + old[j];
-                                               }
-                                       }
-                                       if (complete.empty())
-                                               complete = "i-have-a-lame-nick";
-                                               
-                                       if (!MyPrefix.empty())
-                                               newhost = MyPrefix + MySeparator + complete;
-                                       else
-                                               newhost = complete + MySeparator + MySuffix;
-                               }
-                               if (!newhost.empty())
-                               {
-                                       user->WriteServ("NOTICE "+std::string(user->nick)+" :Setting your virtual host: " + newhost);
-                                       if (!user->ChangeDisplayedHost(newhost.c_str()))
-                                               user->WriteServ("NOTICE "+std::string(user->nick)+" :Could not set your virtual host: " + newhost);
-                                       return;
-                               }
+                               user->WriteNotice("Setting your virtual host: " + newhost);
+                               if (!user->ChangeDisplayedHost(newhost))
+                                       user->WriteNotice("Could not set your virtual host: " + newhost);
+                               return;
                        }
                }
        }