1
0
mirror of https://github.com/anope/anope.git synced 2026-07-02 17:33:13 +02:00

Fixed DNS caching and made DNS cache empty results

(cherry picked from commit 438ae629e51b519d0d5f70531d0262be1b9fe2bc)
This commit is contained in:
Adam
2010-11-09 14:59:35 -05:00
parent fe6d7913ce
commit 0d2db1f9f9
3 changed files with 107 additions and 64 deletions
+95 -60
View File
@@ -7,7 +7,7 @@ static inline unsigned short GetRandomID()
return rand();
}
DNSRequest::DNSRequest(const Anope::string &addr, QueryType qt, bool cache, Module *c) : timeout(NULL), id(0), creator(c), address(addr), QT(qt)
DNSRequest::DNSRequest(const Anope::string &addr, QueryType qt, bool cache, Module *c) : timeout(NULL), use_cache(cache), id(0), creator(c), address(addr), QT(qt)
{
if (!DNSEngine)
DNSEngine = new DNSManager();
@@ -18,36 +18,6 @@ DNSRequest::DNSRequest(const Anope::string &addr, QueryType qt, bool cache, Modu
}
if (DNSEngine->packets.size() == 65535)
throw SocketException("DNS queue full");
Log(LOG_DEBUG_2) << "Resolver: Processing request to lookup " << addr << ", of type " << qt;
if (cache && DNSEngine->CheckCache(this))
{
delete this;
return;
}
DNSPacket *p = new DNSPacket();
p->flags = DNS_QUERYFLAGS_RD;
if (!p->AddQuestion(addr, qt))
{
Log() << "Resolver: Unable to lookup host " << addr << " of type " << qt << " - internal error";
delete p;
delete this;
return;
}
unsigned short packet_id;
while (DNSEngine->requests.count((packet_id = GetRandomID())));
p->id = this->id = packet_id;
DNSEngine->requests[this->id] = this;
DNSEngine->packets.push_back(p);
SocketEngine->MarkWritable(DNSEngine->sock);
this->timeout = new DNSRequestTimeout(this, Config->DNSTimeout);
}
DNSRequest::~DNSRequest()
@@ -68,7 +38,43 @@ DNSRequest::~DNSRequest()
}
}
void DNSRequest::OnError(DNSError error, const Anope::string &message)
void DNSRequest::Process()
{
Log(LOG_DEBUG_2) << "Resolver: Processing request to lookup " << this->address << ", of type " << this->QT;
if (this->use_cache && DNSEngine->CheckCache(this))
{
Log(LOG_DEBUG_2) << "Resolver: Using cached result";
delete this;
return;
}
DNSPacket *p = new DNSPacket();
p->flags = DNS_QUERYFLAGS_RD;
if (!p->AddQuestion(this->address, this->QT))
{
Log() << "Resolver: Unable to lookup host " << this->address << " of type " << this->QT << " - internal error";
delete p;
delete this;
throw SocketException("Unable to lookup host " + this->address + " of type " + stringify(this->QT) + " - internal error");
}
unsigned short packet_id;
do
packet_id = GetRandomID();
while (DNSEngine->requests.count(packet_id));
p->id = this->id = packet_id;
DNSEngine->requests[this->id] = this;
DNSEngine->packets.push_back(p);
SocketEngine->MarkWritable(DNSEngine->sock);
this->timeout = new DNSRequestTimeout(this, Config->DNSTimeout);
}
void DNSRequest::OnError(const DNSRecord *r)
{
}
@@ -207,9 +213,10 @@ inline void DNSPacket::FillBuffer(unsigned char *buffer)
memcpy(&buffer[12], this->payload, this->payload_count);
}
inline DNSRecord::DNSRecord()
inline DNSRecord::DNSRecord(const Anope::string &n) : name(n)
{
this->type = DNS_QUERY_NONE;
this->error = DNS_ERROR_NONE;
this->record_class = this->ttl = this->rdlength = 0;
this->created = Anope::CurTime;
}
@@ -279,46 +286,59 @@ bool DNSSocket::ProcessRead()
if (!(recv_packet.flags & DNS_QUERYFLAGS_QR))
{
Log(LOG_DEBUG_2) << "Resolver: Received a non-answer";
request->OnError(DNS_ERROR_NOT_AN_ANSWER, "Received a non-answer");
DNSRecord rr(request->address);
rr.error = DNS_ERROR_NOT_AN_ANSWER;
request->OnError(&rr);
}
else if (recv_packet.flags & DNS_QUERYFLAGS_OPCODE)
{
Log(LOG_DEBUG_2) << "Resolver: Received a nonstandard query";
request->OnError(DNS_ERROR_NONSTANDARD_QUERY, "Received a nonstandard query");
DNSRecord rr(request->address);
rr.error = DNS_ERROR_NONSTANDARD_QUERY;
request->OnError(&rr);
}
else if (recv_packet.flags & DNS_QUERYFLAGS_RCODE)
{
DNSError error = DNS_ERROR_UNKNOWN;
switch (recv_packet.flags & DNS_QUERYFLAGS_RCODE)
{
case 1:
Log(LOG_DEBUG_2) << "Resolver: Format error";
request->OnError(DNS_ERROR_FORMAT_ERROR, "Format error");
Log(LOG_DEBUG_2) << "Resolver: format error";
error = DNS_ERROR_FORMAT_ERROR;
break;
case 2:
Log(LOG_DEBUG_2) << "Resolver: Server failure";
request->OnError(DNS_ERROR_SERVER_FAILURE, "Server failure");
Log(LOG_DEBUG_2) << "Resolver: server error";
error = DNS_ERROR_SERVER_FAILURE;
break;
case 3:
Log(LOG_DEBUG_2) << "Resolver: Domain name not found";
request->OnError(DNS_ERROR_DOMAIN_NOT_FOUND, "Domain not found");
Log(LOG_DEBUG_2) << "Resolver: domain not found";
error = DNS_ERROR_DOMAIN_NOT_FOUND;
break;
case 4:
Log(LOG_DEBUG_2) << "Resolver: Not Implemented - The name server does not support the requested kind of query.";
request->OnError(DNS_ERROR_NOT_IMPLEMENTED, "Not Implemented - The name server does not support the requested kind of query.");
Log(LOG_DEBUG_2) << "Resolver: not implemented";
error = DNS_ERROR_NOT_IMPLEMENTED;
break;
case 5:
Log(LOG_DEBUG_2) << "Resolver: Server refused to perform the specificed operation";
request->OnError(DNS_ERROR_REFUSED, "Server refused to perform the specified operation");
Log(LOG_DEBUG_2) << "Resolver: refused";
error = DNS_ERROR_REFUSED;
break;
default:
Log(LOG_DEBUG_2) << "Resolver: Unknown error";
request->OnError(DNS_ERROR_UNKNOWN, "Unknown error");
break;
}
DNSRecord *rr = new DNSRecord(request->address);
rr->ttl = 300;
rr->error = error;
request->OnError(rr);
DNSEngine->AddCache(rr);
}
else if (recv_packet.ancount < 1)
{
Log(LOG_DEBUG_2) << "Resolver: No resource records returned";
request->OnError(DNS_ERROR_NO_RECORDS, "No resource records returned");
DNSRecord rr(request->address);
rr.error = DNS_ERROR_NO_RECORDS;
request->OnError(&rr);
}
else
{
@@ -362,8 +382,7 @@ bool DNSSocket::ProcessRead()
else
packet_pos = packet_pos_ptr + 1;
DNSRecord *rr = new DNSRecord;
rr->name = name;
DNSRecord *rr = new DNSRecord(name);
Log(LOG_DEBUG_2) << "Resolver: Received answer for " << name;
@@ -390,7 +409,8 @@ bool DNSSocket::ProcessRead()
if (!inet_ntop(AF_INET, &ip, ipbuf, sizeof(ipbuf)))
{
Log(LOG_DEBUG_2) << "Resolver: Received an invalid IP for DNS_QUERY_A: " << Anope::LastError();
request->OnError(DNS_ERROR_FORMAT_ERROR, "Received an invalid IP from the nameserver: " + Anope::LastError());
rr->error = DNS_ERROR_FORMAT_ERROR;
request->OnError(rr);
delete rr;
rr = NULL;
}
@@ -409,7 +429,8 @@ bool DNSSocket::ProcessRead()
if (!inet_ntop(AF_INET6, &ip, ipbuf, sizeof(ipbuf)))
{
Log(LOG_DEBUG_2) << "Resolver: Received an invalid IP for DNS_QUERY_A: " << Anope::LastError();
request->OnError(DNS_ERROR_FORMAT_ERROR, "Received an invalid IP from the nameserver: " + Anope::LastError());
rr->error = DNS_ERROR_FORMAT_ERROR;
request->OnError(rr);
delete rr;
rr = NULL;
}
@@ -445,8 +466,9 @@ bool DNSSocket::ProcessRead()
break;
}
default:
rr->error = DNS_ERROR_INVALIDTYPE;
request->OnError(rr);
delete rr;
request->OnError(DNS_ERROR_INVALIDTYPE, "Invalid query type");
rr = NULL;
}
@@ -489,7 +511,7 @@ bool DNSSocket::ProcessWrite()
return cont;
}
DNSManager::DNSManager() : Timer(3600, Anope::CurTime, true)
DNSManager::DNSManager() : Timer(300, Anope::CurTime, true)
{
this->sock = NULL;
}
@@ -510,17 +532,22 @@ bool DNSManager::CheckCache(DNSRequest *request)
if (it != this->cache.end())
{
std::multimap<Anope::string, DNSRecord *>::iterator it_end = this->cache.upper_bound(request->address);
bool ret = false;
for (; it != it_end; ++it)
{
DNSRecord *rec = it->second;
if (rec->created + rec->ttl >= Anope::CurTime)
{
request->OnLookupComplete(rec);
if (rec->error == DNS_ERROR_NONE)
request->OnLookupComplete(rec);
else
request->OnError(rec);
ret = true;
}
}
return true;
return ret;
}
return false;
@@ -528,14 +555,18 @@ bool DNSManager::CheckCache(DNSRequest *request)
void DNSManager::Tick(time_t now)
{
for (std::multimap<Anope::string, DNSRecord *>::iterator it = this->cache.begin(), it_end = this->cache.end(); it != it_end; ++it)
Log(LOG_DEBUG_2) << "Resolver: Purging DNS cache";
for (std::multimap<Anope::string, DNSRecord *>::iterator it = this->cache.begin(), it_end = this->cache.end(); it != it_end;)
{
Anope::string host = it->first;
DNSRecord *req = it->second;
++it;
if (req->created + req->ttl < now)
{
this->cache.erase(host);
delete req;
this->cache.erase(it);
}
}
}
@@ -550,7 +581,9 @@ void DNSManager::Cleanup(Module *mod)
if (req->creator && req->creator == mod)
{
req->OnError(DNS_ERROR_UNLOADED, "Module is being unloaded");
DNSRecord rr(req->address);
rr.error = DNS_ERROR_UNLOADED;
req->OnError(&rr);
delete req;
this->requests.erase(id);
}
@@ -569,7 +602,9 @@ DNSRequestTimeout::~DNSRequestTimeout()
void DNSRequestTimeout::Tick(time_t)
{
this->done = true;
this->request->OnError(DNS_ERROR_TIMEOUT, "Request timed out");
DNSRecord rr(this->request->address);
rr.error = DNS_ERROR_TIMEOUT;
this->request->OnError(&rr);
delete this->request;
}