X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_dnsbl.cpp;h=9ad3b05e7e543529e447af284e8fb9d30aa51240;hb=4a126ad130b0a51449343de2f2db6becca0d2819;hp=c9be107b810226c3eed8de086e420c14074da75f;hpb=dd24f8ac713793d5d5a7e959228937f48788ba66;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_dnsbl.cpp b/src/modules/m_dnsbl.cpp index c9be107b8..9ad3b05e7 100644 --- a/src/modules/m_dnsbl.cpp +++ b/src/modules/m_dnsbl.cpp @@ -1,11 +1,16 @@ /* * InspIRCd -- Internet Relay Chat Daemon * + * Copyright (C) 2018-2020 Matt Schatz + * Copyright (C) 2018-2019 linuxdaemon + * Copyright (C) 2013, 2016-2020 Sadie Powell + * Copyright (C) 2013, 2015-2016 Adam + * Copyright (C) 2012-2016 Attila Molnar + * Copyright (C) 2012, 2018 Robby * Copyright (C) 2009-2010 Daniel De Graaf - * Copyright (C) 2006-2008 Robin Burchell - * Copyright (C) 2007 Craig Edwards - * Copyright (C) 2006-2007 Dennis Friis - * Copyright (C) 2007 John Brooks + * Copyright (C) 2007, 2010 Craig Edwards + * Copyright (C) 2007 Dennis Friis + * Copyright (C) 2006-2009 Robin Burchell * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -38,8 +43,16 @@ class DNSBLConfEntry : public refcountbase unsigned long duration; unsigned int bitmask; unsigned char records[256]; - unsigned long stats_hits, stats_misses; - DNSBLConfEntry(): type(A_BITMASK),duration(86400),bitmask(0),stats_hits(0), stats_misses(0) {} + unsigned long stats_hits, stats_misses, stats_errors; + DNSBLConfEntry() + : type(A_BITMASK) + , duration(86400) + , bitmask(0) + , stats_hits(0) + , stats_misses(0) + , stats_errors(0) + { + } }; @@ -47,15 +60,21 @@ class DNSBLConfEntry : public refcountbase */ class DNSBLResolver : public DNS::Request { + private: + irc::sockets::sockaddrs theirsa; std::string theiruid; LocalStringExt& nameExt; LocalIntExt& countExt; reference ConfEntry; public: - DNSBLResolver(DNS::Manager *mgr, Module *me, LocalStringExt& match, LocalIntExt& ctr, const std::string &hostname, LocalUser* u, reference conf) - : DNS::Request(mgr, me, hostname, DNS::QUERY_A, true), theiruid(u->uuid), nameExt(match), countExt(ctr), ConfEntry(conf) + : DNS::Request(mgr, me, hostname, DNS::QUERY_A, true) + , theirsa(u->client_sa) + , theiruid(u->uuid) + , nameExt(match) + , countExt(ctr) + , ConfEntry(conf) { } @@ -64,44 +83,58 @@ class DNSBLResolver : public DNS::Request { /* Check the user still exists */ LocalUser* them = IS_LOCAL(ServerInstance->FindUUID(theiruid)); - if (!them) + if (!them || them->client_sa != theirsa) return; + int i = countExt.get(them); + if (i) + countExt.set(them, i - 1); + + // The DNSBL reply must contain an A result. const DNS::ResourceRecord* const ans_record = r->FindAnswerOfType(DNS::QUERY_A); if (!ans_record) + { + ConfEntry->stats_errors++; + ServerInstance->SNO->WriteGlobalSno('d', "%s returned an result with no IPv4 address.", + ConfEntry->name.c_str()); return; + } - // All replies should be in 127.0.0.0/8 - if (ans_record->rdata.compare(0, 4, "127.") != 0) + // The DNSBL reply must be a valid IPv4 address. + in_addr resultip; + if (inet_pton(AF_INET, ans_record->rdata.c_str(), &resultip) != 1) { - ServerInstance->SNO->WriteGlobalSno('d', "DNSBL: %s returned address outside of acceptable subnet 127.0.0.0/8: %s", ConfEntry->domain.c_str(), ans_record->rdata.c_str()); - ConfEntry->stats_misses++; + ConfEntry->stats_errors++; + ServerInstance->SNO->WriteGlobalSno('d', "%s returned an invalid IPv4 address: %s", + ConfEntry->name.c_str(), ans_record->rdata.c_str()); return; } - int i = countExt.get(them); - if (i) - countExt.set(them, i - 1); - - // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d + // The DNSBL reply should be in the 127.0.0.0/8 range. + if ((resultip.s_addr & 0xFF) != 127) + { + ConfEntry->stats_errors++; + ServerInstance->SNO->WriteGlobalSno('d', "%s returned an IPv4 address which is outside of the 127.0.0.0/8 subnet: %s", + ConfEntry->name.c_str(), ans_record->rdata.c_str()); + return; + } - unsigned int bitmask = 0, record = 0; bool match = false; - in_addr resultip; - - inet_pton(AF_INET, ans_record->rdata.c_str(), &resultip); - + unsigned int result = 0; switch (ConfEntry->type) { case DNSBLConfEntry::A_BITMASK: - bitmask = resultip.s_addr >> 24; /* Last octet (network byte order) */ - bitmask &= ConfEntry->bitmask; - match = (bitmask != 0); - break; + { + result = (resultip.s_addr >> 24) & ConfEntry->bitmask; + match = (result != 0); + break; + } case DNSBLConfEntry::A_RECORD: - record = resultip.s_addr >> 24; /* Last octet */ - match = (ConfEntry->records[record] == 1); - break; + { + result = resultip.s_addr >> 24; + match = (ConfEntry->records[result] == 1); + break; + } } if (match) @@ -147,7 +180,7 @@ class DNSBLResolver : public DNS::Request "*", them->GetIPString()); if (ServerInstance->XLines->AddLine(kl,NULL)) { - ServerInstance->SNO->WriteGlobalSno('x', "K-line added due to DNSBL match on *@%s to expire in %s (on %s): %s", + ServerInstance->SNO->WriteToSnoMask('x', "K-line added due to DNSBL match on *@%s to expire in %s (on %s): %s", them->GetIPString().c_str(), InspIRCd::DurationString(kl->duration).c_str(), InspIRCd::TimeString(kl->expiry).c_str(), reason.c_str()); ServerInstance->XLines->ApplyLines(); @@ -165,7 +198,7 @@ class DNSBLResolver : public DNS::Request "*", them->GetIPString()); if (ServerInstance->XLines->AddLine(gl,NULL)) { - ServerInstance->SNO->WriteGlobalSno('x', "G-line added due to DNSBL match on *@%s to expire in %s (on %s): %s", + ServerInstance->SNO->WriteToSnoMask('x', "G-line added due to DNSBL match on *@%s to expire in %s (on %s): %s", them->GetIPString().c_str(), InspIRCd::DurationString(gl->duration).c_str(), InspIRCd::TimeString(gl->expiry).c_str(), reason.c_str()); ServerInstance->XLines->ApplyLines(); @@ -183,7 +216,7 @@ class DNSBLResolver : public DNS::Request them->GetIPString()); if (ServerInstance->XLines->AddLine(zl,NULL)) { - ServerInstance->SNO->WriteGlobalSno('x', "Z-line added due to DNSBL match on %s to expire in %s (on %s): %s", + ServerInstance->SNO->WriteToSnoMask('x', "Z-line added due to DNSBL match on %s to expire in %s (on %s): %s", them->GetIPString().c_str(), InspIRCd::DurationString(zl->duration).c_str(), InspIRCd::TimeString(zl->expiry).c_str(), reason.c_str()); ServerInstance->XLines->ApplyLines(); @@ -201,7 +234,7 @@ class DNSBLResolver : public DNS::Request } ServerInstance->SNO->WriteGlobalSno('d', "Connecting user %s (%s) detected as being on the '%s' DNS blacklist with result %d", - them->GetFullRealHost().c_str(), them->GetIPString().c_str(), ConfEntry->name.c_str(), (ConfEntry->type==DNSBLConfEntry::A_BITMASK) ? bitmask : record); + them->GetFullRealHost().c_str(), them->GetIPString().c_str(), ConfEntry->name.c_str(), result); } else ConfEntry->stats_misses++; @@ -210,7 +243,7 @@ class DNSBLResolver : public DNS::Request void OnError(const DNS::Query *q) CXX11_OVERRIDE { LocalUser* them = IS_LOCAL(ServerInstance->FindUUID(theiruid)); - if (!them) + if (!them || them->client_sa != theirsa) return; int i = countExt.get(them); @@ -223,6 +256,7 @@ class DNSBLResolver : public DNS::Request return; } + ConfEntry->stats_errors++; ServerInstance->SNO->WriteGlobalSno('d', "An error occurred whilst checking whether %s (%s) is on the '%s' DNS blacklist: %s", them->GetFullRealHost().c_str(), them->GetIPString().c_str(), ConfEntry->name.c_str(), this->manager->GetErrorStr(q->error).c_str()); } @@ -242,17 +276,16 @@ class ModuleDNSBL : public Module, public Stats::EventListener */ DNSBLConfEntry::EnumBanaction str2banaction(const std::string &action) { - if(action.compare("KILL")==0) + if (stdalgo::string::equalsci(action, "kill")) return DNSBLConfEntry::I_KILL; - if(action.compare("KLINE")==0) + if (stdalgo::string::equalsci(action, "kline")) return DNSBLConfEntry::I_KLINE; - if(action.compare("ZLINE")==0) + if (stdalgo::string::equalsci(action, "zline")) return DNSBLConfEntry::I_ZLINE; - if(action.compare("GLINE")==0) + if (stdalgo::string::equalsci(action, "gline")) return DNSBLConfEntry::I_GLINE; - if(action.compare("MARK")==0) + if (stdalgo::string::equalsci(action, "mark")) return DNSBLConfEntry::I_MARK; - return DNSBLConfEntry::I_UNKNOWN; } public: @@ -269,9 +302,15 @@ class ModuleDNSBL : public Module, public Stats::EventListener ServerInstance->SNO->EnableSnomask('d', "DNSBL"); } + void Prioritize() CXX11_OVERRIDE + { + Module* corexline = ServerInstance->Modules->Find("core_xline"); + ServerInstance->Modules->SetPriority(this, I_OnSetUserIP, PRIORITY_AFTER, corexline); + } + Version GetVersion() CXX11_OVERRIDE { - return Version("Provides handling of DNS blacklists", VF_VENDOR); + return Version("Allows the server administrator to check the IP address of connecting users against a DNSBL.", VF_VENDOR); } /** Fill our conf vector with data @@ -289,7 +328,7 @@ class ModuleDNSBL : public Module, public Stats::EventListener e->name = tag->getString("name"); e->ident = tag->getString("ident"); e->host = tag->getString("host"); - e->reason = tag->getString("reason"); + e->reason = tag->getString("reason", "Your IP has been blacklisted.", 1); e->domain = tag->getString("domain"); if (stdalgo::string::equalsci(tag->getString("type"), "bitmask")) @@ -331,13 +370,6 @@ class ModuleDNSBL : public Module, public Stats::EventListener } else { - if (e->reason.empty()) - { - std::string location = tag->getTagLocation(); - ServerInstance->SNO->WriteGlobalSno('d', "DNSBL(%s): empty reason, using defaults", location.c_str()); - e->reason = "Your IP has been blacklisted."; - } - /* add it, all is ok */ newentries.push_back(e); } @@ -348,7 +380,7 @@ class ModuleDNSBL : public Module, public Stats::EventListener void OnSetUserIP(LocalUser* user) CXX11_OVERRIDE { - if ((user->exempt) || !DNS) + if (user->exempt || user->quitting || !DNS) return; // Clients can't be in a DNSBL if they aren't connected via IPv4 or IPv6. @@ -361,7 +393,10 @@ class ModuleDNSBL : public Module, public Stats::EventListener return; } else + { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User has no connect class in OnSetUserIP"); + return; + } std::string reversedip; if (user->client_sa.family() == AF_INET) @@ -424,12 +459,20 @@ class ModuleDNSBL : public Module, public Stats::EventListener std::string* match = nameExt.get(user); if (!match) - return MOD_RES_PASSTHRU; + { + ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "The %s connect class is not suitable as it requires a DNSBL mark", + myclass->GetName().c_str()); + return MOD_RES_DENY; + } - if (InspIRCd::Match(*match, dnsbl)) - return MOD_RES_PASSTHRU; + if (!InspIRCd::Match(*match, dnsbl)) + { + ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "The %s connect class is not suitable as the DNSBL mark (%s) does not match %s", + myclass->GetName().c_str(), match->c_str(), dnsbl.c_str()); + return MOD_RES_DENY; + } - return MOD_RES_DENY; + return MOD_RES_PASSTHRU; } ModResult OnCheckReady(LocalUser *user) CXX11_OVERRIDE @@ -444,20 +487,22 @@ class ModuleDNSBL : public Module, public Stats::EventListener if (stats.GetSymbol() != 'd') return MOD_RES_PASSTHRU; - unsigned long total_hits = 0, total_misses = 0; - + unsigned long total_hits = 0; + unsigned long total_misses = 0; + unsigned long total_errors = 0; for (std::vector >::const_iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); ++i) { total_hits += (*i)->stats_hits; total_misses += (*i)->stats_misses; + total_errors += (*i)->stats_errors; - stats.AddRow(304, "DNSBLSTATS DNSbl \"" + (*i)->name + "\" had " + - ConvToStr((*i)->stats_hits) + " hits and " + ConvToStr((*i)->stats_misses) + " misses"); + stats.AddRow(304, InspIRCd::Format("DNSBLSTATS \"%s\" had %lu hits, %lu misses, and %lu errors", + (*i)->name.c_str(), (*i)->stats_hits, (*i)->stats_misses, (*i)->stats_errors)); } stats.AddRow(304, "DNSBLSTATS Total hits: " + ConvToStr(total_hits)); stats.AddRow(304, "DNSBLSTATS Total misses: " + ConvToStr(total_misses)); - + stats.AddRow(304, "DNSBLSTATS Total errors: " + ConvToStr(total_errors)); return MOD_RES_PASSTHRU; } };