]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_dnsbl.cpp
Remove a large portion of commented craq, and make this fit in better with the rest...
[user/henk/code/inspircd.git] / src / modules / m_dnsbl.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18 #include <stdint.h>
19 #include "inspircd.h"
20 #include "xline.h"
21 #include "dns.h"
22 #include "users.h"
23 #include "channels.h"
24 #include "modules.h"
25
26 /* $ModDesc: Provides handling of DNS blacklists */
27
28 /* Class holding data for a single entry */
29 class DNSBLConfEntry
30 {
31         public:
32                 enum EnumBanaction { I_UNKNOWN, I_KILL, I_ZLINE, I_KLINE, I_GLINE };
33                 std::string name, domain, reason;
34                 EnumBanaction banaction;
35                 long duration;
36                 int bitmask;
37                 unsigned long stats_hits, stats_misses;
38                 DNSBLConfEntry(): duration(86400),bitmask(0),stats_hits(0), stats_misses(0) {}
39                 ~DNSBLConfEntry() { }
40 };
41
42
43 /** Resolver for CGI:IRC hostnames encoded in ident/GECOS
44  */
45 class DNSBLResolver : public Resolver
46 {
47         int theirfd;
48         userrec* them;
49         DNSBLConfEntry *ConfEntry;
50
51     public:
52         DNSBLResolver(Module *me, InspIRCd *ServerInstance, const std::string &hostname, userrec* u, int userfd, DNSBLConfEntry *conf, bool &cached)
53                 : Resolver(ServerInstance, hostname, DNS_QUERY_A, cached, me)
54         {
55                 theirfd = userfd;
56                 them = u;
57                 ConfEntry = conf;
58         }
59
60         virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
61         {
62                 /* Check the user still exists */
63                 if ((them) && (them == ServerInstance->SE->GetRef(theirfd)))
64                 {
65                         // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d
66                         if(result.length())
67                         {
68                                 unsigned int bitmask = 0;
69                                 bool show = false;
70                                 in_addr resultip;
71
72                                 /* Convert the result to an in_addr (we can gaurantee we got ipv4)
73                                  * Whoever did the loop that was here before, I AM CONFISCATING
74                                  * YOUR CRACKPIPE. you know who you are. -- Brain
75                                  */
76                                 inet_aton(result.c_str(), &resultip);
77                                 bitmask = resultip.s_addr >> 24; /* Last octet (network byte order */
78
79                                 bitmask &= ConfEntry->bitmask;
80
81                                 if (bitmask != 0)
82                                 {
83                                         std::string reason = ConfEntry->reason;
84                                         std::string::size_type x = reason.find("%ip%");
85                                         while (x != std::string::npos)
86                                         {
87                                                 reason.erase(x, 4);
88                                                 reason.insert(x, them->GetIPString());
89                                                 x = reason.find("%ip%");
90                                         }
91
92                                         ConfEntry->stats_hits++;
93
94                                         switch (ConfEntry->banaction)
95                                         {
96                                                 case DNSBLConfEntry::I_KILL:
97                                                 {
98                                                         userrec::QuitUser(ServerInstance, them, std::string("Killed (") + reason + ")");
99                                                         break;
100                                                 }
101                                                 case DNSBLConfEntry::I_KLINE:
102                                                 {
103                                                         std::string ban = std::string("*@") + them->GetIPString();
104                                                         show = ServerInstance->XLines->add_kline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), ban.c_str());
105                                                         FOREACH_MOD(I_OnAddKLine,OnAddKLine(ConfEntry->duration, NULL, reason, ban));
106                                                         break;
107                                                 }
108                                                 case DNSBLConfEntry::I_GLINE:
109                                                 {
110                                                         std::string ban = std::string("*@") + them->GetIPString();
111                                                         show = ServerInstance->XLines->add_gline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), ban.c_str());
112                                                         FOREACH_MOD(I_OnAddGLine,OnAddGLine(ConfEntry->duration, NULL, reason, ban));
113                                                         break;
114                                                 }
115                                                 case DNSBLConfEntry::I_ZLINE:
116                                                 {
117                                                         show = ServerInstance->XLines->add_zline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), them->GetIPString());
118                                                         FOREACH_MOD(I_OnAddZLine,OnAddZLine(ConfEntry->duration, NULL, reason, them->GetIPString()));
119                                                         break;
120                                                 }
121                                                 case DNSBLConfEntry::I_UNKNOWN:
122                                                 {
123                                                         break;
124                                                 }
125                                                 break;
126                                         }
127
128                                         if (show)
129                                                 ServerInstance->WriteOpers("*** Connecting user %s detected as being on a DNS blacklist (%s) with result %d", them->GetFullRealHost(), ConfEntry->name.c_str(), bitmask);
130                                 }
131                                 else
132                                         ConfEntry->stats_misses++;
133                         }
134                         else
135                                 ConfEntry->stats_misses++;
136                 }
137         }
138
139         virtual void OnError(ResolverError e, const std::string &errormessage)
140         {
141         }
142
143         virtual ~DNSBLResolver()
144         {
145         }
146 };
147
148 class ModuleDNSBL : public Module
149 {
150  private:
151         std::vector<DNSBLConfEntry *> DNSBLConfEntries;
152
153         /*
154          *      Convert a string to EnumBanaction
155          */
156         DNSBLConfEntry::EnumBanaction str2banaction(const std::string &action)
157         {
158                 if(action.compare("KILL")==0)
159                         return DNSBLConfEntry::I_KILL;
160                 if(action.compare("KLINE")==0)
161                         return DNSBLConfEntry::I_KLINE;
162                 if(action.compare("ZLINE")==0)
163                         return DNSBLConfEntry::I_ZLINE;
164                 if(action.compare("GLINE")==0)
165                         return DNSBLConfEntry::I_GLINE;
166
167                 return DNSBLConfEntry::I_UNKNOWN;
168         }
169  public:
170         ModuleDNSBL(InspIRCd *Me) : Module::Module(Me)
171         {
172                 ReadConf();
173         }
174
175         virtual ~ModuleDNSBL()
176         {
177                 ClearEntries();
178         }
179
180         virtual Version GetVersion()
181         {
182                 return Version(2, 0, 0, 1, VF_VENDOR, API_VERSION);
183         }
184
185         void Implements(char* List)
186         {
187                 List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnStats] = 1;
188         }
189
190         /** Clear entries and free the mem it was using
191          */
192         void ClearEntries()
193         {
194                 std::vector<DNSBLConfEntry *>::iterator i;
195                 for (std::vector<DNSBLConfEntry *>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)
196                         delete *i;
197                 DNSBLConfEntries.clear();
198         }
199
200         /** Fill our conf vector with data
201          */
202         virtual void ReadConf()
203         {
204                 ConfigReader *MyConf = new ConfigReader(ServerInstance);
205                 ClearEntries();
206
207                 for (int i=0; i< MyConf->Enumerate("dnsbl"); i++)
208                 {
209                         DNSBLConfEntry *e = new DNSBLConfEntry();
210
211                         e->name = MyConf->ReadValue("dnsbl", "name", i);
212                         e->reason = MyConf->ReadValue("dnsbl", "reason", i);
213                         e->domain = MyConf->ReadValue("dnsbl", "domain", i);
214                         e->banaction = str2banaction(MyConf->ReadValue("dnsbl", "action", i));
215                         e->duration = ServerInstance->Duration(MyConf->ReadValue("dnsbl", "duration", i).c_str());
216                         e->bitmask = MyConf->ReadInteger("dnsbl", "bitmask", i, false);
217
218                         /* yeah, logic here is a little messy */
219                         if (e->bitmask <= 0)
220                         {
221                                 ServerInstance->WriteOpers("*** DNSBL(#%d): invalid bitmask",i);
222                         }
223                         else if (e->name == "")
224                         {
225                                 ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid name",i);
226                         }
227                         else if (e->domain == "")
228                         {
229                                 ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid domain",i);
230                         }
231                         else if (e->banaction == DNSBLConfEntry::I_UNKNOWN)
232                         {
233                                 ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid banaction", i);
234                         }
235                         else
236                         {
237                                 if (e->reason == "")
238                                 {
239                                         ServerInstance->WriteOpers("*** DNSBL(#%d): empty reason, using defaults",i);
240                                         e->reason = "Your IP has been blacklisted.";
241                                 }
242
243                                 /* add it, all is ok */
244                                 DNSBLConfEntries.push_back(e);
245                                 continue;
246                         }
247
248                         /* delete and drop it, error somewhere */
249                         delete e;
250                 }
251
252                 delete MyConf;
253         }
254
255         virtual void OnRehash(userrec* user, const std::string &parameter)
256         {
257                 ReadConf();
258         }
259
260         /*
261          * We will check each user that connects *locally* (userrec::fd>0)
262          */
263         virtual int OnUserRegister(userrec* user)
264         {
265                 if (IS_LOCAL(user))
266                 {
267                         /* following code taken from bopm, reverses an IP address. */
268                         struct in_addr in;
269                         unsigned char a, b, c, d;
270                         char reversedipbuf[128];
271                         std::string reversedip;
272                         bool success = false;
273
274                         if (!inet_aton(user->GetIPString(), &in))
275                         {
276 #ifdef IPV6
277                                 /* We could have an ipv6 address here */
278                                 std::string x = user->GetIPString();
279                                 /* Is it a 4in6 address? (Compensate for this kernel kludge that people love) */
280                                 if (x.find("0::ffff:") == 0)
281                                 {
282                                         x.erase(x.begin(), x.begin() + 8);
283                                         if (inet_aton(x.c_str(), &in))
284                                                 success = true;
285                                 }
286 #endif
287                         }
288                         else
289                         {
290                                 success = true;
291                         }
292
293                         if (!success)
294                                 return 0;
295
296                         d = (unsigned char) (in.s_addr >> 24) & 0xFF;
297                         c = (unsigned char) (in.s_addr >> 16) & 0xFF;
298                         b = (unsigned char) (in.s_addr >> 8) & 0xFF;
299                         a = (unsigned char) in.s_addr & 0xFF;
300
301                         snprintf(reversedipbuf, 128, "%d.%d.%d.%d", d, c, b, a);
302                         reversedip = std::string(reversedipbuf);
303
304                         // For each DNSBL, we will run through this lookup
305                         for (std::vector<DNSBLConfEntry *>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)
306                         {
307                                 // Fill hostname with a dnsbl style host (d.c.b.a.domain.tld)
308                                 std::string hostname = reversedip + "." + (*i)->domain;
309
310                                 /* now we'd need to fire off lookups for `hostname'. */
311                                 bool cached;
312                                 DNSBLResolver *r = new DNSBLResolver(this, ServerInstance, hostname, user, user->GetFd(), *i, cached);
313                                 ServerInstance->AddResolver(r, cached);
314                         }
315                 }
316
317                 /* don't do anything with this hot potato */
318                 return 0;
319         }
320         
321         virtual int OnStats(char symbol, userrec* user, string_list &results)
322         {
323                 if (symbol != 'd')
324                         return 0;
325                 
326                 unsigned long total_hits = 0, total_misses = 0;
327
328                 for (std::vector<DNSBLConfEntry*>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)
329                 {
330                         total_hits += (*i)->stats_hits;
331                         total_misses += (*i)->stats_misses;
332                         
333                         results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS DNSbl \"" + (*i)->name + "\" had " +
334                                         ConvToStr((*i)->stats_hits) + " hits and " + ConvToStr((*i)->stats_misses) + " misses");
335                 }
336                 
337                 results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS Total hits: " + ConvToStr(total_hits));
338                 results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS Total misses: " + ConvToStr(total_misses));
339                 
340                 return 0;
341         }
342 };
343
344 // stuff down here is the module-factory stuff.
345
346 class ModuleDNSBLFactory : public ModuleFactory
347 {
348  public:
349         ModuleDNSBLFactory()
350         {
351         }
352
353         ~ModuleDNSBLFactory()
354         {
355         }
356
357         virtual Module *CreateModule(InspIRCd *Me)
358         {
359                 return new ModuleDNSBL(Me);
360         }
361
362 };
363
364
365 extern "C" void * init_module( void )
366 {
367         return new ModuleDNSBLFactory;
368 }