X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_dnsbl.cpp;h=dc43dda3f0c6f2045580a47ce77a51855693aa13;hb=d848034590bc402277da975b7efdbc78ce1722fc;hp=32e05aebdaa6e2b14648de3fb610758ac5108df9;hpb=7586cb54da300924f92d4b7b8c121ecabb5e7126;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_dnsbl.cpp b/src/modules/m_dnsbl.cpp index 32e05aebd..dc43dda3f 100644 --- a/src/modules/m_dnsbl.cpp +++ b/src/modules/m_dnsbl.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2018-2020 Matt Schatz * Copyright (C) 2018-2019 linuxdaemon - * Copyright (C) 2013, 2016-2019 Sadie Powell + * Copyright (C) 2013, 2017-2021 Sadie Powell * Copyright (C) 2013, 2015-2016 Adam * Copyright (C) 2012-2016 Attila Molnar * Copyright (C) 2012, 2018 Robby @@ -42,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) + { + } }; @@ -61,7 +71,7 @@ class DNSBLResolver : public DNS::Request 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) + : DNS::Request(mgr, me, hostname, DNS::QUERY_A, true, conf->timeout) , theirsa(u->client_sa) , theiruid(u->uuid) , nameExt(match) @@ -76,16 +86,7 @@ class DNSBLResolver : public DNS::Request /* Check the user still exists */ LocalUser* them = IS_LOCAL(ServerInstance->FindUUID(theiruid)); if (!them || them->client_sa != theirsa) - 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) { - 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; } @@ -94,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) @@ -212,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++; @@ -220,6 +247,20 @@ class DNSBLResolver : public DNS::Request void OnError(const DNS::Query *q) CXX11_OVERRIDE { + 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; @@ -228,11 +269,8 @@ class DNSBLResolver : public DNS::Request 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()); @@ -253,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: @@ -280,6 +317,12 @@ 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("Allows the server administrator to check the IP address of connecting users against a DNSBL.", VF_VENDOR); @@ -300,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")) { @@ -342,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); } @@ -359,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. @@ -372,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) @@ -435,12 +475,20 @@ class ModuleDNSBL : public Module, public Stats::EventListener std::string* match = nameExt.get(user); 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)) - 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 @@ -455,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; } };