]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_hostchange.cpp
Update copyright headers.
[user/henk/code/inspircd.git] / src / modules / m_hostchange.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2013, 2018-2021 Sadie Powell <sadie@witchery.services>
5  *   Copyright (C) 2012-2014 Attila Molnar <attilamolnar@hush.com>
6  *   Copyright (C) 2012 Robby <robby@chatbelgie.be>
7  *   Copyright (C) 2009 Robin Burchell <robin+git@viroteck.net>
8  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
9  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
10  *   Copyright (C) 2005-2007, 2010 Craig Edwards <brain@inspircd.org>
11  *
12  * This file is part of InspIRCd.  InspIRCd is free software: you can
13  * redistribute it and/or modify it under the terms of the GNU General Public
14  * License as published by the Free Software Foundation, version 2.
15  *
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
19  * details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24
25
26 #include "inspircd.h"
27 #include "modules/account.h"
28
29 // Holds information about a <hostchange> rule.
30 class HostRule
31 {
32  public:
33         enum HostChangeAction
34         {
35                 // Add the user's account name to their hostname.
36                 HCA_ADDACCOUNT,
37
38                 // Add the user's nickname to their hostname.
39                 HCA_ADDNICK,
40
41                 // Set the user's hostname to the specific value.
42                 HCA_SET
43         };
44
45  private:
46         HostChangeAction action;
47         std::string host;
48         std::string mask;
49         insp::flat_set<int> ports;
50         std::string prefix;
51         std::string suffix;
52
53  public:
54         HostRule(const std::string& Mask, const std::string& Host, const insp::flat_set<int>& Ports)
55                 : action(HCA_SET)
56                 , host(Host)
57                 , mask(Mask)
58                 , ports(Ports)
59         {
60         }
61
62         HostRule(HostChangeAction Action, const std::string& Mask, const insp::flat_set<int>& Ports, const std::string& Prefix, const std::string& Suffix)
63                 : action(Action)
64                 , mask(Mask)
65                 , ports(Ports)
66                 , prefix(Prefix)
67                 , suffix(Suffix)
68         {
69         }
70
71         HostChangeAction GetAction() const
72         {
73                 return action;
74         }
75
76         const std::string& GetHost() const
77         {
78                 return host;
79         }
80
81         bool Matches(LocalUser* user) const
82         {
83                 if (!ports.empty() && !ports.count(user->server_sa.port()))
84                         return false;
85
86                 if (InspIRCd::MatchCIDR(user->MakeHost(), mask))
87                         return true;
88
89                 return InspIRCd::MatchCIDR(user->MakeHostIP(), mask);
90         }
91
92         void Wrap(const std::string& value, std::string& out) const
93         {
94                 if (!prefix.empty())
95                         out.append(prefix);
96
97                 out.append(value);
98
99                 if (!suffix.empty())
100                         out.append(suffix);
101         }
102 };
103
104 typedef std::vector<HostRule> HostRules;
105
106 class ModuleHostChange : public Module
107 {
108 private:
109         std::bitset<UCHAR_MAX + 1> hostmap;
110         HostRules hostrules;
111
112         std::string CleanName(const std::string& name)
113         {
114                 std::string buffer;
115                 buffer.reserve(name.length());
116                 for (std::string::const_iterator iter = name.begin(); iter != name.end(); ++iter)
117                 {
118                         if (hostmap.test(static_cast<unsigned char>(*iter)))
119                         {
120                                 buffer.push_back(*iter);
121                         }
122                 }
123                 return buffer;
124         }
125
126  public:
127         void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
128         {
129                 HostRules rules;
130
131                 ConfigTagList tags = ServerInstance->Config->ConfTags("hostchange");
132                 for (ConfigIter i = tags.first; i != tags.second; ++i)
133                 {
134                         ConfigTag* tag = i->second;
135
136                         // Ensure that we have the <hostchange:mask> parameter.
137                         const std::string mask = tag->getString("mask");
138                         if (mask.empty())
139                                 throw ModuleException("<hostchange:mask> is a mandatory field, at " + tag->getTagLocation());
140
141                         insp::flat_set<int> ports;
142                         const std::string portlist = tag->getString("ports");
143                         if (!portlist.empty())
144                         {
145                                 irc::portparser portrange(portlist, false);
146                                 while (int port = portrange.GetToken())
147                                         ports.insert(port);
148                         }
149
150                         // Determine what type of host rule this is.
151                         const std::string action = tag->getString("action");
152                         if (stdalgo::string::equalsci(action, "addaccount"))
153                         {
154                                 // The hostname is in the format [prefix]<account>[suffix].
155                                 rules.push_back(HostRule(HostRule::HCA_ADDACCOUNT, mask, ports, tag->getString("prefix"), tag->getString("suffix")));
156                         }
157                         else if (stdalgo::string::equalsci(action, "addnick"))
158                         {
159                                 // The hostname is in the format [prefix]<nick>[suffix].
160                                 rules.push_back(HostRule(HostRule::HCA_ADDNICK, mask, ports, tag->getString("prefix"), tag->getString("suffix")));
161                         }
162                         else if (stdalgo::string::equalsci(action, "set"))
163                         {
164                                 // Ensure that we have the <hostchange:value> parameter.
165                                 const std::string value = tag->getString("value");
166                                 if (value.empty())
167                                         throw ModuleException("<hostchange:value> is a mandatory field when using the 'set' action, at " + tag->getTagLocation());
168
169                                 // The hostname is in the format <value>.
170                                 rules.push_back(HostRule(mask, value, ports));
171                                 continue;
172                         }
173                         else
174                         {
175                                 throw ModuleException(action + " is an invalid <hostchange:action> type, at " + tag->getTagLocation());
176                         }
177                 }
178
179                 ConfigTag* tag = ServerInstance->Config->ConfValue("hostname");
180                 const std::string hmap = tag->getString("charmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789", 1);
181
182                 hostmap.reset();
183                 for (std::string::const_iterator iter = hmap.begin(); iter != hmap.end(); ++iter)
184                         hostmap.set(static_cast<unsigned char>(*iter));
185                 hostrules.swap(rules);
186         }
187
188         Version GetVersion() CXX11_OVERRIDE
189         {
190                 return Version("Allows the server administrator to define custom rules for applying hostnames to users.", VF_VENDOR);
191         }
192
193         void OnUserConnect(LocalUser* user) CXX11_OVERRIDE
194         {
195                 for (HostRules::const_iterator iter = hostrules.begin(); iter != hostrules.end(); ++iter)
196                 {
197                         const HostRule& rule = *iter;
198                         if (!rule.Matches(user))
199                                 continue;
200
201                         std::string newhost;
202                         if (rule.GetAction() == HostRule::HCA_ADDACCOUNT)
203                         {
204                                 // Retrieve the account name.
205                                 const AccountExtItem* accountext = GetAccountExtItem();
206                                 const std::string* accountptr = accountext ? accountext->get(user) : NULL;
207                                 if (!accountptr)
208                                         continue;
209
210                                 // Remove invalid hostname characters.
211                                 std::string accountname = CleanName(*accountptr);
212                                 if (accountname.empty())
213                                         continue;
214
215                                 // Create the hostname.
216                                 rule.Wrap(accountname, newhost);
217                         }
218                         else if (rule.GetAction() == HostRule::HCA_ADDNICK)
219                         {
220                                 // Remove invalid hostname characters.
221                                 const std::string nickname = CleanName(user->nick);
222                                 if (nickname.empty())
223                                         continue;
224
225                                 // Create the hostname.
226                                 rule.Wrap(nickname, newhost);
227                         }
228                         else if (rule.GetAction() == HostRule::HCA_SET)
229                         {
230                                 newhost.assign(rule.GetHost());
231                         }
232
233                         if (!newhost.empty())
234                         {
235                                 user->WriteNotice("Setting your virtual host: " + newhost);
236                                 if (!user->ChangeDisplayedHost(newhost))
237                                         user->WriteNotice("Could not set your virtual host: " + newhost);
238                                 return;
239                         }
240                 }
241         }
242 };
243
244 MODULE_INIT(ModuleHostChange)