00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "inspircd.h"
00015 #include "xline.h"
00016
00017 #ifndef WINDOWS
00018 #include <sys/types.h>
00019 #include <sys/socket.h>
00020 #include <netinet/in.h>
00021 #include <arpa/inet.h>
00022 #endif
00023
00024
00025
00026
00027 class DNSBLConfEntry : public classbase
00028 {
00029 public:
00030 enum EnumBanaction { I_UNKNOWN, I_KILL, I_ZLINE, I_KLINE, I_GLINE };
00031 enum EnumType { A_RECORD, A_BITMASK };
00032 std::string name, domain, reason;
00033 EnumBanaction banaction;
00034 EnumType type;
00035 long duration;
00036 int bitmask;
00037 unsigned char records[256];
00038 unsigned long stats_hits, stats_misses;
00039 DNSBLConfEntry(): type(A_BITMASK),duration(86400),bitmask(0),stats_hits(0), stats_misses(0) {}
00040 ~DNSBLConfEntry() { }
00041 };
00042
00043
00046 class DNSBLResolver : public Resolver
00047 {
00048 int theirfd;
00049 User* them;
00050 DNSBLConfEntry *ConfEntry;
00051
00052 public:
00053
00054 DNSBLResolver(Module *me, InspIRCd *Instance, const std::string &hostname, User* u, int userfd, DNSBLConfEntry *conf, bool &cached)
00055 : Resolver(Instance, hostname, DNS_QUERY_A, cached, me)
00056 {
00057 theirfd = userfd;
00058 them = u;
00059 ConfEntry = conf;
00060 }
00061
00062
00063 virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached, int resultnum = 0)
00064 {
00065
00066 if ((ConfEntry->type == DNSBLConfEntry::A_BITMASK) && (resultnum))
00067 return;
00068
00069
00070 if ((them) && (them == ServerInstance->SE->GetRef(theirfd)))
00071 {
00072
00073 if(result.length())
00074 {
00075 unsigned int bitmask = 0, record = 0;
00076 bool show = false, match = false;
00077 in_addr resultip;
00078
00079 inet_aton(result.c_str(), &resultip);
00080
00081 switch (ConfEntry->type)
00082 {
00083 case DNSBLConfEntry::A_BITMASK:
00084 bitmask = resultip.s_addr >> 24;
00085 bitmask &= ConfEntry->bitmask;
00086 match = (bitmask != 0);
00087 break;
00088 case DNSBLConfEntry::A_RECORD:
00089 record = resultip.s_addr >> 24;
00090 match = (ConfEntry->records[record] == 1);
00091 break;
00092 }
00093
00094 if (match)
00095 {
00096 std::string reason = ConfEntry->reason;
00097 std::string::size_type x = reason.find("%ip%");
00098 while (x != std::string::npos)
00099 {
00100 reason.erase(x, 4);
00101 reason.insert(x, them->GetIPString());
00102 x = reason.find("%ip%");
00103 }
00104
00105 ConfEntry->stats_hits++;
00106
00107 switch (ConfEntry->banaction)
00108 {
00109 case DNSBLConfEntry::I_KILL:
00110 {
00111 ServerInstance->Users->QuitUser(them, std::string("Killed (") + reason + ")");
00112 break;
00113 }
00114 case DNSBLConfEntry::I_KLINE:
00115 {
00116 KLine* kl = new KLine(ServerInstance, ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(),
00117 "*", them->GetIPString());
00118 if (ServerInstance->XLines->AddLine(kl,NULL))
00119 {
00120 ServerInstance->XLines->ApplyLines();
00121 }
00122 else
00123 delete kl;
00124 break;
00125 }
00126 case DNSBLConfEntry::I_GLINE:
00127 {
00128 GLine* gl = new GLine(ServerInstance, ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(),
00129 "*", them->GetIPString());
00130 if (ServerInstance->XLines->AddLine(gl,NULL))
00131 {
00132 ServerInstance->XLines->ApplyLines();
00133 }
00134 else
00135 delete gl;
00136 break;
00137 }
00138 case DNSBLConfEntry::I_ZLINE:
00139 {
00140 ZLine* zl = new ZLine(ServerInstance, ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(),
00141 them->GetIPString());
00142 if (ServerInstance->XLines->AddLine(zl,NULL))
00143 {
00144 ServerInstance->XLines->ApplyLines();
00145 }
00146 else
00147 delete zl;
00148 break;
00149 }
00150 case DNSBLConfEntry::I_UNKNOWN:
00151 {
00152 break;
00153 }
00154 break;
00155 }
00156
00157 if (show)
00158 {
00159 ServerInstance->SNO->WriteToSnoMask('A', "Connecting user %s detected as being on a DNS blacklist (%s) with result %d", them->GetFullRealHost().c_str(), ConfEntry->name.c_str(), bitmask);
00160 }
00161 }
00162 else
00163 ConfEntry->stats_misses++;
00164 }
00165 else
00166 ConfEntry->stats_misses++;
00167 }
00168 }
00169
00170 virtual void OnError(ResolverError e, const std::string &errormessage)
00171 {
00172 }
00173
00174 virtual ~DNSBLResolver()
00175 {
00176 }
00177 };
00178
00179 class ModuleDNSBL : public Module
00180 {
00181 private:
00182 std::vector<DNSBLConfEntry *> DNSBLConfEntries;
00183
00184
00185
00186
00187 DNSBLConfEntry::EnumBanaction str2banaction(const std::string &action)
00188 {
00189 if(action.compare("KILL")==0)
00190 return DNSBLConfEntry::I_KILL;
00191 if(action.compare("KLINE")==0)
00192 return DNSBLConfEntry::I_KLINE;
00193 if(action.compare("ZLINE")==0)
00194 return DNSBLConfEntry::I_ZLINE;
00195 if(action.compare("GLINE")==0)
00196 return DNSBLConfEntry::I_GLINE;
00197
00198 return DNSBLConfEntry::I_UNKNOWN;
00199 }
00200 public:
00201 ModuleDNSBL(InspIRCd *Me) : Module(Me)
00202 {
00203 ReadConf();
00204 Implementation eventlist[] = { I_OnRehash, I_OnUserRegister, I_OnStats };
00205 ServerInstance->Modules->Attach(eventlist, this, 3);
00206 }
00207
00208 virtual ~ModuleDNSBL()
00209 {
00210 ClearEntries();
00211 }
00212
00213 virtual Version GetVersion()
00214 {
00215 return Version("$Id: m_dnsbl.cpp 10781 2008-11-01 20:20:12Z w00t $", VF_VENDOR, API_VERSION);
00216 }
00217
00218
00221 void ClearEntries()
00222 {
00223 for (std::vector<DNSBLConfEntry *>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)
00224 delete *i;
00225 DNSBLConfEntries.clear();
00226 }
00227
00230 virtual void ReadConf()
00231 {
00232 ConfigReader *MyConf = new ConfigReader(ServerInstance);
00233 ClearEntries();
00234
00235 for (int i=0; i< MyConf->Enumerate("dnsbl"); i++)
00236 {
00237 DNSBLConfEntry *e = new DNSBLConfEntry();
00238
00239 e->name = MyConf->ReadValue("dnsbl", "name", i);
00240 e->reason = MyConf->ReadValue("dnsbl", "reason", i);
00241 e->domain = MyConf->ReadValue("dnsbl", "domain", i);
00242
00243 if (MyConf->ReadValue("dnsbl", "type", i) == "bitmask")
00244 {
00245 e->type = DNSBLConfEntry::A_BITMASK;
00246 e->bitmask = MyConf->ReadInteger("dnsbl", "bitmask", i, false);
00247 }
00248 else
00249 {
00250 memset(e->records, 0, sizeof(e->records));
00251 e->type = DNSBLConfEntry::A_RECORD;
00252 irc::portparser portrange(MyConf->ReadValue("dnsbl", "records", i), false);
00253 long item = -1;
00254 while ((item = portrange.GetToken()))
00255 e->records[item] = 1;
00256 }
00257
00258 e->banaction = str2banaction(MyConf->ReadValue("dnsbl", "action", i));
00259 e->duration = ServerInstance->Duration(MyConf->ReadValue("dnsbl", "duration", i));
00260
00261
00262
00263
00264 if ((e->bitmask <= 0) && (DNSBLConfEntry::A_BITMASK == e->type))
00265 {
00266 ServerInstance->SNO->WriteToSnoMask('A', "DNSBL(#%d): invalid bitmask",i);
00267 }
00268 else if (e->name.empty())
00269 {
00270 ServerInstance->SNO->WriteToSnoMask('A', "DNSBL(#%d): Invalid name",i);
00271 }
00272 else if (e->domain.empty())
00273 {
00274 ServerInstance->SNO->WriteToSnoMask('A', "DNSBL(#%d): Invalid domain",i);
00275 }
00276 else if (e->banaction == DNSBLConfEntry::I_UNKNOWN)
00277 {
00278 ServerInstance->SNO->WriteToSnoMask('A', "DNSBL(#%d): Invalid banaction", i);
00279 }
00280 else
00281 {
00282 if (e->reason.empty())
00283 {
00284 ServerInstance->SNO->WriteToSnoMask('A', "DNSBL(#%d): empty reason, using defaults",i);
00285 e->reason = "Your IP has been blacklisted.";
00286 }
00287
00288
00289 DNSBLConfEntries.push_back(e);
00290 continue;
00291 }
00292
00293
00294 delete e;
00295 }
00296
00297 delete MyConf;
00298 }
00299
00300 virtual void OnRehash(User* user, const std::string ¶meter)
00301 {
00302 ReadConf();
00303 }
00304
00305 virtual int OnUserRegister(User* user)
00306 {
00307
00308 if (IS_LOCAL(user))
00309 {
00310
00311 struct in_addr in;
00312 unsigned char a, b, c, d;
00313 char reversedipbuf[128];
00314 std::string reversedip;
00315 bool success;
00316
00317 success = inet_aton(user->GetIPString(), &in);
00318
00319 if (!success)
00320 return 0;
00321
00322 d = (unsigned char) (in.s_addr >> 24) & 0xFF;
00323 c = (unsigned char) (in.s_addr >> 16) & 0xFF;
00324 b = (unsigned char) (in.s_addr >> 8) & 0xFF;
00325 a = (unsigned char) in.s_addr & 0xFF;
00326
00327 snprintf(reversedipbuf, 128, "%d.%d.%d.%d", d, c, b, a);
00328 reversedip = std::string(reversedipbuf);
00329
00330
00331 for (std::vector<DNSBLConfEntry *>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)
00332 {
00333
00334 std::string hostname = reversedip + "." + (*i)->domain;
00335
00336
00337 bool cached;
00338 DNSBLResolver *r = new DNSBLResolver(this, ServerInstance, hostname, user, user->GetFd(), *i, cached);
00339 ServerInstance->AddResolver(r, cached);
00340 }
00341 }
00342
00343
00344 return 0;
00345 }
00346
00347 virtual int OnStats(char symbol, User* user, string_list &results)
00348 {
00349 if (symbol != 'd')
00350 return 0;
00351
00352 unsigned long total_hits = 0, total_misses = 0;
00353
00354 for (std::vector<DNSBLConfEntry*>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)
00355 {
00356 total_hits += (*i)->stats_hits;
00357 total_misses += (*i)->stats_misses;
00358
00359 results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS DNSbl \"" + (*i)->name + "\" had " +
00360 ConvToStr((*i)->stats_hits) + " hits and " + ConvToStr((*i)->stats_misses) + " misses");
00361 }
00362
00363 results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS Total hits: " + ConvToStr(total_hits));
00364 results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS Total misses: " + ConvToStr(total_misses));
00365
00366 return 0;
00367 }
00368 };
00369
00370 MODULE_INIT(ModuleDNSBL)