1
0
mirror of https://github.com/anope/anope.git synced 2026-06-25 14:06:37 +02:00
Files
anope/modules/commands/os_dns.cpp
T
Robby- bf67b9ee5c Make column titles in listings translatable.
Make some more strings translatable, and remove some that don't need translation at all.

Make expirytimes and units translatable.

Make predefined messages in listings also translatable.

Make the remaining command descriptions translatable.

Make some ns/cs info strings equal to dedupe in translation file. Add missing no-autoop setting to cs info output. Make some strings translatable.
2013-09-27 19:11:02 -04:00

881 lines
23 KiB
C++

/*
* (C) 2003-2013 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*/
#include "module.h"
#include "modules/dns.h"
static ServiceReference<DNS::Manager> dnsmanager("DNS::Manager", "dns/manager");
class DNSZone;
class DNSServer;
static Serialize::Checker<std::vector<DNSZone *> > zones("DNSZone");
static Serialize::Checker<std::vector<DNSServer *> > dns_servers("DNSServer");
static std::map<Anope::string, std::list<time_t> > server_quit_times;
struct DNSZone : Serializable
{
Anope::string name;
std::set<Anope::string, ci::less> servers;
DNSZone(const Anope::string &n) : Serializable("DNSZone"), name(n)
{
zones->push_back(this);
}
~DNSZone()
{
std::vector<DNSZone *>::iterator it = std::find(zones->begin(), zones->end(), this);
if (it != zones->end())
zones->erase(it);
}
void Serialize(Serialize::Data &data) const anope_override
{
data["name"] << name;
unsigned count = 0;
for (std::set<Anope::string, ci::less>::iterator it = servers.begin(), it_end = servers.end(); it != it_end; ++it)
data["server" + stringify(count++)] << *it;
}
static Serializable* Unserialize(Serializable *obj, Serialize::Data &data)
{
DNSZone *zone;
Anope::string zone_name;
data["name"] >> zone_name;
if (obj)
{
zone = anope_dynamic_static_cast<DNSZone *>(obj);
data["name"] >> zone->name;
}
else
zone = new DNSZone(zone_name);
zone->servers.clear();
for (unsigned count = 0; true; ++count)
{
Anope::string server_str;
data["server" + stringify(count)] >> server_str;
if (server_str.empty())
break;
zone->servers.insert(server_str);
}
return zone;
}
static DNSZone *Find(const Anope::string &name)
{
for (unsigned i = 0; i < zones->size(); ++i)
if (zones->at(i)->name.equals_ci(name))
{
DNSZone *z = zones->at(i);
z->QueueUpdate();
return z;
}
return NULL;
}
};
class DNSServer : public Serializable
{
Anope::string server_name;
std::vector<Anope::string> ips;
unsigned limit;
/* wants to be in the pool */
bool pooled;
/* is actually in the pool */
bool active;
public:
std::set<Anope::string, ci::less> zones;
time_t repool;
DNSServer(const Anope::string &sn) : Serializable("DNSServer"), server_name(sn), limit(0), pooled(false), active(false), repool(0)
{
dns_servers->push_back(this);
}
~DNSServer()
{
std::vector<DNSServer *>::iterator it = std::find(dns_servers->begin(), dns_servers->end(), this);
if (it != dns_servers->end())
dns_servers->erase(it);
}
const Anope::string &GetName() const { return server_name; }
std::vector<Anope::string> &GetIPs() { return ips; }
unsigned GetLimit() const { return limit; }
void SetLimit(unsigned l) { limit = l; }
bool Pooled() const { return pooled; }
void Pool(bool p)
{
if (!p)
this->SetActive(p);
pooled = p;
}
bool Active() const { return pooled && active; }
void SetActive(bool p)
{
if (p)
this->Pool(p);
active = p;
if (dnsmanager)
{
dnsmanager->UpdateSerial();
for (std::set<Anope::string, ci::less>::iterator it = zones.begin(), it_end = zones.end(); it != it_end; ++it)
dnsmanager->Notify(*it);
}
}
void Serialize(Serialize::Data &data) const anope_override
{
data["server_name"] << server_name;
for (unsigned i = 0; i < ips.size(); ++i)
data["ip" + stringify(i)] << ips[i];
data["limit"] << limit;
data["pooled"] << pooled;
unsigned count = 0;
for (std::set<Anope::string, ci::less>::iterator it = zones.begin(), it_end = zones.end(); it != it_end; ++it)
data["zone" + stringify(count++)] << *it;
}
static Serializable* Unserialize(Serializable *obj, Serialize::Data &data)
{
DNSServer *req;
Anope::string server_name;
data["server_name"] >> server_name;
if (obj)
{
req = anope_dynamic_static_cast<DNSServer *>(obj);
req->server_name = server_name;
}
else
req = new DNSServer(server_name);
for (unsigned i = 0; true; ++i)
{
Anope::string ip_str;
data["ip" + stringify(i)] >> ip_str;
if (ip_str.empty())
break;
req->ips.push_back(ip_str);
}
data["limit"] >> req->limit;
data["pooled"] >> req->pooled;
req->zones.clear();
for (unsigned i = 0; true; ++i)
{
Anope::string zone_str;
data["zone" + stringify(i)] >> zone_str;
if (zone_str.empty())
break;
req->zones.insert(zone_str);
}
return req;
}
static DNSServer *Find(const Anope::string &s)
{
for (unsigned i = 0; i < dns_servers->size(); ++i)
if (dns_servers->at(i)->GetName().equals_ci(s))
{
DNSServer *serv = dns_servers->at(i);
serv->QueueUpdate();
return serv;
}
return NULL;
}
};
class CommandOSDNS : public Command
{
void DisplayPoolState(CommandSource &source)
{
if (dns_servers->empty())
{
source.Reply(_("There are no configured servers."));
return;
}
ListFormatter lf(source.GetAccount());
lf.AddColumn(_("Server")).AddColumn(_("IP")).AddColumn(_("Limit")).AddColumn(_("State"));
for (unsigned i = 0; i < dns_servers->size(); ++i)
{
DNSServer *s = dns_servers->at(i);
Server *srv = Server::Find(s->GetName(), true);
ListFormatter::ListEntry entry;
entry["Server"] = s->GetName();
entry["Limit"] = s->GetLimit() ? stringify(s->GetLimit()) : Language::Translate(source.GetAccount(), _("None"));
Anope::string ip_str;
for (unsigned j = 0; j < s->GetIPs().size(); ++j)
ip_str += s->GetIPs()[j] + " ";
ip_str.trim();
if (ip_str.empty())
ip_str = "None";
entry["IP"] = ip_str;
if (!srv)
entry["State"] = Language::Translate(source.GetAccount(), _("Split"));
else if (s->Active())
entry["State"] = Language::Translate(source.GetAccount(), _("Pooled/Active"));
else if (s->Pooled())
entry["State"] = Language::Translate(source.GetAccount(), _("Pooled/Not Active"));
else
entry["State"] = Language::Translate(source.GetAccount(), _("Unpooled"));
lf.AddEntry(entry);
}
std::vector<Anope::string> replies;
lf.Process(replies);
if (!zones->empty())
{
ListFormatter lf2(source.GetAccount());
lf2.AddColumn(_("Zone")).AddColumn(_("Servers"));
for (unsigned i = 0; i < zones->size(); ++i)
{
const DNSZone *z = zones->at(i);
ListFormatter::ListEntry entry;
entry["Zone"] = z->name;
Anope::string server_str;
for (std::set<Anope::string, ci::less>::iterator it = z->servers.begin(), it_end = z->servers.end(); it != it_end; ++it)
server_str += *it + " ";
server_str.trim();
if (server_str.empty())
server_str = "None";
entry["Servers"] = server_str;
lf2.AddEntry(entry);
}
lf2.Process(replies);
}
for (unsigned i = 0; i < replies.size(); ++i)
source.Reply(replies[i]);
}
void AddZone(CommandSource &source, const std::vector<Anope::string> &params)
{
const Anope::string &zone = params[1];
if (DNSZone::Find(zone))
{
source.Reply(_("Zone %s already exists."), zone.c_str());
return;
}
Log(LOG_ADMIN, source, this) << "to add zone " << zone;
new DNSZone(zone);
source.Reply(_("Added zone %s."), zone.c_str());
}
void DelZone(CommandSource &source, const std::vector<Anope::string> &params)
{
const Anope::string &zone = params[1];
DNSZone *z = DNSZone::Find(zone);
if (!z)
{
source.Reply(_("Zone %s does not exist."), zone.c_str());
return;
}
Log(LOG_ADMIN, source, this) << "to delete zone " << z->name;
for (std::set<Anope::string, ci::less>::iterator it = z->servers.begin(), it_end = z->servers.end(); it != it_end; ++it)
{
DNSServer *s = DNSServer::Find(*it);
if (s)
s->zones.erase(z->name);
}
source.Reply(_("Zone %s removed."), z->name.c_str());
delete z;
}
void AddServer(CommandSource &source, const std::vector<Anope::string> &params)
{
DNSServer *s = DNSServer::Find(params[1]);
const Anope::string &zone = params.size() > 2 ? params[2] : "";
if (s)
{
if (zone.empty())
{
source.Reply(_("Server %s already exists."), s->GetName().c_str());
}
else
{
DNSZone *z = DNSZone::Find(zone);
if (!z)
{
source.Reply(_("Zone %s does not exist."), zone.c_str());
return;
}
else if (z->servers.count(s->GetName()))
{
source.Reply(_("Server %s is already in zone %s."), s->GetName().c_str(), z->name.c_str());
return;
}
z->servers.insert(s->GetName());
s->zones.insert(zone);
Log(LOG_ADMIN, source, this) << "to add server " << s->GetName() << " to zone " << z->name;
source.Reply(_("Server %s added to zone %s."), s->GetName().c_str(), z->name.c_str());
}
return;
}
Server *serv = Server::Find(params[1], true);
if (!serv || serv == Me || serv->IsJuped())
{
source.Reply(_("Server %s is not linked to the network."), params[1].c_str());
return;
}
s = new DNSServer(params[1]);
if (zone.empty())
{
Log(LOG_ADMIN, source, this) << "to add server " << s->GetName();
source.Reply(_("Added server %s."), s->GetName().c_str());
}
else
{
DNSZone *z = DNSZone::Find(zone);
if (!z)
{
source.Reply(_("Zone %s does not exist."), zone.c_str());
delete s;
return;
}
Log(LOG_ADMIN, source, this) << "to add server " << s->GetName() << " to zone " << zone;
z->servers.insert(s->GetName());
s->zones.insert(z->name);
}
}
void DelServer(CommandSource &source, const std::vector<Anope::string> &params)
{
DNSServer *s = DNSServer::Find(params[1]);
const Anope::string &zone = params.size() > 2 ? params[2] : "";
if (!s)
{
source.Reply(_("Server %s does not exist."), params[1].c_str());
return;
}
else if (!zone.empty())
{
DNSZone *z = DNSZone::Find(zone);
if (!z)
{
source.Reply(_("Zone %s does not exist."), zone.c_str());
return;
}
else if (!z->servers.count(s->GetName()))
{
source.Reply(_("Server %s is not in zone %s."), s->GetName().c_str(), z->name.c_str());
return;
}
Log(LOG_ADMIN, source, this) << "to remove server " << s->GetName() << " from zone " << z->name;
z->servers.erase(s->GetName());
source.Reply(_("Removed server %s from zone %s."), s->GetName().c_str(), z->name.c_str());
return;
}
else if (Server::Find(s->GetName(), true))
{
source.Reply(_("Server %s must be quit before it can be deleted."), s->GetName().c_str());
return;
}
for (std::set<Anope::string, ci::less>::iterator it = s->zones.begin(), it_end = s->zones.end(); it != it_end; ++it)
{
DNSZone *z = DNSZone::Find(*it);
if (z)
z->servers.erase(s->GetName());
}
Log(LOG_ADMIN, source, this) << "to delete server " << s->GetName();
source.Reply(_("Removed server %s."), s->GetName().c_str());
delete s;
}
void AddIP(CommandSource &source, const std::vector<Anope::string> &params)
{
DNSServer *s = DNSServer::Find(params[1]);
if (!s)
{
source.Reply(_("Server %s does not exist."), params[1].c_str());
return;
}
for (unsigned i = 0; i < s->GetIPs().size(); ++i)
if (params[2].equals_ci(s->GetIPs()[i]))
{
source.Reply(_("IP %s already exists for %s."), s->GetIPs()[i].c_str(), s->GetName().c_str());
return;
}
sockaddrs addr(params[2]);
if (!addr.valid())
{
source.Reply(_("%s is not a valid IP address."), params[2].c_str());
return;
}
s->GetIPs().push_back(params[2]);
source.Reply(_("Added IP %s to %s."), params[2].c_str(), s->GetName().c_str());
Log(LOG_ADMIN, source, this) << "to add IP " << params[2] << " to " << s->GetName();
if (s->Active() && dnsmanager)
{
dnsmanager->UpdateSerial();
for (std::set<Anope::string, ci::less>::iterator it = s->zones.begin(), it_end = s->zones.end(); it != it_end; ++it)
dnsmanager->Notify(*it);
}
}
void DelIP(CommandSource &source, const std::vector<Anope::string> &params)
{
DNSServer *s = DNSServer::Find(params[1]);
if (!s)
{
source.Reply(_("Server %s does not exist."), params[1].c_str());
return;
}
for (unsigned i = 0; i < s->GetIPs().size(); ++i)
if (params[2].equals_ci(s->GetIPs()[i]))
{
s->GetIPs().erase(s->GetIPs().begin() + i);
source.Reply(_("Removed IP %s from %s."), params[2].c_str(), s->GetName().c_str());
Log(LOG_ADMIN, source, this) << "to remove IP " << params[2] << " from " << s->GetName();
if (s->GetIPs().empty())
{
s->repool = 0;
s->Pool(false);
}
if (s->Active() && dnsmanager)
{
dnsmanager->UpdateSerial();
for (std::set<Anope::string, ci::less>::iterator it = s->zones.begin(), it_end = s->zones.end(); it != it_end; ++it)
dnsmanager->Notify(*it);
}
return;
}
source.Reply(_("IP %s does not exist for %s."), params[2].c_str(), s->GetName().c_str());
}
void OnSet(CommandSource &source, const std::vector<Anope::string> &params)
{
DNSServer *s = DNSServer::Find(params[1]);
if (!s)
{
source.Reply(_("Server %s does not exist."), params[1].c_str());
return;
}
if (params[2].equals_ci("LIMIT"))
{
try
{
unsigned l = convertTo<unsigned>(params[3]);
s->SetLimit(l);
if (l)
source.Reply(_("User limit for %s set to %d."), s->GetName().c_str(), l);
else
source.Reply(_("User limit for %s removed."), s->GetName().c_str());
}
catch (const ConvertException &ex)
{
source.Reply(_("Invalid value for LIMIT. Must be numerical."));
}
}
else
source.Reply(_("Unknown SET option."));
}
void OnPool(CommandSource &source, const std::vector<Anope::string> &params)
{
DNSServer *s = DNSServer::Find(params[1]);
if (!s)
{
source.Reply(_("Server %s does not exist."), params[1].c_str());
return;
}
else if (!Server::Find(s->GetName(), true))
{
source.Reply(_("Server %s is not currently linked."), s->GetName().c_str());
return;
}
else if (s->Pooled())
{
source.Reply(_("Server %s is already pooled."), s->GetName().c_str());
return;
}
else if (s->GetIPs().empty())
{
source.Reply(_("Server %s has no configured IPs."), s->GetName().c_str());
return;
}
s->SetActive(true);
source.Reply(_("Pooled %s."), s->GetName().c_str());
Log(LOG_ADMIN, source, this) << "to pool " << s->GetName();
}
void OnDepool(CommandSource &source, const std::vector<Anope::string> &params)
{
DNSServer *s = DNSServer::Find(params[1]);
if (!s)
{
source.Reply(_("Server %s does not exist."), params[1].c_str());
return;
}
else if (!s->Pooled())
{
source.Reply(_("Server %s is not pooled."), s->GetName().c_str());
return;
}
s->Pool(false);
source.Reply(_("Depooled %s."), s->GetName().c_str());
Log(LOG_ADMIN, source, this) << "to depool " << s->GetName();
}
public:
CommandOSDNS(Module *creator) : Command(creator, "operserv/dns", 0, 3)
{
this->SetDesc(_("Manage DNS zones for this network"));
this->SetSyntax(_("ADDZONE \037zone.name\037"));
this->SetSyntax(_("DELZONE \037zone.name\037"));
this->SetSyntax(_("ADDSERVER \037server.name\037 [\037zone.name\037]"));
this->SetSyntax(_("DELSERVER \037server.name\037 [\037zone.name\037]"));
this->SetSyntax(_("ADDIP \037server.name\037 \037ip\037"));
this->SetSyntax(_("DELIP \037server.name\037 \037ip\037"));
this->SetSyntax(_("SET \037server.name\037 \037option\037 \037value\037"));
this->SetSyntax(_("POOL \037server.name\037"));
this->SetSyntax(_("DEPOOL \037server.name\037"));
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
{
if (params.empty())
this->DisplayPoolState(source);
else if (params[0].equals_ci("ADDZONE") && params.size() > 1)
this->AddZone(source, params);
else if (params[0].equals_ci("DELZONE") && params.size() > 1)
this->DelZone(source, params);
else if (params[0].equals_ci("ADDSERVER") && params.size() > 1)
this->AddServer(source, params);
else if (params[0].equals_ci("DELSERVER") && params.size() > 1)
this->DelServer(source, params);
else if (params[0].equals_ci("ADDIP") && params.size() > 2)
this->AddIP(source, params);
else if (params[0].equals_ci("DELIP") && params.size() > 2)
this->DelIP(source, params);
else if (params[0].equals_ci("SET") && params.size() > 3)
this->OnSet(source, params);
else if (params[0].equals_ci("POOL") && params.size() > 1)
this->OnPool(source, params);
else if (params[0].equals_ci("DEPOOL") && params.size() > 1)
this->OnDepool(source, params);
else
this->OnSyntaxError(source, "");
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("This command allows managing DNS zones used for controlling what servers users\n"
"are directed to when connecting. Omitting all parameters prints out the status of\n"
"the DNS zone.\n"
" \n"
"\002ADDZONE\002 adds a zone, eg us.yournetwork.tld. Servers can then be added to this\n"
"zone with the \002ADDSERVER\002 command.\n"
" \n"
"The \002ADDSERVER\002 command adds a server to the given zone. When a query is done, the\n"
"zone in question is served if it exists, else all servers in all zones are served.\n"
"A server may be in more than one zone.\n"
" \n"
"The \002ADDIP\002 command associates an IP with a server.\n"
" \n"
"The \002POOL\002 and \002DEPOOL\002 commands actually add and remove servers to their given zones."));
return true;
}
};
class ModuleDNS : public Module
{
Serialize::Type zone_type, dns_type;
CommandOSDNS commandosdns;
time_t ttl;
int user_drop_mark;
time_t user_drop_time;
time_t user_drop_readd_time;
bool remove_split_servers;
bool readd_connected_servers;
time_t last_warn;
public:
ModuleDNS(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR),
zone_type("DNSZone", DNSZone::Unserialize), dns_type("DNSServer", DNSServer::Unserialize), commandosdns(this),
last_warn(0)
{
for (unsigned j = 0; j < dns_servers->size(); ++j)
{
DNSServer *s = dns_servers->at(j);
if (s->Pooled() && Server::Find(s->GetName(), true))
s->SetActive(true);
}
}
~ModuleDNS()
{
for (unsigned i = zones->size(); i > 0; --i)
delete zones->at(i - 1);
for (unsigned i = dns_servers->size(); i > 0; --i)
delete dns_servers->at(i - 1);
}
void OnReload(Configuration::Conf *conf) anope_override
{
Configuration::Block *block = conf->GetModule(this);
this->ttl = block->Get<time_t>("ttl");
this->user_drop_mark = block->Get<int>("user_drop_mark");
this->user_drop_time = block->Get<time_t>("user_drop_time");
this->user_drop_readd_time = block->Get<time_t>("user_drop_readd_time");
this->remove_split_servers = block->Get<bool>("remove_split_servers");
this->readd_connected_servers = block->Get<bool>("readd_connected_servers");
}
void OnNewServer(Server *s) anope_override
{
if (s == Me || s->IsJuped())
return;
if (!Me->IsSynced() || this->readd_connected_servers)
{
DNSServer *dns = DNSServer::Find(s->GetName());
if (dns && dns->Pooled() && !dns->Active() && !dns->GetIPs().empty())
{
dns->SetActive(true);
Log(this) << "Pooling server " << s->GetName();
}
}
}
void OnServerQuit(Server *s) anope_override
{
DNSServer *dns = DNSServer::Find(s->GetName());
if (dns && dns->Pooled() && dns->Active())
{
dns->SetActive(false);
Log(this) << "Depooling delinked server " << s->GetName();
}
}
void OnUserConnect(User *u, bool &exempt) anope_override
{
if (!u->Quitting() && u->server)
{
DNSServer *s = DNSServer::Find(u->server->GetName());
/* Check for user limit reached */
if (s && s->Pooled() && s->Active() && s->GetLimit() && u->server->users >= s->GetLimit())
{
Log(this) << "Depooling full server " << s->GetName() << ": " << u->server->users << " users";
s->SetActive(false);
}
}
}
void OnPreUserLogoff(User *u) anope_override
{
if (u && u->server)
{
DNSServer *s = DNSServer::Find(u->server->GetName());
if (!s || !s->Pooled())
return;
/* Check for dropping under userlimit */
if (s->GetLimit() && !s->Active() && s->GetLimit() > u->server->users)
{
Log(this) << "Pooling server " << s->GetName();
s->SetActive(true);
}
if (this->user_drop_mark > 0)
{
std::list<time_t>& times = server_quit_times[u->server->GetName()];
times.push_back(Anope::CurTime);
if (times.size() > static_cast<unsigned>(this->user_drop_mark))
times.pop_front();
if (times.size() == static_cast<unsigned>(this->user_drop_mark))
{
time_t diff = Anope::CurTime - *times.begin();
/* Check for very fast user drops */
if (s->Active() && diff <= this->user_drop_time)
{
Log(this) << "Depooling server " << s->GetName() << ": dropped " << this->user_drop_mark << " users in " << diff << " seconds";
s->repool = Anope::CurTime + this->user_drop_readd_time;
s->SetActive(false);
}
/* Check for needing to re-pool a server that dropped users */
else if (!s->Active() && s->repool && s->repool <= Anope::CurTime)
{
s->SetActive(true);
s->repool = 0;
Log(this) << "Pooling server " << s->GetName();
}
}
}
}
}
void OnDnsRequest(DNS::Query &req, DNS::Query *packet) anope_override
{
if (req.questions.empty())
return;
/* Currently we reply to any QR for A/AAAA */
const DNS::Question& q = req.questions[0];
if (q.type != DNS::QUERY_A && q.type != DNS::QUERY_AAAA && q.type != DNS::QUERY_AXFR && q.type != DNS::QUERY_ANY)
return;
DNSZone *zone = DNSZone::Find(q.name);
size_t answer_size = packet->answers.size();
if (zone)
{
for (std::set<Anope::string, ci::less>::iterator it = zone->servers.begin(), it_end = zone->servers.end(); it != it_end; ++it)
{
DNSServer *s = DNSServer::Find(*it);
if (!s || !s->Active())
continue;
for (unsigned j = 0; j < s->GetIPs().size(); ++j)
{
DNS::QueryType q_type = s->GetIPs()[j].find(':') != Anope::string::npos ? DNS::QUERY_AAAA : DNS::QUERY_A;
if (q.type == DNS::QUERY_AXFR || q.type == DNS::QUERY_ANY || q_type == q.type)
{
DNS::ResourceRecord rr(q.name, q_type);
rr.ttl = this->ttl;
rr.rdata = s->GetIPs()[j];
packet->answers.push_back(rr);
}
}
}
}
if (packet->answers.size() == answer_size)
{
/* Default zone */
for (unsigned i = 0; i < dns_servers->size(); ++i)
{
DNSServer *s = dns_servers->at(i);
if (!s->Active())
continue;
for (unsigned j = 0; j < s->GetIPs().size(); ++j)
{
DNS::QueryType q_type = s->GetIPs()[j].find(':') != Anope::string::npos ? DNS::QUERY_AAAA : DNS::QUERY_A;
if (q.type == DNS::QUERY_AXFR || q.type == DNS::QUERY_ANY || q_type == q.type)
{
DNS::ResourceRecord rr(q.name, q_type);
rr.ttl = this->ttl;
rr.rdata = s->GetIPs()[j];
packet->answers.push_back(rr);
}
}
}
}
if (packet->answers.size() == answer_size)
{
if (last_warn + 60 < Anope::CurTime)
{
last_warn = Anope::CurTime;
Log(this) << "Warning! There are no pooled servers!";
}
/* Something messed up, just return them all and hope one is available */
for (unsigned i = 0; i < dns_servers->size(); ++i)
{
DNSServer *s = dns_servers->at(i);
for (unsigned j = 0; j < s->GetIPs().size(); ++j)
{
DNS::QueryType q_type = s->GetIPs()[j].find(':') != Anope::string::npos ? DNS::QUERY_AAAA : DNS::QUERY_A;
if (q.type == DNS::QUERY_AXFR || q.type == DNS::QUERY_ANY || q_type == q.type)
{
DNS::ResourceRecord rr(q.name, q_type);
rr.ttl = this->ttl;
rr.rdata = s->GetIPs()[j];
packet->answers.push_back(rr);
}
}
}
if (packet->answers.size() == answer_size)
{
Log(this) << "Error! There are no servers with any IPs of type " << q.type;
/* Send back an empty answer anyway */
}
}
}
};
MODULE_INIT(ModuleDNS)