]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_dnsbl.cpp
Untested! New m_watch that should be hundreds of times faster (im not joking either)
[user/henk/code/inspircd.git] / src / modules / m_dnsbl.cpp
1 /*
2  * Formerly written and maintained by satmd.
3  * This version written and maintained by w00t.
4  */
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <stdint.h>
10 #include "inspircd.h"
11 #include "dns.h"
12 #include "users.h"
13 #include "channels.h"
14 #include "modules.h"
15
16 /* $ModDesc: Provides handling of DNS blacklists */
17
18 /* Class holding data for a single entry */
19 class DNSBLConfEntry
20 {
21         public:
22                 enum EnumBanaction { I_UNKNOWN, I_KILL, I_ZLINE, I_KLINE, I_GLINE };
23                 std::string name, domain, reason;
24                 EnumBanaction banaction;
25                 long duration;
26                 int bitmask;
27                 DNSBLConfEntry(): duration(86400),bitmask(0) {}
28 };
29
30
31 /** Resolver for CGI:IRC hostnames encoded in ident/GECOS
32  */
33 class DNSBLResolver : public Resolver
34 {
35         int theirfd;
36         userrec* them;
37         DNSBLConfEntry *ConfEntry;
38
39     public:
40         DNSBLResolver(Module *me, InspIRCd *ServerInstance, const std::string &hostname, userrec* u, int userfd, DNSBLConfEntry *conf)
41                 : Resolver(ServerInstance, hostname, DNS_QUERY_A, me)
42         {
43                 theirfd = userfd;
44                 them = u;
45                 ConfEntry = conf;
46         }
47
48         virtual void OnLookupComplete(const std::string &result)
49         {
50                 /* Check the user still exists */
51                 if ((them) && (them == ServerInstance->SE->GetRef(theirfd)))
52                 {
53                         ServerInstance->Log(DEBUG, "m_dnsbl:  %s got a result from dnsbl %s", them->nick, ConfEntry->name.c_str());
54
55                         // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d
56                         if(result.length())
57                         {
58                                 unsigned int bitmask=0;
59                                 unsigned int octetpos=0;
60                                 std::string tmp = result;
61
62                                 while(tmp.length()>0)
63                                 {
64                                         std::string octet;
65                                         unsigned int lastdot = tmp.rfind(".");
66
67                                         if (lastdot == std::string::npos)
68                                         {
69                                                 octet=tmp;
70                                                 tmp.clear();
71                                         }
72                                         else
73                                         {
74                                                 octet=tmp.substr(lastdot+1,tmp.length()-lastdot+1);
75                                                 tmp.resize(lastdot);
76                                         }
77
78                                         bitmask += (256 ^ octetpos) * atoi(octet.c_str());
79                                         octetpos += 1;
80                                 }
81
82                                 bitmask &= ConfEntry->bitmask;
83
84                                 if (bitmask != 0)
85                                 {
86                                         std::string reason = ConfEntry->reason;
87
88                                         while (int pos = reason.find("%ip%") != std::string::npos)
89                                         {
90                                                 reason.replace(pos, 4, them->GetIPString());
91                                         }
92
93                                         ServerInstance->WriteOpers("*** Connecting user %s detected as being on a DNS blacklist (%s) with result %d", them->GetFullRealHost(), ConfEntry->name.c_str(), bitmask);
94
95                                         switch (ConfEntry->banaction)
96                                         {
97                                                 case DNSBLConfEntry::I_KILL:
98                                                 {
99                                                         them->QuitUser(ServerInstance, them, std::string("Killed (") + reason + ")");
100                                                         break;
101                                                 }
102                                                 case DNSBLConfEntry::I_KLINE:
103                                                 {
104                                                         ServerInstance->AddKLine(ConfEntry->duration, ServerInstance->Config->ServerName, reason, std::string("*@") + them->GetIPString());
105                                                         break;
106                                                 }
107                                                 case DNSBLConfEntry::I_GLINE:
108                                                 {
109                                                         ServerInstance->AddGLine(ConfEntry->duration, ServerInstance->Config->ServerName, reason, std::string("*@") + them->GetIPString());
110                                                         break;
111                                                 }
112                                                 case DNSBLConfEntry::I_ZLINE:
113                                                 {
114                                                         ServerInstance->AddZLine(ConfEntry->duration, ServerInstance->Config->ServerName, reason, them->GetIPString());
115                                                         break;
116                                                 }
117                                                 case DNSBLConfEntry::I_UNKNOWN:
118                                                 {
119                                                         break;
120                                                 }
121                                                 break;
122                                         }
123                                 }
124                         }
125                 }
126         }
127
128         virtual void OnError(ResolverError e, const std::string &errormessage)
129         {
130                 /*
131                 this just means they don't appear in the respective dnsbl
132                 if ((them) && (them == ServerInstance->SE->GetRef(theirfd)))
133                 {
134                 }
135                 */
136                 /* Check the user still exists */
137                 if ((them) && (them == ServerInstance->SE->GetRef(theirfd)))
138                 {
139                         ServerInstance->Log(DEBUG, "m_dnsbl:  %s got an error while resolving for dnsbl %s", them->nick, ConfEntry->name.c_str());
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         }
178         
179         virtual Version GetVersion()
180         {
181                 return Version(2, 0, 0, 0, 0, API_VERSION);
182         }
183
184         void Implements(char* List)
185         {
186                 List[I_OnRehash] = List[I_OnUserRegister] = 1;
187         }
188
189         /*
190          * Fill our conf vector with data
191          */     
192         virtual void ReadConf()
193         {
194                 ConfigReader *MyConf = new ConfigReader(ServerInstance);
195                 DNSBLConfEntries.clear();
196
197                 for (int i=0; i< MyConf->Enumerate("dnsbl"); i++)
198                 {
199                         DNSBLConfEntry *e = new DNSBLConfEntry();
200
201                         e->name = MyConf->ReadValue("dnsbl", "name", i);
202                         e->reason = MyConf->ReadValue("dnsbl", "reason", i);
203                         e->domain = MyConf->ReadValue("dnsbl", "domain", i);
204                         e->banaction = str2banaction(MyConf->ReadValue("dnsbl", "action", i));
205                         e->duration = ServerInstance->Duration(MyConf->ReadValue("dnsbl", "duration", i).c_str());
206                         e->bitmask = MyConf->ReadInteger("dnsbl", "bitmask", i, false);
207
208                         /* yeah, logic here is a little messy */
209                         if (e->bitmask <= 0)
210                         {
211                                 ServerInstance->WriteOpers("*** DNSBL(#%d): invalid bitmask",i);
212                         }
213                         else if (e->name == "")
214                         {
215                                 ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid name",i);
216                         }
217                         else if (e->domain == "")
218                         {
219                                 ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid domain",i);
220                         }
221                         else if (e->banaction == DNSBLConfEntry::I_UNKNOWN)
222                         {
223                                 ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid banaction", i);
224                         }
225                         else
226                         {
227                                 if (e->reason == "")
228                                 {
229                                         ServerInstance->WriteOpers("*** DNSBL(#%d): empty reason, using defaults",i);
230                                         e->reason = "Your IP has been blacklisted.";
231                                 }
232
233                                 /* add it, all is ok */
234                                 DNSBLConfEntries.push_back(e);
235                                 delete MyConf;
236                                 return;
237                         }
238
239                         /* delete and drop it, error somewhere */
240                         delete e;
241                 }
242
243                 delete MyConf;
244         }
245         
246         
247         virtual void OnRehash(const std::string &parameter)
248         {
249                 ReadConf();
250         }
251
252         /*
253          * We will check each user that connects *locally* (userrec::fd>0)
254          */
255         virtual int OnUserRegister(userrec* user)
256         {
257                 if (IS_LOCAL(user))
258                 {
259                         /* following code taken from bopm, reverses an IP address. */
260                         struct in_addr in;
261                         unsigned char a, b, c, d;
262                         char reversedipbuf[128];
263                         std::string reversedip;
264
265                         if (!inet_aton(user->GetIPString(), &in))
266                         {
267                                 ServerInstance->WriteOpers("Invalid IP address in m_dnsbl! Bailing check");
268                                 return 0;
269                         }
270
271                         d = (unsigned char) (in.s_addr >> 24) & 0xFF;
272                         c = (unsigned char) (in.s_addr >> 16) & 0xFF;
273                         b = (unsigned char) (in.s_addr >> 8) & 0xFF;
274                         a = (unsigned char) in.s_addr & 0xFF;
275
276                         snprintf(reversedipbuf, 128, "%d.%d.%d.%d", d, c, b, a);
277                         reversedip = std::string(reversedipbuf);
278
279 /*
280         this is satmd's old code
281                         std::string reversedip;
282                         std::string userip = user->GetIPString();
283                         std::string tempip = userip;
284
285                         // reversedip will created in there
286                         while (tempip.length()>0)
287                         {
288                                 unsigned int lastdot=tempip.rfind(".");
289                                 if (lastdot == std::string::npos)
290                                 {
291                                         reversedip+=tempip;
292                                         tempip.clear();
293                                 }
294                                 else
295                                 {
296                                         reversedip += tempip.substr(lastdot+1,tempip.length()-lastdot+1);
297                                         reversedip += ".";
298                                         tempip.resize(lastdot);
299                                 }
300                         }
301 */
302                 
303                         // For each DNSBL, we will run through this lookup
304                         for (std::vector<DNSBLConfEntry *>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)
305                         {
306                                 // Fill hostname with a dnsbl style host (d.c.b.a.domain.tld)
307                                 std::string hostname=reversedip+"."+ (*i)->domain;
308
309                                 ServerInstance->Log(DEBUG, "m_dnsbl: sending %s for resolution", hostname.c_str());
310
311                                 /* now we'd need to fire off lookups for `hostname'. */
312                                 DNSBLResolver *r = new DNSBLResolver(this, ServerInstance, hostname, user, user->GetFd(), *i);
313                                 ServerInstance->AddResolver(r);
314                         }
315                 }
316
317                 /* don't do anything with this hot potato */
318                 return 0;
319         }
320 };
321
322 // stuff down here is the module-factory stuff.
323
324 class ModuleDNSBLFactory : public ModuleFactory
325 {
326  public:
327         ModuleDNSBLFactory()
328         {
329         }
330         
331         ~ModuleDNSBLFactory()
332         {
333         }
334         
335         virtual Module *CreateModule(InspIRCd *Me)
336         {
337                 return new ModuleDNSBL(Me);
338         }
339         
340 };
341
342
343 extern "C" void * init_module( void )
344 {
345         return new ModuleDNSBLFactory;
346 }
347