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