]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_cloaking.cpp
b4cb90aa208eaaa743c896e77fdbd2ed7974e81d
[user/henk/code/inspircd.git] / src / modules / m_cloaking.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
6  *                       E-mail:
7  *                <brain@chatspike.net>
8  *                <Craig@chatspike.net>
9  *     
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *            the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 #include "inspircd_config.h"
18 #include "configreader.h"
19 #include "inspircd.h"
20 #include "users.h"
21 #include "channels.h"
22 #include "modules.h"
23
24 #include "m_md5.h"
25
26 /* $ModDesc: Provides masking of user hostnames */
27 /* $ModDep: m_md5.h */
28
29 static const char* xtab[] = {"F92E45D871BCA630", "A1B9D80C72E653F4", "1ABC078934DEF562", "ABCDEF5678901234"};
30
31 /** Handles user mode +x
32  */
33 class CloakUser : public ModeHandler
34 {
35         
36         std::string prefix;
37         unsigned int key1;
38         unsigned int key2;
39         unsigned int key3;
40         unsigned int key4;
41         Module* Sender;
42         Module* MD5Provider;
43         
44  public:
45         CloakUser(InspIRCd* Instance, Module* Source, Module* MD5) : ModeHandler(Instance, 'x', 0, 0, false, MODETYPE_USER, false), Sender(Source), MD5Provider(MD5)
46         {
47         }
48
49         ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
50         {
51                 /* Only opers can change other users modes */
52                 if ((source != dest) && (!*source->oper))
53                         return MODEACTION_DENY;
54
55                 /* For remote clients, we dont take any action, we just allow it.
56                  * The local server where they are will set their cloak instead.
57                  */
58                 if (!IS_LOCAL(dest))
59                         return MODEACTION_ALLOW;
60
61                 if (adding)
62                 {
63                         if(!dest->IsModeSet('x'))
64                         {
65                                 /* The mode is being turned on - so attempt to
66                                  * allocate the user a cloaked host using a non-reversible
67                                  * algorithm (its simple, but its non-reversible so the
68                                  * simplicity doesnt really matter). This algorithm
69                                  * will not work if the user has only one level of domain
70                                  * naming in their hostname (e.g. if they are on a lan or
71                                  * are connecting via localhost) -- this doesnt matter much.
72                                  */
73                         
74                                 if (strchr(dest->host,'.') || strchr(dest->host,':'))
75                                 {
76                                         /* InspIRCd users have two hostnames; A displayed
77                                          * hostname which can be modified by modules (e.g.
78                                          * to create vhosts, implement chghost, etc) and a
79                                          * 'real' hostname which you shouldnt write to.
80                                          */
81
82                                         char* n = strstr(dest->host,".");
83                                         if (!n)
84                                                 n = strstr(dest->host,":");
85
86                                         std::string a = n;
87
88                                         std::string b;
89                                         insp_inaddr testaddr;
90                                         std::string hostcloak = prefix + "-" + MD5SumRequest(Sender, MD5Provider, dest->host).Send() + a;
91                                 
92                                         /* Fix by brain - if the cloaked host is > the max length of a host (64 bytes
93                                          * according to the DNS RFC) then tough titty, they get cloaked as an IP. 
94                                          * Their ISP shouldnt go to town on subdomains, or they shouldnt have a kiddie
95                                          * vhost.
96                                          */
97
98                                         if ((insp_aton(dest->host,&testaddr) < 1) && (hostcloak.length() <= 64))
99                                         {
100                                                 // if they have a hostname, make something appropriate
101                                                 b = hostcloak;
102                                         }
103                                         else
104                                         {
105                                                 b = ((b.find(':') == std::string::npos) ? Cloak4(dest->host) : Cloak6(dest->host));
106                                         }
107                                         ServerInstance->Log(DEBUG,"cloak: allocated "+b);
108                                         dest->ChangeDisplayedHost(b.c_str());
109                                 }
110                                 
111                                 dest->SetMode('x',true);
112                                 return MODEACTION_ALLOW;
113                         }
114                 }
115                 else
116                 {
117                         if (dest->IsModeSet('x'))
118                         {
119                                 /* User is removing the mode, so just restore their real host
120                                  * and make it match the displayed one.
121                                  */
122                                 dest->ChangeDisplayedHost(dest->host);
123                                 dest->SetMode('x',false);
124                                 return MODEACTION_ALLOW;
125                         }
126                 }
127
128                 return MODEACTION_DENY;
129         }
130
131         std::string Cloak4(const char* ip)
132         {
133                 unsigned int iv[] = { key1, key2, key3, key4 };
134                 irc::sepstream seps(ip, '.');
135                 std::string ra1, ra2, ra3, ra4;
136                 int i1, i2, i3, i4;
137                 std::string octet1 = seps.GetToken();
138                 std::string octet2 = seps.GetToken();
139                 std::string octet3 = seps.GetToken();
140                 std::string octet4 = seps.GetToken();
141                 i1 = atoi(octet1.c_str());
142                 i2 = atoi(octet2.c_str());
143                 i3 = atoi(octet3.c_str());
144                 i4 = atoi(octet4.c_str());
145                 octet4 = octet1 + "." + octet2 + "." + octet3 + "." + octet4;
146                 octet3 = octet1 + "." + octet2 + "." + octet3;
147                 octet2 = octet1 + "." + octet2;
148
149                 MD5ResetRequest(Sender, MD5Provider).Send();
150                 MD5KeyRequest(Sender, MD5Provider, iv).Send();
151
152                 MD5HexRequest(Sender, MD5Provider, xtab[(key1+i1) % 4]).Send();
153                 ra1 = std::string(MD5SumRequest(Sender, MD5Provider, octet1).Send()).substr(0,6);
154
155                 MD5HexRequest(Sender, MD5Provider, xtab[(key2+i2) % 4]).Send();
156                 ra2 = std::string(MD5SumRequest(Sender, MD5Provider, octet2).Send()).substr(0,6);
157
158                 MD5HexRequest(Sender, MD5Provider, xtab[(key3+i3) % 4]).Send();
159                 ra3 = std::string(MD5SumRequest(Sender, MD5Provider, octet3).Send()).substr(0,6);
160
161                 MD5HexRequest(Sender, MD5Provider, xtab[(key4+i4) % 4]).Send();
162                 ra4 = std::string(MD5SumRequest(Sender, MD5Provider, octet4).Send()).substr(0,6);
163
164                 /* This is safe as we know the length generated by our genhash is always 16 */
165                 return std::string().append(ra1).append(".").append(ra2).append(".").append(ra3).append(".").append(ra4);
166         }
167
168         std::string Cloak6(const char* ip)
169         {
170                 unsigned int iv[] = { key1, key2, key3, key4 };
171                 std::vector<std::string> hashies;
172                 std::string item = "";
173                 int rounds = 0;
174
175                 MD5ResetRequest(Sender, MD5Provider).Send();
176                 MD5KeyRequest(Sender, MD5Provider, iv).Send();
177
178                 for (const char* input = ip; *input; input++)
179                 {
180                         item += *input;
181                         if (item.length() > 5)
182                         {
183                                 MD5HexRequest(Sender, MD5Provider, xtab[(key1+rounds) % 4]).Send();
184                                 hashies.push_back(std::string(MD5SumRequest(Sender, MD5Provider, item).Send()).substr(0,10));
185                                 item = "";
186                         }
187                         rounds++;
188                 }
189                 if (!item.empty())
190                 {
191                         MD5HexRequest(Sender, MD5Provider, xtab[(key1+rounds) % 4]).Send();
192                         hashies.push_back(std::string(MD5SumRequest(Sender, MD5Provider, item).Send()).substr(0,10));
193                         item = "";
194                 }
195                 return irc::stringjoiner(":", hashies, 0, hashies.size() - 1).GetJoined();
196         }
197
198         /* XXX: Uncomment and call to use the test suite
199         void TestSuite()
200         {
201                 printf("%s %s\n", "192.168.1.1", Cloak4("192.168.1.1").c_str());
202                 printf("%s %s\n", "192.168.1.2", Cloak4("192.168.1.2").c_str());
203                 printf("%s %s\n", "192.168.10.1", Cloak4("192.168.10.1").c_str());
204                 printf("%s %s\n", "192.168.10.1", Cloak4("192.168.10.2").c_str());
205                 printf("%s %s\n", "192.169.1.1", Cloak4("192.169.1.1").c_str());
206                 printf("%s %s\n", "192.169.2.1", Cloak4("192.169.2.1").c_str());
207                 printf("%s %s\n", "200.168.1.1", Cloak4("200.168.1.1").c_str());
208                 printf("%s %s\n", "200.168.1.3", Cloak4("200.168.1.3").c_str());
209                 printf("%s %s\n", "200.168.3.3", Cloak4("200.168.3.3").c_str());
210                 printf("%s %s\n", "200.169.4.3", Cloak4("200.169.4.3").c_str());
211                 printf("---\n");
212                 printf("%s %s\n", "9a05:2f00:3f11::5f12::1", Cloak6("9a05:2f00:3f11::5f12::1").c_str());
213                 printf("%s %s\n", "9a05:2f00:3f11::5f12::2", Cloak6("9a05:2f00:3f11::5f12::2").c_str());
214                 printf("%s %s\n", "9a05:2f00:3f11::5a12::1", Cloak6("9a05:2f00:3f11::5a12::1").c_str());
215                 printf("%s %s\n", "9a05:2f00:3f11::5a12::2", Cloak6("9a05:2f00:3f11::5a12::2").c_str());
216                 printf("%s %s\n", "9a05:3f01:3f11::5f12::1", Cloak6("9a05:3f01:3f11::5f12::1").c_str());
217                 printf("%s %s\n", "9a05:4f00:3f11::5f13::2", Cloak6("9a05:4f00:3f11::5f13::2").c_str());
218                 printf("%s %s\n", "ffff:2f00:3f11::5f12::1", Cloak6("ffff:2f00:3f11::5f12::1").c_str());
219                 printf("%s %s\n", "ffff:2f00:3f11::5f13::2", Cloak6("ffff:2f00:3f11::5f13::2").c_str());
220                 exit(0);
221         }
222         */
223         
224         void DoRehash()
225         {
226                 ConfigReader Conf(ServerInstance);
227                 key1 = key2 = key3 = key4 = 0;
228                 key1 = Conf.ReadInteger("cloak","key1",0,false);
229                 key2 = Conf.ReadInteger("cloak","key2",0,false);
230                 key3 = Conf.ReadInteger("cloak","key3",0,false);
231                 key4 = Conf.ReadInteger("cloak","key4",0,false);
232                 
233                 prefix = Conf.ReadValue("cloak","prefix",0);
234                 if (prefix == "")
235                 {
236                         prefix = ServerInstance->Config->Network;
237                 }
238                 if (!key1 && !key2 && !key3 && !key4)
239                 {
240                         ModuleException ex("You have not defined cloak keys for m_cloaking!!! THIS IS INSECURE AND SHOULD BE CHECKED!");
241                         throw (ex);
242                 }
243         }
244 };
245
246
247 class ModuleCloaking : public Module
248 {
249  private:
250         
251         CloakUser* cu;
252         Module* MD5Module;
253
254  public:
255         ModuleCloaking(InspIRCd* Me)
256                 : Module::Module(Me)
257         {
258                 MD5Module = ServerInstance->FindModule("m_md5.so");
259                 if (!MD5Module)
260                         throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_cloaking.so.");
261
262                 /* Create new mode handler object */
263                 cu = new CloakUser(ServerInstance, this, MD5Module);
264
265                 /* Register it with the core */         
266                 ServerInstance->AddMode(cu, 'x');
267
268                 OnRehash("");
269         }
270         
271         virtual ~ModuleCloaking()
272         {
273                 ServerInstance->Modes->DelMode(cu);
274                 DELETE(cu);
275         }
276         
277         virtual Version GetVersion()
278         {
279                 // returns the version number of the module to be
280                 // listed in /MODULES
281                 return Version(1,1,0,2,VF_COMMON|VF_VENDOR,API_VERSION);
282         }
283
284         virtual void OnRehash(const std::string &parameter)
285         {
286                 cu->DoRehash();
287         }
288
289         void Implements(char* List)
290         {
291                 List[I_OnRehash] = 1;
292         }
293 };
294
295 // stuff down here is the module-factory stuff. For basic modules you can ignore this.
296
297 class ModuleCloakingFactory : public ModuleFactory
298 {
299  public:
300         ModuleCloakingFactory()
301         {
302         }
303         
304         ~ModuleCloakingFactory()
305         {
306         }
307         
308         virtual Module * CreateModule(InspIRCd* Me)
309         {
310                 return new ModuleCloaking(Me);
311         }
312         
313 };
314
315
316 extern "C" void * init_module( void )
317 {
318         return new ModuleCloakingFactory;
319 }