anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

m_dnsbl.cpp (5264B)

      1 /*
      2  *
      3  * (C) 2003-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Please read COPYING and README for further details.
      7  */
      8 
      9 #include "module.h"
     10 #include "modules/dns.h"
     11 
     12 using namespace DNS;
     13 
     14 static ServiceReference<XLineManager> akills("XLineManager", "xlinemanager/sgline");
     15 static ServiceReference<Manager> dnsmanager("DNS::Manager", "dns/manager");
     16 
     17 struct Blacklist
     18 {
     19 	struct Reply
     20 	{
     21 		int code;
     22 		Anope::string reason;
     23 		bool allow_account;
     24 
     25 		Reply() : code(0), allow_account(false) { }
     26 	};
     27 
     28 	Anope::string name;
     29 	time_t bantime;
     30 	Anope::string reason;
     31 	std::vector<Reply> replies;
     32 
     33 	Blacklist() : bantime(0) { }
     34 
     35 	Reply *Find(int code)
     36 	{
     37 		for (unsigned int i = 0; i < replies.size(); ++i)
     38 			if (replies[i].code == code)
     39 				return &replies[i];
     40 		return NULL;
     41 	}
     42 };
     43 
     44 class DNSBLResolver : public Request
     45 {
     46 	Reference<User> user;
     47 	Blacklist blacklist;
     48 	bool add_to_akill;
     49 
     50  public:
     51 	DNSBLResolver(Module *c, User *u, const Blacklist &b, const Anope::string &host, bool add_akill) : Request(dnsmanager, c, host, QUERY_A, true), user(u), blacklist(b), add_to_akill(add_akill) { }
     52 
     53 	void OnLookupComplete(const Query *record) anope_override
     54 	{
     55 		if (!user || user->Quitting())
     56 			return;
     57 
     58 		const ResourceRecord &ans_record = record->answers[0];
     59 		// Replies should be in 127.0.0.0/8
     60 		if (ans_record.rdata.find("127.") != 0)
     61 			return;
     62 
     63 		sockaddrs sresult;
     64 		sresult.pton(AF_INET, ans_record.rdata);
     65 		int result = sresult.sa4.sin_addr.s_addr >> 24;
     66 
     67 		Blacklist::Reply *reply = blacklist.Find(result);
     68 		if (!blacklist.replies.empty() && !reply)
     69 			return;
     70 
     71 		if (reply && reply->allow_account && user->Account())
     72 			return;
     73 
     74 		Anope::string reason = this->blacklist.reason, addr = user->ip.addr();
     75 		reason = reason.replace_all_cs("%n", user->nick);
     76 		reason = reason.replace_all_cs("%u", user->GetIdent());
     77 		reason = reason.replace_all_cs("%g", user->realname);
     78 		reason = reason.replace_all_cs("%h", user->host);
     79 		reason = reason.replace_all_cs("%i", addr);
     80 		reason = reason.replace_all_cs("%r", reply ? reply->reason : "");
     81 		reason = reason.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname"));
     82 
     83 		BotInfo *OperServ = Config->GetClient("OperServ");
     84 		Log(creator, "dnsbl", OperServ) << user->GetMask() << " (" << addr << ") appears in " << this->blacklist.name;
     85 		XLine *x = new XLine("*@" + addr, OperServ ? OperServ->nick : "m_dnsbl", Anope::CurTime + this->blacklist.bantime, reason, XLineManager::GenerateUID());
     86 		if (this->add_to_akill && akills)
     87 		{
     88 			akills->AddXLine(x);
     89 			akills->Send(NULL, x);
     90 		}
     91 		else
     92 		{
     93 			IRCD->SendAkill(NULL, x);
     94 			delete x;
     95 		}
     96 	}
     97 };
     98 
     99 class ModuleDNSBL : public Module
    100 {
    101 	std::vector<Blacklist> blacklists;
    102 	std::set<cidr> exempts;
    103 	bool check_on_connect;
    104 	bool check_on_netburst;
    105 	bool add_to_akill;
    106 
    107  public:
    108 	ModuleDNSBL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR | EXTRA)
    109 	{
    110 
    111 	}
    112 
    113 	void OnReload(Configuration::Conf *conf) anope_override
    114 	{
    115 		Configuration::Block *block = conf->GetModule(this);
    116 		this->check_on_connect = block->Get<bool>("check_on_connect");
    117 		this->check_on_netburst = block->Get<bool>("check_on_netburst");
    118 		this->add_to_akill = block->Get<bool>("add_to_akill", "yes");
    119 
    120 		this->blacklists.clear();
    121 		for (int i = 0; i < block->CountBlock("blacklist"); ++i)
    122 		{
    123 			Configuration::Block *bl = block->GetBlock("blacklist", i);
    124 			Blacklist blacklist;
    125 
    126 			blacklist.name = bl->Get<Anope::string>("name");
    127 			if (blacklist.name.empty())
    128 				continue;
    129 			blacklist.bantime = bl->Get<time_t>("time", "4h");
    130 			blacklist.reason = bl->Get<Anope::string>("reason");
    131 
    132 			for (int j = 0; j < bl->CountBlock("reply"); ++j)
    133 			{
    134 				Configuration::Block *reply = bl->GetBlock("reply", j);
    135 				Blacklist::Reply r;
    136 
    137 				r.code = reply->Get<int>("code");
    138 				r.reason = reply->Get<Anope::string>("reason");
    139 				r.allow_account = reply->Get<bool>("allow_account");
    140 
    141 				blacklist.replies.push_back(r);
    142 			}
    143 
    144 			this->blacklists.push_back(blacklist);
    145 		}
    146 
    147 		this->exempts.clear();
    148 		for (int i = 0; i < block->CountBlock("exempt"); ++i)
    149 		{
    150 			Configuration::Block *bl = block->GetBlock("exempt", i);
    151 			this->exempts.insert(bl->Get<Anope::string>("ip"));
    152 		}
    153 	}
    154 
    155 	void OnUserConnect(User *user, bool &exempt) anope_override
    156 	{
    157 		if (exempt || user->Quitting() || (!this->check_on_connect && !Me->IsSynced()) || !dnsmanager)
    158 			return;
    159 
    160 		if (!this->check_on_netburst && !user->server->IsSynced())
    161 			return;
    162 
    163 		if (!user->ip.valid())
    164 			/* User doesn't have a valid IP (spoof/etc) */
    165 			return;
    166 
    167 		if (this->blacklists.empty())
    168 			return;
    169 
    170 		if (this->exempts.count(user->ip.addr()))
    171 		{
    172 			Log(LOG_DEBUG) << "User " << user->nick << " is exempt from dnsbl check - ip: " << user->ip.addr();
    173 			return;
    174 		}
    175 
    176 		Anope::string reverse = user->ip.reverse();
    177 
    178 		for (unsigned i = 0; i < this->blacklists.size(); ++i)
    179 		{
    180 			const Blacklist &b = this->blacklists[i];
    181 
    182 			Anope::string dnsbl_host = reverse + "." + b.name;
    183 			DNSBLResolver *res = NULL;
    184 			try
    185 			{
    186 				res = new DNSBLResolver(this, user, b, dnsbl_host, this->add_to_akill);
    187 				dnsmanager->Process(res);
    188 			}
    189 			catch (const SocketException &ex)
    190 			{
    191 				delete res;
    192 				Log(this) << ex.GetReason();
    193 			}
    194 		}
    195 	}
    196 };
    197 
    198 MODULE_INIT(ModuleDNSBL)