summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/modules.example.conf8
-rw-r--r--include/modules/dns.h4
-rw-r--r--modules/commands/os_dns.cpp12
-rw-r--r--modules/m_dns.cpp110
4 files changed, 121 insertions, 13 deletions
diff --git a/data/modules.example.conf b/data/modules.example.conf
index aaf7048b2..030a01258 100644
--- a/data/modules.example.conf
+++ b/data/modules.example.conf
@@ -66,6 +66,14 @@ module { name = "help" }
* if you want your records to be updated without much delay.
*/
refresh = 3600
+
+ /* A notify block. There should probably be one per nameserver listed in 'nameservers'.
+ */
+ notify
+ {
+ ip = "192.0.2.0"
+ port = 53
+ }
}
/*
diff --git a/include/modules/dns.h b/include/modules/dns.h
index 44b9370cb..71697cc32 100644
--- a/include/modules/dns.h
+++ b/include/modules/dns.h
@@ -38,13 +38,14 @@ namespace DNS
/* A lookup for any record */
QUERY_ANY = 255
};
-
+
/** Flags that can be AND'd into DNSPacket::flags to receive certain values
*/
enum
{
QUERYFLAGS_QR = 0x8000,
QUERYFLAGS_OPCODE = 0x7800,
+ QUERYFLAGS_OPCODE_NOTIFY = 0x2000,
QUERYFLAGS_AA = 0x400,
QUERYFLAGS_TC = 0x200,
QUERYFLAGS_RD = 0x100,
@@ -126,6 +127,7 @@ namespace DNS
virtual bool HandlePacket(ReplySocket *s, const unsigned char *const data, int len, sockaddrs *from) = 0;
virtual void UpdateSerial() = 0;
+ virtual void Notify(const Anope::string &zone) = 0;
virtual uint32_t GetSerial() const = 0;
};
diff --git a/modules/commands/os_dns.cpp b/modules/commands/os_dns.cpp
index 1df401112..717cbf29b 100644
--- a/modules/commands/os_dns.cpp
+++ b/modules/commands/os_dns.cpp
@@ -131,7 +131,11 @@ class DNSServer : public Serializable
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
@@ -458,7 +462,11 @@ class CommandOSDNS : public Command
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)
@@ -485,7 +493,11 @@ class CommandOSDNS : public Command
}
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;
}
diff --git a/modules/m_dns.cpp b/modules/m_dns.cpp
index 422d035b3..214e97cf4 100644
--- a/modules/m_dns.cpp
+++ b/modules/m_dns.cpp
@@ -612,6 +612,39 @@ class UDPSocket : public ReplySocket
}
};
+class NotifySocket : public Socket
+{
+ Packet *packet;
+ public:
+ NotifySocket(bool v6, Packet *p) : Socket(-1, v6, SOCK_DGRAM), packet(p)
+ {
+ SocketEngine::Change(this, false, SF_READABLE);
+ SocketEngine::Change(this, true, SF_WRITABLE);
+ }
+
+ bool ProcessWrite() anope_override
+ {
+ if (!packet)
+ return false;
+
+ Log(LOG_DEBUG_2) << "Resolver: Notifying slave " << packet->addr.addr();
+
+ try
+ {
+ unsigned char buffer[524];
+ unsigned short len = packet->Pack(buffer, sizeof(buffer));
+
+ sendto(this->GetFD(), reinterpret_cast<char *>(buffer), len, 0, &packet->addr.sa, packet->addr.size());
+ }
+ catch (const SocketException &) { }
+
+ delete packet;
+ packet = NULL;
+
+ return false;
+ }
+};
+
class MyManager : public Manager, public Timer
{
uint32_t serial;
@@ -624,6 +657,8 @@ class MyManager : public Manager, public Timer
bool listen;
sockaddrs addrs;
+
+ std::vector<std::pair<Anope::string, short> > notify;
public:
std::map<unsigned short, Request *> requests;
@@ -652,7 +687,7 @@ class MyManager : public Manager, public Timer
this->cache.clear();
}
- void SetIPPort(const Anope::string &nameserver, const Anope::string &ip, unsigned short port)
+ void SetIPPort(const Anope::string &nameserver, const Anope::string &ip, unsigned short port, std::vector<std::pair<Anope::string, short> > n)
{
delete udpsock;
delete tcpsock;
@@ -677,8 +712,26 @@ class MyManager : public Manager, public Timer
{
Log() << "Unable to bind dns to " << ip << ":" << port << ": " << ex.GetReason();
}
+
+ notify = n;
+ }
+
+ private:
+ unsigned short GetID()
+ {
+ if (this->udpsock->GetPackets().size() == 65535)
+ throw SocketException("DNS queue full");
+
+ static unsigned short cur_id = rand();
+
+ do
+ cur_id = (cur_id + 1) & 0xFFFF;
+ while (!cur_id || this->requests.count(cur_id));
+
+ return cur_id;
}
+ public:
void Process(Request *req) anope_override
{
Log(LOG_DEBUG_2) << "Resolver: Processing request to lookup " << req->name << ", of type " << req->type;
@@ -693,16 +746,7 @@ class MyManager : public Manager, public Timer
if (!this->udpsock)
throw SocketException("No dns socket");
- if (this->udpsock->GetPackets().size() == 65535)
- throw SocketException("DNS queue full");
-
- do
- {
- static unsigned short cur_id = rand();
- cur_id = req->id = (cur_id + 1) & 0xFFFF;
- }
- while (!req->id || this->requests.count(req->id));
-
+ req->id = GetID();
this->requests[req->id] = req;
req->SetSecs(timeout);
@@ -877,6 +921,37 @@ class MyManager : public Manager, public Timer
serial = Anope::CurTime;
}
+ void Notify(const Anope::string &zone) anope_override
+ {
+ /* notify slaves of the update */
+ for (unsigned i = 0; i < notify.size(); ++i)
+ {
+ const Anope::string &ip = notify[i].first;
+ short port = notify[i].second;
+
+ sockaddrs addr;
+ addr.pton(ip.find(':') != Anope::string::npos ? AF_INET6 : AF_INET, ip, port);
+ if (!addr.valid())
+ return;
+
+ Packet *packet = new Packet(this, &addr);
+ packet->flags = QUERYFLAGS_AA | QUERYFLAGS_OPCODE_NOTIFY;
+ try
+ {
+ packet->id = GetID();
+ }
+ catch (const SocketException &)
+ {
+ delete packet;
+ continue;
+ }
+
+ packet->questions.push_back(Question(zone, QUERY_SOA));
+
+ new NotifySocket(ip.find(':') != Anope::string::npos ? AF_INET6 : AF_INET, packet);
+ }
+ }
+
uint32_t GetSerial() const anope_override
{
return serial;
@@ -936,6 +1011,8 @@ class ModuleDNS : public Module
Anope::string ip;
int port;
+ std::vector<std::pair<Anope::string, short> > notify;
+
public:
ModuleDNS(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR), manager(this)
{
@@ -954,6 +1031,15 @@ class ModuleDNS : public Module
nameservers = block->Get<const Anope::string>("nameservers", "ns1.example.com");
refresh = block->Get<int>("refresh", "3600");
+ for (int i = 0; i < block->CountBlock("notify"); ++i)
+ {
+ Configuration::Block *n = block->GetBlock("notify", i);
+ Anope::string nip = n->Get<Anope::string>("ip");
+ short nport = n->Get<short>("port");
+
+ notify.push_back(std::make_pair(nip, nport));
+ }
+
if (Anope::IsFile(nameserver))
{
std::ifstream f(nameserver.c_str());
@@ -991,7 +1077,7 @@ class ModuleDNS : public Module
try
{
- this->manager.SetIPPort(nameserver, ip, port);
+ this->manager.SetIPPort(nameserver, ip, port, notify);
}
catch (const SocketException &ex)
{