]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_cloaking.cpp
Improved strhashcomp with no allocations
[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 using namespace std;
18
19 // Hostname cloaking (+x mode) module for inspircd.
20 // version 1.0.0.1 by brain (C. J. Edwards) Mar 2004.
21 //
22 // When loaded this module will automatically set the
23 // +x mode on all connecting clients.
24 //
25 // Setting +x on a client causes the module to change the
26 // dhost entry (displayed host) for each user who has the
27 // mode, cloaking their host. Unlike unreal, the algorithm
28 // is non-reversible as uncloaked hosts are passed along
29 // the server->server link, and all encoding of hosts is
30 // done locally on the server by this module.
31
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include "users.h"
37 #include "channels.h"
38 #include "modules.h"
39
40 /* $ModDesc: Provides masking of user hostnames */
41
42
43 /* The four core functions - F1 is optimized somewhat */
44
45 #define F1(x, y, z) (z ^ (x & (y ^ z)))
46 #define F2(x, y, z) F1(z, x, y)
47 #define F3(x, y, z) (x ^ y ^ z)
48 #define F4(x, y, z) (y ^ (x | ~z))
49 #define MD5STEP(f,w,x,y,z,in,s) (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
50
51 typedef unsigned long word32;
52 typedef unsigned char byte;
53
54 struct xMD5Context {
55         word32 buf[4];
56         word32 bytes[2];
57         word32 in[16];
58 };
59
60 class ModuleCloaking : public Module
61 {
62  private:
63
64         Server *Srv;
65         std::string prefix;
66         int key1;
67         int key2;
68         int key3;
69         int key4;
70
71         void byteSwap(word32 *buf, unsigned words)
72         {
73                 byte *p = (byte *)buf;
74         
75                 do
76                 {
77                         *buf++ = (word32)((unsigned)p[3] << 8 | p[2]) << 16 |
78                                 ((unsigned)p[1] << 8 | p[0]);
79                         p += 4;
80                 } while (--words);
81         }
82
83         void xMD5Init(struct xMD5Context *ctx)
84         {
85                 ctx->buf[0] = key1;
86                 ctx->buf[1] = key2;
87                 ctx->buf[2] = key3;
88                 ctx->buf[3] = key4;
89
90                 ctx->bytes[0] = 0;
91                 ctx->bytes[1] = 0;
92         }
93
94         void xMD5Update(struct xMD5Context *ctx, byte const *buf, int len)
95         {
96                 word32 t;
97
98                 /* Update byte count */
99
100                 t = ctx->bytes[0];
101                 if ((ctx->bytes[0] = t + len) < t)
102                         ctx->bytes[1]++;        /* Carry from low to high */
103
104                 t = 64 - (t & 0x3f);    /* Space available in ctx->in (at least 1) */
105                 if ((unsigned)t > (unsigned)len)
106                 {
107                         memcpy((byte *)ctx->in + 64 - (unsigned)t, buf, len);
108                         return;
109                 }
110                 /* First chunk is an odd size */
111                 memcpy((byte *)ctx->in + 64 - (unsigned)t, buf, (unsigned)t);
112                 byteSwap(ctx->in, 16);
113                 xMD5Transform(ctx->buf, ctx->in);
114                 buf += (unsigned)t;
115                 len -= (unsigned)t;
116
117                 /* Process data in 64-byte chunks */
118                 while (len >= 64)
119                 {
120                         memcpy(ctx->in, buf, 64);
121                         byteSwap(ctx->in, 16);
122                         xMD5Transform(ctx->buf, ctx->in);
123                         buf += 64;
124                         len -= 64;
125                 }
126
127                 /* Handle any remaining bytes of data. */
128                 memcpy(ctx->in, buf, len);
129         }
130
131         void xMD5Final(byte digest[16], struct xMD5Context *ctx)
132         {
133                 int count = (int)(ctx->bytes[0] & 0x3f); /* Bytes in ctx->in */
134                 byte *p = (byte *)ctx->in + count;      /* First unused byte */
135
136                 /* Set the first char of padding to 0x80.  There is always room. */
137                 *p++ = 0x80;
138
139                 /* Bytes of padding needed to make 56 bytes (-8..55) */
140                 count = 56 - 1 - count;
141
142                 if (count < 0)
143                 {       /* Padding forces an extra block */
144                         memset(p, 0, count+8);
145                         byteSwap(ctx->in, 16);
146                         xMD5Transform(ctx->buf, ctx->in);
147                         p = (byte *)ctx->in;
148                         count = 56;
149                 }
150                 memset(p, 0, count+8);
151                 byteSwap(ctx->in, 14);
152
153                 /* Append length in bits and transform */
154                 ctx->in[14] = ctx->bytes[0] << 3;
155                 ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
156                 xMD5Transform(ctx->buf, ctx->in);
157
158                 byteSwap(ctx->buf, 4);
159                 memcpy(digest, ctx->buf, 16);
160                 memset(ctx, 0, sizeof(ctx));
161         }
162
163         void xMD5Transform(word32 buf[4], word32 const in[16])
164         {
165                 register word32 a, b, c, d;
166
167                 a = buf[0];
168                 b = buf[1];
169                 c = buf[2];
170                 d = buf[3];
171
172                 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
173                 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
174                 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
175                 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
176                 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
177                 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
178                 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
179                 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
180                 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
181                 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
182                 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
183                 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
184                 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
185                 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
186                 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
187                 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
188
189                 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
190                 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
191                 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
192                 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
193                 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
194                 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
195                 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
196                 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
197                 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
198                 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
199                 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
200                 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
201                 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
202                 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
203                 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
204                 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
205
206                 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
207                 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
208                 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
209                 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
210                 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
211                 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
212                 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
213                 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
214                 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
215                 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
216                 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
217                 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
218                 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
219                 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
220                 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
221                 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
222
223                 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
224                 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
225                 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
226                 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
227                 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
228                 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
229                 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
230                 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
231                 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
232                 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
233                 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
234                 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
235                 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
236                 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
237                 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
238                 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
239
240                 buf[0] += a;
241                 buf[1] += b;
242                 buf[2] += c;
243                 buf[3] += d;
244         }
245
246
247         void MyMD5(void *dest, void *orig, int len)
248         {
249                 struct xMD5Context context;
250         
251                 xMD5Init(&context);
252                 xMD5Update(&context, (const unsigned char*)orig, len);
253                 xMD5Final((unsigned char*)dest, &context);
254         }
255
256
257         void GenHash(char* src, char* dest)
258         {
259                 // purposefully lossy md5 - only gives them the most significant 4 bits
260                 // of every md5 output byte.
261                 int i = 0;
262                 unsigned char bytes[16];
263                 char hash[MAXBUF];
264                 *hash = 0;
265                 MyMD5((char*)bytes,src,strlen(src));
266                 for (i = 0; i < 16; i++)
267                 {
268                         const char* xtab = "F92E45D871BCA630";
269                         unsigned char hi = xtab[bytes[i] / 16];
270                         char hx[2];
271                         hx[0] = hi;
272                         hx[1] = '\0';
273                         strlcat(hash,hx,MAXBUF);
274                 }
275                 strlcpy(dest,hash,MAXBUF);
276         }
277          
278  public:
279         ModuleCloaking(Server* Me)
280                 : Module::Module(Me)
281         {
282                 // We must take a copy of the Server class to work with
283                 Srv = Me;
284                 
285                 // we must create a new mode. Set the parameters so the
286                 // mode doesn't require oper, and is a client usermode
287                 // with no parameters (actually, you cant have params for a umode!)
288                 Srv->AddExtendedMode('x',MT_CLIENT,false,0,0);
289
290                 OnRehash("");
291         }
292         
293         virtual ~ModuleCloaking()
294         {
295         }
296         
297         virtual Version GetVersion()
298         {
299                 // returns the version number of the module to be
300                 // listed in /MODULES
301                 return Version(1,0,0,1,VF_STATIC|VF_VENDOR);
302         }
303
304         virtual void OnRehash(std::string parameter)
305         {
306                 ConfigReader* Conf = new ConfigReader();
307                 key1 = key2 = key3 = key4 = 0;
308                 key1 = Conf->ReadInteger("cloak","key1",0,false);
309                 key2 = Conf->ReadInteger("cloak","key2",0,false);
310                 key3 = Conf->ReadInteger("cloak","key3",0,false);
311                 key4 = Conf->ReadInteger("cloak","key4",0,false);
312                 prefix = Conf->ReadValue("cloak","prefix",0);
313                 if (prefix == "")
314                 {
315                         prefix = Srv->GetNetworkName();
316                 }
317                 if (!key1 && !key2 && !key3 && !key4)
318                 {
319                         ModuleException ex("You have not defined cloak keys for m_cloaking!!! THIS IS INSECURE AND SHOULD BE CHECKED!");
320                         throw (ex);
321                 }
322
323                 /*ctx->buf[0] = 0x67452301;
324                 ctx->buf[1] = 0xefcdab89;
325                 ctx->buf[2] = 0x98badcfe;
326                 ctx->buf[3] = 0x10325476;*/
327         }
328
329         void Implements(char* List)
330         {
331                 List[I_OnRehash] = List[I_OnExtendedMode] = List[I_OnUserConnect] = 1;
332         }
333         
334         virtual int OnExtendedMode(userrec* user, void* target, char modechar, int type, bool mode_on, string_list &params)
335         {
336                 // this method is called for any extended mode character.
337                 // all module modes for all modules pass through here
338                 // (unless another module further up the chain claims them)
339                 // so we must be VERY careful to only act upon modes which
340                 // we have claimed ourselves. This is a feature to allow
341                 // modules to 'spy' on extended mode activity if they so wish.
342                 if ((modechar == 'x') && (type == MT_CLIENT))
343                 {
344                         // OnExtendedMode gives us a void* as the target, we must cast
345                         // it into a userrec* or a chanrec* depending on the value of
346                         // the 'type' parameter (MT_CLIENT or MT_CHANNEL)
347                         userrec* dest = (userrec*)target;
348                         
349                         // we've now determined that this is our mode character...
350                         // is the user adding the mode to their list or removing it?
351                         if (mode_on)
352                         {
353                                 // the mode is being turned on - so attempt to
354                                 // allocate the user a cloaked host using a non-reversible
355                                 // algorithm (its simple, but its non-reversible so the
356                                 // simplicity doesnt really matter). This algorithm
357                                 // will not work if the user has only one level of domain
358                                 // naming in their hostname (e.g. if they are on a lan or
359                                 // are connecting via localhost) -- this doesnt matter much.
360                                 if (strchr(dest->host,'.'))
361                                 {
362                                         // in inspircd users have two hostnames. A displayed
363                                         // hostname which can be modified by modules (e.g.
364                                         // to create vhosts, implement chghost, etc) and a
365                                         // 'real' hostname which you shouldnt write to.
366                                         std::string a = strstr(dest->host,".");
367                                         char ra[64];
368                                         this->GenHash(dest->host,ra);
369                                         std::string b = "";
370                                         in_addr testaddr;
371                                         if (!inet_aton(dest->host,&testaddr))
372                                         {
373                                                 // if they have a hostname, make something appropriate
374                                                 b = prefix + "-" + std::string(ra) + a;
375                                         }
376                                         else
377                                         {
378                                                 // else, they have an ip
379                                                 b = std::string(ra) + "." + prefix + ".cloak";
380                                         }
381                                         Srv->Log(DEBUG,"cloak: allocated "+b);
382                                         Srv->ChangeHost(dest,b);
383                                 }
384                         }
385                         else
386                         {
387                                 // user is removing the mode, so just restore their real host
388                                 // and make it match the displayed one.
389                                 Srv->ChangeHost(dest,dest->host);
390                         }
391                         // this mode IS ours, and we have handled it. If we chose not to handle it,
392                         // for example the user cannot cloak as they have a vhost or such, then
393                         // we could return 0 here instead of 1 and the core would not send the mode
394                         // change to the user.
395                         return 1;
396                 }
397                 else
398                 {
399                         // this mode isn't ours, we have to bail and return 0 to not handle it.
400                         return 0;
401                 }
402         }
403
404         virtual void OnUserConnect(userrec* user)
405         {
406                 // Heres the weird bit. When a user connects we must set +x on them, so
407                 // we're going to use the SendMode method of the Server class to send
408                 // the mode to the client. This is basically the same as sending an
409                 // SAMODE in unreal. Note that to the user it will appear as if they set
410                 // the mode on themselves.
411                 
412                 char* modes[2];                 // only two parameters
413                 modes[0] = user->nick;          // first parameter is the nick
414                 modes[1] = "+x";                // second parameter is the mode
415                 Srv->SendMode(modes,2,user);    // send these, forming the command "MODE <nick> +x"
416         }
417
418 };
419
420 // stuff down here is the module-factory stuff. For basic modules you can ignore this.
421
422 class ModuleCloakingFactory : public ModuleFactory
423 {
424  public:
425         ModuleCloakingFactory()
426         {
427         }
428         
429         ~ModuleCloakingFactory()
430         {
431         }
432         
433         virtual Module * CreateModule(Server* Me)
434         {
435                 return new ModuleCloaking(Me);
436         }
437         
438 };
439
440
441 extern "C" void * init_module( void )
442 {
443         return new ModuleCloakingFactory;
444 }
445