X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_dnsbl.cpp;h=dc43dda3f0c6f2045580a47ce77a51855693aa13;hb=HEAD;hp=a645e2cd16b47d91bb54460cb24db2dce2d2aa5a;hpb=f2e3fd5952b23209b084bde4f464e6643c8a00ff;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_dnsbl.cpp b/src/modules/m_dnsbl.cpp index a645e2cd1..dc43dda3f 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, 2017-2021 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 @@ -37,9 +42,19 @@ class DNSBLConfEntry : public refcountbase EnumType type; unsigned long duration; unsigned int bitmask; + unsigned int timeout; 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) + , timeout(0) + , stats_hits(0) + , stats_misses(0) + , stats_errors(0) + { + } }; @@ -47,15 +62,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, conf->timeout) + , theirsa(u->client_sa) + , theiruid(u->uuid) + , nameExt(match) + , countExt(ctr) + , ConfEntry(conf) { } @@ -63,18 +84,9 @@ class DNSBLResolver : public DNS::Request void OnLookupComplete(const DNS::Query *r) CXX11_OVERRIDE { /* Check the user still exists */ - LocalUser* them = (LocalUser*)ServerInstance->FindUUID(theiruid); - if (!them) - return; - - const DNS::ResourceRecord* const ans_record = r->FindAnswerOfType(DNS::QUERY_A); - if (!ans_record) - return; - - // All replies should be in 127.0.0.0/8 - if (ans_record->rdata.compare(0, 4, "127.") != 0) + LocalUser* them = IS_LOCAL(ServerInstance->FindUUID(theiruid)); + if (!them || them->client_sa != theirsa) { - 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++; return; } @@ -83,25 +95,51 @@ class DNSBLResolver : public DNS::Request if (i) countExt.set(them, i - 1); - // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d + // 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; + } - unsigned int bitmask = 0, record = 0; - bool match = false; + // The DNSBL reply must be a valid IPv4 address. in_addr resultip; + if (inet_pton(AF_INET, ans_record->rdata.c_str(), &resultip) != 1) + { + ConfEntry->stats_errors++; + ServerInstance->SNO->WriteGlobalSno('d', "%s returned an invalid IPv4 address: %s", + ConfEntry->name.c_str(), ans_record->rdata.c_str()); + return; + } - inet_pton(AF_INET, ans_record->rdata.c_str(), &resultip); + // 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; + } + bool match = false; + 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,9 +185,9 @@ class DNSBLResolver : public DNS::Request "*", them->GetIPString()); if (ServerInstance->XLines->AddLine(kl,NULL)) { - std::string timestr = InspIRCd::TimeString(kl->expiry); - ServerInstance->SNO->WriteGlobalSno('x', "K-line added due to DNSBL match on *@%s to expire on %s: %s", - them->GetIPString().c_str(), timestr.c_str(), reason.c_str()); + 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(); } else @@ -165,9 +203,9 @@ class DNSBLResolver : public DNS::Request "*", them->GetIPString()); if (ServerInstance->XLines->AddLine(gl,NULL)) { - std::string timestr = InspIRCd::TimeString(gl->expiry); - ServerInstance->SNO->WriteGlobalSno('x', "G-line added due to DNSBL match on *@%s to expire on %s: %s", - them->GetIPString().c_str(), timestr.c_str(), reason.c_str()); + 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(); } else @@ -183,9 +221,9 @@ class DNSBLResolver : public DNS::Request them->GetIPString()); if (ServerInstance->XLines->AddLine(zl,NULL)) { - std::string timestr = InspIRCd::TimeString(zl->expiry); - ServerInstance->SNO->WriteGlobalSno('x', "Z-line added due to DNSBL match on %s to expire on %s: %s", - them->GetIPString().c_str(), timestr.c_str(), reason.c_str()); + 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(); } else @@ -201,7 +239,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++; @@ -209,19 +247,30 @@ class DNSBLResolver : public DNS::Request void OnError(const DNS::Query *q) CXX11_OVERRIDE { - LocalUser* them = (LocalUser*)ServerInstance->FindUUID(theiruid); - if (!them) + bool is_miss = true; + switch (q->error) + { + case DNS::ERROR_NO_RECORDS: + case DNS::ERROR_DOMAIN_NOT_FOUND: + ConfEntry->stats_misses++; + break; + + default: + ConfEntry->stats_errors++; + is_miss = false; + break; + } + + LocalUser* them = IS_LOCAL(ServerInstance->FindUUID(theiruid)); + if (!them || them->client_sa != theirsa) return; int i = countExt.get(them); if (i) countExt.set(them, i - 1); - if (q->error == DNS::ERROR_NO_RECORDS || q->error == DNS::ERROR_DOMAIN_NOT_FOUND) - { - ConfEntry->stats_misses++; + if (is_miss) return; - } 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 +291,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 +317,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,8 +343,9 @@ 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"); + e->timeout = tag->getDuration("timeout", 0); if (stdalgo::string::equalsci(tag->getString("type"), "bitmask")) { @@ -331,13 +386,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 +396,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 +409,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) @@ -384,6 +435,7 @@ class ModuleDNSBL : public Module, public Stats::EventListener reversedip.push_back(*it); reversedip.push_back('.'); } + reversedip.erase(reversedip.length() - 1, 1); } else return; @@ -420,11 +472,23 @@ class ModuleDNSBL : public Module, public Stats::EventListener std::string dnsbl; if (!myclass->config->readString("dnsbl", dnsbl)) return MOD_RES_PASSTHRU; + std::string* match = nameExt.get(user); - std::string myname = match ? *match : ""; - if (dnsbl == myname) - return MOD_RES_PASSTHRU; - return MOD_RES_DENY; + if (!match) + { + 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)) + { + 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_PASSTHRU; } ModResult OnCheckReady(LocalUser *user) CXX11_OVERRIDE @@ -439,20 +503,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; } };