X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_dnsbl.cpp;h=6265ca85a88fafd3f8a49f5b9e027e5be0ebf9f3;hb=0a6b1e1a7de92e078a98f0b955d2624e5b85e4c1;hp=ab24873ce3225326d37c6ada9a2e578c53875814;hpb=454c8d374955d2ffb3ec1fca39a6efc32032c649;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_dnsbl.cpp b/src/modules/m_dnsbl.cpp index ab24873ce..6265ca85a 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 @@ -35,7 +40,7 @@ class DNSBLConfEntry : public refcountbase std::string name, ident, host, domain, reason; EnumBanaction banaction; EnumType type; - long duration; + unsigned long duration; unsigned int bitmask; unsigned char records[256]; unsigned long stats_hits, stats_misses; @@ -43,19 +48,25 @@ class DNSBLConfEntry : public refcountbase }; -/** Resolver for CGI:IRC hostnames encoded in ident/GECOS +/** Resolver for CGI:IRC hostnames encoded in ident/real name */ 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) { } @@ -63,8 +74,8 @@ 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) + 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); @@ -74,7 +85,7 @@ class DNSBLResolver : public DNS::Request // All replies should be in 127.0.0.0/8 if (ans_record->rdata.compare(0, 4, "127.") != 0) { - ServerInstance->SNO->WriteGlobalSno('a', "DNSBL: %s returned address outside of acceptable subnet 127.0.0.0/8: %s", ConfEntry->domain.c_str(), ans_record->rdata.c_str()); + 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; } @@ -128,13 +139,13 @@ class DNSBLResolver : public DNS::Request { if (!ConfEntry->ident.empty()) { - them->WriteNumeric(304, "Your ident has been set to " + ConfEntry->ident + " because you matched " + reason); + them->WriteNotice("Your ident has been set to " + ConfEntry->ident + " because you matched " + reason); them->ChangeIdent(ConfEntry->ident); } if (!ConfEntry->host.empty()) { - them->WriteNumeric(304, "Your host has been set to " + ConfEntry->host + " because you matched " + reason); + them->WriteNotice("Your host has been set to " + ConfEntry->host + " because you matched " + reason); them->ChangeDisplayedHost(ConfEntry->host); } @@ -147,9 +158,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 +176,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 +194,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 @@ -200,7 +211,8 @@ class DNSBLResolver : public DNS::Request break; } - ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s%s detected as being on a DNS blacklist (%s) with result %d", them->nick.empty() ? "" : "", them->GetFullRealHost().c_str(), ConfEntry->domain.c_str(), (ConfEntry->type==DNSBLConfEntry::A_BITMASK) ? bitmask : record); + 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); } else ConfEntry->stats_misses++; @@ -208,8 +220,8 @@ class DNSBLResolver : public DNS::Request void OnError(const DNS::Query *q) CXX11_OVERRIDE { - LocalUser* them = (LocalUser*)ServerInstance->FindUUID(theiruid); - if (!them) + LocalUser* them = IS_LOCAL(ServerInstance->FindUUID(theiruid)); + if (!them || them->client_sa != theirsa) return; int i = countExt.get(them); @@ -217,13 +229,21 @@ class DNSBLResolver : public DNS::Request countExt.set(them, i - 1); if (q->error == DNS::ERROR_NO_RECORDS || q->error == DNS::ERROR_DOMAIN_NOT_FOUND) + { ConfEntry->stats_misses++; + 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()); } }; +typedef std::vector > DNSBLConfList; + class ModuleDNSBL : public Module, public Stats::EventListener { - std::vector > DNSBLConfEntries; + DNSBLConfList DNSBLConfEntries; dynamic_reference DNS; LocalStringExt nameExt; LocalIntExt countExt; @@ -233,17 +253,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: @@ -255,16 +274,21 @@ class ModuleDNSBL : public Module, public Stats::EventListener { } + void init() CXX11_OVERRIDE + { + ServerInstance->SNO->EnableSnomask('d', "DNSBL"); + } + 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 */ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { - DNSBLConfEntries.clear(); + DNSBLConfList newentries; ConfigTagList dnsbls = ServerInstance->Config->ConfTags("dnsbl"); for(ConfigIter i = dnsbls.first; i != dnsbls.second; ++i) @@ -275,13 +299,13 @@ 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 (tag->getString("type") == "bitmask") + if (stdalgo::string::equalsci(tag->getString("type"), "bitmask")) { e->type = DNSBLConfEntry::A_BITMASK; - e->bitmask = tag->getInt("bitmask", 0, 0, UINT_MAX); + e->bitmask = tag->getUInt("bitmask", 0, 0, UINT_MAX); } else { @@ -301,37 +325,28 @@ class ModuleDNSBL : public Module, public Stats::EventListener /* yeah, logic here is a little messy */ if ((e->bitmask <= 0) && (DNSBLConfEntry::A_BITMASK == e->type)) { - std::string location = tag->getTagLocation(); - ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): invalid bitmask", location.c_str()); + throw ModuleException("Invalid at " + tag->getTagLocation()); } else if (e->name.empty()) { - std::string location = tag->getTagLocation(); - ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): Invalid name", location.c_str()); + throw ModuleException("Empty at " + tag->getTagLocation()); } else if (e->domain.empty()) { - std::string location = tag->getTagLocation(); - ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): Invalid domain", location.c_str()); + throw ModuleException("Empty at " + tag->getTagLocation()); } else if (e->banaction == DNSBLConfEntry::I_UNKNOWN) { - std::string location = tag->getTagLocation(); - ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): Invalid banaction", location.c_str()); + throw ModuleException("Unknown at " + tag->getTagLocation()); } else { - if (e->reason.empty()) - { - std::string location = tag->getTagLocation(); - ServerInstance->SNO->WriteGlobalSno('a', "DNSBL(%s): empty reason, using defaults", location.c_str()); - e->reason = "Your IP has been blacklisted."; - } - /* add it, all is ok */ - DNSBLConfEntries.push_back(e); + newentries.push_back(e); } } + + DNSBLConfEntries.swap(newentries); } void OnSetUserIP(LocalUser* user) CXX11_OVERRIDE @@ -339,6 +354,10 @@ class ModuleDNSBL : public Module, public Stats::EventListener if ((user->exempt) || !DNS) return; + // Clients can't be in a DNSBL if they aren't connected via IPv4 or IPv6. + if (user->client_sa.family() != AF_INET && user->client_sa.family() != AF_INET6) + return; + if (user->MyClass) { if (!user->MyClass->config->getBool("usednsbl", true)) @@ -348,7 +367,7 @@ class ModuleDNSBL : public Module, public Stats::EventListener ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User has no connect class in OnSetUserIP"); std::string reversedip; - if (user->client_sa.sa.sa_family == AF_INET) + if (user->client_sa.family() == AF_INET) { unsigned int a, b, c, d; d = (unsigned int) (user->client_sa.in4.sin_addr.s_addr >> 24) & 0xFF; @@ -358,7 +377,7 @@ class ModuleDNSBL : public Module, public Stats::EventListener reversedip = ConvToStr(d) + "." + ConvToStr(c) + "." + ConvToStr(b) + "." + ConvToStr(a); } - else if (user->client_sa.sa.sa_family == AF_INET6) + else if (user->client_sa.family() == AF_INET6) { const unsigned char* ip = user->client_sa.in6.sin6_addr.s6_addr; @@ -368,6 +387,7 @@ class ModuleDNSBL : public Module, public Stats::EventListener reversedip.push_back(*it); reversedip.push_back('.'); } + reversedip.erase(reversedip.length() - 1, 1); } else return; @@ -404,11 +424,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